diff --git a/Gemfile.lock b/Gemfile.lock
index 423426e462..3ece387b3d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -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)
diff --git a/config/constants/settings/definition.rb b/config/constants/settings/definition.rb
index 952444e64e..5749125176 100644
--- a/config/constants/settings/definition.rb
+++ b/config/constants/settings/definition.rb
@@ -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)
diff --git a/config/constants/settings/definitions.rb b/config/constants/settings/definitions.rb
index cb8569221c..601e52a23e 100644
--- a/config/constants/settings/definitions.rb
+++ b/config/constants/settings/definitions.rb
@@ -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
diff --git a/config/locales/crowdin/ca.yml b/config/locales/crowdin/ca.yml
index 488163f8db..5e263f74f4 100644
--- a/config/locales/crowdin/ca.yml
+++ b/config/locales/crowdin/ca.yml
@@ -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 add-on."
+ enterprise_info_html: "és un add-on de l'edició Enterprise ."
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:
- Add new attribute groups
- Rename attribute groups
- Add a table of related work packages
+ L'edició Enterprise et permet personalitzar la configuració de formularis amb aquests add-ons extra:
- Afegeix nous grups d'atributs
- Canvia el nom dels grups d'atributs
- Afegeix una taula de paquets de treball relacionats
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:
- Allow multi-select for custom fields of type List or User
+ L'edició Enterprise afegirà add-ons extra pels camps personalitzats de paquets de treball:
- Permet múltiple selecció dels camps personalitzats pels estils Llista o Usuari
text_wp_status_read_only_html: >
- The Enterprise edition will add these additional add-ons for work packages' statuses fields:
- Allow to mark work packages to read-only for specific statuses
+ L'edició Enterprise afegirà add-ons extra pels estats de paquets de treball:
- Permet marcar paquets de treball com a només lectura per a estats específics
text_project_custom_field_html: >
- The Enterprise edition will add these additional add-ons for projects' custom fields:
- Add custom fields for projects to your Project list to create a project portfolio view
+ L'edició Enterprise afegirà add-ons extra pels camps personalitzats de projectes:
- Afegeix camps personalitzats pels teus projectes a la teva llista de projectes per crear una vista de cartera de projectes
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, actualitza el teu pla 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:
diff --git a/config/locales/crowdin/es.yml b/config/locales/crowdin/es.yml
index fe3199e4c2..975840e169 100644
--- a/config/locales/crowdin/es.yml
+++ b/config/locales/crowdin/es.yml
@@ -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:
- Allow multi-select for custom fields of type List or User
+ La edición Enterprise añadirá estos add-ons extra para los campos personalizados de los paquetes de trabajo:
- Permitir la selección múltiple de campos personalizados de tipo Lista o Usuario
text_wp_status_read_only_html: >
- The Enterprise edition will add these additional add-ons for work packages' statuses fields:
- Allow to mark work packages to read-only for specific statuses
+ La edición Enterprise añadirá estos add-ons extras para los campos de estado de los paquetes de trabajo:
- Permitir marcar como solo lectura los paquetes de trabajo en estados específicos
text_project_custom_field_html: >
- The Enterprise edition will add these additional add-ons for projects' custom fields:
- Add custom fields for projects to your Project list to create a project portfolio view
+ La edición Enterprise añadirá estos add-ons extra para los campos personalizados de los proyectos:
- Añadir campos personalizados para proyectos a tu lista de proyectos para crear una vista porfolio de proyectos
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. actualice su plan 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:
diff --git a/config/locales/crowdin/fr.yml b/config/locales/crowdin/fr.yml
index 544bfce3c9..f679510964 100644
--- a/config/locales/crowdin/fr.yml
+++ b/config/locales/crowdin/fr.yml
@@ -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 add-on."
+ enterprise_info_html: "est un 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 the Net::LDAP documentation.
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.
Warning: 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.
Avertissement : 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:
- Add new attribute groups
- Rename attribute groups
- Add a table of related work packages
+ L'édition Entreprise vous permet de personnaliser la configuration du formulaire avec ces add-ons supplémentaires :
- Ajouter de nouveaux groupes d'attributs
- Renommer les groupes d'attributs
- Ajouter une table des lots de travaux connexes
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:
- Allow multi-select for custom fields of type List or User
+ L'édition Entreprise ajoutera ces add-ons supplémentaires pour les champs personnalisés des lots de travaux :
- Autoriser la sélection multiple pour les champs personnalisés de type Liste ou Utilisateur
text_wp_status_read_only_html: >
- The Enterprise edition will add these additional add-ons for work packages' statuses fields:
- Allow to mark work packages to read-only for specific statuses
+ L'édition Entreprise ajoutera ces add-ons supplémentaires pour les champs de statut des lots de travaux :
- Permet de marquer les lots de travaux en lecture seule pour des statuts spécifiques
text_project_custom_field_html: >
- The Enterprise edition will add these additional add-ons for projects' custom fields:
- Add custom fields for projects to your Project list to create a project portfolio view
+ L'édition Entreprise ajoutera ces add-ons supplémentaires pour les champs personnalisés des projets :
- Ajouter des champs personnalisés pour les projets à votre liste de projets pour créer une vue du portefeuille de projets
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 mettre à jour votre plan 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:
diff --git a/config/locales/crowdin/js-ca.yml b/config/locales/crowdin/js-ca.yml
index 4d6ca28126..ecede0cceb 100644
--- a/config/locales/crowdin/js-ca.yml
+++ b/config/locales/crowdin/js-ca.yml
@@ -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 add-on."
+ enterprise_info_html: "%{feature_title} és un add-on de l'edició Enterprise ."
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 notification settings to ensure you never miss an important update.'
+ change_notification_settings: 'Pots modificar la teva configuració de notificacions 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.
Check out the Enterprise edition'
+ description_no_ee: 'No tens accés al projecte i per tant, no s''han enviat els correus electrònics.
Fes una ullada a l''edició Enterprise'
principal:
label:
name_or_email: 'Nom o adreça de correu electrònic'
diff --git a/config/locales/crowdin/js-es.yml b/config/locales/crowdin/js-es.yml
index e798de4310..8bf973dbef 100644
--- a/config/locales/crowdin/js-es.yml
+++ b/config/locales/crowdin/js-es.yml
@@ -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 add-on."
+ enterprise_info_html: "%{feature_title} es un add-on de la edición Enterprise ."
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.
Check out the Enterprise edition'
+ description_no_ee: 'No tiene acceso al proyecto y no se enviarán correos electrónicos.
Consulte edición Enterprise'
principal:
label:
name_or_email: 'Nombre o dirección de correo electrónico'
diff --git a/config/locales/crowdin/js-fr.yml b/config/locales/crowdin/js-fr.yml
index db743e1f1d..9ba61e3aed 100644
--- a/config/locales/crowdin/js-fr.yml
+++ b/config/locales/crowdin/js-fr.yml
@@ -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 add-on."
+ enterprise_info_html: "%{feature_title} est un 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.
Check out the Enterprise edition'
+ description_no_ee: 'N''a pas accès au projet et aucun courriel n''est envoyé.
Consultez la version Entreprise.'
principal:
label:
name_or_email: 'Nom ou adresse e-mail'
diff --git a/docs/installation-and-operations/configuration/README.md b/docs/installation-and-operations/configuration/README.md
index 2c8fb9e605..d68198e665 100644
--- a/docs/installation-and-operations/configuration/README.md
+++ b/docs/installation-and-operations/configuration/README.md
@@ -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
diff --git a/docs/installation-and-operations/operation/upgrading/README.md b/docs/installation-and-operations/operation/upgrading/README.md
index a8f8ba3e10..f1607a2c8f 100644
--- a/docs/installation-and-operations/operation/upgrading/README.md
+++ b/docs/installation-and-operations/operation/upgrading/README.md
@@ -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
diff --git a/docs/release-notes/12-4-3/README.md b/docs/release-notes/12-4-3/README.md
new file mode 100644
index 0000000000..ac557f0f48
--- /dev/null
+++ b/docs/release-notes/12-4-3/README.md
@@ -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.
+
+
+#### 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
diff --git a/docs/release-notes/README.md b/docs/release-notes/README.md
index 6e114ac7eb..f861dc5bb8 100644
--- a/docs/release-notes/README.md
+++ b/docs/release-notes/README.md
@@ -14,6 +14,13 @@ Stay up to date and get an overview of the new features included in the releases
+## 12.4.3
+
+Release date: 2023-01-30
+
+[Release Notes](12-4-3/)
+
+
## 12.4.2
Release date: 2023-01-16
diff --git a/docs/use-cases/portfolio-management/README.md b/docs/use-cases/portfolio-management/README.md
index 977df4b0d3..76d68f6a75 100644
--- a/docs/use-cases/portfolio-management/README.md
+++ b/docs/use-cases/portfolio-management/README.md
@@ -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)
diff --git a/docs/use-cases/resource-management/README.md b/docs/use-cases/resource-management/README.md
index 88fed82153..a528bd1a34 100644
--- a/docs/use-cases/resource-management/README.md
+++ b/docs/use-cases/resource-management/README.md
@@ -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.
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index daca693f3d..9477110204 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -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": {
diff --git a/frontend/package.json b/frontend/package.json
index 338ec4d9c9..d8fc46eaa1 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -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",
diff --git a/frontend/src/app/core/state/storages/storages.query.ts b/frontend/src/app/core/state/storage-files/storage-files.model.ts
similarity index 81%
rename from frontend/src/app/core/state/storages/storages.query.ts
rename to frontend/src/app/core/state/storage-files/storage-files.model.ts
index 03669d19c9..ecb0fdb223 100644
--- a/frontend/src/app/core/state/storages/storages.query.ts
+++ b/frontend/src/app/core/state/storage-files/storage-files.model.ts
@@ -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 {}
+export interface IStorageFiles {
+ files:IStorageFile[];
+ parent:IStorageFile;
+ _type:'StorageFiles';
+ _links:IHalResourceLinks;
+}
diff --git a/frontend/src/app/core/state/storage-files/storage-files.service.ts b/frontend/src/app/core/state/storage-files/storage-files.service.ts
index 983045e8e5..b741ec1e82 100644
--- a/frontend/src/app/core/state/storage-files/storage-files.service.ts
+++ b/frontend/src/app/core/state/storage-files/storage-files.service.ts
@@ -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 {
- protected createStore():CollectionStore {
- 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 {
- if (this.collectionExists(link.href)) {
- return this.collection(link.href);
+ files(link:IHalResourceLink):Observable {
+ 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>(link.href)
- .pipe(
- tap((collection) => {
- insertCollectionIntoState(this.store, collection, link.href);
- }),
- map((collection) => collection._embedded.elements),
- take(1),
- );
+ return this.httpClient
+ .get(link.href)
+ .pipe(tap((storageFiles) => this.insert(storageFiles, link.href)));
}
uploadLink(link:IPrepareUploadLink):Observable {
- return this.http.request(link.method, link.href, { body: link.payload });
+ return this.httpClient.request(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 {
+ return this
+ .query
+ .selectEntity(id)
+ .pipe(filter(isDefinedEntity));
+ }
+
+ private lookupMany(ids:ID[]):Observable {
+ 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,
+ },
+ },
+ }));
}
}
diff --git a/frontend/src/app/core/state/storage-files/storage-files.store.ts b/frontend/src/app/core/state/storage-files/storage-files.store.ts
index d16e8383e4..a4a9890eb5 100644
--- a/frontend/src/app/core/state/storage-files/storage-files.store.ts
+++ b/frontend/src/app/core/state/storage-files/storage-files.store.ts
@@ -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 {}
+export interface IStorageFilesResponse {
+ files:ID[];
+ parent:ID;
+}
+
+export interface IStorageFilesState extends EntityState {
+ files:Record;
+}
@StoreConfig({
name: 'storage-files',
resettable: true,
})
-export class StorageFilesStore extends EntityStore {
+export class StorageFilesStore extends EntityStore {
constructor() {
- super(createInitialCollectionState());
+ super({ files: {} });
}
}
diff --git a/frontend/src/app/shared/components/datepicker/multi-date-modal/multi-date.modal.ts b/frontend/src/app/shared/components/datepicker/multi-date-modal/multi-date.modal.ts
index 78dfb33bfb..036d9ad1de 100644
--- a/frontend/src/app/shared/components/datepicker/multi-date-modal/multi-date.modal.ts
+++ b/frontend/src/app/shared/components/datepicker/multi-date-modal/multi-date.modal.ts
@@ -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),
);
},
},
diff --git a/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.html b/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.html
index 8a805f2702..ea1aa243f0 100644
--- a/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.html
+++ b/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.html
@@ -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">
diff --git a/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.ts b/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.ts
index 1f82bf3069..4ae08a58eb 100644
--- a/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.ts
+++ b/frontend/src/app/shared/components/datepicker/single-date-modal/single-date.modal.ts
@@ -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),
);
},
},
diff --git a/frontend/src/app/shared/components/header-project-select/list/header-project-select-list.component.html b/frontend/src/app/shared/components/header-project-select/list/header-project-select-list.component.html
index 35c94ae11a..ff0c31af9e 100644
--- a/frontend/src/app/shared/components/header-project-select/list/header-project-select-list.component.html
+++ b/frontend/src/app/shared/components/header-project-select/list/header-project-select-list.component.html
@@ -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 @@
{{ project.name }}
diff --git a/frontend/src/app/shared/components/storages/file-link-list-item/file-link-list-item.html b/frontend/src/app/shared/components/storages/file-link-list-item/file-link-list-item.html
index e45abbe5cc..272ce78c06 100644
--- a/frontend/src/app/shared/components/storages/file-link-list-item/file-link-list-item.html
+++ b/frontend/src/app/shared/components/storages/file-link-list-item/file-link-list-item.html
@@ -20,12 +20,10 @@
'op-file-list--item-action_view-not-allowed': !viewAllowed
}"
[href]="fileLink._links.staticOriginOpen.href"
- [title]="fileLink.originData.name"
target="_blank"
>
{
- 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);
diff --git a/frontend/src/app/shared/components/storages/file-picker-modal/file-picker-modal.component.ts b/frontend/src/app/shared/components/storages/file-picker-modal/file-picker-modal.component.ts
index 7e5af3ee05..c056680980 100644
--- a/frontend/src/app/shared/components/storages/file-picker-modal/file-picker-modal.component.ts
+++ b/frontend/src/app/shared/components/storages/file-picker-modal/file-picker-modal.component.ts
@@ -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),
diff --git a/frontend/src/app/shared/components/storages/location-picker-modal/location-picker-modal.component.ts b/frontend/src/app/shared/components/storages/location-picker-modal/location-picker-modal.component.ts
index 68b55b617e..66b17ca098 100644
--- a/frontend/src/app/shared/components/storages/location-picker-modal/location-picker-modal.component.ts
+++ b/frontend/src/app/shared/components/storages/location-picker-modal/location-picker-modal.component.ts
@@ -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')
diff --git a/frontend/src/app/shared/components/storages/storage-file-list-item/storage-file-list-item.html b/frontend/src/app/shared/components/storages/storage-file-list-item/storage-file-list-item.html
index d017f9858d..8ed11dee7b 100644
--- a/frontend/src/app/shared/components/storages/storage-file-list-item/storage-file-list-item.html
+++ b/frontend/src/app/shared/components/storages/storage-file-list-item/storage-file-list-item.html
@@ -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
}"
>
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,
) {}
diff --git a/lib/redmine/menu_manager/top_menu/projects_menu.rb b/lib/redmine/menu_manager/top_menu/projects_menu.rb
index 37c2a5e1a3..b1f644864f 100644
--- a/lib/redmine/menu_manager/top_menu/projects_menu.rb
+++ b/lib/redmine/menu_manager/top_menu/projects_menu.rb
@@ -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
diff --git a/lib/tasks/setting.rake b/lib/tasks/setting.rake
index 2d9a252ad9..f59f962da5 100644
--- a/lib/tasks/setting.rake
+++ b/lib/tasks/setting.rake
@@ -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
diff --git a/modules/backlogs/config/locales/crowdin/be.yml b/modules/backlogs/config/locales/crowdin/be.yml
index 4d12c8c986..fa1a9d2e25 100644
--- a/modules/backlogs/config/locales/crowdin/be.yml
+++ b/modules/backlogs/config/locales/crowdin/be.yml
@@ -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"
diff --git a/modules/boards/config/locales/crowdin/js-ca.yml b/modules/boards/config/locales/crowdin/js-ca.yml
index a2ff27fc36..7b4ddfdc72 100644
--- a/modules/boards/config/locales/crowdin/js-ca.yml
+++ b/modules/boards/config/locales/crowdin/js-ca.yml
@@ -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:
diff --git a/modules/boards/config/locales/crowdin/js-es.yml b/modules/boards/config/locales/crowdin/js-es.yml
index c435110357..59cb3d65e6 100644
--- a/modules/boards/config/locales/crowdin/js-es.yml
+++ b/modules/boards/config/locales/crowdin/js-es.yml
@@ -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'
diff --git a/modules/boards/config/locales/crowdin/js-fr.yml b/modules/boards/config/locales/crowdin/js-fr.yml
index 86f94e5964..96fdc3b404 100644
--- a/modules/boards/config/locales/crowdin/js-fr.yml
+++ b/modules/boards/config/locales/crowdin/js-fr.yml
@@ -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:
diff --git a/modules/grids/config/locales/crowdin/js-ca.yml b/modules/grids/config/locales/crowdin/js-ca.yml
index d624b336df..b2bc547b6f 100644
--- a/modules/grids/config/locales/crowdin/js-ca.yml
+++ b/modules/grids/config/locales/crowdin/js-ca.yml
@@ -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'
diff --git a/modules/grids/config/locales/crowdin/js-es.yml b/modules/grids/config/locales/crowdin/js-es.yml
index 662a26a30e..3fee121aba 100644
--- a/modules/grids/config/locales/crowdin/js-es.yml
+++ b/modules/grids/config/locales/crowdin/js-es.yml
@@ -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:
diff --git a/modules/grids/config/locales/crowdin/js-fr.yml b/modules/grids/config/locales/crowdin/js-fr.yml
index b879ba9264..25f8a4109e 100644
--- a/modules/grids/config/locales/crowdin/js-fr.yml
+++ b/modules/grids/config/locales/crowdin/js-fr.yml
@@ -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é'
diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb
index e650ee646e..ea70dcc538 100644
--- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb
+++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb
@@ -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
diff --git a/modules/storages/lib/api/v3/storage_files/storage_file_collection_representer.rb b/modules/storages/app/models/storages/storage_files.rb
similarity index 89%
rename from modules/storages/lib/api/v3/storage_files/storage_file_collection_representer.rb
rename to modules/storages/app/models/storages/storage_files.rb
index d1d1454ebd..24e7a91b60 100644
--- a/modules/storages/lib/api/v3/storage_files/storage_file_collection_representer.rb
+++ b/modules/storages/app/models/storages/storage_files.rb
@@ -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
diff --git a/modules/storages/app/views/storages/project_settings/index.html.erb b/modules/storages/app/views/storages/project_settings/index.html.erb
index 7892d0aabe..fcb8a3ab95 100644
--- a/modules/storages/app/views/storages/project_settings/index.html.erb
+++ b/modules/storages/app/views/storages/project_settings/index.html.erb
@@ -18,4 +18,4 @@
<%= rails_cell ::Storages::ProjectsStoragesTableCell, @projects_storages %>
<% else %>
<%= render partial: '/storages/project_settings/toast_no_storage_set_up' %>
-<% end %>
\ No newline at end of file
+<% end %>
diff --git a/modules/storages/config/locales/crowdin/af.yml b/modules/storages/config/locales/crowdin/af.yml
index e2019b8ffa..4e0287179f 100644
--- a/modules/storages/config/locales/crowdin/af.yml
+++ b/modules/storages/config/locales/crowdin/af.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/ar.yml b/modules/storages/config/locales/crowdin/ar.yml
index 5a402f27c1..53ca514de2 100644
--- a/modules/storages/config/locales/crowdin/ar.yml
+++ b/modules/storages/config/locales/crowdin/ar.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/az.yml b/modules/storages/config/locales/crowdin/az.yml
index cc2d5a84cf..3d7573de88 100644
--- a/modules/storages/config/locales/crowdin/az.yml
+++ b/modules/storages/config/locales/crowdin/az.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/be.yml b/modules/storages/config/locales/crowdin/be.yml
index feb366ed5d..8169ad590c 100644
--- a/modules/storages/config/locales/crowdin/be.yml
+++ b/modules/storages/config/locales/crowdin/be.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/bg.yml b/modules/storages/config/locales/crowdin/bg.yml
index 99a20c6c31..af1c44cb92 100644
--- a/modules/storages/config/locales/crowdin/bg.yml
+++ b/modules/storages/config/locales/crowdin/bg.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/ca.yml b/modules/storages/config/locales/crowdin/ca.yml
index 5658d86a71..2fb58f9d9f 100644
--- a/modules/storages/config/locales/crowdin/ca.yml
+++ b/modules/storages/config/locales/crowdin/ca.yml
@@ -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"
diff --git a/modules/storages/config/locales/crowdin/ckb-IR.yml b/modules/storages/config/locales/crowdin/ckb-IR.yml
index 7d14c93569..044b254126 100644
--- a/modules/storages/config/locales/crowdin/ckb-IR.yml
+++ b/modules/storages/config/locales/crowdin/ckb-IR.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/cs.yml b/modules/storages/config/locales/crowdin/cs.yml
index 28d78841e8..72c1bc1969 100644
--- a/modules/storages/config/locales/crowdin/cs.yml
+++ b/modules/storages/config/locales/crowdin/cs.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/da.yml b/modules/storages/config/locales/crowdin/da.yml
index 0a8be44d09..62b7564fcf 100644
--- a/modules/storages/config/locales/crowdin/da.yml
+++ b/modules/storages/config/locales/crowdin/da.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/de.yml b/modules/storages/config/locales/crowdin/de.yml
index e5f20d0392..20b27171c7 100644
--- a/modules/storages/config/locales/crowdin/de.yml
+++ b/modules/storages/config/locales/crowdin/de.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/el.yml b/modules/storages/config/locales/crowdin/el.yml
index f96a282364..e276536c96 100644
--- a/modules/storages/config/locales/crowdin/el.yml
+++ b/modules/storages/config/locales/crowdin/el.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/eo.yml b/modules/storages/config/locales/crowdin/eo.yml
index c6bb3f1489..add561ad77 100644
--- a/modules/storages/config/locales/crowdin/eo.yml
+++ b/modules/storages/config/locales/crowdin/eo.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/es.yml b/modules/storages/config/locales/crowdin/es.yml
index 62ad8fb2d6..7c950b1ecc 100644
--- a/modules/storages/config/locales/crowdin/es.yml
+++ b/modules/storages/config/locales/crowdin/es.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/et.yml b/modules/storages/config/locales/crowdin/et.yml
index d94ae9ff82..25edf2de99 100644
--- a/modules/storages/config/locales/crowdin/et.yml
+++ b/modules/storages/config/locales/crowdin/et.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/eu.yml b/modules/storages/config/locales/crowdin/eu.yml
index 6396c0c922..8c09dbb708 100644
--- a/modules/storages/config/locales/crowdin/eu.yml
+++ b/modules/storages/config/locales/crowdin/eu.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/fa.yml b/modules/storages/config/locales/crowdin/fa.yml
index 73760d3749..fe288696da 100644
--- a/modules/storages/config/locales/crowdin/fa.yml
+++ b/modules/storages/config/locales/crowdin/fa.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/fi.yml b/modules/storages/config/locales/crowdin/fi.yml
index 44e80ca7f0..6a8f6dd2ac 100644
--- a/modules/storages/config/locales/crowdin/fi.yml
+++ b/modules/storages/config/locales/crowdin/fi.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/fil.yml b/modules/storages/config/locales/crowdin/fil.yml
index 4d8bdb5750..6c3761a294 100644
--- a/modules/storages/config/locales/crowdin/fil.yml
+++ b/modules/storages/config/locales/crowdin/fil.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/fr.yml b/modules/storages/config/locales/crowdin/fr.yml
index 149b536970..654aa47e81 100644
--- a/modules/storages/config/locales/crowdin/fr.yml
+++ b/modules/storages/config/locales/crowdin/fr.yml
@@ -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"
diff --git a/modules/storages/config/locales/crowdin/he.yml b/modules/storages/config/locales/crowdin/he.yml
index bcf3d8e11f..1bb87741d6 100644
--- a/modules/storages/config/locales/crowdin/he.yml
+++ b/modules/storages/config/locales/crowdin/he.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/hi.yml b/modules/storages/config/locales/crowdin/hi.yml
index 0e11f3fe64..c6fc44882c 100644
--- a/modules/storages/config/locales/crowdin/hi.yml
+++ b/modules/storages/config/locales/crowdin/hi.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/hr.yml b/modules/storages/config/locales/crowdin/hr.yml
index d59a0bdf12..5ea1d57b55 100644
--- a/modules/storages/config/locales/crowdin/hr.yml
+++ b/modules/storages/config/locales/crowdin/hr.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/hu.yml b/modules/storages/config/locales/crowdin/hu.yml
index 7fae0134fd..683b09885f 100644
--- a/modules/storages/config/locales/crowdin/hu.yml
+++ b/modules/storages/config/locales/crowdin/hu.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/id.yml b/modules/storages/config/locales/crowdin/id.yml
index b17f4e97e4..5f05127fb9 100644
--- a/modules/storages/config/locales/crowdin/id.yml
+++ b/modules/storages/config/locales/crowdin/id.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/it.yml b/modules/storages/config/locales/crowdin/it.yml
index e920a807e6..a343ae1d4e 100644
--- a/modules/storages/config/locales/crowdin/it.yml
+++ b/modules/storages/config/locales/crowdin/it.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/ja.yml b/modules/storages/config/locales/crowdin/ja.yml
index 563cfb5528..59f2ea7984 100644
--- a/modules/storages/config/locales/crowdin/ja.yml
+++ b/modules/storages/config/locales/crowdin/ja.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/js-ca.yml b/modules/storages/config/locales/crowdin/js-ca.yml
index 504754a7a6..b9a05a9520 100644
--- a/modules/storages/config/locales/crowdin/js-ca.yml
+++ b/modules/storages/config/locales/crowdin/js-ca.yml
@@ -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."
diff --git a/modules/storages/config/locales/crowdin/js-es.yml b/modules/storages/config/locales/crowdin/js-es.yml
index 0367afb5de..700bfeb376 100644
--- a/modules/storages/config/locales/crowdin/js-es.yml
+++ b/modules/storages/config/locales/crowdin/js-es.yml
@@ -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}.
diff --git a/modules/storages/config/locales/crowdin/js-fr.yml b/modules/storages/config/locales/crowdin/js-fr.yml
index 22df894f43..3cabf519f8 100644
--- a/modules/storages/config/locales/crowdin/js-fr.yml
+++ b/modules/storages/config/locales/crowdin/js-fr.yml
@@ -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."
diff --git a/modules/storages/config/locales/crowdin/js-ru.yml b/modules/storages/config/locales/crowdin/js-ru.yml
index 9fa909f611..4be25fa6de 100644
--- a/modules/storages/config/locales/crowdin/js-ru.yml
+++ b/modules/storages/config/locales/crowdin/js-ru.yml
@@ -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}.
diff --git a/modules/storages/config/locales/crowdin/ko.yml b/modules/storages/config/locales/crowdin/ko.yml
index c68eefcdbe..1540325ea1 100644
--- a/modules/storages/config/locales/crowdin/ko.yml
+++ b/modules/storages/config/locales/crowdin/ko.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/lol.yml b/modules/storages/config/locales/crowdin/lol.yml
index 8519f7527b..87f5aeb8b8 100644
--- a/modules/storages/config/locales/crowdin/lol.yml
+++ b/modules/storages/config/locales/crowdin/lol.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/lt.yml b/modules/storages/config/locales/crowdin/lt.yml
index 50befa97cc..8cfc7c9308 100644
--- a/modules/storages/config/locales/crowdin/lt.yml
+++ b/modules/storages/config/locales/crowdin/lt.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/lv.yml b/modules/storages/config/locales/crowdin/lv.yml
index ab87b6f85d..cb064695b5 100644
--- a/modules/storages/config/locales/crowdin/lv.yml
+++ b/modules/storages/config/locales/crowdin/lv.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/ne.yml b/modules/storages/config/locales/crowdin/ne.yml
index c61aee343c..6f3de8d8ff 100644
--- a/modules/storages/config/locales/crowdin/ne.yml
+++ b/modules/storages/config/locales/crowdin/ne.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/nl.yml b/modules/storages/config/locales/crowdin/nl.yml
index f023a96e0c..c23c7f4c53 100644
--- a/modules/storages/config/locales/crowdin/nl.yml
+++ b/modules/storages/config/locales/crowdin/nl.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/no.yml b/modules/storages/config/locales/crowdin/no.yml
index f8587db714..3e7dcfe92e 100644
--- a/modules/storages/config/locales/crowdin/no.yml
+++ b/modules/storages/config/locales/crowdin/no.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/pl.yml b/modules/storages/config/locales/crowdin/pl.yml
index 467364967f..fb8157849e 100644
--- a/modules/storages/config/locales/crowdin/pl.yml
+++ b/modules/storages/config/locales/crowdin/pl.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/pt.yml b/modules/storages/config/locales/crowdin/pt.yml
index fab16bd1cd..210279b156 100644
--- a/modules/storages/config/locales/crowdin/pt.yml
+++ b/modules/storages/config/locales/crowdin/pt.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/ro.yml b/modules/storages/config/locales/crowdin/ro.yml
index 1883090f43..604718872d 100644
--- a/modules/storages/config/locales/crowdin/ro.yml
+++ b/modules/storages/config/locales/crowdin/ro.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/ru.yml b/modules/storages/config/locales/crowdin/ru.yml
index 25c16b2db3..7ee9effbfc 100644
--- a/modules/storages/config/locales/crowdin/ru.yml
+++ b/modules/storages/config/locales/crowdin/ru.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/rw.yml b/modules/storages/config/locales/crowdin/rw.yml
index 0466f7e43c..afb7d47db7 100644
--- a/modules/storages/config/locales/crowdin/rw.yml
+++ b/modules/storages/config/locales/crowdin/rw.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/si.yml b/modules/storages/config/locales/crowdin/si.yml
index 9542877cdf..65d31ae963 100644
--- a/modules/storages/config/locales/crowdin/si.yml
+++ b/modules/storages/config/locales/crowdin/si.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/sk.yml b/modules/storages/config/locales/crowdin/sk.yml
index 6104eac3c7..cd2f3c8656 100644
--- a/modules/storages/config/locales/crowdin/sk.yml
+++ b/modules/storages/config/locales/crowdin/sk.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/sl.yml b/modules/storages/config/locales/crowdin/sl.yml
index e5af792470..58cf83f43d 100644
--- a/modules/storages/config/locales/crowdin/sl.yml
+++ b/modules/storages/config/locales/crowdin/sl.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/sv.yml b/modules/storages/config/locales/crowdin/sv.yml
index d83adc04a0..505dee0a81 100644
--- a/modules/storages/config/locales/crowdin/sv.yml
+++ b/modules/storages/config/locales/crowdin/sv.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/th.yml b/modules/storages/config/locales/crowdin/th.yml
index 4208aa3c30..6a8e97888f 100644
--- a/modules/storages/config/locales/crowdin/th.yml
+++ b/modules/storages/config/locales/crowdin/th.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/tr.yml b/modules/storages/config/locales/crowdin/tr.yml
index ff5d818813..4113331657 100644
--- a/modules/storages/config/locales/crowdin/tr.yml
+++ b/modules/storages/config/locales/crowdin/tr.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/uk.yml b/modules/storages/config/locales/crowdin/uk.yml
index 43b63ade5b..0811889bbf 100644
--- a/modules/storages/config/locales/crowdin/uk.yml
+++ b/modules/storages/config/locales/crowdin/uk.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/vi.yml b/modules/storages/config/locales/crowdin/vi.yml
index d6f29b5fcc..5ad5e55388 100644
--- a/modules/storages/config/locales/crowdin/vi.yml
+++ b/modules/storages/config/locales/crowdin/vi.yml
@@ -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:
diff --git a/modules/storages/config/locales/crowdin/zh-TW.yml b/modules/storages/config/locales/crowdin/zh-TW.yml
index 8292070e75..31d0cd2717 100644
--- a/modules/storages/config/locales/crowdin/zh-TW.yml
+++ b/modules/storages/config/locales/crowdin/zh-TW.yml
@@ -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:
diff --git a/modules/storages/config/locales/en.yml b/modules/storages/config/locales/en.yml
index 035174e5bc..d06c6aa90b 100644
--- a/modules/storages/config/locales/en.yml
+++ b/modules/storages/config/locales/en.yml
@@ -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:
diff --git a/modules/storages/lib/api/v3/storage_files/storage_files_api.rb b/modules/storages/lib/api/v3/storage_files/storage_files_api.rb
index 0e239b8693..c0874b5e7b 100644
--- a/modules/storages/lib/api/v3/storage_files/storage_files_api.rb
+++ b/modules/storages/lib/api/v3/storage_files/storage_files_api.rb
@@ -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,
diff --git a/modules/storages/lib/api/v3/storage_files/storage_files_representer.rb b/modules/storages/lib/api/v3/storage_files/storage_files_representer.rb
new file mode 100644
index 0000000000..019f6acc8e
--- /dev/null
+++ b/modules/storages/lib/api/v3/storage_files/storage_files_representer.rb
@@ -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
diff --git a/modules/storages/spec/common/peripherals/storage_requests_spec.rb b/modules/storages/spec/common/peripherals/storage_requests_spec.rb
index 57cca01dc6..c615b524e9 100644
--- a/modules/storages/spec/common/peripherals/storage_requests_spec.rb
+++ b/modules/storages/spec/common/peripherals/storage_requests_spec.rb
@@ -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}" }
)
diff --git a/modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb b/modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb
new file mode 100644
index 0000000000..ddc7479bf9
--- /dev/null
+++ b/modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb
@@ -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
diff --git a/modules/storages/spec/requests/api/v3/storages/storage_files_spec.rb b/modules/storages/spec/requests/api/v3/storages/storage_files_spec.rb
index b72b3b2245..264ddbfde3 100644
--- a/modules/storages/spec/requests/api/v3/storages/storage_files_spec.rb
+++ b/modules/storages/spec/requests/api/v3/storages/storage_files_spec.rb
@@ -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
diff --git a/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb b/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb
index 0500761c57..05ac219cf6 100644
--- a/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb
+++ b/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb
@@ -68,10 +68,10 @@ describe 'Datepicker modal individual non working days (WP #44453)',
# Wait for the datepicker to be initialized
datepicker.expect_visible
+ datepicker.show_date non_working_day_this_week.date
datepicker.expect_non_working non_working_day_this_week.date
- datepicker.select_year non_working_day_next_year.date.year
- datepicker.select_month non_working_day_next_year.date.month
+ datepicker.show_date non_working_day_next_year.date
datepicker.expect_non_working non_working_day_next_year.date
end
diff --git a/spec/features/work_packages/datepicker/datepicker_parent_spec.rb b/spec/features/work_packages/datepicker/datepicker_parent_spec.rb
index 8a5fe7a82e..fc01e64054 100644
--- a/spec/features/work_packages/datepicker/datepicker_parent_spec.rb
+++ b/spec/features/work_packages/datepicker/datepicker_parent_spec.rb
@@ -75,6 +75,15 @@ describe 'Datepicker logic on parents',
it 'disables the non working days options' do
datepicker.expect_ignore_non_working_days_disabled
+ datepicker.expect_scheduling_mode false
+
+ first_monday = Time.zone.today.beginning_of_month.next_occurring(:monday)
+ datepicker.expect_disabled(first_monday)
+
+ datepicker.toggle_scheduling_mode
+ datepicker.expect_scheduling_mode true
+
+ datepicker.expect_not_disabled(first_monday)
end
end
end
diff --git a/spec/lib/api/v3/support/collection_examples.rb b/spec/lib/api/v3/support/collection_examples.rb
new file mode 100644
index 0000000000..e26b832190
--- /dev/null
+++ b/spec/lib/api/v3/support/collection_examples.rb
@@ -0,0 +1,37 @@
+#-- 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.
+#++
+
+shared_examples_for 'collection' do |name|
+ it "has the #{name} property" do
+ represented_elements = value.map { |v| element_decorator.new(v, current_user: user) }
+
+ expect(subject)
+ .to be_json_eql(represented_elements.to_json)
+ .at_path(name.to_s)
+ end
+end
diff --git a/spec/support/components/datepicker/datepicker.rb b/spec/support/components/datepicker/datepicker.rb
index 6715f064f8..01225162f4 100644
--- a/spec/support/components/datepicker/datepicker.rb
+++ b/spec/support/components/datepicker/datepicker.rb
@@ -65,13 +65,22 @@ module Components
end
end
- ##
- # Set a ISO8601 date through the datepicker
- def set_date(date)
+ # Change the datepicker visible area.
+ #
+ # @param date the date to navigate to. Can be a Date or a String with
+ # ISO8601 formatted date.
+ def show_date(date)
date = Date.parse(date) unless date.is_a?(Date)
select_year date.year
select_month date.strftime('%B')
+ end
+
+ # Set a ISO8601 date through the datepicker
+ def set_date(date)
+ date = Date.parse(date) unless date.is_a?(Date)
+
+ show_date(date)
select_day date.day
end
@@ -117,5 +126,29 @@ module Components
expect(page).to have_selector(".flatpickr-day.flatpickr-non-working-day[aria-label='#{label}']",
wait: 20)
end
+
+ ##
+ # Expect the given date to be non working
+ def expect_working(date)
+ label = date.strftime('%B %-d, %Y')
+ expect(page).to have_selector(".flatpickr-day:not(.flatpickr-non-working-day)[aria-label='#{label}']",
+ wait: 20)
+ end
+
+ ##
+ # Expect the given date to be non working
+ def expect_disabled(date)
+ label = date.strftime('%B %-d, %Y')
+ expect(page).to have_selector(".flatpickr-day.flatpickr-disabled[aria-label='#{label}']",
+ wait: 20)
+ end
+
+ ##
+ # Expect the given date to be non working
+ def expect_not_disabled(date)
+ label = date.strftime('%B %-d, %Y')
+ expect(page).to have_selector(".flatpickr-day:not(.flatpickr-disabled)[aria-label='#{label}']",
+ wait: 20)
+ end
end
end