Merge remote-tracking branch 'origin/dev' into 44455-replace-weekdays-api-with-individual-nwd-days-api-in-gantt

pull/11934/head
Oliver Günther 2 years ago
commit c230ff2da7
No known key found for this signature in database
GPG Key ID: A3A8BDAD7C0C552C
  1. 6
      Gemfile.lock
  2. 19
      config/constants/settings/definition.rb
  3. 147
      config/constants/settings/definitions.rb
  4. 66
      config/locales/crowdin/ca.yml
  5. 8
      config/locales/crowdin/es.yml
  6. 72
      config/locales/crowdin/fr.yml
  7. 40
      config/locales/crowdin/js-ca.yml
  8. 16
      config/locales/crowdin/js-es.yml
  9. 40
      config/locales/crowdin/js-fr.yml
  10. 2
      docs/installation-and-operations/configuration/README.md
  11. 16
      docs/installation-and-operations/operation/upgrading/README.md
  12. 29
      docs/release-notes/12-4-3/README.md
  13. 7
      docs/release-notes/README.md
  14. 2
      docs/use-cases/portfolio-management/README.md
  15. 2
      docs/use-cases/resource-management/README.md
  16. 440
      frontend/package-lock.json
  17. 4
      frontend/package.json
  18. 11
      frontend/src/app/core/state/storage-files/storage-files.model.ts
  19. 83
      frontend/src/app/core/state/storage-files/storage-files.service.ts
  20. 18
      frontend/src/app/core/state/storage-files/storage-files.store.ts
  21. 6
      frontend/src/app/shared/components/datepicker/multi-date-modal/multi-date.modal.ts
  22. 4
      frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.html
  23. 19
      frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.ts
  24. 2
      frontend/src/app/shared/components/header-project-select/list/header-project-select-list.component.html
  25. 1
      frontend/src/app/shared/components/project-include/list/project-include-list.component.html
  26. 2
      frontend/src/app/shared/components/storages/file-link-list-item/file-link-list-item.html
  27. 8
      frontend/src/app/shared/components/storages/file-picker-base-modal.component.ts/file-picker-base-modal.component.ts
  28. 1
      frontend/src/app/shared/components/storages/file-picker-modal/file-picker-modal.component.ts
  29. 5
      frontend/src/app/shared/components/storages/location-picker-modal/location-picker-modal.component.ts
  30. 3
      frontend/src/app/shared/components/storages/storage-file-list-item/storage-file-list-item.html
  31. 9
      frontend/src/app/shared/components/storages/storage-file-list-item/storage-file-list-item.ts
  32. 2
      lib/redmine/menu_manager/top_menu/projects_menu.rb
  33. 3
      lib/tasks/setting.rake
  34. 8
      modules/backlogs/config/locales/crowdin/be.yml
  35. 4
      modules/boards/config/locales/crowdin/js-ca.yml
  36. 2
      modules/boards/config/locales/crowdin/js-es.yml
  37. 4
      modules/boards/config/locales/crowdin/js-fr.yml
  38. 4
      modules/grids/config/locales/crowdin/js-ca.yml
  39. 2
      modules/grids/config/locales/crowdin/js-es.yml
  40. 4
      modules/grids/config/locales/crowdin/js-fr.yml
  41. 9
      modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb
  42. 8
      modules/storages/app/models/storages/storage_files.rb
  43. 2
      modules/storages/app/views/storages/project_settings/index.html.erb
  44. 2
      modules/storages/config/locales/crowdin/af.yml
  45. 2
      modules/storages/config/locales/crowdin/ar.yml
  46. 2
      modules/storages/config/locales/crowdin/az.yml
  47. 2
      modules/storages/config/locales/crowdin/be.yml
  48. 2
      modules/storages/config/locales/crowdin/bg.yml
  49. 2
      modules/storages/config/locales/crowdin/ca.yml
  50. 2
      modules/storages/config/locales/crowdin/ckb-IR.yml
  51. 2
      modules/storages/config/locales/crowdin/cs.yml
  52. 2
      modules/storages/config/locales/crowdin/da.yml
  53. 2
      modules/storages/config/locales/crowdin/de.yml
  54. 2
      modules/storages/config/locales/crowdin/el.yml
  55. 2
      modules/storages/config/locales/crowdin/eo.yml
  56. 4
      modules/storages/config/locales/crowdin/es.yml
  57. 2
      modules/storages/config/locales/crowdin/et.yml
  58. 2
      modules/storages/config/locales/crowdin/eu.yml
  59. 2
      modules/storages/config/locales/crowdin/fa.yml
  60. 2
      modules/storages/config/locales/crowdin/fi.yml
  61. 2
      modules/storages/config/locales/crowdin/fil.yml
  62. 2
      modules/storages/config/locales/crowdin/fr.yml
  63. 2
      modules/storages/config/locales/crowdin/he.yml
  64. 2
      modules/storages/config/locales/crowdin/hi.yml
  65. 2
      modules/storages/config/locales/crowdin/hr.yml
  66. 2
      modules/storages/config/locales/crowdin/hu.yml
  67. 2
      modules/storages/config/locales/crowdin/id.yml
  68. 2
      modules/storages/config/locales/crowdin/it.yml
  69. 2
      modules/storages/config/locales/crowdin/ja.yml
  70. 20
      modules/storages/config/locales/crowdin/js-ca.yml
  71. 4
      modules/storages/config/locales/crowdin/js-es.yml
  72. 10
      modules/storages/config/locales/crowdin/js-fr.yml
  73. 2
      modules/storages/config/locales/crowdin/js-ru.yml
  74. 2
      modules/storages/config/locales/crowdin/ko.yml
  75. 2
      modules/storages/config/locales/crowdin/lol.yml
  76. 2
      modules/storages/config/locales/crowdin/lt.yml
  77. 2
      modules/storages/config/locales/crowdin/lv.yml
  78. 2
      modules/storages/config/locales/crowdin/ne.yml
  79. 2
      modules/storages/config/locales/crowdin/nl.yml
  80. 2
      modules/storages/config/locales/crowdin/no.yml
  81. 2
      modules/storages/config/locales/crowdin/pl.yml
  82. 2
      modules/storages/config/locales/crowdin/pt.yml
  83. 2
      modules/storages/config/locales/crowdin/ro.yml
  84. 4
      modules/storages/config/locales/crowdin/ru.yml
  85. 2
      modules/storages/config/locales/crowdin/rw.yml
  86. 2
      modules/storages/config/locales/crowdin/si.yml
  87. 2
      modules/storages/config/locales/crowdin/sk.yml
  88. 2
      modules/storages/config/locales/crowdin/sl.yml
  89. 2
      modules/storages/config/locales/crowdin/sv.yml
  90. 2
      modules/storages/config/locales/crowdin/th.yml
  91. 2
      modules/storages/config/locales/crowdin/tr.yml
  92. 2
      modules/storages/config/locales/crowdin/uk.yml
  93. 2
      modules/storages/config/locales/crowdin/vi.yml
  94. 2
      modules/storages/config/locales/crowdin/zh-TW.yml
  95. 2
      modules/storages/config/locales/en.yml
  96. 3
      modules/storages/lib/api/v3/storage_files/storage_files_api.rb
  97. 49
      modules/storages/lib/api/v3/storage_files/storage_files_representer.rb
  98. 45
      modules/storages/spec/common/peripherals/storage_requests_spec.rb
  99. 88
      modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb
  100. 34
      modules/storages/spec/requests/api/v3/storages/storage_files_spec.rb
  101. Some files were not shown because too many files have changed in this diff Show More

@ -291,7 +291,7 @@ GEM
awesome_nested_set (3.5.0)
activerecord (>= 4.0.0, < 7.1)
aws-eventstream (1.2.0)
aws-partitions (1.697.0)
aws-partitions (1.701.0)
aws-sdk-core (3.169.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
@ -300,7 +300,7 @@ GEM
aws-sdk-kms (1.62.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.118.0)
aws-sdk-s3 (1.119.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@ -901,7 +901,7 @@ GEM
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
secure_headers (6.5.0)
selenium-webdriver (4.7.1)
selenium-webdriver (4.8.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)

@ -36,10 +36,12 @@ module Settings
:env_alias
attr_writer :value,
:description,
:allowed
def initialize(name,
default:,
description: nil,
format: nil,
writable: true,
allowed: nil,
@ -52,6 +54,7 @@ module Settings
self.writable = writable
self.allowed = allowed
self.env_alias = env_alias
self.description = description.presence || :"setting_#{name}"
end
def default
@ -62,6 +65,14 @@ module Settings
cast(@value)
end
def description
if @description.is_a?(Symbol)
I18n.t(@description, default: nil)
else
@description
end
end
def serialized?
%i[array hash].include?(format)
end
@ -124,6 +135,7 @@ module Settings
# @param [Object] default The default value the setting has if not overridden.
# @param [nil] format The format the value is in e.g. symbol, array, hash, string. If a value is present,
# the format is deferred.
# @param [nil] description A human-readable description of this setting.
# @param [TrueClass] writable Whether the value can be set in the UI. In case the value is set via file or ENV var,
# this will be set to false later on and UI elements that refer to the definition will be disabled.
# @param [nil] allowed The array of allowed values that can be assigned to the definition.
@ -136,6 +148,7 @@ module Settings
def add(name,
default:,
format: nil,
description: nil,
writable: true,
allowed: nil,
env_alias: nil)
@ -145,6 +158,7 @@ module Settings
definition = new(name,
format:,
description:,
default:,
writable:,
allowed:,
@ -274,8 +288,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
@ -329,6 +343,7 @@ module Settings
env_name_alias(definition)
].compact
end
public :possible_env_names
def env_name_nested(definition)

@ -39,24 +39,29 @@ Settings::Definition.define do
add :after_first_login_redirect_url,
format: :string,
description: 'URL users logging in for the first time will be redirected to (e.g., a help screen)',
default: nil,
writable: false
add :after_login_default_redirect_url,
description: 'Override URL to which logged in users are redirected instead of the My page',
format: :string,
default: nil,
writable: false
add :apiv3_cors_enabled,
description: 'Enable CORS headers for APIv3 server responses',
default: false
add :apiv3_cors_origins,
default: []
add :apiv3_docs_enabled,
description: 'Enable interactive APIv3 documentation as part of the application',
default: true
add :apiv3_enable_basic_auth,
description: 'Enable API token or global basic authentication for APIv3 requests',
default: true,
writable: false
@ -77,21 +82,25 @@ Settings::Definition.define do
# Carrierwave storage type. Possible values are, among others, :file and :fog.
# The latter requires further configuration.
add :attachments_storage,
description: 'File storage configuration',
default: :file,
format: :symbol,
allowed: %i[file fog],
writable: false
add :attachments_storage_path,
description: 'File storage disk location (only applicable for local file storage)',
format: :string,
default: nil,
writable: false
add :attachments_grace_period,
description: 'Time to wait before uploaded files not attached to any container are removed',
default: 180,
writable: false
add :auth_source_sso,
description: 'Configuration for Header-based Single Sign-On',
format: :hash,
default: nil,
writable: false
@ -104,6 +113,7 @@ Settings::Definition.define do
# user: admin
# password: 123456
add :authentication,
description: 'Configuration options for global basic auth',
format: :hash,
default: nil,
writable: false
@ -117,14 +127,17 @@ Settings::Definition.define do
default: 0
add :autologin_cookie_name,
description: 'Cookie name for autologin cookie',
default: 'autologin',
writable: false
add :autologin_cookie_path,
description: 'Cookie path for autologin cookie',
default: '/',
writable: false
add :autologin_cookie_secure,
description: 'Cookie secure mode for autologin cookie',
default: false,
writable: false
@ -134,32 +147,39 @@ Settings::Definition.define do
allowed: -> { Redmine::I18n.all_languages }
add :avatar_link_expiry_seconds,
description: 'Cache duration for avatar image API responses',
default: 24.hours.to_i,
writable: false
# Allow users with the required permissions to create backups via the web interface or API.
add :backup_enabled,
description: 'Enable application backups through the UI',
default: true,
writable: false
add :backup_daily_limit,
description: 'Maximum number of application backups allowed per day',
default: 3,
writable: false
add :backup_initial_waiting_period,
description: 'Wait time before newly created backup tokens are usable',
default: 24.hours,
format: :integer,
writable: false
add :backup_include_attachments,
description: 'Allow inclusion of attachments in application backups',
default: true,
writable: false
add :backup_attachment_size_max_sum_mb,
description: 'Maximum limit of attachment size to include into application backups',
default: 1024,
writable: false
add :blacklisted_routes,
description: 'Blocked routes to prevent access to certain modules or pages',
default: [],
writable: false
@ -167,15 +187,19 @@ Settings::Definition.define do
default: true
add :boards_demo_data_available,
description: 'Internal setting determining availability of demo seed data',
default: false
add :brute_force_block_minutes,
description: 'Number of minutes to block users after presumed brute force attack',
default: 30
add :brute_force_block_after_failed_logins,
description: 'Number of login attempts per user before assuming brute force attack',
default: 20
add :cache_expires_in_seconds,
description: 'Expiration time for memcache entries, empty for no expiry be default',
format: :integer,
default: nil,
writable: false
@ -185,39 +209,47 @@ Settings::Definition.define do
# use dalli defaults for memcache
add :cache_memcache_server,
description: 'The memcache server host and IP',
format: :string,
default: nil,
writable: false
add :cache_namespace,
format: :string,
description: 'Namespace for cache keys, useful when multiple applications use a single memcache server',
default: nil,
writable: false
add :commit_fix_done_ratio,
description: 'Progress to apply when commit fixes work package',
default: 100
add :commit_fix_keywords,
description: 'Keywords to look for in commit for fixing work packages',
default: 'fixes,closes'
add :commit_fix_status_id,
description: 'Assigned status when fixing keyword is found',
format: :integer,
default: nil,
allowed: -> { Status.pluck(:id) + [nil] }
# encoding used to convert commit logs to UTF-8
add :commit_logs_encoding,
description: "Encoding used to convert commit logs to UTF-8",
default: 'UTF-8'
add :commit_logtime_activity_id,
description: :setting_commit_logtime_activity_id,
format: :integer,
default: nil,
allowed: -> { TimeEntryActivity.pluck(:id) + [nil] }
add :commit_logtime_enabled,
description: "Allow logging time through commit message",
default: false
add :commit_ref_keywords,
description: "Keywords used in commits for referencing work packages",
default: 'refs,references,IssueID'
add :consent_decline_mail,
@ -234,7 +266,7 @@ Settings::Definition.define do
add :consent_info,
default: {
en: "## Consent\n\nYou need to agree to the [privacy and security policy]" +
"(https://www.openproject.org/data-privacy-and-security/) of this OpenProject instance."
"(https://www.openproject.org/data-privacy-and-security/) of this OpenProject instance."
}
# Indicates whether or not users need to consent to something such as privacy policy.
@ -246,10 +278,12 @@ Settings::Definition.define do
# Allow in-context translations to be loaded with CSP
add :crowdin_in_context_translations,
description: 'Add crowdin in-context translations helper',
default: true,
writable: false
add :database_cipher_key,
description: 'Encryption key for repository credentials',
format: :string,
default: nil,
writable: false
@ -270,10 +304,12 @@ Settings::Definition.define do
].freeze
add :default_auto_hide_popups,
description: 'Whether to automatically hide success notifications by default',
default: true
# user configuration
add :default_comment_sort_order,
description: 'Default sort order for activities',
default: 'asc',
writable: false
@ -299,55 +335,59 @@ Settings::Definition.define do
add :diff_max_lines_displayed,
default: 1500
# only applicable in conjunction with fog (effectively S3) attachments
# which will be uploaded directly to the cloud storage rather than via OpenProject's
# server process.
add :direct_uploads,
description: 'Enable direct uploads to AWS S3. Only applicable with enabled Fog / AWS S3 configuration',
default: true,
writable: false
add :disable_browser_cache,
description: 'Prevent browser from caching any logged-in responses for security reasons',
default: true,
writable: false
# allow to disable default modules
add :disabled_modules,
description: 'A list of module names to prevent access to in the application',
default: [],
writable: false
add :disable_password_choice,
description: "If enabled a user's password cannot be set to an arbitrary value, but can only be randomized.",
default: false,
writable: false
add :disable_password_login,
description: 'Disable internal logins and instead only allow SSO through OmniAuth.',
default: false,
writable: false
add :display_subprojects_work_packages,
default: true
# Destroy all sessions for current_user on logout
add :drop_old_sessions_on_logout,
description: 'Destroy all sessions for current_user on logout',
default: true,
writable: false
# Destroy all sessions for current_user on login
add :drop_old_sessions_on_login,
description: 'Destroy all sessions for current_user on login',
default: false,
writable: false
add :edition,
format: :string,
default: 'standard',
description: 'OpenProject edition mode',
writable: false,
allowed: %w[standard bim]
add :ee_manager_visible,
description: 'Show or hide the Enterprise configuration page and enterprise banners',
default: true,
writable: false
# Enable internal asset server
add :enable_internal_assets_server,
description: 'Serve assets through the Rails internal asset server',
default: false,
writable: false
@ -386,14 +426,17 @@ Settings::Definition.define do
# Allow connections for trial creation and booking
add :enterprise_trial_creation_host,
description: 'Host for EE trial service',
default: 'https://augur.openproject.com',
writable: false
add :enterprise_chargebee_site,
description: 'Site name for EE trial service',
default: 'openproject-enterprise',
writable: false
add :enterprise_plan,
description: 'Default EE selected plan',
default: 'enterprise-on-premises---euro---1-year',
writable: false
@ -413,26 +456,30 @@ Settings::Definition.define do
format: :integer,
allowed: [1, 4]
# Configure fog, e.g. when using an S3 uploader
add :fog,
description: 'Configure fog, e.g. when using an S3 uploader',
default: {}
add :fog_download_url_expires_in,
description: 'Expiration time in seconds of created shared presigned URLs',
default: 21600, # 6h by default as 6 hours is max in S3 when using IAM roles
writable: false
# Additional / overridden help links
add :force_help_link,
description: 'You can set a custom URL for the help button in application header menu.',
format: :string,
default: nil,
writable: false
add :force_formatting_help_link,
description: 'You can set a custom URL for the help button in the WYSIWYG editor.',
format: :string,
default: nil,
writable: false
add :forced_single_page_size,
description: 'Forced page size for manually sorted work package views',
default: 250
add :host_name,
@ -440,6 +487,7 @@ Settings::Definition.define do
# Health check configuration
add :health_checks_authentication_password,
description: 'Add an authentication challenge for the /health_check endpoint',
format: :string,
default: nil,
writable: false
@ -447,18 +495,21 @@ Settings::Definition.define do
# Maximum number of backed up jobs (that are not yet executed)
# before health check fails
add :health_checks_jobs_queue_count_threshold,
description: 'Set threshold of backed up background jobs to fail health check',
format: :integer,
default: 50,
writable: false
## Maximum number of minutes that jobs have not yet run after their designated 'run_at' time
add :health_checks_jobs_never_ran_minutes_ago,
description: 'Set threshold of outstanding background jobs to fail health check',
format: :integer,
default: 5,
writable: false
## Maximum number of unprocessed requests in puma's backlog.
add :health_checks_backlog_threshold,
description: 'Set threshold of outstanding HTTP requests to fail health check',
format: :integer,
default: 20,
writable: false
@ -466,15 +517,17 @@ Settings::Definition.define do
# Default gravatar image, set to something other than 404
# to ensure a default is returned
add :gravatar_fallback_image,
description: 'Set default gravatar image fallback',
default: '404',
writable: false
add :hidden_menu_items,
description: 'Hide menu items in the menu sidebar for each main menu (such as Administration and Projects).',
default: {},
writable: false
# Impressum link to be set, nil by default (= hidden)
add :impressum_link,
description: 'Impressum link to be set, hidden by default',
format: :string,
default: nil,
writable: false
@ -488,6 +541,7 @@ Settings::Definition.define do
default: nil
add :internal_password_confirmation,
description: 'Require password confirmations for certain administrative actions',
default: true,
writable: false
@ -497,24 +551,24 @@ Settings::Definition.define do
add :journal_aggregation_time_minutes,
default: 5
# Allow override of LDAP options
add :ldap_force_no_page,
description: 'Force LDAP to respond as a single page, in case paged responses do not work with your server.',
format: :string,
default: nil,
writable: false
# Allow users to manually sync groups in a different way
# than the provided job using their own cron
add :ldap_groups_disable_sync_job,
description: 'Deactivate regular synchronization job for groups in case scheduled as a separate cronjob',
default: false,
writable: false
add :ldap_users_disable_sync_job,
description: 'Deactive user attributes synchronization from LDAP',
default: false,
writable: false
# Update users' status through the synchronization job
add :ldap_users_sync_status,
description: 'Enable user status (locked/unlocked) synchronization from LDAP',
format: :boolean,
default: false,
writable: false
@ -525,7 +579,9 @@ Settings::Definition.define do
writable: true
add :log_level,
description: 'Set the OpenProject logger level',
default: Rails.env.development? ? 'debug' : 'info',
allowed: %w[debug info warn error fatal],
writable: false
add :log_requesting_user,
@ -533,6 +589,7 @@ Settings::Definition.define do
# Use lograge to format logs, off by default
add :lograge_formatter,
description: 'Use lograge formatter for outputting logs',
default: nil,
format: :string,
writable: false
@ -541,6 +598,7 @@ Settings::Definition.define do
default: false
add :lost_password,
description: 'Activate or deactivate lost password form',
default: true
add :mail_from,
@ -564,10 +622,13 @@ Settings::Definition.define do
add :main_content_language,
default: 'english',
writable: false
description: 'Main content language for PostgreSQL full text features',
writable: false,
allowed: %w[danish dutch english finnish french german hungarian
italian norwegian portuguese romanian russian simple spanish swedish turkish]
# Check for missing migrations in internal errors
add :migration_check_on_exceptions,
description: 'Check for missing migrations in internal errors',
default: true,
writable: false
@ -578,29 +639,29 @@ Settings::Definition.define do
allowed: -> { Role.pluck(:id) }
add :oauth_allow_remapping_of_existing_users,
description: 'When set to false, prevent users from other identity providers to take over accounts connected ' \
'to another identity provider.',
default: true
add :omniauth_direct_login_provider,
description: 'Clicking on login sends a login request to the specified OmniAuth provider.',
format: :string,
default: nil,
writable: false
add :override_bcrypt_cost_factor,
description: "Set a custom BCrypt cost factor for deriving a user's bcrypt hash.",
format: :string,
default: nil,
writable: false
add :notification_email_delay_minutes,
default: 15
add :notification_email_digest_time,
default: '08:00'
add :onboarding_video_url,
description: 'Onboarding guide instructional video URL',
default: 'https://player.vimeo.com/video/163426858?autoplay=1',
writable: false
add :onboarding_enabled,
description: 'Enable or disable onboarding guided tour for new users',
default: true,
writable: false
@ -634,30 +695,31 @@ Settings::Definition.define do
format: :string
add :rails_asset_host,
description: 'Custom asset hostname for serving assets (e.g., Cloudfront)',
format: :string,
default: nil,
writable: false
add :rails_cache_store,
description: 'Set cache store implemenation to use with OpenProject',
format: :symbol,
default: :file_store,
writable: false,
allowed: %i[file_store memcache]
# url-path prefix
add :rails_relative_url_root,
description: 'Set a URL prefix / base path to run OpenProject under, e.g., host.tld/openproject',
default: '',
writable: false
# Assume we're running in an TLS terminated connection.
add :https,
description: 'Set assumed connection security for the Rails processes',
format: :boolean,
default: -> { Rails.env.production? },
writable: false
# Allow disabling of HSTS headers and http -> https redirects
# for non-localhost hosts
add :hsts,
description: 'Allow disabling of HSTS headers and http -> https redirects',
format: :boolean,
default: true,
writable: false
@ -668,7 +730,9 @@ Settings::Definition.define do
},
writable: false
add :report_incoming_email_errors, default: true
add :report_incoming_email_errors,
description: 'Respond to incoming mails with error details',
default: true
add :repositories_automatic_managed_vendor,
default: nil,
@ -726,6 +790,7 @@ Settings::Definition.define do
default: true
add :security_badge_url,
description: 'URL of the update check badge',
default: "https://releases.openproject.com/v1/check.svg",
writable: false
@ -733,11 +798,13 @@ Settings::Definition.define do
default: 2
add :sendmail_arguments,
description: 'Arguments to call sendmail with in case it is configured as outgoing email setup',
format: :string,
default: "-i",
writable: false
add :sendmail_location,
description: 'Location of sendmail to call if it is configured as outgoing email setup',
format: :string,
default: "/usr/sbin/sendmail"
@ -745,14 +812,16 @@ Settings::Definition.define do
add :appsignal_frontend_key,
format: :string,
default: nil,
description: 'Appsignal API key for JavaScript error reporting',
writable: false
add :session_cookie_name,
description: 'Set session cookie name',
default: '_open_project_session',
writable: false
# where to store session data
add :session_store,
description: 'Where to store session data',
default: :active_record_store,
writable: false
@ -763,28 +832,28 @@ Settings::Definition.define do
default: 120
add :show_community_links,
description: 'Enable or disable links to OpenProject community instances',
default: true,
writable: false
# Show pending migrations as warning bar
add :show_pending_migrations_warning,
description: 'Enable or disable warning bar in case of pending migrations',
default: true,
writable: false
# Show mismatched protocol/hostname warning
# in settings where they must differ this can be disabled
add :show_setting_mismatch_warning,
description: 'Show mismatched protocol/hostname warning. In cases where they must differ this can be disabled',
default: true,
writable: false
# Render storage information
add :show_storage_information,
description: 'Show available and taken storage information under administration / info',
default: true,
writable: false
# Render warning bars (pending migrations, deprecation, unsupported browsers)
# Set to false to globally disable this for all users!
add :show_warning_bars,
description: 'Render warning bars (pending migrations, deprecation, unsupported browsers)',
default: true,
writable: false
@ -799,6 +868,7 @@ Settings::Definition.define do
env_alias: 'SMTP_ENABLE_STARTTLS_AUTO'
add :smtp_openssl_verify_mode,
description: 'Globally set verify mode for OpenSSL. Careful: Setting to none will disable any SSL verification!',
format: :string,
default: "peer",
allowed: %w[none peer client_once fail_if_no_peer_cert],
@ -835,13 +905,15 @@ Settings::Definition.define do
env_alias: 'SMTP_PASSWORD'
add :software_name,
description: 'Override software application name',
default: 'OpenProject'
add :software_url,
description: 'Override software application URL',
default: 'https://www.openproject.org/'
# Slow query logging threshold in ms
add :sql_slow_query_threshold,
description: 'Time limit in ms after which queries will be logged as slow queries',
default: 2000,
writable: false
@ -850,8 +922,8 @@ Settings::Definition.define do
format: :integer,
allowed: [1, 6, 7]
# enable statsd metrics (currently puma only) by configuring host
add :statsd,
description: 'enable statsd metrics (currently puma only) by configuring host',
default: {
'host' => nil,
'port' => 8125
@ -859,9 +931,11 @@ Settings::Definition.define do
writable: false
add :sys_api_enabled,
description: 'Enable internal system API for setting up managed repositories',
default: false
add :sys_api_key,
description: 'Internal system API key for setting up managed repositories',
default: nil,
format: :string
@ -889,6 +963,7 @@ Settings::Definition.define do
allowed: -> { User::USER_FORMATS_STRUCTURE.keys }
add :web,
description: 'Web worker count and threads configuration',
default: {
'workers' => 2,
'timeout' => 120,
@ -936,11 +1011,13 @@ Settings::Definition.define do
default: false
add :working_days,
description: 'Set working days of the week (Array of 1 to 7, where 1=Monday, 7=Sunday)',
format: :array,
allowed: Array(1..7),
default: Array(1..5) # Sat, Sun being non-working days
add :youtube_channel,
description: 'Link to YouTube channel in help menu',
default: 'https://www.youtube.com/c/OpenProjectCommunity',
writable: false
end

@ -49,7 +49,7 @@ ca:
main-menu-border-color: "Vora del menú principal"
custom_colors: "Colors personalitzats"
customize: "Personalitza la teva instal·lació d'OpenProject amb el teu propi logotip i colors."
enterprise_notice: "As a special 'Thank you!' for their financial contribution to develop OpenProject, this tiny add-on is only available for Enterprise edition support subscribers."
enterprise_notice: "Com un \"Gràcies!\" especial per la contribució financera al desenvolupament d'OpenProject, aquest petit add-on només està disponible pels subscriptors de l'edició Enterprise."
enterprise_more_info: "Nota: el logotip utilitzat serà accessible públicament."
manage_colors: "Edita les opcions de selecció de colors"
instructions:
@ -64,15 +64,15 @@ ca:
main-menu-bg-color: "Color de fons del menú lateral de l'esquerra."
theme_warning: Canviant el tema substituiràs el teu estil personalitzat. El disseny es perdrà. Estàs segur que vols continuar?
enterprise:
upgrade_to_ee: "Upgrade to the Enterprise edition"
add_token: "Upload an Enterprise edition support token"
upgrade_to_ee: "Actualitza a l'edició Enterprise"
add_token: "Carrega un token de suport de l'edició Enterprise"
delete_token_modal:
text: "Are you sure you want to remove the current Enterprise edition token used?"
text: "Estàs segur que vols eliminar el token de l'edició Enterprise utilitzat?"
title: "Eliminar el token"
replace_token: "Substitueix el teu token de suport actual"
order: "Order Enterprise on-premises edition"
paste: "Paste your Enterprise edition support token"
required_for_feature: "This add-on is only available with an active Enterprise edition support token."
order: "Ordena l'edició Enterpise on-premises"
paste: "Enganxa el teu token de suport de l'edició Enterprise"
required_for_feature: "Aquest add-om només està disponible amb un token de suport de l'edició Enterprise."
enterprise_link: "Per a més informació, cliqueu aquí."
start_trial: 'Inicia la prova gratuïta'
book_now: 'Reserva ara'
@ -80,7 +80,7 @@ ca:
buttons:
upgrade: "Actualitza ara"
contact: "Contacta amb nosaltres per una demostració"
enterprise_info_html: "is an Enterprise <span class='spot-icon spot-icon_enterprise-addons'></span> add-on."
enterprise_info_html: "és un add-on de l'edició Enterprise <span class='spot-icon spot-icon_enterprise-badge'></span>."
upgrade_info: "Si us plau, actualitza a una versió de pagament per tal d'activar i començar a utilitzar aquesta funcionalitat en el teu equip."
journal_aggregation:
explanation:
@ -319,7 +319,7 @@ ca:
settings: "Configuració"
form_configuration: "Configuració del formulari"
more_info_text_html: >
Enterprise edition allows you to customize form configuration with these additional add-ons: <br> <ul class="%{list_styling_class}"> <li><b>Add new attribute groups</b></li> <li><b>Rename attribute groups</b></li> <li><b>Add a table of related work packages</b></li> </ul>
L'edició Enterprise et permet personalitzar la configuració de formularis amb aquests add-ons extra: <br> <ul class="%{list_styling_class}"><ul class="%{list_styling_class}"> <li><b>Afegeix nous grups d'atributs</b></li> <li><b>Canvia el nom dels grups d'atributs</b></li> <li><b>Afegeix una taula de paquets de treball relacionats</b></li> </ul>
projects: "Projectes"
enabled_projects: "Projectes habilitats"
edit_query: "Edita la taula"
@ -333,7 +333,7 @@ ca:
wiki:
page_not_editable_index: La pàgina sol·licitada no existeix (encara). Se t'ha redirigit a la pàgina índex de totes les pàgines wiki.
no_results_title_text: Actualment no hi ha cap pàgina wiki.
print_hint: This will print the content of this wiki page without any navigation bars.
print_hint: Aquesta acció imprimirà el contingut de la pàgina wiki sense cap barra de navegació.
index:
no_results_content_text: Afegiu una nova pàgina wiki
work_flows:
@ -372,7 +372,7 @@ ca:
account:
delete: "Elimina el compte"
delete_confirmation: "Segur que vols eliminar aquest compte?"
deletion_pending: "Account has been locked and was scheduled for deletion. Note that this process takes place in the background. It might take a few moments until the user is fully deleted."
deletion_pending: "El compte ha estat bloquejat i està programada per eliminar-se. Tingues en compte que aquesta acció es processa de fons. Pot tardar uns moments fins que l'usuari estigui eliminat completament."
deletion_info:
data_consequences:
other: "De les dades de l'usuari ha creat (per exemple, correu electrònic, preferències, paquets de treball, wiki entrades) se n'esborraran tantes com sigui possible. Fixeu-vos que dades com paquets de treball i entrades de la wiki no es poden suprimir sense que obstaculitzin la feina d'altres usuaris. Aquestes dades es reassignaran a un compte genèric anomenat \"Usuari esborrat\". Com que les dades de cada usuari suprimit es reassignen sempre a aquest compte genèric no serà possible distingir les dades d'aquest usuari de les dades d'un altre usuari esborrat."
@ -584,7 +584,7 @@ ca:
confirmation: "no coincideix amb el %{attribute}."
could_not_be_copied: "%{dependency} no s'ha pogut copiar (completament)."
does_not_exist: "no existeix."
error_enterprise_only: "%{action} is only available in the OpenProject Enterprise edition"
error_enterprise_only: "%{action} només està disponible en l'edició Enterprise d'OpenProject"
error_unauthorized: "no és possible accedir."
error_readonly: "es va intentar d'escriure-hi però no és modificable."
email: "no és una adreça de correu electrònic vàlida."
@ -634,7 +634,7 @@ ca:
auth_source:
attributes:
tls_certificate_string:
invalid_certificate: "The provided SSL certificate is invalid: %{additional_message}"
invalid_certificate: "El certificat SSL proporcionat és invàlid: %{additional_message}"
format: "%{message}"
attachment:
attributes:
@ -689,7 +689,7 @@ ca:
non_working_day:
attributes:
date:
taken: "A non-working day already exists for %{value}."
taken: "Un dia no laborable ja existeix el %{value}."
format: "%{message}"
parse_schema_filter_params_service:
attributes:
@ -702,7 +702,7 @@ ca:
foreign_wps_reference_version: 'Els paquets de treball en projectes no descendents referencien versions del projecte o els seus descendents.'
attributes:
base:
archive_permission_missing_on_subprojects: "You do not have the permissions required to archive all sub-projects. Please contact an administrator."
archive_permission_missing_on_subprojects: "No tens els permisos requerits per arxivar tots els subprojectes. Si us plau, contacta amb un administrador."
types:
in_use_by_work_packages: "encara en ús pels paquets de treball: %{types}"
enabled_modules:
@ -1267,11 +1267,11 @@ ca:
ee:
upsale:
form_configuration:
description: "Customize the form configuration with these additional add-ons:"
description: "Personalitza la configuració del formulari amb aquests add-ons extres:"
add_groups: "Afegir un nou atribut de grups"
rename_groups: "Canviar de nom atribut de grups"
project_filters:
description_html: "Filtering and sorting on custom fields is an Enterprise edition add-on."
description_html: "Filtrar i ordenar camps personalitzats és un add-on de l'edició Enterprise."
enumeration_activities: "Activitats de rastrejament del temps"
enumeration_work_package_priorities: "Prioritats dels paquets de treball"
enumeration_reported_project_statuses: "Estats de projecte notificats"
@ -1293,7 +1293,7 @@ ca:
error_cookie_missing: 'La cookie d''OpenProject no s''ha trobat. Assegureu-vos que les cookies estan habilitades, ja que aquesta aplicació no pot funcionar correctament sense.'
error_custom_option_not_found: "L'opció no existeix."
error_enterprise_activation_user_limit: "El teu compte no s'ha pogut activar (límit d'usuaris assolit). Si us plau, contacte amb el teu administrador per obtenir accés."
error_enterprise_token_invalid_domain: "The Enterprise edition is not active. Your Enterprise token's domain (%{actual}) does not match the system's host name (%{expected})."
error_enterprise_token_invalid_domain: "L'edició Enterprise no està activa. El domini del token Enterprise (%{actual}) no concorda amb el nom d'allotjament del sistema (%{expected})."
error_failed_to_delete_entry: 'Error a l''eliminar aquesta entrada.'
error_in_dependent: "Error en intentar alterar objectes dependents: %{dependent_class} #%{related_id} -%{related_subject}: %{error}" #%{related_id} -%{related_subject}: %{error}"
error_in_new_dependent: "Error en intentar crear objectes dependents: %{dependent_class} #%{related_id} -%{related_subject}: %{error}" #%{related_id} -%{related_subject}: %{error}"
@ -1331,8 +1331,8 @@ ca:
changeset: 'Conjunt de canvis editat'
message: Missatge editat
news: Notícies
project_attributes: 'Project attributes edited'
projects: 'Project edited'
project_attributes: 'Atributs del projecte editats'
projects: 'Projecte editat'
reply: Respost
time_entry: 'Registre horari editat'
wiki_page: 'Pàgina wiki editada'
@ -1340,7 +1340,7 @@ ca:
work_package_edit: 'Paquet de treball editat'
work_package_note: 'Afegida nota al paquet de treball'
title:
project: "Project: %{name}"
project: "Projecte: %{name}"
export:
your_work_packages_export: "La teva exportació de paquets de treball"
succeeded: "L'exportació s'ha completat amb èxit."
@ -1384,10 +1384,10 @@ ca:
blocks:
community: "Comunitat OpenProject"
upsale:
title: "Upgrade to Enterprise edition"
title: "Actualitza a l'edició Enterprise"
more_info: "Més informació"
links:
upgrade_enterprise_edition: "Upgrade to Enterprise edition"
upgrade_enterprise_edition: "Actualitza a l'edició Enterprise"
postgres_migration: "Migrant la teva instal·lació a PostgreSQL"
user_guides: "Guies d'usuari"
faq: "Preguntes Més Freqüents"
@ -1603,7 +1603,7 @@ ca:
label_enumerations: "Enumeracions"
label_enterprise: "Enterprise"
label_enterprise_active_users: "%{current}/%{limit} usuaris actius registrats"
label_enterprise_edition: "Enterprise edition"
label_enterprise_edition: "Edició Enterprise."
label_environment: "Entorn"
label_estimates_and_time: "Estimacions i temps"
label_equals: "és"
@ -1793,8 +1793,8 @@ ca:
label_product_version: "Versió del producte"
label_professional_support: "Suport professional"
label_profile: "Perfil"
label_project_activity: "Project activity"
label_project_attribute_plural: "Project attributes"
label_project_activity: "Activitat del projecte"
label_project_attribute_plural: "Atributs de projecte"
label_project_count: "Nombre total de projectes"
label_project_copy_notifications: "Envia notificacions de correu electrònic durant la còpia del projecte"
label_project_latest: "Últims projectes"
@ -2212,7 +2212,7 @@ ca:
permission_add_work_packages: "Afegir paquets de treball"
permission_add_messages: "Publicar missatges"
permission_add_project: "Crear un projecte"
permission_archive_project: "Archive project"
permission_archive_project: "Arxiva el projecte"
permission_manage_user: "Crear i editar usuaris"
permission_manage_placeholder_user: "Crea, edita i elimina usuaris de marcador de posició"
permission_add_subprojects: "Crear subprojectes"
@ -2612,11 +2612,11 @@ ca:
text_custom_field_hint_activate_per_project_and_type: >
Els camps personalitzats han d'activar-se per classe de paquet de treball i per projecte.
text_wp_custom_field_html: >
The Enterprise edition will add these additional add-ons for work packages' custom fields: <br> <ul> <li><b>Allow multi-select for custom fields of type List or User</b></li> </ul>
L'edició Enterprise afegirà add-ons extra pels camps personalitzats de paquets de treball: <br> <ul> <li><b>Permet múltiple selecció dels camps personalitzats pels estils Llista o Usuari</b></li> </ul>
text_wp_status_read_only_html: >
The Enterprise edition will add these additional add-ons for work packages' statuses fields: <br> <ul> <li><b>Allow to mark work packages to read-only for specific statuses</b></li> </ul>
L'edició Enterprise afegirà add-ons extra pels estats de paquets de treball: <br> <ul> <li><b>Permet marcar paquets de treball com a només lectura per a estats específics</b></li> </ul>
text_project_custom_field_html: >
The Enterprise edition will add these additional add-ons for projects' custom fields: <br> <ul> <li><b>Add custom fields for projects to your Project list to create a project portfolio view</b></li> </ul>
L'edició Enterprise afegirà add-ons extra pels camps personalitzats de projectes: <br> <ul> <li><b>Afegeix camps personalitzats pels teus projectes a la teva llista de projectes per crear una vista de cartera de projectes</b></li> </ul>
text_custom_logo_instructions: >
Es recomana un logo blanc amb fons transparent. Per a un millor resultat tant en pantalles retina o convencionals assegura't que la teva imatge té unes dimensions de 460px per 60px.
text_custom_favicon_instructions: >
@ -2918,7 +2918,7 @@ ca:
warning_user_limit_reached: >
Límit d'usuaris assolit. No pots activar cap més usuari. Si us plau, <a href="%{upgrade_url}">actualitza el teu pla</a> o bloqueja a membres per permetre nous usuaris.
warning_user_limit_reached_instructions: >
You reached your user limit (%{current}/%{max} active users). Please contact sales@openproject.com to upgrade your Enterprise edition plan and add additional users.
Has assolit el nombre d'usuaris límit (%{current}/%{max} usuaris actius. Si us plau, posa't en contacte amb sales@openproject.com per actualitzar la teva edició Enterpirse i afegir nous usuaris.
warning_protocol_mismatch_html: >
warning_bar:
@ -2956,8 +2956,8 @@ ca:
working: "%{day} és ara laboral"
non_working: "%{day} és ara no laboral"
dates:
working: "%{date} is now working"
non_working: "%{date} is now non-working"
working: "%{day} és ara laboral"
non_working: "%{day} és ara no laboral"
nothing_to_preview: "Res per previsualitzar"
api_v3:
attributes:

@ -2619,11 +2619,11 @@ es:
text_custom_field_hint_activate_per_project_and_type: >
Los campos personalizados se deben activar en cada tipo de paquete de trabajo y en cada proyecto por separado.
text_wp_custom_field_html: >
The Enterprise edition will add these additional add-ons for work packages' custom fields: <br> <ul> <li><b>Allow multi-select for custom fields of type List or User</b></li> </ul>
La edición Enterprise añadirá estos add-ons extra para los campos personalizados de los paquetes de trabajo: <br> <ul> <li><b>Permitir la selección múltiple de campos personalizados de tipo Lista o Usuario</b></li> </ul>
text_wp_status_read_only_html: >
The Enterprise edition will add these additional add-ons for work packages' statuses fields: <br> <ul> <li><b>Allow to mark work packages to read-only for specific statuses</b></li> </ul>
La edición Enterprise añadirá estos add-ons extras para los campos de estado de los paquetes de trabajo: <br> <ul> <li><b>Permitir marcar como solo lectura los paquetes de trabajo en estados específicos</b></li> </ul>
text_project_custom_field_html: >
The Enterprise edition will add these additional add-ons for projects' custom fields: <br> <ul> <li><b>Add custom fields for projects to your Project list to create a project portfolio view</b></li> </ul>
La edición Enterprise añadirá estos add-ons extra para los campos personalizados de los proyectos: <br> <ul> <li><b>Añadir campos personalizados para proyectos a tu lista de proyectos para crear una vista porfolio de proyectos</b></li> </ul>
text_custom_logo_instructions: >
Se recomienda usar un logotipo blanco sobre un fondo transparente. Para obtener los mejores resultados, tanto en pantallas convencionales como en las del tipo Retina, asegúrese de que las dimensiones de la imagen sean de 460 × 60 px.
text_custom_favicon_instructions: >
@ -2924,7 +2924,7 @@ es:
warning_user_limit_reached: >
Alcanzado el límite de usuarios. No se puede activar ningún usuario más. <a href="%{upgrade_url}">actualice su plan</a> o bloquee miembros para permitir usuarios adicionales.
warning_user_limit_reached_instructions: >
You reached your user limit (%{current}/%{max} active users). Please contact sales@openproject.com to upgrade your Enterprise edition plan and add additional users.
Has alcanzado el límite de usuarios (%{current}/%{max} usuarios activos). Por favor, contacta con sales@openproject.com para mejorar tu plan de edición Enterprise y añadir usuarios adicionales.
warning_protocol_mismatch_html: >
warning_bar:

@ -49,7 +49,7 @@ fr:
main-menu-border-color: "Bordure du menu principal"
custom_colors: "Couleurs personnalisées"
customize: "Personnalisez votre installation OpenProject avec votre propre logo et couleurs."
enterprise_notice: "As a special 'Thank you!' for their financial contribution to develop OpenProject, this tiny add-on is only available for Enterprise edition support subscribers."
enterprise_notice: "Comme remerciement spécial pour leur contribution financière au développement d'OpenProject, cet add-on n’est disponible que pour les titulaires d'une version Entreprise."
enterprise_more_info: "Remarque : le logo utilisé sera accessible publiquement."
manage_colors: "Modifier les options du sélecteur de couleur"
instructions:
@ -64,15 +64,15 @@ fr:
main-menu-bg-color: "Couleur d’arrière-plan du menu de gauche."
theme_warning: Le changement de thème écrasera votre style personnalisé. Le design sera alors perdu. Êtes-vous sûr de vouloir continuer ?
enterprise:
upgrade_to_ee: "Upgrade to the Enterprise edition"
add_token: "Upload an Enterprise edition support token"
upgrade_to_ee: "Passer à la version Entreprise"
add_token: "Charger un jeton de support pour la version Entreprise"
delete_token_modal:
text: "Are you sure you want to remove the current Enterprise edition token used?"
text: "Voulez-vous vraiment supprimer le jeton actuellement utilisé pour l'édition Entreprise ?"
title: "Supprimer le jeton"
replace_token: "Remplacer votre licence actuelle"
order: "Order Enterprise on-premises edition"
paste: "Paste your Enterprise edition support token"
required_for_feature: "This add-on is only available with an active Enterprise edition support token."
order: "Commander l'édition Entreprise autohebergée"
paste: "Coller votre jeton de support pour la version Entreprise"
required_for_feature: "Cet add-on n'est disponible qu'avec un jeton de support actif pour la version Entreprise."
enterprise_link: "Pour plus d'informations, cliquez ici."
start_trial: 'Commencer l''essai gratuit'
book_now: 'Réserver maintenant'
@ -80,7 +80,7 @@ fr:
buttons:
upgrade: "Passer au plan supérieur"
contact: "Contactez-nous pour une démo"
enterprise_info_html: "is an Enterprise <span class='spot-icon spot-icon_enterprise-addons'></span> add-on."
enterprise_info_html: "est un <span class='spot-icon spot-icon_enterprise-addons'></span> add-on Entreprise."
upgrade_info: "Veuillez passer à un plan payant pour l'activer et commencer à l'utiliser dans votre équipe."
journal_aggregation:
explanation:
@ -138,7 +138,7 @@ fr:
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'
encryption_details: 'LDAPS / STARTTLS options'
encryption_details: 'Options LDAPS / STARTTLS'
system_account: 'Compte système'
system_account_legend: |
OpenProject nécessite un accès en lecture seule via un compte système pour rechercher des utilisateurs et des groupes dans votre arborescence LDAP.
@ -152,16 +152,16 @@ fr:
plain: 'aucune'
simple_tls: 'LDAPS'
start_tls: 'STARTTLS'
plain_description: "Opens an unencrypted connection to the LDAP server. Not recommended for production."
simple_tls_description: "Use LDAPS. Requires a separate port on the LDAP server. This mode is often deprecated, we recommend using STARTTLS whenever possible."
start_tls_description: "Sends a STARTTLS command after connecting to the standard LDAP port. Recommended for encrypted connections."
plain_description: "Ouvre une connexion non chiffrée au serveur LDAP. Déconseillé en production."
simple_tls_description: "Utiliser LDAPS. Nécessite un port séparé sur le serveur LDAP. Ce mode est souvent obsolète, nous vous recommandons d'utiliser STARTTLS dès que possible."
start_tls_description: "Envoie une commande STARTTLS après la connexion au port LDAP standard. Recommandé pour les connexions chiffrées."
section_more_info_link_html: >
Cette section concerne la sécurité de connexion de cette source d'authentification LDAP. Pour plus d'informations, visitez <a href="%{link}">the Net::LDAP documentation</a>.
tls_options:
verify_peer: "Verify SSL certificate"
verify_peer: "Vérifier le certificat SSL"
verify_peer_description_html: >
Enables strict SSL verification of the certificate trusted chain. <br/> <strong>Warning:</strong> Unchecking this option disables SSL verification of the LDAP server certificate. This exposes your connection to Man in the Middle attacks.
tls_certificate_description: "If the LDAP server certificate is not in the trust sources of this system, you can add it manually here. Enter a PEM X509 certifiate string."
Active la vérification SSL stricte de la chaîne de confiance du certificat. <br/> <strong> Avertissement :</strong> décocher cette option désactive la vérification SSL du certificat de serveur LDAP. Cela expose votre connexion aux attaques de type "Man In The Middle".
tls_certificate_description: "Si le certificat du serveur LDAP n'appartient pas aux sources de confiance de ce système, vous pouvez manuellement l'ajouter ici. Entrez une chaîne de certificat PEM X509."
forums:
show:
no_results_title_text: Il n'y a actuellement aucun message pour le forum.
@ -322,7 +322,7 @@ fr:
settings: "Paramètres"
form_configuration: "Configuration du formulaire"
more_info_text_html: >
Enterprise edition allows you to customize form configuration with these additional add-ons: <br> <ul class="%{list_styling_class}"> <li><b>Add new attribute groups</b></li> <li><b>Rename attribute groups</b></li> <li><b>Add a table of related work packages</b></li> </ul>
L'édition Entreprise vous permet de personnaliser la configuration du formulaire avec ces add-ons supplémentaires : <br> <ul class="%{list_styling_class}"> <li><b>Ajouter de nouveaux groupes d'attributs</b></li> <li><b>Renommer les groupes d'attributs</b></li> <li><b>Ajouter une table des lots de travaux connexes</b></li> </ul>
projects: "Projets"
enabled_projects: "Projets activés"
edit_query: "Modifier le tableau"
@ -376,7 +376,7 @@ fr:
account:
delete: "Supprimer le compte"
delete_confirmation: "Êtes-vous sûr de vouloir supprimer le compte ?"
deletion_pending: "Account has been locked and was scheduled for deletion. Note that this process takes place in the background. It might take a few moments until the user is fully deleted."
deletion_pending: "Le compte a été verrouillé et a été programmé pour suppression. Notez que ce processus a lieu en arrière-plan. Cela peut prendre quelques instants avant que l'utilisateur soit complètement supprimé."
deletion_info:
data_consequences:
other: "Les données créées par l'utilisateur (e.g. e-mail, préférences, lots de travaux, entrées wiki) seront supprimées autant que possible. Notez toutefois que les données comme les lots de travaux et les entrées wiki ne peuvent pas être supprimées sans impacter le travail des autres utilisateurs. Ces données sont donc réaffectées à un compte appelé «Utilisateur supprimé». Étant donné que les données de chaque compte supprimé sont réaffectées à ce compte, il ne sera plus possible de distinguer les données créées par cet utilisateur de celles d'un autre compte supprimé."
@ -426,7 +426,7 @@ fr:
host: "Hôte"
onthefly: "Création automatique d'un utilisateur"
port: "Port"
tls_certificate_string: "LDAP server SSL certificate"
tls_certificate_string: "Certificat SSL du serveur LDAP"
changeset:
repository: "Référentiel"
comment:
@ -588,7 +588,7 @@ fr:
confirmation: "ne correspond pas à %{attribute}."
could_not_be_copied: "%{dependency} n'a pas pu être copié (entièrement)."
does_not_exist: "n'existe pas."
error_enterprise_only: "%{action} is only available in the OpenProject Enterprise edition"
error_enterprise_only: "%{action} n'est disponible que dans la version Entreprise d'OpenProject."
error_unauthorized: "est interdit d'accès."
error_readonly: "a tenté d'être écrit mais n'est pas accessible en écriture."
email: "n'est pas une adresse e-mail valide."
@ -638,7 +638,7 @@ fr:
auth_source:
attributes:
tls_certificate_string:
invalid_certificate: "The provided SSL certificate is invalid: %{additional_message}"
invalid_certificate: "Le certificat SSL fourni est invalide : %{additional_message}"
format: "%{message}"
attachment:
attributes:
@ -693,7 +693,7 @@ fr:
non_working_day:
attributes:
date:
taken: "A non-working day already exists for %{value}."
taken: "Un jour non ouvrable existe déjà pour %{value}."
format: "%{message}"
parse_schema_filter_params_service:
attributes:
@ -706,7 +706,7 @@ fr:
foreign_wps_reference_version: 'Les lots de travaux dans les projets non-descendants font référence aux versions du projet ou de ses descendants.'
attributes:
base:
archive_permission_missing_on_subprojects: "You do not have the permissions required to archive all sub-projects. Please contact an administrator."
archive_permission_missing_on_subprojects: "Vous n'avez pas les permissions requises pour archiver tous les sous-projets. Veuillez contacter un administrateur."
types:
in_use_by_work_packages: "toujours en cours d'utilisation par les lots de travaux : %{types}"
enabled_modules:
@ -1271,11 +1271,11 @@ fr:
ee:
upsale:
form_configuration:
description: "Customize the form configuration with these additional add-ons:"
description: "Personnaliser la configuration du formulaire avec ces add-ons supplémentaires :"
add_groups: "Ajouter de nouveaux groupes d’attributs"
rename_groups: "Renommer les groupes d’attributs"
project_filters:
description_html: "Filtering and sorting on custom fields is an Enterprise edition add-on."
description_html: "Le filtrage et le tri sur les champs personnalisés sont un add-on de l'édition Entreprise."
enumeration_activities: "Activités de suivi du temps"
enumeration_work_package_priorities: "Priorités du Lot de Travaux"
enumeration_reported_project_statuses: "Statuts de projet signalés"
@ -1297,7 +1297,7 @@ fr:
error_cookie_missing: 'Le cookie OpenProject est manquant. Assurez-vous que les cookies sont activés, sans quoi cette application ne fonctionnera pas correctement.'
error_custom_option_not_found: "L'option n'existe pas."
error_enterprise_activation_user_limit: "Votre compte n'a pas pu être activé (limite d'utilisateurs atteinte). Veuillez contacter votre administrateur pour obtenir l'accès."
error_enterprise_token_invalid_domain: "The Enterprise edition is not active. Your Enterprise token's domain (%{actual}) does not match the system's host name (%{expected})."
error_enterprise_token_invalid_domain: "La version Entreprise n'est pas active. Le domaine de votre jeton Entreprise (%{actual}) ne correspond pas au nom d'hôte du système (%{expected})."
error_failed_to_delete_entry: 'Échec lors de la suppression de cette entrée.'
error_in_dependent: "Erreur lors de la tentative de modification de l'objet dépendant : %{dependent_class} #%{related_id} - %{related_subject} : %{error}" #%{related_id} - %{related_subject} : %{error}"
error_in_new_dependent: "Erreur lors de la tentative de création d'un objet dépendant : %{dependent_class} - %{related_subject} : %{error}"
@ -1388,10 +1388,10 @@ fr:
blocks:
community: "Communauté OpenProject"
upsale:
title: "Upgrade to Enterprise edition"
title: "Passer à la version Entreprise"
more_info: "Plus d'informations"
links:
upgrade_enterprise_edition: "Upgrade to Enterprise edition"
upgrade_enterprise_edition: "Passer à la version Entreprise"
postgres_migration: "Migration de votre installation vers PostgreSQL"
user_guides: "Guides d'utilisation"
faq: "FAQ"
@ -1607,7 +1607,7 @@ fr:
label_enumerations: "Énumérations"
label_enterprise: "Entreprise"
label_enterprise_active_users: "%{current}/%{limit} utilisateurs actifs inscrits"
label_enterprise_edition: "Enterprise edition"
label_enterprise_edition: "Version Entreprise"
label_environment: "Environement"
label_estimates_and_time: "Estimations et temps"
label_equals: "est"
@ -1797,7 +1797,7 @@ fr:
label_product_version: "Version du produit"
label_professional_support: "Support professionnel"
label_profile: "Profil"
label_project_activity: "Project activity"
label_project_activity: "Activité du projet"
label_project_attribute_plural: "Attributs du projet"
label_project_count: "Nombre total de projets"
label_project_copy_notifications: "Notifier par courriel lors de la copie du projet"
@ -2221,7 +2221,7 @@ fr:
permission_add_work_packages: "Ajouter des lots de travaux"
permission_add_messages: "Poster des messages"
permission_add_project: "Créer un projet"
permission_archive_project: "Archive project"
permission_archive_project: "Archiver le projet"
permission_manage_user: "Créer et éditer des utilisateurs"
permission_manage_placeholder_user: "Créer, modifier et supprimer des utilisateurs fictifs"
permission_add_subprojects: "Créer des sous-projets"
@ -2623,11 +2623,11 @@ fr:
text_custom_field_hint_activate_per_project_and_type: >
Les champs personnalisés doivent être activés par type de lot de travaux et par projet.
text_wp_custom_field_html: >
The Enterprise edition will add these additional add-ons for work packages' custom fields: <br> <ul> <li><b>Allow multi-select for custom fields of type List or User</b></li> </ul>
L'édition Entreprise ajoutera ces add-ons supplémentaires pour les champs personnalisés des lots de travaux : <br> <ul> <li><b>Autoriser la sélection multiple pour les champs personnalisés de type Liste ou Utilisateur</b></li> </ul>
text_wp_status_read_only_html: >
The Enterprise edition will add these additional add-ons for work packages' statuses fields: <br> <ul> <li><b>Allow to mark work packages to read-only for specific statuses</b></li> </ul>
L'édition Entreprise ajoutera ces add-ons supplémentaires pour les champs de statut des lots de travaux : <br> <ul> <li><b>Permet de marquer les lots de travaux en lecture seule pour des statuts spécifiques</b></li> </ul>
text_project_custom_field_html: >
The Enterprise edition will add these additional add-ons for projects' custom fields: <br> <ul> <li><b>Add custom fields for projects to your Project list to create a project portfolio view</b></li> </ul>
L'édition Entreprise ajoutera ces add-ons supplémentaires pour les champs personnalisés des projets : <br> <ul> <li><b>Ajouter des champs personnalisés pour les projets à votre liste de projets pour créer une vue du portefeuille de projets</b></li> </ul>
text_custom_logo_instructions: >
Un logo blanc sur fond transparent est recommandé. Pour obtenir les meilleurs résultats sur les deux, affichage classique et retina, assurez-vous que les dimensions de votre image soient de 460px par 60px.
text_custom_favicon_instructions: >
@ -2928,7 +2928,7 @@ fr:
warning_user_limit_reached: >
Limite d'utilisateur atteinte. Vous ne pouvez plus activer d'autres utilisateurs. Veuillez <a href="%{upgrade_url}">mettre à jour votre plan</a> ou bloquez des membres pour permettre d'autres utilisateurs.
warning_user_limit_reached_instructions: >
You reached your user limit (%{current}/%{max} active users). Please contact sales@openproject.com to upgrade your Enterprise edition plan and add additional users.
Vous avez atteint le nombre limite d'utilisateurs (%{current}/%{max} utilisateurs actifs). Veuillez contacter sales@openproject.com pour mettre à jour votre abonnement Entreprise et ajouter des utilisateurs supplémentaires.
warning_protocol_mismatch_html: >
warning_bar:
@ -2966,8 +2966,8 @@ fr:
working: "%{day} est maintenant un jour ouvrable"
non_working: "%{day} est maintenant un jour non ouvrable"
dates:
working: "%{date} is now working"
non_working: "%{date} is now non-working"
working: "%{date} est maintenant un jour ouvrable"
non_working: "%{date} est maintenant un jour non ouvrable"
nothing_to_preview: "Rien à afficher en apperçu"
api_v3:
attributes:

@ -224,14 +224,14 @@ ca:
status_label: "Estat:"
status_confirmed: "confirmat"
status_waiting: "correu electrònic enviat - esperant la confirmació"
test_ee: "Test the Enterprise edition 14 days for free"
quick_overview: "Get a quick overview of project management and team collaboration with OpenProject Enterprise edition."
test_ee: "Prova l'edició Enterprise de forma gratuïta per 14 dies"
quick_overview: "Obté una visió general ràpida de la gestió de projectes i col·laboració d'equips amb l'edició Enterprise d'OpenProject."
upsale:
become_hero: "Sigues un heroi!"
enterprise_info_html: "%{feature_title} is an Enterprise <span class='spot-icon spot-icon_enterprise-addons'></span> add-on."
enterprise_info_html: "%{feature_title} és un add-on de l'edició Enterprise <span class='spot-icon spot-icon_enterprise-badge'></span>."
upgrade_info: "Si us plau, actualitza a una versió de pagament per tal d'activar i començar a utilitzar-la en el teu equip."
benefits:
description: "What are the benefits of the Enterprise on-premises edition?"
description: "Quins són els beneficis de l'edició Enterprise on-premises?"
high_security: "Funcions de seguretat"
high_security_text: "Inici de sessió únic (SAML, OpenID Conenct, CAS), grups LDAP."
installation: "Suport d'instal·lació"
@ -249,9 +249,9 @@ ca:
link_quote: "Obtenir un pressupost"
more_info: "Més informació"
text: >
The OpenProject Enterprise edition builds on top of the Community edition. It includes Enterprise add-ons and professional support mainly aimed at organizations with more than 10 users that manage business critical projects with OpenProject.
L'edició Enterprise d'OpenProject es construeix a sobre de l'edició Community. Inclou Enterprise add-ons i suport professional pensat especialment per a organitzacions de més de 10 usuaris que manegin projectes empresarialment crítics amb OpenProject.
unlimited: "Il·limitat"
you_contribute: "Developers need to pay their bills, too. By upgrading to the Enterprise edition, you will be supporting this open source community effort and contributing to its development, maintenance and continuous improvement."
you_contribute: "Els desenvolupadors també han de pagar les seves factures. Actualitzant a l'edició Enterprise, donaràs suport aquesta comunitat de codi obert i contribuiràs al seu desenvolupament, manteniment i millora continua."
custom_actions:
date:
specific: 'en'
@ -280,8 +280,8 @@ ca:
one: "Primer criteri d'ordenació"
two: "Segon criteri d'ordenació"
three: "Tercer criteri d'ordenació"
upsale_for_more: "Advanced filters allow you to also filter for file names and content of work package attachments. Please upgrade to a paid plan to use this add-on."
upsale_link: 'Enterprise edition.'
upsale_for_more: "Els filtres avançats et permeten també filtrar per noms de fitxer o contingut adjuntat en paquets de treball. Si us plau, actualitza a un pla de pagament per utilitzar aquest add-on."
upsale_link: 'Edició Enterprise.'
general_text_no: "no"
general_text_yes: "sí"
general_text_No: "No"
@ -475,10 +475,10 @@ ca:
label_custom_queries: "Privat"
label_columns: "Columnes"
label_attachments: Fitxers adjunts
label_drop_files: "Drop files here to attach files."
label_drop_or_click_files: "Drop files here or click to attach files."
label_drop_files: "Arrossega fitxers aquí per adjuntar-los."
label_drop_or_click_files: "Arrossega fitxers o fes clic aquí per adjuntar-los."
label_drop_folders_hint: No pots carregar carpetes com a fitxers adjunts. Si us plau, selecciona fitxers únics.
label_add_attachments: "Attach files"
label_add_attachments: "Adjuntar arxius"
label_formattable_attachment_hint: "Adjuntar i enllaça fitxers arrossegant-los en aquest camp, o enganxant-los des del porta-papers."
label_remove_file: "Eliminar %{fileName}"
label_remove_watcher: "Elimina l'observador %{name}"
@ -572,7 +572,7 @@ ca:
one: ' i 1 altre'
other: ' i %{count} altres'
no_results:
at_all: 'New notifications will appear here when there is activity that concerns you.'
at_all: 'Noves notificacions apareixeran aquí quan hi hagi activitat que sigui important per a tu.'
with_current_filter: 'En aquest moment no hi han notificacions en aquesta vista'
mark_all_read: 'Marca tot com a llegit'
mark_as_read: 'Marca com a llegit'
@ -595,7 +595,7 @@ ca:
watched: 'Observador'
date_alert: 'Alerta per dates'
settings:
change_notification_settings: 'You can modify your <a target="_blank" href="%{url}">notification settings</a> to ensure you never miss an important update.'
change_notification_settings: 'Pots modificar la teva <a target="_blank" href="%{url}">configuració de notificacions</a> per assegurar-te que mai et perds informació important.'
title: "Configuració de notificacions"
notify_me: "Notifica’m"
reminders:
@ -657,7 +657,7 @@ ca:
project:
required_outside_context: >
Si us plau, selecciona un projecte on crear el paquet de treball per a veure tots els atributs. Només pots seleccionar projectes que tinguin activat la classe indicada anteriorment.
details_activity: 'Project details activity'
details_activity: 'Detalls de l''activitat del projecte'
context: 'Context del projecte'
work_package_belongs_to: 'Aquest paquet de treball pertany al projecte %{projectname}.'
click_to_switch_context: 'Obre aquest paquet de treball en aquell projecte.'
@ -708,8 +708,8 @@ ca:
reset_title: "Reiniciar la configuració del formulari"
confirm_reset: >
Alerta: Estàs segur que vols reiniciar la configuració del formulari? Això reiniciarà els atributs als seus grups per defecte i desactivarà TOTS els camps personalitzats.
upgrade_to_ee: "Upgrade to Enterprise on-premises edition"
upgrade_to_ee_text: "Wow! If you need this add-on you are a super pro! Would you mind supporting us OpenSource developers by becoming an Enterprise edition client?"
upgrade_to_ee: "Actualitza a l'edició Enterprise on-premises"
upgrade_to_ee_text: "Ostres! Si necessita aquesta funció ets un súper pro! T'importaria donar suport als nostres desenvolupadors de codi obert convertint-te en client de l'edició Enterprise?"
more_information: "Més informació"
nevermind: "Sense importància"
edit:
@ -856,7 +856,7 @@ ca:
zooms: "Nivell de zoom"
outlines: "Nivell de jerarquia"
upsale:
ee_only: 'Enterprise edition add-on'
ee_only: 'Add-on de l''edició Enterprise'
wiki_formatting:
strong: "Negreta"
italic: "Cursiva"
@ -1047,7 +1047,7 @@ ca:
upsale:
attribute_highlighting: 'Necessites ressaltar alguns paquets de treball per sobre de la resta?'
relation_columns: 'Necessites veure les relacions en una llista de paquets de treball?'
check_out_link: 'Check out the Enterprise edition.'
check_out_link: 'Fes una ullada a l''edició Enterprise.'
relation_filters:
filter_work_packages_by_relation_type: 'Filtra paquets de treball per classe de relació'
tabs:
@ -1191,9 +1191,9 @@ ca:
description: 'Permisos basats en el rol assignat en el projecte seleccionat'
placeholder:
title: 'Usuari de marcador de posició'
title_no_ee: 'Placeholder user (Enterprise edition only add-on)'
title_no_ee: 'Usuari de marcador de posició (add-on només de l''edició Enterprise)'
description: 'No té accés al projecte i no s''han enviat els correus electrònics.'
description_no_ee: 'Has no access to the project and no emails are sent out. <br>Check out the <a href="%{eeHref}" target="_blank">Enterprise edition</a>'
description_no_ee: 'No tens accés al projecte i per tant, no s''han enviat els correus electrònics. <br>Fes una ullada a <a href="%{eeHref}" target="_blank">l''edició Enterprise</a>'
principal:
label:
name_or_email: 'Nom o adreça de correu electrònic'

@ -225,13 +225,13 @@ es:
status_confirmed: "confirmado"
status_waiting: "correo electrónico enviado - esperando confirmación"
test_ee: "Pruebe la edición Enterprise de forma gratuita durante 14 días"
quick_overview: "Get a quick overview of project management and team collaboration with OpenProject Enterprise edition."
quick_overview: "Obtenga un resumen rápido sobre la gestión de proyectos y la colaboración en equipo con OpenProject edición Enterprise."
upsale:
become_hero: "¡Conviértete en un héroe!"
enterprise_info_html: "%{feature_title} is an Enterprise <span class='spot-icon spot-icon_enterprise-addons'></span> add-on."
enterprise_info_html: "%{feature_title} es un add-on de la edición Enterprise <span class='spot-icon spot-icon_enterprise-badge'></span>."
upgrade_info: "Actualice a un plan de pago para activarla y empiece a usarla en su equipo."
benefits:
description: "What are the benefits of the Enterprise on-premises edition?"
description: "¿Cuáles son las ventajas de la edición Enterprise on-premises?"
high_security: "Funcionalidades de seguridad"
high_security_text: "Inicio de sesión único (SAML, OpenID Connect, CAS), grupos LDAP."
installation: "Ayuda en la instalación"
@ -249,9 +249,9 @@ es:
link_quote: "Solicitar presupuesto"
more_info: "Más información"
text: >
The OpenProject Enterprise edition builds on top of the Community edition. It includes Enterprise add-ons and professional support mainly aimed at organizations with more than 10 users that manage business critical projects with OpenProject.
La edición Enterprise de OpenProject esta basada en la edición Community. Incluye Enterprise add-ons y soporte profesional dirigida principalmente a organizaciones con más de 10 usuarios que gestionen proyectos empresariales críticos con OpenProject.
unlimited: "Ilimitado"
you_contribute: "Developers need to pay their bills, too. By upgrading to the Enterprise edition, you will be supporting this open source community effort and contributing to its development, maintenance and continuous improvement."
you_contribute: "Los desarrolladores también tienen que pagar sus facturas. Al actualizar a edición Enterprise, apoyará el esfuerzo de la comunidad de código abierto y contribuirá a su desarrollo, mantenimiento y mejora continua."
custom_actions:
date:
specific: 'en'
@ -280,7 +280,7 @@ es:
one: "Primer criterio de ordenación"
two: "Segundo criterio de ordenación"
three: "Tercer criterio de ordenación"
upsale_for_more: "Advanced filters allow you to also filter for file names and content of work package attachments. Please upgrade to a paid plan to use this add-on."
upsale_for_more: "Los filtros avanzados te permiten también filtrar los nombres de los archivos y el contenido de los archivos adjuntos del paquete de trabajo. Por favor, actualice a un plan de pago para utilizar este add-on."
upsale_link: 'Edición Enterprise.'
general_text_no: "no"
general_text_yes: "sí"
@ -709,7 +709,7 @@ es:
confirm_reset: >
Advertencia: ¿Está seguro de que quiere restablecer la configuración del formulario? Se restablecerán los atributos al grupo predeterminado y se deshabilitarán TODOS los campos personalizados.
upgrade_to_ee: "Actualizar a edición Enterprise on-premises"
upgrade_to_ee_text: "Wow! If you need this add-on you are a super pro! Would you mind supporting us OpenSource developers by becoming an Enterprise edition client?"
upgrade_to_ee_text: "¡Vaya! Si necesita está opción, entonces ¡es un usuario experto! ¿Le importaría apoyar a los desarrolladores de código abierto convirtiéndose en cliente de la edición Enterprise?"
more_information: "Más información"
nevermind: "No importa"
edit:
@ -1193,7 +1193,7 @@ es:
title: 'Usuario de marcador de posición'
title_no_ee: 'Usuario de marcador de posición (add-on solo para edición Enterprise)'
description: 'No tiene acceso al proyecto y no se enviarán correos electrónicos.'
description_no_ee: 'Has no access to the project and no emails are sent out. <br>Check out the <a href="%{eeHref}" target="_blank">Enterprise edition</a>'
description_no_ee: 'No tiene acceso al proyecto y no se enviarán correos electrónicos. <br>Consulte <a href="%{eeHref}" target="_blank">edición Enterprise</a>'
principal:
label:
name_or_email: 'Nombre o dirección de correo electrónico'

@ -224,19 +224,19 @@ fr:
status_label: "Statut :"
status_confirmed: "confirmé"
status_waiting: "e-mail envoyé - en attente de confirmation"
test_ee: "Test the Enterprise edition 14 days for free"
quick_overview: "Get a quick overview of project management and team collaboration with OpenProject Enterprise edition."
test_ee: "Essayez gratuitement la version Entreprise pendant 14 jours"
quick_overview: "Obtenez un aperçu rapide de la gestion de projets et de la collaboration en équipe avec la version Entreprise d'OpenProject."
upsale:
become_hero: "Devenez un héros !"
enterprise_info_html: "%{feature_title} is an Enterprise <span class='spot-icon spot-icon_enterprise-addons'></span> add-on."
enterprise_info_html: "%{feature_title} est un <span class='spot-icon spot-icon_enterprise-addons'></span>add-on Entreprise."
upgrade_info: "Veuillez passer à une offre payante pour l'activer et commencer à l'utiliser dans votre équipe."
benefits:
description: "What are the benefits of the Enterprise on-premises edition?"
description: "Quels sont les avantages de l'édition Entreprise autohébergée ?"
high_security: "Fonctionnalités de sécurité"
high_security_text: "Single sign on (SAML, OpenID Connect, CAS), LDAP groups."
high_security_text: "Authentification unique (SAML, OpenID Connect, CAS), groupes LDAP."
installation: "Assistance à l'installation"
installation_text: "Des ingénieurs logiciel expérimentés vous guident à travers le processus complet d'installation et de configuration de votre propre infrastructure."
premium_features: "Enterprise add-ons"
premium_features: "Add-ons Entreprise"
premium_features_text: "Tableaux agiles, thème et logo personnalisés, graphiques, flux de travail intelligents avec actions personnalisées, recherche en plein texte des pièces jointes de lots de travaux et champs personnalisés à choix multiples"
professional_support: "Support professionnel"
professional_support_text: "Obtenez une assitance fiable et à haut contact de la part d'ingénieurs d'assistance expérimentés qui ont une connaissance approfondie de la mise en œuvre d'OpenProject dans des environnements critiques pour l'entreprise."
@ -249,9 +249,9 @@ fr:
link_quote: "Obtenir un devis"
more_info: "Plus d'informations"
text: >
The OpenProject Enterprise edition builds on top of the Community edition. It includes Enterprise add-ons and professional support mainly aimed at organizations with more than 10 users that manage business critical projects with OpenProject.
La version Entreprise d'OpenProject s'appuie sur la version Community. Elle comprend des add-ons Entreprise et un support professionnel principalement destiné aux organisations comptant plus de 10 utilisateurs gérant des projets critiques avec OpenProject.
unlimited: "Illimité"
you_contribute: "Developers need to pay their bills, too. By upgrading to the Enterprise edition, you will be supporting this open source community effort and contributing to its development, maintenance and continuous improvement."
you_contribute: "Les développeurs aussi ont besoin de payer leurs factures. En passant à la version Entreprise, vous soutiendrez cet effort communautaire open source et contribuerez à son développement, sa maintenance et son amélioration continue."
custom_actions:
date:
specific: 'le'
@ -280,8 +280,8 @@ fr:
one: "Premier critère de tri"
two: "Second critère de tri"
three: "Troisième critère de tri"
upsale_for_more: "Advanced filters allow you to also filter for file names and content of work package attachments. Please upgrade to a paid plan to use this add-on."
upsale_link: 'Enterprise edition.'
upsale_for_more: "Les filtres avancés vous permettent également de filtrer les noms de fichiers et le contenu des pièces jointes du lot de travaux. Veuillez passer à une offre payante pour utiliser cet add-on."
upsale_link: 'Version Entreprise'
general_text_no: "non"
general_text_yes: "oui"
general_text_No: "Non"
@ -625,18 +625,18 @@ fr:
global:
immediately:
title: 'Participant'
description: 'Notifications for all activities in work packages you are involved in (assignee, accountable or watcher).'
description: 'Notifications pour toute activité sur les lots de travaux vous concernant (assigné, responsable ou observateur).'
delayed:
title: 'Non participants'
description: 'Additional notifications for activities in all projects.'
description: 'Notifications additionnelles lors d''activité sur tous les projects.'
date_alerts:
title: 'Alarmes'
description: 'Automatic notifications when important dates are approaching for open work packages you are involved in (assignee, accountable or watcher).'
description: 'Notifications automatiques lorsque des dates importantes approchent pour les lots de travaux ouverts vous concernant (assigné, responsable ou observateur).'
teaser_text: 'Avec les alarmes, vous serez informé(e) à l''approche des dates de début ou de fin vous concernant afin de ne jamais manquer ou oublier une échéance importante.'
overdue: En cas de retard
project_specific:
title: 'Paramètres de notification spécifiques au projet'
description: 'These project-specific settings override default settings above.'
description: 'Ces paramètres spécifiques au projet remplacent les paramètres par défaut ci-dessus.'
add: 'Ajouter un paramètre pour le projet'
already_selected: 'Ce projet est déjà sélectionné'
remove: 'Suppression des paramètres de projet'
@ -657,7 +657,7 @@ fr:
project:
required_outside_context: >
Veuillez choisir un projet pour créer le lot de travaux et voir tous les attributs. Vous pouvez seulement sélectionner des projets ayant le type ci-dessus activé.
details_activity: 'Project details activity'
details_activity: 'Activité des détails du projet'
context: 'Contexte du projet'
work_package_belongs_to: 'Ce lot de travaux appartient au projet %{projectname}.'
click_to_switch_context: 'Ouvrir ce lot de travaux dans ce projet.'
@ -708,8 +708,8 @@ fr:
reset_title: "Réinitialiser la configuration du formulaire"
confirm_reset: >
Avertissement : êtes-vous sûr de vouloir réinitialiser la configuration du formulaire ? Ceci va réinitialiser les attributs à leur groupe par défaut et désactiver TOUS les champs personnalisés.
upgrade_to_ee: "Upgrade to Enterprise on-premises edition"
upgrade_to_ee_text: "Wow! If you need this add-on you are a super pro! Would you mind supporting us OpenSource developers by becoming an Enterprise edition client?"
upgrade_to_ee: "Mettre à niveau vers la version Entreprise autohébergée"
upgrade_to_ee_text: "Waouh ! Si vous avez besoin de cette fonctionnalité, vous êtes un véritable pro ! Cela vous dérangerait-il de soutenir les développeurs Open Source en devenant un client de la version Entreprise ?"
more_information: "Plus d'informations"
nevermind: "Peu importe"
edit:
@ -1047,7 +1047,7 @@ fr:
upsale:
attribute_highlighting: 'Vous avez besoin de lots de travaux qui sortent du lot ?'
relation_columns: 'Besoin de voir les relations sur la liste des lots de travaux ?'
check_out_link: 'Check out the Enterprise edition.'
check_out_link: 'Découvrez l’édition Entreprise.'
relation_filters:
filter_work_packages_by_relation_type: 'Filtrer les lots de travaux par type de relation'
tabs:
@ -1191,9 +1191,9 @@ fr:
description: 'Permissions basées sur le rôle attribué dans le projet sélectionné'
placeholder:
title: 'Utilisateur de remplacement'
title_no_ee: 'Placeholder user (Enterprise edition only add-on)'
title_no_ee: 'Utilisateur fictif (add-on de la version Entreprise uniquement)'
description: 'N''a pas d''accès au projet et aucun e-mail n''est envoyé.'
description_no_ee: 'Has no access to the project and no emails are sent out. <br>Check out the <a href="%{eeHref}" target="_blank">Enterprise edition</a>'
description_no_ee: 'N''a pas accès au projet et aucun courriel n''est envoyé. <br>Consultez la <a href="%{eeHref}" target="_blank">version Entreprise</a>.'
principal:
label:
name_or_email: 'Nom ou adresse e-mail'

@ -616,7 +616,7 @@ To disable 2FA altogether and remove all menus from the system, so that users ca
```yaml
OPENPROJECT_2FA_DISABLED="true"
OPENPROJECT_2FA_ACTIVE__STRATEGIES="[]
OPENPROJECT_2FA_ACTIVE__STRATEGIES="[]"
```
### statsd

@ -33,6 +33,22 @@ sudo apt-get install --only-upgrade openproject
sudo openproject configure
```
**A note for Ubuntu 22.04 installations**
On Ubuntu 22.04., you might see warnings like these:
> W: https://dl.packager.io/srv/deb/opf/openproject/stable/12/ubuntu/dists/22.04/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
This message is due to Ubuntu 22.04 switching to a more secure way of adding repository sources, which is not yet supported by the repository provider. There is ongoing work on this item, the message is for information only.
If you get an error like the following:
> E: Repository 'https://dl.packager.io/srv/deb/opf/openproject/stable/12/ubuntu 22.04 InRelease' changed its 'Origin' value from '' to 'https://packager.io/gh/opf/openproject'
> E: Repository 'https://dl.packager.io/srv/deb/opf/openproject/stable/12/ubuntu 22.04 InRelease' changed its 'Label' value from '' to 'Ubuntu 22.04 packages for opf/openproject'
These two messages messages are expected, due to a change in Origin and Label repository metadata, to better explain what the repository is about. You should allow the change, and/or run `sudo apt-get update --allow-releaseinfo-change` for the update to go through.
### CentOS / RHEL
```bash

@ -0,0 +1,29 @@
---
title: OpenProject 12.4.3
sidebar_navigation:
title: 12.4.3
release_version: 12.4.3
release_date: 2023-01-30
---
# OpenProject 12.4.3
Release date: 2023-01-30
We released [OpenProject 12.4.3](https://community.openproject.com/versions/1621).
The release contains several bug fixes and we recommend updating to the newest version.
<!--more-->
#### Bug fixes and changes
- Fixed: Custom field in cost report show "not found" after custom filed's value \[[#34978](https://community.openproject.com/wp/34978)\]
- Fixed: Race condition with outdated OAuth access token \[[#45799](https://community.openproject.com/wp/45799)\]
- Fixed: Notifications API are still showing errors in case of not authorized / other errors \[[#45854](https://community.openproject.com/wp/45854)\]
- Fixed: Administration: Permissions report page doesn't work in french in 12.4.1 \[[#45892](https://community.openproject.com/wp/45892)\]
#### Contributions
A big thanks to community members for reporting bugs and helping us identifying and providing fixes.
Special thanks for reporting and finding bugs go to
Paolo De Marco, Simon Rohart

@ -14,6 +14,13 @@ Stay up to date and get an overview of the new features included in the releases
<!--- New release notes are generated below. Do not remove comment. -->
<!--- RELEASE MARKER -->
## 12.4.3
Release date: 2023-01-30
[Release Notes](12-4-3/)
## 12.4.2
Release date: 2023-01-16

@ -32,7 +32,7 @@ You can add a visual component to the overview by clicking on the **Open as Gant
![OpenProject projects in Gantt view](gantt_view.png)
**Step 3:** You can also configure this view using the button with the three dots at the upper right corner and select **Configure**.
Step 3: You can also configure this view using the button with the three dots at the upper right corner and select **Configure**.
![OpenProject configure projects overview](openrpoject_configure_projects_overview.png)

@ -48,7 +48,7 @@ You will see the estimated, spent and remaining hours summed up by user, as well
![OpenProject work packages sums](openproject_work_packages_sum.png)
## Gannt chart view
## Gantt chart view
You could also add the Gantt view to add an additional dimension to your overview.

@ -723,13 +723,13 @@
"dev": true
},
"node_modules/@angular-eslint/eslint-plugin": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.1.0.tgz",
"integrity": "sha512-3RRDnxaCEI5DdKq3hipXvrxctPPssrUXnNbgczJRIJ3cssr4ndobCSNqUSepA6vWj5mWe7w+nnh4vgfhZ5keig==",
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.0.tgz",
"integrity": "sha512-yJGbmSUU0B0MFJ48ktpkqqEK+zv5k9iwlZSqEHtiQMKvDelfluovnEusihel7uPRo1c1iVlbSgXfGpxpUCfocA==",
"dev": true,
"dependencies": {
"@angular-eslint/utils": "15.1.0",
"@typescript-eslint/utils": "5.44.0"
"@angular-eslint/utils": "15.2.0",
"@typescript-eslint/utils": "5.48.1"
},
"peerDependencies": {
"eslint": "^7.20.0 || ^8.0.0",
@ -953,14 +953,34 @@
"node": ">=10"
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@angular-eslint/bundled-angular-compiler": {
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.0.tgz",
"integrity": "sha512-a0bfXxYyGoWJHrVQ4QER0HdRgselcTtJeyqiFPAxID2ZxF0IBGKLNTtugUTXekEmiLev8yGLX9TqAtthN57fEg==",
"dev": true
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@angular-eslint/utils": {
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.0.tgz",
"integrity": "sha512-qfTOKQ+aef/YER679/xN1E+FkZKMd0I73P6txUZAb9k2G1ACVktG+wOUIBfgjIlUVq9Q01AV91LGOWcd+rdEEA==",
"dev": true,
"dependencies": {
"@angular-eslint/bundled-angular-compiler": "15.2.0",
"@typescript-eslint/utils": "5.48.1"
},
"peerDependencies": {
"eslint": "^7.20.0 || ^8.0.0",
"typescript": "*"
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz",
"integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0"
"@typescript-eslint/types": "5.48.1",
"@typescript-eslint/visitor-keys": "5.48.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -971,9 +991,9 @@
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz",
"integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -984,13 +1004,13 @@
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz",
"integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0",
"@typescript-eslint/types": "5.48.1",
"@typescript-eslint/visitor-keys": "5.48.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -1011,16 +1031,16 @@
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz",
"integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"@typescript-eslint/scope-manager": "5.48.1",
"@typescript-eslint/types": "5.48.1",
"@typescript-eslint/typescript-estree": "5.48.1",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
@ -1037,12 +1057,12 @@
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz",
"integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/types": "5.48.1",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -1053,15 +1073,6 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -1079,6 +1090,15 @@
}
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/eslint-visitor-keys": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@angular-eslint/eslint-plugin/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -1116,6 +1136,167 @@
"@angular/cli": ">= 15.0.0 < 16.0.0"
}
},
"node_modules/@angular-eslint/schematics/node_modules/@angular-eslint/eslint-plugin": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.1.0.tgz",
"integrity": "sha512-3RRDnxaCEI5DdKq3hipXvrxctPPssrUXnNbgczJRIJ3cssr4ndobCSNqUSepA6vWj5mWe7w+nnh4vgfhZ5keig==",
"dev": true,
"dependencies": {
"@angular-eslint/utils": "15.1.0",
"@typescript-eslint/utils": "5.44.0"
},
"peerDependencies": {
"eslint": "^7.20.0 || ^8.0.0",
"typescript": "*"
}
},
"node_modules/@angular-eslint/schematics/node_modules/@typescript-eslint/scope-manager": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@angular-eslint/schematics/node_modules/@typescript-eslint/types": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@angular-eslint/schematics/node_modules/@typescript-eslint/typescript-estree": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@angular-eslint/schematics/node_modules/@typescript-eslint/utils": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/@angular-eslint/schematics/node_modules/@typescript-eslint/visitor-keys": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.44.0",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@angular-eslint/schematics/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@angular-eslint/schematics/node_modules/eslint-visitor-keys": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@angular-eslint/schematics/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/@angular-eslint/schematics/node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@angular-eslint/template-parser": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.1.0.tgz",
@ -49033,39 +49214,55 @@
"dev": true
},
"@angular-eslint/eslint-plugin": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.1.0.tgz",
"integrity": "sha512-3RRDnxaCEI5DdKq3hipXvrxctPPssrUXnNbgczJRIJ3cssr4ndobCSNqUSepA6vWj5mWe7w+nnh4vgfhZ5keig==",
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.2.0.tgz",
"integrity": "sha512-yJGbmSUU0B0MFJ48ktpkqqEK+zv5k9iwlZSqEHtiQMKvDelfluovnEusihel7uPRo1c1iVlbSgXfGpxpUCfocA==",
"dev": true,
"requires": {
"@angular-eslint/utils": "15.1.0",
"@typescript-eslint/utils": "5.44.0"
"@angular-eslint/utils": "15.2.0",
"@typescript-eslint/utils": "5.48.1"
},
"dependencies": {
"@angular-eslint/bundled-angular-compiler": {
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.2.0.tgz",
"integrity": "sha512-a0bfXxYyGoWJHrVQ4QER0HdRgselcTtJeyqiFPAxID2ZxF0IBGKLNTtugUTXekEmiLev8yGLX9TqAtthN57fEg==",
"dev": true
},
"@angular-eslint/utils": {
"version": "15.2.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.2.0.tgz",
"integrity": "sha512-qfTOKQ+aef/YER679/xN1E+FkZKMd0I73P6txUZAb9k2G1ACVktG+wOUIBfgjIlUVq9Q01AV91LGOWcd+rdEEA==",
"dev": true,
"requires": {
"@angular-eslint/bundled-angular-compiler": "15.2.0",
"@typescript-eslint/utils": "5.48.1"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz",
"integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0"
"@typescript-eslint/types": "5.48.1",
"@typescript-eslint/visitor-keys": "5.48.1"
}
},
"@typescript-eslint/types": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz",
"integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz",
"integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0",
"@typescript-eslint/types": "5.48.1",
"@typescript-eslint/visitor-keys": "5.48.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -49074,37 +49271,29 @@
}
},
"@typescript-eslint/utils": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz",
"integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"@typescript-eslint/scope-manager": "5.48.1",
"@typescript-eslint/types": "5.48.1",
"@typescript-eslint/typescript-estree": "5.48.1",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
"version": "5.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz",
"integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/types": "5.48.1",
"eslint-visitor-keys": "^3.3.0"
},
"dependencies": {
"eslint-visitor-keys": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"dev": true
}
}
},
"debug": {
@ -49116,6 +49305,12 @@
"ms": "2.1.2"
}
},
"eslint-visitor-keys": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -49298,6 +49493,105 @@
"ignore": "5.2.0",
"strip-json-comments": "3.1.1",
"tmp": "0.2.1"
},
"dependencies": {
"@angular-eslint/eslint-plugin": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.1.0.tgz",
"integrity": "sha512-3RRDnxaCEI5DdKq3hipXvrxctPPssrUXnNbgczJRIJ3cssr4ndobCSNqUSepA6vWj5mWe7w+nnh4vgfhZ5keig==",
"dev": true,
"requires": {
"@angular-eslint/utils": "15.1.0",
"@typescript-eslint/utils": "5.44.0"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz",
"integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0"
}
},
"@typescript-eslint/types": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz",
"integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz",
"integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/visitor-keys": "5.44.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.3.7",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/utils": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz",
"integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.44.0",
"@typescript-eslint/types": "5.44.0",
"@typescript-eslint/typescript-estree": "5.44.0",
"eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0",
"semver": "^7.3.7"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.44.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz",
"integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.44.0",
"eslint-visitor-keys": "^3.3.0"
}
},
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
},
"eslint-visitor-keys": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
"integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
"dev": true
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
}
}
},
"@angular-eslint/template-parser": {

@ -174,8 +174,8 @@
"build:watch": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --watch --named-chunks",
"tokens:generate": "theo src/app/spot/styles/tokens/tokens.yml --transform web --format sass,json --dest src/app/spot/styles/tokens/dist",
"icon-font:generate": "node ./src/app/spot/icon-font/generate.js ./src/app/spot/icon-font",
"serve": "NG_PERSISTENT_BUILD_CACHE=1 node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --public-host http://localhost:4200",
"serve:test": "NG_PERSISTENT_BUILD_CACHE=1 node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --disable-host-check --public-host http://frontend-test:4200",
"serve": "node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --public-host http://localhost:4200",
"serve:test": "node --max_old_space_size=8096 ./node_modules/@angular/cli/bin/ng serve --host 0.0.0.0 --disable-host-check --public-host http://frontend-test:4200",
"test": "ng test --watch=false",
"test:watch": "ng test --watch=true",
"lint": "esprint check",

@ -26,7 +26,12 @@
// See COPYRIGHT and LICENSE files for more details.
//++
import { QueryEntity } from '@datorama/akita';
import { StoragesState } from 'core-app/core/state/storages/storages.store';
import { IHalResourceLinks } from 'core-app/core/state/hal-resource';
import { IStorageFile } from 'core-app/core/state/storage-files/storage-file.model';
export class StoragesQuery extends QueryEntity<StoragesState> {}
export interface IStorageFiles {
files:IStorageFile[];
parent:IStorageFile;
_type:'StorageFiles';
_links:IHalResourceLinks;
}

@ -27,52 +27,79 @@
//++
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map, take, tap } from 'rxjs/operators';
import { combineLatest, Observable } from 'rxjs';
import {
CollectionStore,
ResourceCollectionService,
} from 'core-app/core/state/resource-collection.service';
import { IStorageFile } from 'core-app/core/state/storage-files/storage-file.model';
import { IHALCollection } from 'core-app/core/apiv3/types/hal-collection.type';
filter, map, take, tap,
} from 'rxjs/operators';
import { IHalResourceLink } from 'core-app/core/state/hal-resource';
import { StorageFilesStore } from 'core-app/core/state/storage-files/storage-files.store';
import { insertCollectionIntoState } from 'core-app/core/state/collection-store';
import { IUploadLink } from 'core-app/core/state/storage-files/upload-link.model';
import { IPrepareUploadLink } from 'core-app/core/state/storages/storage.model';
import { IStorageFiles } from 'core-app/core/state/storage-files/storage-files.model';
import { HttpClient } from '@angular/common/http';
import { ID, QueryEntity } from '@datorama/akita';
import { IStorageFile } from 'core-app/core/state/storage-files/storage-file.model';
import isDefinedEntity from 'core-app/core/state/is-defined-entity';
@Injectable()
export class StorageFilesResourceService extends ResourceCollectionService<IStorageFile> {
protected createStore():CollectionStore<IStorageFile> {
return new StorageFilesStore();
}
export class StorageFilesResourceService {
private readonly store:StorageFilesStore = new StorageFilesStore();
private readonly query = new QueryEntity(this.store);
constructor(private readonly httpClient:HttpClient) {}
files(link:IHalResourceLink):Observable<IStorageFile[]> {
if (this.collectionExists(link.href)) {
return this.collection(link.href);
files(link:IHalResourceLink):Observable<IStorageFiles> {
const value = this.store.getValue().files[link.href];
if (value !== undefined) {
return combineLatest([this.lookupMany(value.files), this.lookup(value.parent)])
.pipe(
map(([files, parent]):IStorageFiles => ({
files, parent, _type: 'StorageFiles', _links: { self: link },
})),
take(1),
);
}
return this.http
.get<IHALCollection<IStorageFile>>(link.href)
.pipe(
tap((collection) => {
insertCollectionIntoState(this.store, collection, link.href);
}),
map((collection) => collection._embedded.elements),
take(1),
);
return this.httpClient
.get<IStorageFiles>(link.href)
.pipe(tap((storageFiles) => this.insert(storageFiles, link.href)));
}
uploadLink(link:IPrepareUploadLink):Observable<IUploadLink> {
return this.http.request<IUploadLink>(link.method, link.href, { body: link.payload });
return this.httpClient.request<IUploadLink>(link.method, link.href, { body: link.payload });
}
reset():void {
this.store.reset();
}
protected basePath():string {
return this.apiV3Service.storages.files.path;
private lookup(id:ID):Observable<IStorageFile> {
return this
.query
.selectEntity(id)
.pipe(filter(isDefinedEntity));
}
private lookupMany(ids:ID[]):Observable<IStorageFile[]> {
return this.query.selectMany(ids);
}
private insert(storageFiles:IStorageFiles, link:string):void {
this.store.upsertMany([...storageFiles.files, storageFiles.parent]);
const fileIds = storageFiles.files.map((file) => file.id);
const parentId = storageFiles.parent.id;
this.store.update(({ files }) => ({
files: {
...files,
[link]: {
files: fileIds,
parent: parentId,
},
},
}));
}
}

@ -26,18 +26,26 @@
// See COPYRIGHT and LICENSE files for more details.
//++
import { EntityStore, StoreConfig } from '@datorama/akita';
import { CollectionState, createInitialCollectionState } from 'core-app/core/state/collection-store';
import {
EntityState, EntityStore, ID, StoreConfig,
} from '@datorama/akita';
import { IStorageFile } from 'core-app/core/state/storage-files/storage-file.model';
export interface StorageFilesState extends CollectionState<IStorageFile> {}
export interface IStorageFilesResponse {
files:ID[];
parent:ID;
}
export interface IStorageFilesState extends EntityState<IStorageFile> {
files:Record<string, IStorageFilesResponse>;
}
@StoreConfig({
name: 'storage-files',
resettable: true,
})
export class StorageFilesStore extends EntityStore<StorageFilesState> {
export class StorageFilesStore extends EntityStore<IStorageFilesState> {
constructor() {
super(createInitialCollectionState());
super({ files: {} });
}
}

@ -66,7 +66,6 @@ import {
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { FormResource } from 'core-app/features/hal/resources/form-resource';
import { DateModalRelationsService } from 'core-app/shared/components/datepicker/services/date-modal-relations.service';
import { DateModalSchedulingService } from 'core-app/shared/components/datepicker/services/date-modal-scheduling.service';
import {
areDatesEqual,
mappedDate,
@ -103,7 +102,6 @@ export type FieldUpdates =
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
providers: [
DateModalSchedulingService,
DateModalRelationsService,
],
})
@ -114,8 +112,6 @@ export class MultiDateModalComponent extends OpModalComponent implements AfterVi
@InjectField() halEditing:HalResourceEditingService;
@InjectField() dateModalScheduling:DateModalSchedulingService;
@InjectField() dateModalRelations:DateModalRelationsService;
@InjectField() deviceService:DeviceService;
@ -505,7 +501,7 @@ export class MultiDateModalComponent extends OpModalComponent implements AfterVi
this.ignoreNonWorkingDays,
await this.datePickerInstance?.isNonWorkingDay(dayElem.dateObj),
minimalDate,
this.dateModalScheduling.isDayDisabled(dayElem, minimalDate),
this.isDayDisabled(dayElem, minimalDate),
);
},
},

@ -34,7 +34,7 @@
slot="input"
name="date"
class="op-datepicker-modal--date-field"
[ngClass]="{ 'op-datepicker-modal--date-field_current': this.dateModalScheduling.isSchedulable }"
[ngClass]="{ 'op-datepicker-modal--date-field_current': this.isSchedulable }"
[(ngModel)]="date"
(ngModelChange)="dateChangedManually$.next()"
[showClearButton]="true"
@ -43,7 +43,7 @@
slot="action"
type="button"
class="spot-link"
[ngClass]="{ 'op-datepicker-modal--hidden-link': !dateModalScheduling.isSchedulable }"
[ngClass]="{ 'op-datepicker-modal--hidden-link': !isSchedulable }"
(click)="setToday()"
[textContent]="text.today">
</button>

@ -63,7 +63,6 @@ import {
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
import { FormResource } from 'core-app/features/hal/resources/form-resource';
import { DateModalRelationsService } from 'core-app/shared/components/datepicker/services/date-modal-relations.service';
import { DateModalSchedulingService } from 'core-app/shared/components/datepicker/services/date-modal-scheduling.service';
import {
mappedDate,
onDayCreate,
@ -79,7 +78,6 @@ import { DeviceService } from 'core-app/core/browser/device.service';
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
providers: [
DateModalSchedulingService,
DateModalRelationsService,
],
})
@ -90,8 +88,6 @@ export class SingleDateModalComponent extends OpModalComponent implements AfterV
@InjectField() halEditing:HalResourceEditingService;
@InjectField() dateModalScheduling:DateModalSchedulingService;
@InjectField() dateModalRelations:DateModalRelationsService;
@InjectField() deviceService:DeviceService;
@ -196,6 +192,17 @@ export class SingleDateModalComponent extends OpModalComponent implements AfterV
this.cdRef.detectChanges();
}
/**
* Returns whether the user can alter the dates of the work package.
*/
get isSchedulable():boolean {
return this.scheduleManually || !this.dateModalRelations.isParent;
}
isDayDisabled(dayElement:DayElement, minimalDate?:Date|null):boolean {
return !this.isSchedulable || (!this.scheduleManually && !!minimalDate && dayElement.dateObj <= minimalDate);
}
changeNonWorkingDays():void {
this.initializeDatepicker();
@ -217,7 +224,7 @@ export class SingleDateModalComponent extends OpModalComponent implements AfterV
this.changeset.setValue('ignoreNonWorkingDays', this.ignoreNonWorkingDays);
// Apply the dates if they could be changed
if (this.dateModalScheduling.isSchedulable) {
if (this.isSchedulable) {
this.changeset.setValue('date', mappedDate(this.date));
}
@ -288,7 +295,7 @@ export class SingleDateModalComponent extends OpModalComponent implements AfterV
this.ignoreNonWorkingDays,
await this.datePickerInstance?.isNonWorkingDay(dayElem.dateObj),
minimalDate,
this.dateModalScheduling.isDayDisabled(dayElem, minimalDate),
this.isDayDisabled(dayElem, minimalDate),
);
},
},

@ -12,7 +12,6 @@
'spot-list--item-action_disabled': project.disabled,
'spot-list--item-action_active': (searchableProjectListService.selectedItemID$ | async) === project.id
}"
[title]="project.name"
[href]="extendedProjectUrl(project.id)"
[attr.data-list-selector]="projectListActionIdentifier"
[attr.data-project-id]="project.id"
@ -25,7 +24,6 @@
</a>
<span
*ngIf="project.disabled"
[title]="project.name"
class="spot-list--item-action spot-list--item-action_disabled"
[ngClass]="{
'spot-list--item-action_active': (searchableProjectListService.selectedItemID$ | async) === project.id

@ -34,7 +34,6 @@
class="spot-list--item-title spot-list--item-title_ellipse-text"
data-qa-selector="op-project-include-list--item-title"
[opSearchHighlight]="searchText"
[title]="project.name"
>{{ project.name }}</div>
</label>
</ng-container>

@ -20,12 +20,10 @@
'op-file-list--item-action_view-not-allowed': !viewAllowed
}"
[href]="fileLink._links.staticOriginOpen.href"
[title]="fileLink.originData.name"
target="_blank"
>
<div
class="spot-list--item-title op-file-list--item-title"
[title]="fileLink.originData.name"
>
<span
class="spot-icon spot-icon_{{fileLinkIcon.icon}} op-files-tab--icon op-files-tab--icon_{{fileLinkIcon.clazz}}"

@ -96,8 +96,8 @@ export abstract class FilePickerBaseModalComponent extends OpModalComponent impl
this.storageFilesResourceService
.files(makeFilesCollectionLink(this.storageLink, '/'))
.subscribe((files) => {
const root = files.find((file) => file.name === '/');
.subscribe((storageFiles) => {
const root = storageFiles.parent;
if (root === undefined) {
throw new Error('Collection does not contain a root directory!');
}
@ -112,7 +112,7 @@ export abstract class FilePickerBaseModalComponent extends OpModalComponent impl
}],
);
this.storageFiles$.next(files.filter((file) => file.name !== '/'));
this.storageFiles$.next(storageFiles.files);
this.loading$.next(false);
});
}
@ -157,7 +157,7 @@ export abstract class FilePickerBaseModalComponent extends OpModalComponent impl
this.loadingSubscription = this.storageFilesResourceService
.files(makeFilesCollectionLink(this.storageLink, directory.location))
.pipe(map((files) => files.filter((file) => file.name !== this.currentDirectory.name)))
.pipe(map((storageFiles) => storageFiles.files.filter((file) => file.name !== this.currentDirectory.name)))
.subscribe((files) => {
this.storageFiles$.next(files);
this.loading$.next(false);

@ -149,6 +149,7 @@ export class FilePickerModalComponent extends FilePickerBaseModalComponent {
this.isAlreadyLinked(file),
index === 0,
this.enterDirectoryCallback(file),
false,
this.tooltip(file),
{
selected: this.selection.has(file.id as string),

@ -113,11 +113,16 @@ export class LocationPickerModalComponent extends FilePickerBaseModalComponent {
!isDirectory(file),
index === 0,
this.enterDirectoryCallback(file),
this.isConstrained(file),
this.tooltip(file),
undefined,
);
}
private isConstrained(file:IStorageFile):boolean {
return !file.permissions.some((permission) => permission === 'writeable');
}
private tooltip(file:IStorageFile):string|undefined {
if (isDirectory(file)) {
return file.permissions.some((permission) => permission === 'writeable')

@ -13,7 +13,7 @@
data-qa-selector="op-files-picker-modal--list-item"
[ngClass]="{
'spot-list--item-action_disabled': content.disabled,
'op-file-list--item-action_view-not-allowed': !content.isWriteable
'op-file-list--item-action_view-not-allowed': content.isConstrained
}"
>
<spot-checkbox
@ -25,7 +25,6 @@
<div
class="spot-list--item-title op-file-list--item-title"
[title]="content.name"
>
<span
class="spot-icon spot-icon_{{content.icon.icon}} op-files-tab--icon op-files-tab--icon_{{content.icon.clazz}}"

@ -63,20 +63,13 @@ export class StorageFileListItem {
return isDirectory(this.storageFile);
}
get isWriteable():boolean {
return this.storageFile.permissions.some((permission) => permission === 'writeable');
}
get isReadable():boolean {
return this.storageFile.permissions.some((permission) => permission === 'readable');
}
constructor(
private readonly timezoneService:TimezoneService,
private readonly storageFile:IStorageFile,
public readonly disabled:boolean,
public readonly isFirst:boolean,
public readonly enterDirectory:() => void,
public readonly isConstrained:boolean,
public readonly tooltip?:string,
public readonly checkbox?:StorageFileListItemCheckbox,
) {}

@ -37,7 +37,7 @@ module Redmine::MenuManager::TopMenu::ProjectsMenu
private
def render_projects_dropdown
content_tag(:li, class: 'op-app-menu--item', title: I18n.t(:label_project_view_all)) do
content_tag(:li, class: 'op-app-menu--item') do
angular_component_tag('op-header-project-select')
end
end

@ -62,7 +62,8 @@ namespace :setting do
desc 'List the supported environment variables to override settings'
task available_envs: :environment do
Settings::Definition.all.sort_by(&:name).each do |definition|
puts "#{Settings::Definition.possible_env_names(definition).first} (default=#{definition.default.inspect})"
puts "#{Settings::Definition.possible_env_names(definition).first}" \
" (default=#{definition.default.inspect}) #{definition.description}"
end
end
end

@ -37,15 +37,15 @@ be:
must_block_at_least_one_work_package: "must contain the ID of at least one ticket."
parent_id:
parent_child_relationship_across_projects: "is invalid because the work package '%{work_package_name}' is a backlog task and therefore cannot have a parent outside of the current project."
type_must_be_one_of_the_following: "Type must be one of the following: %{type_names}."
type_must_be_one_of_the_following: "Тып мусіць быць адным з наступных: %{type_names}."
version_id:
task_version_must_be_the_same_as_story_version: "must be the same as the parent story's version."
sprint:
cannot_end_before_it_starts: "Sprint cannot end before it starts."
backlogs:
add_new_story: "New Story"
any: "any"
backlog_settings: "Backlogs settings"
add_new_story: "Новая Гісторыя"
any: "любы"
backlog_settings: "Налады бэклогу"
burndown_graph: "Burndown Graph"
card_paper_size: "Paper size for card printing"
chart_options: "Chart options"

@ -7,7 +7,7 @@ ca:
label_unnamed_list: 'Llista sense nom'
label_board_type: 'Tipus de taulell'
upsale:
teaser_text: 'Would you like to automate your workflows with Boards? Advanced boards are an Enterprise add-on. Please upgrade to a paid plan.'
teaser_text: 'T''agradaria automatitzar els teus processos de treball amb taulells? Els taulells avançats són un add-on de l''edició Enterprise. Si us plau, actualitza a un pla de pagament.'
upgrade: 'Actualitzeu ara'
lists:
delete: 'Suprimeix la llista'
@ -62,7 +62,7 @@ ca:
status: Estat
version: Versió
subproject: Subprojecte
subtasks: Parent-child
subtasks: Pare-fill
basic: Bàsic
select_attribute: "Atribut d'acció"
add_list_modal:

@ -7,7 +7,7 @@ es:
label_unnamed_list: 'Lista sin nombre'
label_board_type: 'Tipo de panel'
upsale:
teaser_text: 'Would you like to automate your workflows with Boards? Advanced boards are an Enterprise add-on. Please upgrade to a paid plan.'
teaser_text: '¿Quieres automatizar tus flujos de trabajo con Paneles? Los paneles avanzados son un add-on de la edición Enterprise. Por favor, actualice a un plan de pago.'
upgrade: 'Actualizar ahora'
lists:
delete: 'Eliminar lista'

@ -7,7 +7,7 @@ fr:
label_unnamed_list: 'Liste sans nom'
label_board_type: 'Type de tableau'
upsale:
teaser_text: 'Would you like to automate your workflows with Boards? Advanced boards are an Enterprise add-on. Please upgrade to a paid plan.'
teaser_text: 'Voulez-vous automatiser vos flux de travail avec des tableaux ? Les tableaux avancés sont un add-on Entreprise. Veuillez passer à une offre payante.'
upgrade: 'Passer au plan supérieur'
lists:
delete: 'Supprimer la liste'
@ -62,7 +62,7 @@ fr:
status: Statut
version: Version
subproject: Sous-projet
subtasks: Parent-child
subtasks: Parent-enfant
basic: Basique
select_attribute: "Attribut d'action"
add_list_modal:

@ -5,8 +5,8 @@ ca:
remove: 'Elimina els widgets'
configure: 'Configurar widget'
upsale:
text: "Some widgets, like the work package graph widget, are only available in the Enterprise edition."
link: 'Enterprise edition.'
text: "Alguns widgets com la gràfica de paquet de treball només estan disponibles en l'edició Enterprise."
link: 'Edició Enterprise.'
widgets:
custom_text:
title: 'Text personalitzat'

@ -5,7 +5,7 @@ es:
remove: 'Quitar widget'
configure: 'Configurar widget'
upsale:
text: "Some widgets, like the work package graph widget, are only available in the Enterprise edition."
text: "Algunos widgets, como el widget de gráfico de paquetes de trabajo, solo están disponibles en la edición Enterprise."
link: 'Edición Enterprise.'
widgets:
custom_text:

@ -5,8 +5,8 @@ fr:
remove: 'Supprimer le widget'
configure: 'Configurer le widget'
upsale:
text: "Some widgets, like the work package graph widget, are only available in the Enterprise edition."
link: 'Enterprise edition.'
text: "Certains composants, comme le composant de graphique des lots de travaux, ne sont disponibles que dans l'édition Entreprise."
link: 'Version Entreprise'
widgets:
custom_text:
title: 'Texte personnalisé'

@ -106,9 +106,12 @@ module Storages::Peripherals::StorageInteraction::Nextcloud
.xpath('//d:response')
.to_a
a.map do |file_element|
storage_file(file_element)
end
parent, *files =
a.map do |file_element|
storage_file(file_element)
end
::Storages::StorageFiles.new(files, parent)
end
end

@ -26,7 +26,11 @@
# See COPYRIGHT and LICENSE files for more details.
#++
module API::V3::StorageFiles
class StorageFileCollectionRepresenter < ::API::Decorators::UnpaginatedCollection
class Storages::StorageFiles
attr_reader :files, :parent
def initialize(files, parent = nil)
@files = files
@parent = parent
end
end

@ -18,4 +18,4 @@
<%= rails_cell ::Storages::ProjectsStoragesTableCell, @projects_storages %>
<% else %>
<%= render partial: '/storages/project_settings/toast_no_storage_set_up' %>
<% end %>
<% end %>

@ -79,7 +79,7 @@ af:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ ar:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ az:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ be:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ bg:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -51,7 +51,7 @@ ca:
type_link_text: "\"Integració d'OpenProject\""
name: "Dona un nom al teu emmagatzematge per tal que els usuaris el puguin diferenciar d'altres."
host: "Si us plau, afegeix l'adreça d'allotjament del teu emmagatzematge incloent el https://. No pot més llarg de 255 caràcters."
no_storage_set_up: "There are no file storages set up yet."
no_storage_set_up: "No hi ha emmagatzematges de fitxers configurats encara."
setting_up_additional_storages: "Per configurar emmagatzematges de fitxers addicionals, si us plau, visita"
setting_up_additional_storages_non_admin: "Els administradors poden configurar emmagatzematges de fitxers addicionals a través d'Administració / Emmagatzematges de fitxers."
setting_up_storages: "Per configurar emmagatzematges de fitxers, si us plau, visita"

@ -79,7 +79,7 @@ ckb-IR:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ cs:
label_new_storage: "Nové úložiště"
label_storage: "Úložiště"
label_storages: "Úložiště"
no_results: "Zatím nejsou nastaveny žádné úložiště."
no_results: "No storages set up yet."
provider_types:
label: "Typ poskytovatele"
nextcloud:

@ -79,7 +79,7 @@ da:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ de:
label_new_storage: "Neuer Speicher"
label_storage: "Speicher"
label_storages: "Speicher"
no_results: "Noch kein Speicher eingerichtet."
no_results: "No storages set up yet."
provider_types:
label: "Anbieter-Typ"
nextcloud:

@ -79,7 +79,7 @@ el:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ eo:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -51,7 +51,7 @@ es:
type_link_text: "“Integración OpenProject”"
name: "Dale un nombre a tu almacenamiento para que los usuarios puedan diferenciar entre múltiples almacenamientos."
host: "Por favor añade la dirección de host de tu almacenamiento incluyendo el https://. No debe tener más de 255 caracteres."
no_storage_set_up: "There are no file storages set up yet."
no_storage_set_up: "Aún no se han configurado los almacenamientos de archivos."
setting_up_additional_storages: "Para configurar almacenes de archivos adicionales, visite"
setting_up_additional_storages_non_admin: "Los administradores pueden configurar almacenes de archivos adicionales en Administración > Almacenes de archivos."
setting_up_storages: "Para configurar almacenes de archivos, visite"
@ -79,7 +79,7 @@ es:
label_new_storage: "Nuevo almacén"
label_storage: "Almacén"
label_storages: "Almacenes"
no_results: "Aún no se han configurado almacenes."
no_results: "Aún no se han configurado almacenes de archivos."
provider_types:
label: "Tipo de proveedor"
nextcloud:

@ -79,7 +79,7 @@ et:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ eu:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ fa:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ fi:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ fil:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -51,7 +51,7 @@ fr:
type_link_text: "« Intégration OpenProject »"
name: "Donnez à votre stockage un nom pour que les utilisateurs puissent se différencier entre plusieurs stockages."
host: "Veuillez ajouter l'adresse d'hôte de votre stockage, y compris le https://. Il ne doit pas dépasser 255 caractères."
no_storage_set_up: "There are no file storages set up yet."
no_storage_set_up: "Aucun stockage de fichiers configuré pour le moment."
setting_up_additional_storages: "Pour configurer des stockages de fichiers supplémentaires, veuillez visiter"
setting_up_additional_storages_non_admin: "Les administrateurs peuvent configurer des stockages de fichiers supplémentaires dans Administration / Stockages de fichiers."
setting_up_storages: "Pour configurer des stockages de fichiers, veuillez visiter"

@ -79,7 +79,7 @@ he:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ hi:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ hr:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ hu:
label_new_storage: "Új tárhely"
label_storage: "Tárhely"
label_storages: "Tárhelyek"
no_results: "Még nincs tárhely beállítva."
no_results: "No storages set up yet."
provider_types:
label: "Szolgáltató típusa"
nextcloud:

@ -79,7 +79,7 @@ id:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ it:
label_new_storage: "Nuovo archivio"
label_storage: "Archivio"
label_storages: "Archivi"
no_results: "Ancora nessun archivio configurato."
no_results: "No storages set up yet."
provider_types:
label: "Tipo di fonte"
nextcloud:

@ -79,7 +79,7 @@ ja:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -5,8 +5,8 @@ ca:
link_files_in_storage: "Fitxers enllaçats a %{storageType}"
link_existing_files: "Enllaça fitxers existents"
upload_files: "Carregar fitxers"
drop_files: "Drop files here to upload them to %{name}."
drop_or_click_files: "Drop files here or click to upload them to %{name}."
drop_files: "Arrossega els fitxers aquí per carregar-los a %{name}."
drop_or_click_files: "Arrossega els fitxers o fes clic aquí per carregar-los a %{name}."
login: "%{storageType} inici de sessió"
login_to: "Inicia sessió a %{storageType}"
no_connection: "%{storageType} sense connexió"
@ -25,12 +25,12 @@ ca:
not_logged_in: >
Per afegir un enllaç, veure o pujar fitxers relacionats amb aquest paquet de treball si us plau inicia sessió a %{storageType}.
files:
directory_not_writeable: "You do not have to permission to add files to this folder."
dragging_many_files: "The upload to %{storageType} supports only one file at once."
file_not_selectable_location: "Selecting a file is not possible in the process of choosing a location."
directory_not_writeable: "No tens permís per afegir arxius dins d'aquesta carpeta."
dragging_many_files: "La càrrega a %{storageType} només permet un fitxer per càrrega."
file_not_selectable_location: "Seleccionar un fitxer, no és possible en el procés de tria d'ubicació."
file_links:
empty: >
Currently there are no linked files to this work package. Start linking files with the action below or from within %{storageType}.
Actualment no hi ha cap fitxer enllaçat a aquest paquet de treball. Comença a enllaçar fitxers amb l'acció de sota o dins de %{storageType}.
download: "Descarrega %{fileName}"
no_permission: "No tens permisos per veure aquest fitxer."
open: 'Obre el fitxer a l''emmagatzematge'
@ -46,11 +46,11 @@ ca:
one: "Enllaça 1 fitxer"
other: "Enllaça %{count} fitxers"
success_create:
one: "Successfully created 1 file link."
other: "Successfully created %{count} file links."
upload_error: "An error occurred uploading the file '%{fileName}'."
one: "1 enllaç de fitxer creat correctament."
other: "%{count} enllaços de fitxer creat correctament."
upload_error: "S'ha produït un error al carregar el fitxer \"%{fileName}\"."
link_uploaded_file_error: >
An error occurred linking the recently uploaded file '%{fileName}' to the work package %{workPackageId}.
S'ha produït un error en enllaçar els fitxers carregats recentment "%{fileName}" al paquet de treball %{workPackageId}.
not_allowed_tooltip: "Si us plau, inicia sessió a Nextcloud per accedir a aquest fitxer"
already_linked_file: "Aquest fitxer ja està enllaçat a aquest paquet de treball."
already_linked_directory: "Aquest directori ja està enllaçat a aquest paquet de treball."

@ -25,9 +25,9 @@ es:
not_logged_in: >
Para añadir un enlace, ver o subir archivos relacionados con este paquete de trabajo, por favor inicie sesión en %{storageType}.
files:
directory_not_writeable: "You do not have to permission to add files to this folder."
directory_not_writeable: "No tiene permiso para añadir archivos en esta carpeta."
dragging_many_files: "La carga a %{storageType} solo admite un archivo a la vez."
file_not_selectable_location: "Selecting a file is not possible in the process of choosing a location."
file_not_selectable_location: "No es posible seleccionar un archivo en el proceso de seleccionar una ubicación."
file_links:
empty: >
Actualmente no hay archivos enlazados a este paquete de trabajo. Vincule sus primeros archivos usando la acción de abajo o desde %{storageType}.

@ -25,9 +25,9 @@ fr:
not_logged_in: >
Pour ajouter un lien, voir ou téléverser des fichiers liés à ce lot de travaux, veuillez vous connecter à %{storageType}.
files:
directory_not_writeable: "You do not have to permission to add files to this folder."
dragging_many_files: "The upload to %{storageType} supports only one file at once."
file_not_selectable_location: "Selecting a file is not possible in the process of choosing a location."
directory_not_writeable: "Vous n'avez pas la permission d'ajouter des fichiers à ce dossier."
dragging_many_files: "Le téléversement vers %{storageType} ne supporte qu'un seul fichier à la fois."
file_not_selectable_location: "La sélection d'un fichier est impossible pendant le processus de sélection d'un emplacement."
file_links:
empty: >
Il n'y a actuellement aucun fichier lié à ce lot de travaux. Commencez à lier les fichiers avec l'action ci-dessous ou à partir de %{storageType}.
@ -48,9 +48,9 @@ fr:
success_create:
one: "Un lien de fichier a été créé avec succès."
other: "%{count} liens de fichier ont été créés avec succès."
upload_error: "An error occurred uploading the file '%{fileName}'."
upload_error: "Une erreur s'est produite lors du téléversement du fichier '%{fileName}'."
link_uploaded_file_error: >
An error occurred linking the recently uploaded file '%{fileName}' to the work package %{workPackageId}.
Une erreur s'est produite lors de la liaison du fichier '%{fileName}' récemment téléversé au lot de travaux %{workPackageId}.
not_allowed_tooltip: "Veuillez vous connecter à Nextcloud pour accéder à ce fichier"
already_linked_file: "Ce fichier est déjà lié à ce lot de travaux."
already_linked_directory: "Ce répertoire est déjà lié à ce lot de travaux."

@ -27,7 +27,7 @@ ru:
files:
directory_not_writeable: "Вам не хватает прав для добавления файлов в эту папку."
dragging_many_files: "Загрузка в %{storageType} поддерживает только один файл одновременно."
file_not_selectable_location: "Selecting a file is not possible in the process of choosing a location."
file_not_selectable_location: "Выбор файла невозможен в процессе выбора местоположения."
file_links:
empty: >
В настоящее время нет файлов связанных с этим пакетом работ. Начните привязку файлов с действием ниже или внутри %{storageType}.

@ -79,7 +79,7 @@ ko:
label_new_storage: "새로운 저장소"
label_storage: "저장소"
label_storages: "저장소"
no_results: "아직 저장소가 설정되지 않았습니다."
no_results: "No storages set up yet."
provider_types:
label: "공급자 유형"
nextcloud:

@ -79,7 +79,7 @@ lol:
label_new_storage: "crwdns807964:0crwdne807964:0"
label_storage: "crwdns807966:0crwdne807966:0"
label_storages: "crwdns807968:0crwdne807968:0"
no_results: "crwdns807970:0crwdne807970:0"
no_results: "crwdns844783:0crwdne844783:0"
provider_types:
label: "crwdns807972:0crwdne807972:0"
nextcloud:

@ -79,7 +79,7 @@ lt:
label_new_storage: "Nauja saugykla"
label_storage: "Saugykla"
label_storages: "Saugyklos"
no_results: "Dar nenustatyta jokia saugykla"
no_results: "No storages set up yet."
provider_types:
label: "Tiekėjo tipas"
nextcloud:

@ -79,7 +79,7 @@ lv:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ ne:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ nl:
label_new_storage: "Nieuwe opslag"
label_storage: "Opslag"
label_storages: "Opslagplaatsen"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Type provider"
nextcloud:

@ -79,7 +79,7 @@
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ pl:
label_new_storage: "Nowy magazyn"
label_storage: "Magazyn"
label_storages: "Magazyny"
no_results: "Brak skonfigurowanych magazynów."
no_results: "No storages set up yet."
provider_types:
label: "Typ dostawcy"
nextcloud:

@ -79,7 +79,7 @@ pt:
label_new_storage: "Novo armazenamento"
label_storage: "Armazenamento"
label_storages: "Armazenamentos"
no_results: "Ainda não há armazenamento configurado."
no_results: "No storages set up yet."
provider_types:
label: "Tipo de provedor"
nextcloud:

@ -79,7 +79,7 @@ ro:
label_new_storage: "Stocare nouă"
label_storage: "Depozitare"
label_storages: "Depozite"
no_results: "Nici o stocare setată, încă."
no_results: "No storages set up yet."
provider_types:
label: "Tip furnizor"
nextcloud:

@ -51,7 +51,7 @@ ru:
type_link_text: "«Интеграционный OpenProject»"
name: "Дайте вашему хранилищу имя, чтобы пользователи могли различать между несколькими хранилищами."
host: "Пожалуйста, добавьте адрес вашего хранилища, включая https://. Он не должен быть длиннее 255 символов."
no_storage_set_up: "There are no file storages set up yet."
no_storage_set_up: "Нет настроенных хранилищ файлов."
setting_up_additional_storages: "Для настройки дополнительных файловых хранилищ посетите"
setting_up_additional_storages_non_admin: "Администраторы могут настроить дополнительные файловые хранилища в Администрировании / Файловых хранилищах."
setting_up_storages: "Для настройки файловых хранилищ посетите"
@ -79,7 +79,7 @@ ru:
label_new_storage: "Новое хранилище"
label_storage: "Хранилище"
label_storages: "Хранилища"
no_results: "Хранилища пока не настроены."
no_results: "Хранилища еще не настроены."
provider_types:
label: "Тип поставщика"
nextcloud:

@ -79,7 +79,7 @@ rw:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ si:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ sk:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ sl:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ sv:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ th:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ tr:
label_new_storage: "Yeni depolama"
label_storage: "Depolama"
label_storages: "Depolamalar"
no_results: "Henüz bir depo kurulmadı."
no_results: "No storages set up yet."
provider_types:
label: "Sağlayıcı türü"
nextcloud:

@ -79,7 +79,7 @@ uk:
label_new_storage: "Нове сховище"
label_storage: "Сховище"
label_storages: "Сховища"
no_results: "Сховища поки не створено."
no_results: "No storages set up yet."
provider_types:
label: "Тип постачальника"
nextcloud:

@ -79,7 +79,7 @@ vi:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -79,7 +79,7 @@ zh-TW:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -88,7 +88,7 @@ en:
label_new_storage: "New storage"
label_storage: "Storage"
label_storages: "Storages"
no_results: "No storages set up, yet."
no_results: "No storages set up yet."
provider_types:
label: "Provider type"
nextcloud:

@ -38,9 +38,8 @@ module API::V3::StorageFiles
(files_query(@storage, current_user) >> execute_files_query(params[:parent]))
.match(
on_success: ->(files) do
API::V3::StorageFiles::StorageFileCollectionRepresenter.new(
API::V3::StorageFiles::StorageFilesRepresenter.new(
files,
self_link: api_v3_paths.storage_files(@storage.id),
current_user:
)
end,

@ -0,0 +1,49 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 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 API::V3::StorageFiles
class StorageFilesRepresenter < ::API::Decorators::Single
link :self do
{ href: "#{::API::V3::URN_PREFIX}storages:storage_files:no_link_provided" }
end
collection :files,
getter: ->(*) do
represented.files.map { |file| API::V3::StorageFiles::StorageFileRepresenter.new(file, current_user:) }
end,
exec_context: :decorator
property :parent,
getter: ->(*) { API::V3::StorageFiles::StorageFileRepresenter.new(represented.parent, current_user:) },
exec_context: :decorator
def _type
'StorageFiles'
end
end
end

@ -204,7 +204,8 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
on_success: ->(query) do
result = query.call(nil)
expect(result).to be_success
expect(result.result.size).to eq(5)
expect(result.result.files.size).to eq(4)
expect(result.result.parent).not_to be_nil
end,
on_failure: ->(error) do
raise "Files query could not be created: #{error}"
@ -219,9 +220,9 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
on_success: ->(query) do
result = query.call(nil)
expect(result).to be_success
expect(result.result[1].name).to eq('Folder1')
expect(result.result[1].mime_type).to eq('application/x-op-directory')
expect(result.result[1].id).to eq('11')
expect(result.result.files[0].name).to eq('Folder1')
expect(result.result.files[0].mime_type).to eq('application/x-op-directory')
expect(result.result.files[0].id).to eq('11')
end,
on_failure: ->(error) do
raise "Files query could not be created: #{error}"
@ -237,13 +238,13 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
result = query.call(nil)
expect(result).to be_success
expect(result.result[1].mime_type).to eq('application/x-op-directory')
expect(result.result[1].permissions).to include(:readable)
expect(result.result[1].permissions).to include(:writeable)
expect(result.result.files[0].mime_type).to eq('application/x-op-directory')
expect(result.result.files[0].permissions).to include(:readable)
expect(result.result.files[0].permissions).to include(:writeable)
expect(result.result[2].mime_type).to eq('application/x-op-directory')
expect(result.result[2].permissions).to include(:readable)
expect(result.result[2].permissions).not_to include(:writeable)
expect(result.result.files[1].mime_type).to eq('application/x-op-directory')
expect(result.result.files[1].permissions).to include(:readable)
expect(result.result.files[1].permissions).not_to include(:writeable)
end,
on_failure: ->(error) do
raise "Files query could not be created: #{error}"
@ -259,13 +260,13 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
result = query.call(nil)
expect(result).to be_success
expect(result.result[3].mime_type).to eq('text/markdown')
expect(result.result[3].permissions).to include(:readable)
expect(result.result[3].permissions).to include(:writeable)
expect(result.result.files[2].mime_type).to eq('text/markdown')
expect(result.result.files[2].permissions).to include(:readable)
expect(result.result.files[2].permissions).to include(:writeable)
expect(result.result[4].mime_type).to eq('application/pdf')
expect(result.result[4].permissions).to include(:readable)
expect(result.result[4].permissions).not_to include(:writeable)
expect(result.result.files[3].mime_type).to eq('application/pdf')
expect(result.result.files[3].permissions).to include(:readable)
expect(result.result.files[3].permissions).not_to include(:writeable)
end,
on_failure: ->(error) do
raise "Files query could not be created: #{error}"
@ -280,9 +281,9 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
on_success: ->(query) do
result = query.call(nil)
expect(result).to be_success
expect(result.result[3].name).to eq('README.md')
expect(result.result[3].mime_type).to eq('text/markdown')
expect(result.result[3].id).to eq('12')
expect(result.result.files[2].name).to eq('README.md')
expect(result.result.files[2].mime_type).to eq('text/markdown')
expect(result.result.files[2].id).to eq('12')
end,
on_failure: ->(error) do
raise "Files query could not be created: #{error}"
@ -299,7 +300,7 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
.match(
on_success: ->(query) {
result = query.call(parent)
expect(result.result[3].location).to eq('/Photos/Birds/README.md')
expect(result.result.files[2].location).to eq('/Photos/Birds/README.md')
},
on_failure: ->(error) { raise "Files query could not be created: #{error}" }
)
@ -317,7 +318,7 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
.match(
on_success: ->(query) {
result = query.call(nil)
expect(result.result[3].location).to eq('/README.md')
expect(result.result.files[2].location).to eq('/README.md')
},
on_failure: ->(error) { raise "Files query could not be created: #{error}" }
)
@ -336,7 +337,7 @@ describe Storages::Peripherals::StorageRequests, webmock: true do
.match(
on_success: ->(query) {
result = query.call(parent)
expect(result.result[3].location).to eq('/Photos/Birds/README.md')
expect(result.result.files[2].location).to eq('/Photos/Birds/README.md')
},
on_failure: ->(error) { raise "Files query could not be created: #{error}" }
)

@ -0,0 +1,88 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2023 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'
describe API::V3::StorageFiles::StorageFilesRepresenter do
let(:user) { build_stubbed(:user) }
let(:created_at) { DateTime.now }
let(:last_modified_at) { DateTime.now }
let(:parent) do
Storages::StorageFile.new(
23,
'/',
2048,
'application/x-op-directory',
created_at,
last_modified_at,
'admin',
'admin',
'/',
%i[readable writeable]
)
end
let(:file) do
Storages::StorageFile.new(
42,
'readme.md',
4096,
'text/plain',
created_at,
last_modified_at,
'admin',
'admin',
'/readme.md',
%i[readable writeable]
)
end
let(:files) do
Storages::StorageFiles.new([file], parent)
end
let(:representer) { described_class.new(files, current_user: user) }
subject { representer.to_json }
describe 'properties' do
it_behaves_like 'property', :_type do
let(:value) { representer._type }
end
it_behaves_like 'collection', :files do
let(:value) { files.files }
let(:element_decorator) { API::V3::StorageFiles::StorageFileRepresenter }
end
it_behaves_like 'property', :parent do
let(:value) { API::V3::StorageFiles::StorageFileRepresenter.new(files.parent, current_user: user) }
end
end
end

@ -62,20 +62,24 @@ describe 'API v3 storage files', content_type: :json, webmock: true do
describe 'GET /api/v3/storages/:storage_id/files' do
let(:path) { api_v3_paths.storage_files(storage.id) }
let(:files) do
[
Storages::StorageFile.new(1, 'new_younglings.md', 4096, 'text/markdown', DateTime.now, DateTime.now,
'Obi-Wan Kenobi', 'Obi-Wan Kenobi', '/', %i[readable]),
Storages::StorageFile.new(2, 'holocron_inventory.md', 4096, 'text/markdown', DateTime.now, DateTime.now,
let(:response) do
Storages::StorageFiles.new(
[
Storages::StorageFile.new(1, 'new_younglings.md', 4096, 'text/markdown', DateTime.now, DateTime.now,
'Obi-Wan Kenobi', 'Obi-Wan Kenobi', '/', %i[readable]),
Storages::StorageFile.new(2, 'holocron_inventory.md', 4096, 'text/markdown', DateTime.now, DateTime.now,
'Obi-Wan Kenobi', 'Obi-Wan Kenobi', '/', %i[readable writeable])
],
Storages::StorageFile.new(32, '/', 4096 * 2, 'application/x-op-directory', DateTime.now, DateTime.now,
'Obi-Wan Kenobi', 'Obi-Wan Kenobi', '/', %i[readable writeable])
]
)
end
describe 'with successful response' do
before do
storage_requests = instance_double(Storages::Peripherals::StorageRequests)
files_query = Proc.new do
ServiceResult.success(result: files)
ServiceResult.success(result: response)
end
allow(storage_requests).to receive(:files_query).and_return(ServiceResult.success(result: files_query))
allow(Storages::Peripherals::StorageRequests).to receive(:new).and_return(storage_requests)
@ -83,14 +87,16 @@ describe 'API v3 storage files', content_type: :json, webmock: true do
subject { last_response.body }
it { is_expected.to be_json_eql(files.length.to_json).at_path('count') }
it { is_expected.to be_json_eql(files[0].id.to_json).at_path('_embedded/elements/0/id') }
it { is_expected.to be_json_eql(files[0].name.to_json).at_path('_embedded/elements/0/name') }
it { is_expected.to be_json_eql(files[1].id.to_json).at_path('_embedded/elements/1/id') }
it { is_expected.to be_json_eql(files[1].name.to_json).at_path('_embedded/elements/1/name') }
it { is_expected.to be_json_eql(response.files[0].id.to_json).at_path('files/0/id') }
it { is_expected.to be_json_eql(response.files[0].name.to_json).at_path('files/0/name') }
it { is_expected.to be_json_eql(response.files[1].id.to_json).at_path('files/1/id') }
it { is_expected.to be_json_eql(response.files[1].name.to_json).at_path('files/1/name') }
it { is_expected.to be_json_eql(files[0].permissions.to_json).at_path('_embedded/elements/0/permissions') }
it { is_expected.to be_json_eql(files[1].permissions.to_json).at_path('_embedded/elements/1/permissions') }
it { is_expected.to be_json_eql(response.files[0].permissions.to_json).at_path('files/0/permissions') }
it { is_expected.to be_json_eql(response.files[1].permissions.to_json).at_path('files/1/permissions') }
it { is_expected.to be_json_eql(response.parent.id.to_json).at_path('parent/id') }
it { is_expected.to be_json_eql(response.parent.name.to_json).at_path('parent/name') }
end
describe 'with files query creation failed' do

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save