decidim-core 0.31.1 → 0.31.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/announcement_cell.rb +10 -2
  3. data/app/cells/decidim/attachments_file_tab/show.erb +1 -1
  4. data/app/cells/decidim/content_blocks/participatory_space_metadata/content.erb +2 -2
  5. data/app/cells/decidim/nav_links/show.erb +3 -3
  6. data/app/cells/decidim/statistic/show.erb +6 -6
  7. data/app/cells/decidim/upload_modal/files.erb +12 -8
  8. data/app/cells/decidim/upload_modal_cell.rb +11 -4
  9. data/app/controllers/concerns/decidim/direct_upload.rb +2 -12
  10. data/app/controllers/decidim/devise/sessions_controller.rb +7 -0
  11. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +2 -2
  12. data/app/jobs/decidim/export_participatory_space_job.rb +1 -1
  13. data/app/models/decidim/attachment.rb +22 -1
  14. data/app/packs/src/decidim/controllers/account_form/controller.js +8 -0
  15. data/app/packs/src/decidim/controllers/language_change/controller.js +38 -0
  16. data/app/packs/src/decidim/controllers/language_change/language_change.test.js +105 -0
  17. data/app/packs/src/decidim/direct_uploads/upload_field.js +1 -1
  18. data/app/packs/stylesheets/decidim/_flash.scss +1 -1
  19. data/app/packs/stylesheets/decidim/_modal_update.scss +1 -1
  20. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +1 -1
  21. data/app/services/decidim/open_data_exporter.rb +1 -1
  22. data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +1 -1
  23. data/config/locales/ca-IT.yml +5 -0
  24. data/config/locales/ca.yml +5 -0
  25. data/config/locales/cs.yml +37 -0
  26. data/config/locales/el.yml +1 -0
  27. data/config/locales/en.yml +5 -0
  28. data/config/locales/es-MX.yml +5 -0
  29. data/config/locales/es-PY.yml +5 -0
  30. data/config/locales/es.yml +5 -0
  31. data/config/locales/eu.yml +8 -4
  32. data/config/locales/fr-CA.yml +4 -0
  33. data/config/locales/fr.yml +5 -0
  34. data/config/locales/ja.yml +4 -0
  35. data/config/locales/ro-RO.yml +4 -1
  36. data/config/locales/sv.yml +284 -43
  37. data/lib/decidim/core/version.rb +1 -1
  38. data/lib/decidim/form_builder.rb +41 -7
  39. metadata +8 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a09ab97ba5e294cac771913b5136ad740e670befc9509ca5827cf86d215f9fa6
4
- data.tar.gz: ad5ddc3a2ea6c21d8ed9dea42ee2a9307ba44799a8f4ca90c5253f3a75c217dd
3
+ metadata.gz: d24b967768820d8eb01abd435e318b7a869af854b0f374ca54c54a6dddbdddb6
4
+ data.tar.gz: f4374ee02ae0c5c9a580c8ad1c371c6552719be39b40e22cdf3d37018464950c
5
5
  SHA512:
6
- metadata.gz: 0cbb0319b8de1e90e2f6d3f4eb52d81ff023c9849d902a6569084065b8e9ec2ef76b48d811d23ada7731f48a2defa940764c6846bf1ae59797d83ab78afb351b
7
- data.tar.gz: 34ef4ee5189225382525aa6c01c09f7b1a4bc39c1edbec9a7beff9408acacb8766ece1cf6688962d70d4695e2be708b48f74f9fe69d023d675ffe2e10ebf51e3
6
+ metadata.gz: a4baebaa527bd42897989aee6feeb29b4bf2773872b3bb7f8379a230111a94f0ee8565e15b02599fb6a1c20bb83a24feed96707448eecc70b866d74a8dd34bec
7
+ data.tar.gz: 47436bb0abfd556afcebe781b153aaaa9e960653be07fdf19486f11d82bfc40b61472dc24cfbc397838b19638a395bbad3dc3af8e1d791b2277412b3b56e719d
@@ -68,15 +68,23 @@ module Decidim
68
68
  def clean_body
69
69
  return unless body
70
70
 
71
- Array(body).map { |paragraph| tag.p(clean(paragraph)) }.join
71
+ Array(body).map { |paragraph| clean(paragraph) }.join
72
72
  end
73
73
 
74
74
  def clean_announcement
75
+ return if announcement.is_a?(Hash) && announcement.values.all?(&:blank?)
76
+
75
77
  clean(announcement)
76
78
  end
77
79
 
78
80
  def clean(value)
79
- decidim_sanitize_admin(translated_attribute(value))
81
+ return if value.blank? || value.nil?
82
+
83
+ if value.include?("rich-text-display")
84
+ decidim_sanitize_admin(translated_attribute(value))
85
+ else
86
+ tag.p(decidim_sanitize_admin(translated_attribute(value)))
87
+ end
80
88
  end
81
89
  end
82
90
  end
@@ -1,3 +1,3 @@
1
1
  <div class="row column">
2
- <%= form.upload :file, button_class: "button button__sm button__transparent-secondary" %>
2
+ <%= form.upload :file, attachments: form.object.file.present? ? [form.object.file] : [], button_class: "button button__sm button__transparent-secondary" %>
3
3
  </div>
@@ -2,9 +2,9 @@
2
2
  <% metadata_valued_items.each do |item| %>
3
3
  <div class="participatory-space__metadata-item">
4
4
  <div class="participatory-space__metadata-item-title">
5
- <span><%= item[:title] %></span>
5
+ <p><%= item[:title] %></p>
6
6
  </div>
7
- <span><%= item[:value] %></span>
7
+ <p><%= item[:value] %></p>
8
8
  </div>
9
9
  <% end %>
10
10
  </div>
@@ -1,14 +1,14 @@
1
1
  <div class="participatory-space__nav-container">
2
- <button id="dropdown-trigger-participatory-space" data-controller="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true" data-open-md="true">
2
+ <button id="dropdown-trigger-participatory-space" data-controller="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true">
3
3
  <span><%= t("decidim.searches.filters.jump_to") %></span>
4
4
  <%= icon "arrow-down-s-line" %>
5
5
  <%= icon "arrow-up-s-line" %>
6
6
  </button>
7
- <ul id="dropdown-menu-participatory-space" class="participatory-space__nav">
7
+ <ul id="dropdown-menu-participatory-space" class="participatory-space__nav" aria-hidden="true">
8
8
  <% model.each do |item| %>
9
9
  <li role="menuitem">
10
10
  <%= link_to item[:url], class: "participatory-space__nav-item" do %>
11
- <%= item[:name] %>
11
+ <%= decidim_escape_translated(item[:name]) %>
12
12
  <%= icon "arrow-right-line" %>
13
13
  <% end %>
14
14
  </li>
@@ -1,9 +1,9 @@
1
1
  <div class="statistic <%= stat_dom_class %>" data-statistic>
2
2
  <div class="statistic__header">
3
3
  <div class="statistic__metric">
4
- <div class="statistic__title" title="<%= stat_title %>">
4
+ <p class="statistic__title" title="<%= stat_title %>">
5
5
  <%= stat_title %>
6
- </div>
6
+ </p>
7
7
  <div class="statistic__tooltip">
8
8
  <%= information_tooltip %>
9
9
  </div>
@@ -13,14 +13,14 @@
13
13
  </div>
14
14
  </div>
15
15
  <% if second_stat_number %>
16
- <div class="statistic__second-number">
16
+ <p class="statistic__second-number">
17
17
  <%= stat_sub_title %>
18
18
  <span class="font-semibold"><%= second_stat_number %></span>
19
- </div>
19
+ </p>
20
20
  <% else %>
21
21
  <p class="h-[21px]"></p>
22
22
  <% end %>
23
- <div class="statistic__number">
23
+ <p class="statistic__number">
24
24
  <%= stat_number %>
25
- </div>
25
+ </p>
26
26
  </div>
@@ -1,9 +1,9 @@
1
1
  <div class="upload-modal__files-container upload-container-for-<%= attribute %> <%= with_title %>">
2
2
  <div>
3
- <%= label %>
3
+ <%= options[:paragraph] == true ? paragraph : label %>
4
4
 
5
5
  <% if options[:help_text].present? %>
6
- <span class="help-text"><%= options[:help_text] %></span>
6
+ <p class="help-text"><%= options[:help_text] %></p>
7
7
  <% end %>
8
8
 
9
9
  <%# NOTE: this block is about wrapping a default image for the avatar with the new styles,
@@ -22,24 +22,28 @@
22
22
  <div class="upload-modal__files" data-active-uploads="<%= modal_id %>">
23
23
  <% attachments.each do |attachment| %>
24
24
  <% next if [Array, Hash].any? { |klass| attachment.is_a? klass } %>
25
+ <% is_persisted_attachment = attachment.is_a?(Decidim::Attachment) && attachment.persisted? %>
26
+ <% attachment_blob = blob(attachment) %>
25
27
 
26
- <div class="attachment-details" data-attachment-id="<%= attachment.id %>" data-title="<%= title_for(attachment) %>" data-filename="<%= file_name_for(attachment) %>" data-state="uploaded">
27
- <% if file_attachment_path(attachment) && blob(attachment).image? %>
28
+ <div class="attachment-details"<% if is_persisted_attachment %> data-attachment-id="<%= attachment.id %>"<% end %> data-title="<%= title_for(attachment) %>" data-filename="<%= file_name_for(attachment) %>" data-state="uploaded" data-hidden-field="<%= attachment_blob&.signed_id %>">
29
+ <% if file_attachment_path(attachment) && attachment_blob&.image? %>
28
30
  <div><%= image_tag(file_attachment_path(attachment), alt: "") %></div>
29
31
  <% elsif uploader_default_image_path(attribute).present? %>
30
32
  <div><%= image_tag uploader_default_image_path(attribute) %></div>
31
33
  <% end %>
32
34
 
33
35
  <% if has_title? %>
34
- <span><%= title_for(attachment) %></span>
35
- <%= form.hidden_field attribute, multiple: true, value: attachment.id, id: attachment.id %>
36
+ <p><%= title_for(attachment) %></p>
36
37
  <% else %>
37
- <% if blob(attachment).image? %>
38
- <span><%= title_for(attachment) %></span>
38
+ <% if attachment_blob&.image? %>
39
+ <p><%= title_for(attachment) %></p>
39
40
  <% else %>
40
41
  <%= link_to title_for(attachment), file_attachment_path(attachment), class: "w-full break-all mb-2" %>
41
42
  <% end %>
42
43
  <% end %>
44
+ <% if attachment_blob.present? %>
45
+ <%= form.hidden_field attribute, value: attachment_blob.signed_id, id: "hidden_#{attribute}_#{attachment_blob.id}" %>
46
+ <% end %>
43
47
  </div>
44
48
  <% end %>
45
49
  </div>
@@ -30,6 +30,10 @@ module Decidim
30
30
  form.send(:custom_label, attribute, options[:label], { required: required?, for: nil })
31
31
  end
32
32
 
33
+ def paragraph
34
+ form.send(:custom_paragraph, attribute, options[:label], { required: required? })
35
+ end
36
+
33
37
  def button_label
34
38
  return button_edit_label if attachments.count.positive?
35
39
 
@@ -71,13 +75,16 @@ module Decidim
71
75
  end
72
76
 
73
77
  # By default FoundationRailsHelper adds form errors next to input, but since input is in the modal
74
- # and modal is hidden by default, we need to add an additional validation field to the form.
78
+ # and modal is hidden by default, we add a hidden checkbox field to handle HTML5 validation.
75
79
  # This should only be necessary when file is required by the form.
80
+ # Note: Validation errors are now displayed in the main form area, not inside the modal.
76
81
  def input_validation_field
77
82
  object_name = form.object.present? ? "#{form.object.model_name.param_key}[#{add_attribute}_validation]" : "#{add_attribute}_validation"
78
- input = check_box_tag object_name, 1, attachments.present?, class: "reset-defaults", hidden: true, label: false, required: required?
79
- message = form.send(:abide_error_element, add_attribute) + form.send(:error_and_help_text, add_attribute)
80
- input + message
83
+ check_box_tag object_name, 1, attachments.present?, class: "reset-defaults", hidden: true, label: false, required: required?, id: validation_field_id
84
+ end
85
+
86
+ def validation_field_id
87
+ "#{attribute}_validation"
81
88
  end
82
89
 
83
90
  def explanation
@@ -9,8 +9,6 @@ module Decidim
9
9
  skip_before_action :verify_organization
10
10
 
11
11
  before_action :check_organization!,
12
- :check_authenticated!,
13
- :check_user_belongs_to_organization,
14
12
  :validate_direct_upload
15
13
  end
16
14
 
@@ -42,16 +40,6 @@ module Decidim
42
40
  head :unauthorized if current_organization.blank? && current_admin.blank?
43
41
  end
44
42
 
45
- def check_authenticated!
46
- head :unauthorized if current_user.blank? && current_admin.blank?
47
- end
48
-
49
- def check_user_belongs_to_organization
50
- return if current_admin.present?
51
-
52
- head :unauthorized unless current_organization == current_user.organization
53
- end
54
-
55
43
  def allowed_extensions
56
44
  if user_has_elevated_role?
57
45
  current_organization.settings.upload_allowed_file_extensions_admin
@@ -71,6 +59,8 @@ module Decidim
71
59
  private
72
60
 
73
61
  def user_has_elevated_role?
62
+ return false if current_user.blank? || current_organization.blank? || current_user.organization != current_organization
63
+
74
64
  [
75
65
  current_user&.admin?,
76
66
  defined?(Decidim::Assemblies::AssembliesWithUserRole) && Decidim::Assemblies::AssembliesWithUserRole.for(current_user).any?,
@@ -9,6 +9,8 @@ module Decidim
9
9
 
10
10
  before_action :check_sign_in_enabled, only: :create
11
11
 
12
+ rescue_from ActionController::InvalidAuthenticityToken, with: :redirect_to_referer_or_path
13
+
12
14
  def create
13
15
  super do |user|
14
16
  if user.admin?
@@ -44,6 +46,11 @@ module Decidim
44
46
 
45
47
  private
46
48
 
49
+ def redirect_to_referer_or_path
50
+ set_flash_message(:alert, "csrf_token", scope: "devise.failure")
51
+ redirect_back(fallback_location: root_path) && return
52
+ end
53
+
47
54
  def check_sign_in_enabled
48
55
  redirect_to new_user_session_path unless current_organization.sign_in_enabled?
49
56
  end
@@ -117,9 +117,9 @@ module Decidim
117
117
  end
118
118
 
119
119
  def message(value)
120
- return content_tag(:div, value, class: "flash__message") unless value.is_a?(Hash)
120
+ return content_tag(:p, value, class: "flash__message") unless value.is_a?(Hash)
121
121
 
122
- content_tag(:div, class: "flash__message") do
122
+ content_tag(:p, class: "flash__message") do
123
123
  concat value[:title]
124
124
  concat content_tag(:span, value[:body], class: "flash__message-body")
125
125
  end
@@ -11,7 +11,7 @@ module Decidim
11
11
  manifest.name == name.to_sym
12
12
  end
13
13
 
14
- collection = export_manifest.collection.call(participatory_space)
14
+ collection = export_manifest.collection.call(participatory_space, user)
15
15
  serializer = export_manifest.serializer
16
16
 
17
17
  export_data = Decidim::Exporters.find_exporter(format).new(collection, serializer).export
@@ -9,7 +9,7 @@ module Decidim
9
9
  include Traceable
10
10
 
11
11
  before_save :set_content_type_and_size, if: :attached?
12
- before_validation :set_link_content_type_and_size, if: :link?
12
+ before_validation :set_link_content_type_and_size, if: :editable_link?
13
13
 
14
14
  translatable_fields :title, :description
15
15
  belongs_to :attachment_collection, class_name: "Decidim::AttachmentCollection", optional: true
@@ -69,6 +69,20 @@ module Decidim
69
69
  link.present?
70
70
  end
71
71
 
72
+ # Whether this attachment is a link that can be edited or not.
73
+ #
74
+ # Returns Boolean.
75
+ def editable_link?
76
+ !destroyed? && !frozen? && link?
77
+ end
78
+
79
+ # Whether this attachment has a file or not.
80
+ #
81
+ # Returns Boolean.
82
+ def file?
83
+ file.attached?
84
+ end
85
+
72
86
  # Which kind of file this is.
73
87
  #
74
88
  # Returns String.
@@ -123,5 +137,12 @@ module Decidim
123
137
  def self.log_presenter_class_for(_log)
124
138
  Decidim::AdminLog::AttachmentPresenter
125
139
  end
140
+
141
+ def can_participate?(user)
142
+ return true unless attached_to
143
+ return true unless attached_to.respond_to?(:can_participate?)
144
+
145
+ attached_to.can_participate?(user)
146
+ end
126
147
  end
127
148
  end
@@ -42,6 +42,10 @@ export default class extends Controller {
42
42
  }
43
43
 
44
44
  setupMutationObserver() {
45
+ if (!this.newPasswordPanel) {
46
+ return;
47
+ }
48
+
45
49
  this.observer = new MutationObserver(() => {
46
50
  let ariaHiddenValue = this.newPasswordPanel.getAttribute("aria-hidden");
47
51
  this.newPwVisible = ariaHiddenValue === "false";
@@ -54,6 +58,10 @@ export default class extends Controller {
54
58
  }
55
59
 
56
60
  setupEmailChangeListener() {
61
+ if (!this.emailField) {
62
+ return;
63
+ }
64
+
57
65
  this.emailField.addEventListener("change", () => {
58
66
  this.emailChanged = this.emailField.value !== this.originalEmail;
59
67
  this.toggleOldPassword();
@@ -0,0 +1,38 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ /**
4
+ * This controller is used to change the active tab when the language is changed in the admin or system panel.
5
+ * It uses a select element to list the languages available in the platform and adds an observer that would set
6
+ * the tab the active tab to what is selected in the select element by toggling the aria-hidden attribute on the
7
+ * tab container.
8
+ */
9
+ export default class extends Controller {
10
+ connect() {
11
+ this.handleChange = this.handleChange.bind(this);
12
+ this.element.addEventListener("change", this.handleChange);
13
+ }
14
+
15
+ disconnect() {
16
+ this.element.removeEventListener("change", this.handleChange)
17
+ }
18
+
19
+ handleChange(event) {
20
+ let targetTabPaneSelector = event.target.value;
21
+ let tabsContent = event.target.parentElement.parentElement.nextElementSibling;
22
+
23
+ if (!tabsContent) {
24
+ return;
25
+ }
26
+
27
+ let activeTabContent = tabsContent.querySelector(".is-active");
28
+ if (activeTabContent) {
29
+ activeTabContent.ariaHidden = "true";
30
+ activeTabContent.classList.remove("is-active");
31
+ }
32
+ let activePane = tabsContent.querySelector(targetTabPaneSelector);
33
+ if (activePane) {
34
+ activePane.ariaHidden = "false";
35
+ activePane.classList.add("is-active");
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,105 @@
1
+ /* global jest */
2
+ /* eslint max-lines: ["error", 360] */
3
+ import { Application } from "@hotwired/stimulus"
4
+ import LanguageChangeController from "src/decidim/controllers/language_change/controller";
5
+
6
+ describe("LanguageChangeController", () => {
7
+ let application = null;
8
+ let controller = null;
9
+ let selectElement = null;
10
+ let tabsContent = null;
11
+ let panel0 = null;
12
+ let panel1 = null;
13
+
14
+ beforeEach(() => {
15
+ application = Application.start();
16
+ application.register("language-change", LanguageChangeController);
17
+
18
+ document.body.innerHTML = `
19
+ <div class="label--tabs">
20
+ <label for="update_organization_name">Name</label>
21
+ <div>
22
+ <select id="update_organization-name-tabs" class="language-change" data-controller="language-change">
23
+ <option value="#update_organization-name-tabs-name-panel-0">English</option>
24
+ <option value="#update_organization-name-tabs-name-panel-1">Bulgarian</option>
25
+ </select>
26
+ </div>
27
+ </div>
28
+ <div class="tabs-content" data-tabs-content="update_organization-name-tabs">
29
+ <div class="tabs-panel is-active" id="update_organization-name-tabs-name-panel-0" aria-hidden="false">
30
+ <input type="text" value="Example" name="update_organization[name_en]" id="update_organization_name_en">
31
+ </div>
32
+ <div class="tabs-panel" id="update_organization-name-tabs-name-panel-1" aria-hidden="true">
33
+ <input type="text" value="Example BG" name="update_organization[name_bg]" id="update_organization_name_bg">
34
+ </div>
35
+ </div>
36
+ `;
37
+
38
+ selectElement = document.querySelector("select[data-controller='language-change']");
39
+ tabsContent = document.querySelector(".tabs-content");
40
+ panel0 = document.querySelector("#update_organization-name-tabs-name-panel-0");
41
+ panel1 = document.querySelector("#update_organization-name-tabs-name-panel-1");
42
+
43
+ return new Promise((resolve) => {
44
+ setTimeout(() => {
45
+ controller = application.getControllerForElementAndIdentifier(selectElement, "language-change");
46
+ resolve();
47
+ }, 0);
48
+ });
49
+ });
50
+
51
+ afterEach(() => {
52
+ application.stop();
53
+ document.body.innerHTML = "";
54
+ });
55
+
56
+ describe("connect / disconnect", () => {
57
+ it("adds a change listener on connect", () => {
58
+ const addSpy = jest.spyOn(selectElement, "addEventListener");
59
+
60
+ controller.disconnect();
61
+ controller.connect();
62
+
63
+ expect(addSpy).toHaveBeenCalledWith("change", expect.any(Function));
64
+ addSpy.mockRestore();
65
+ });
66
+
67
+ it("removes the change listener on disconnect", () => {
68
+ const removeSpy = jest.spyOn(selectElement, "removeEventListener");
69
+
70
+ controller.disconnect();
71
+
72
+ expect(removeSpy).toHaveBeenCalledWith("change", controller.handleChange);
73
+ removeSpy.mockRestore();
74
+ });
75
+ });
76
+
77
+ describe("handleChange", () => {
78
+ it("toggles active tab panel and aria-hidden", () => {
79
+ selectElement.value = "#update_organization-name-tabs-name-panel-1";
80
+
81
+ controller.handleChange({ target: selectElement });
82
+
83
+ expect(panel0.classList.contains("is-active")).toBe(false);
84
+ expect(panel0.ariaHidden).toBe("true");
85
+ expect(panel1.classList.contains("is-active")).toBe(true);
86
+ expect(panel1.ariaHidden).toBe("false");
87
+ });
88
+
89
+ it("does nothing when tabs content is missing", () => {
90
+ tabsContent.remove();
91
+
92
+ expect(() => controller.handleChange({ target: selectElement })).not.toThrow();
93
+ });
94
+
95
+ it("activates the target panel when no panel is active", () => {
96
+ panel0.classList.remove("is-active");
97
+
98
+ selectElement.value = "#update_organization-name-tabs-name-panel-1";
99
+ controller.handleChange({ target: selectElement });
100
+
101
+ expect(panel1.classList.contains("is-active")).toBe(true);
102
+ expect(panel1.ariaHidden).toBe("false");
103
+ });
104
+ });
105
+ });
@@ -79,7 +79,7 @@ const updateActiveUploads = (modal) => {
79
79
  const template = `
80
80
  <div ${attachmentIdOrHiddenField} data-filename="${escapeQuotes(file.name)}" data-title="${escapeQuotes(title)}">
81
81
  ${(/image/).test(file.type) && "<div><img src=\"data:,\" role=\"presentation\" /></div>" || ""}
82
- <span>${escapeHtml(title)}</span>
82
+ <p>${escapeHtml(title)}</p>
83
83
  ${hidden}
84
84
  </div>
85
85
  `
@@ -1,5 +1,5 @@
1
1
  .flash {
2
- @apply flex justify-start gap-4 border-l-4 border-secondary my-4 p-4 bg-secondary/5;
2
+ @apply flex justify-start gap-4 border-l-4 border-secondary my-4 p-4 bg-secondary/5 break-all;
3
3
 
4
4
  &__icon {
5
5
  svg {
@@ -127,7 +127,7 @@
127
127
  @apply w-full rounded bg-background flex items-center justify-center py-4 [&_img]:object-cover [&_img]:h-[200px];
128
128
  }
129
129
 
130
- span {
130
+ p {
131
131
  @apply text-sm text-gray-2 mx-auto w-full break-all mb-2;
132
132
  }
133
133
  }
@@ -99,7 +99,7 @@
99
99
  @apply divide-y divide-white [&>li]:py-3.5 first:[&>li]:pt-0 last:[&>li]:pb-0;
100
100
 
101
101
  &-container {
102
- @apply ml-0 md:ml-6 bg-primary p-3 md:p-6 rounded w-full md:w-auto self-start;
102
+ @apply mb-8 ml-0 md:ml-6 bg-primary p-3 md:p-6 rounded w-full md:w-auto self-start;
103
103
 
104
104
  [id*="dropdown-menu"] {
105
105
  @apply mx-0;
@@ -118,7 +118,7 @@ module Decidim
118
118
 
119
119
  def data_for_participatory_space(export_manifest)
120
120
  collection = participatory_spaces.filter { |space| space.manifest.name == export_manifest.manifest.name }.flat_map do |participatory_space|
121
- export_manifest.collection.call(participatory_space)
121
+ export_manifest.collection.call(participatory_space, nil)
122
122
  end
123
123
 
124
124
  serializer = export_manifest.open_data_serializer.nil? ? export_manifest.serializer : export_manifest.open_data_serializer
@@ -31,7 +31,7 @@
31
31
  </div>
32
32
  <% end %>
33
33
 
34
- <p class="h3 mt-2"><%= t("decidim.block_user_mailer.notify.hello") %>&nbsp;<%= current_user.name %></p>
34
+ <p class="h3 mt-2"><%= t("layouts.decidim.header.mobile_account_greeting", user_name: current_user.name) %></p>
35
35
 
36
36
  <ul>
37
37
  <%= render partial: "layouts/decidim/header/main_links_dropdown" %>
@@ -1057,6 +1057,9 @@ ca-IT:
1057
1057
  explanation: 'Instruccions per a la imatge:'
1058
1058
  message_1: Preferiblement una imatge apaïsada que no tingui cap text.
1059
1059
  message_2: El servei retalla la imatge.
1060
+ import_file:
1061
+ explanation: 'Instruccions per al fitxer d''importació:'
1062
+ message_1: Ha de ser un document JSON descarregat mitjançant la funció d'exportació.
1060
1063
  file_validation:
1061
1064
  allowed_file_extensions: 'Tipus de fitxers admesos: %{extensions}'
1062
1065
  max_file_dimension: 'Mides máximes de l''arxiu: %{resolution} pixels'
@@ -1801,6 +1804,7 @@ ca-IT:
1801
1804
  send_paranoid_instructions: Si la teva adreça de correu electrònic existeix a la nostra base de dades, rebràs un correu electrònic amb instruccions per confirmar la teva adreça en pocs minuts.
1802
1805
  failure:
1803
1806
  already_authenticated: Ja has iniciat la sessió.
1807
+ csrf_token: No es pot verificar la teva sol·licitud. Si us plau, torna a provar-ho.
1804
1808
  inactive: El teu compte encara no està activat.
1805
1809
  invalid: El %{authentication_keys} o la contrasenya no són vàlids.
1806
1810
  invited: Tens una invitació pendent, accepta-la per acabar de crear el teu compte.
@@ -2128,6 +2132,7 @@ ca-IT:
2128
2132
  confirm_title_close_ephemeral_session: Abans de sortir d'aquesta pàgina…
2129
2133
  log_in: Entra
2130
2134
  main_menu: Menú principal
2135
+ mobile_account_greeting: Hola %{user_name},
2131
2136
  user_menu: Menú d'usuari
2132
2137
  impersonation_warning:
2133
2138
  close_session: Tanca la sessió
@@ -1057,6 +1057,9 @@ ca:
1057
1057
  explanation: 'Instruccions per a la imatge:'
1058
1058
  message_1: Preferiblement una imatge apaïsada que no tingui cap text.
1059
1059
  message_2: El servei retalla la imatge.
1060
+ import_file:
1061
+ explanation: 'Instruccions per al fitxer d''importació:'
1062
+ message_1: Ha de ser un document JSON descarregat mitjançant la funció d'exportació.
1060
1063
  file_validation:
1061
1064
  allowed_file_extensions: 'Tipus de fitxers admesos: %{extensions}'
1062
1065
  max_file_dimension: 'Mides máximes de l''arxiu: %{resolution} pixels'
@@ -1801,6 +1804,7 @@ ca:
1801
1804
  send_paranoid_instructions: Si la teva adreça de correu electrònic existeix a la nostra base de dades, rebràs un correu electrònic amb instruccions per confirmar la teva adreça en pocs minuts.
1802
1805
  failure:
1803
1806
  already_authenticated: Ja has iniciat la sessió.
1807
+ csrf_token: No es pot verificar la teva sol·licitud. Si us plau, torna a provar-ho.
1804
1808
  inactive: El teu compte encara no està activat.
1805
1809
  invalid: El %{authentication_keys} o la contrasenya no són vàlids.
1806
1810
  invited: Tens una invitació pendent, accepta-la per acabar de crear el teu compte.
@@ -2128,6 +2132,7 @@ ca:
2128
2132
  confirm_title_close_ephemeral_session: Abans de sortir d'aquesta pàgina…
2129
2133
  log_in: Entra
2130
2134
  main_menu: Menú principal
2135
+ mobile_account_greeting: Hola %{user_name},
2131
2136
  user_menu: Menú d'usuari
2132
2137
  impersonation_warning:
2133
2138
  close_session: Tanca la sessió