alchemy_cms 6.0.5 → 6.0.6

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.

Potentially problematic release.


This version of alchemy_cms might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c5eb21e30df422e1b214dd34d5d6166d8aaf195d393590efdf1e6a16a1247910
4
- data.tar.gz: aa579d8246cfc7952a2f2491c86a78e272733eb7c21d993d4302201ee2b1a3f3
3
+ metadata.gz: ac4238ff0e22f613444f1ae9124a20bf4e884f2f7c4f8fe05c1e8d0bd147cad7
4
+ data.tar.gz: 02e2877398db81eb4c58a1afbad4c0355020da0fb7505c895d493d40a93223d7
5
5
  SHA512:
6
- metadata.gz: 4b92efbc92492ccbc49ff95249672d5083499898d6ce70644b68a44fdc49720a716986c138211c308c1e3cf3a7b614db6d04a9463399c81c8167b31622aa1f5c
7
- data.tar.gz: 4d297aea832eeea8b51183b234bcad0cacc168283e07f1d83ca180e1a59fb02601756869e74c3348f10b14308a62e660d6dd2b0a04251da51b4c574435e4518a
6
+ metadata.gz: 2bacfe8d1e126cc3a3e31f5dfdb1346efb1398adf33dac32e4e58731bcfd11580d51544797a59d563361ee28c5d4a37a76a7659b7534651a574c7903820cc994
7
+ data.tar.gz: '04198e8f916fd87a5a1587129b86480cde12cbab889acfa2baaf23a34ed966292cc24312c1b731648c556e27fc3045b0a5b56d43ab6124abacbcb33cdf05fab2'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 6.0.6 (2022-05-30)
2
+
3
+ - Add task to eagerly generate ingredients pictures thumbnails [#2342](https://github.com/AlchemyCMS/alchemy_cms/pull/2342) ([tvdeyen](https://github.com/tvdeyen))
4
+ - Add spec for ingredients migrator; fix preloading in Rails 6.1+ [#2340](https://github.com/AlchemyCMS/alchemy_cms/pull/2340) ([mamhoff](https://github.com/mamhoff))
5
+ - Extract element ingredient migrator [#2337](https://github.com/AlchemyCMS/alchemy_cms/pull/2337) ([tvdeyen](https://github.com/tvdeyen))
6
+ - Update published_at only after page has been published. [#2331](https://github.com/AlchemyCMS/alchemy_cms/pull/2331) ([pascalbetz](https://github.com/pascalbetz))
7
+ - Add element groups functionality for cleaning up editors [#2124](https://github.com/AlchemyCMS/alchemy_cms/pull/2124) ([dbwinger](https://github.com/dbwinger))
8
+ - Eagerload at the controller or job layer [#2313](https://github.com/AlchemyCMS/alchemy_cms/pull/2313) ([mamhoff](https://github.com/mamhoff))
9
+
1
10
  ## 6.0.5 (2022-05-11)
2
11
 
3
12
  - Extract element ingredient migrator [#2337](https://github.com/AlchemyCMS/alchemy_cms/pull/2337) ([tvdeyen](https://github.com/tvdeyen))
@@ -15,6 +15,7 @@ Alchemy.ElementEditors =
15
15
  init: ->
16
16
  @element_area = $("#element_area")
17
17
  @bindEvents()
18
+ @expandContentGroups()
18
19
  return
19
20
 
20
21
  # Binds click events on several DOM elements from element editors
@@ -36,12 +37,20 @@ Alchemy.ElementEditors =
36
37
  # Binds the custom SaveElement event
37
38
  @element_area.on "SaveElement.Alchemy", '.element-editor', (e, data) =>
38
39
  @onSaveElement(e, data)
40
+ @element_area.on "click", '[data-toggle-content-group]', (e) =>
41
+ @onToggleContentGroup(e)
39
42
  # Listen to postMessage messages from the preview frame
40
43
  window.addEventListener 'message', (e) =>
41
44
  @onMessage(e.data)
42
45
  true
43
46
  return
44
47
 
48
+ # Expands content groups that are stored in sessionStorage as expanded
49
+ expandContentGroups: ->
50
+ if $expanded_content_groups = sessionStorage.getItem('Alchemy.expanded_content_groups')
51
+ for header_id in JSON.parse($expanded_content_groups) then do (header_id) =>
52
+ $('#' + header_id).closest('.content-group').addClass('expanded');
53
+
45
54
  # Selects and scrolls to element with given id in the preview window.
46
55
  #
47
56
  focusElementPreview: (element_id) ->
@@ -170,6 +179,23 @@ Alchemy.ElementEditors =
170
179
  Alchemy.Buttons.enable($element)
171
180
  true
172
181
 
182
+ # Toggle visibility of the content fields in the group
183
+ onToggleContentGroup: (event) ->
184
+ $group_div = $(event.currentTarget).closest('.content-group');
185
+ $group_div.toggleClass('expanded');
186
+
187
+ $expanded_content_groups = JSON.parse(sessionStorage.getItem('Alchemy.expanded_content_groups') || '[]');
188
+ # Add or remove depending on whether this content group is expanded
189
+ if $group_div.hasClass('expanded')
190
+ if $expanded_content_groups.indexOf(event.currentTarget.id) == -1
191
+ $expanded_content_groups.push(event.currentTarget.id);
192
+ else
193
+ $expanded_content_groups = $expanded_content_groups.filter (value) ->
194
+ value != event.currentTarget.id
195
+
196
+ sessionStorage.setItem('Alchemy.expanded_content_groups', JSON.stringify($expanded_content_groups))
197
+ false
198
+
173
199
  # Event handlers
174
200
 
175
201
  onMessage: (data) ->
@@ -414,6 +414,41 @@
414
414
  }
415
415
  }
416
416
 
417
+ .content-group {
418
+ width: 100%;
419
+ padding: $default-padding 0;
420
+ position: relative;
421
+ border-bottom: 1px solid $medium-gray;
422
+
423
+ &:last-child {
424
+ border-bottom: none;
425
+ padding-bottom: 0;
426
+ }
427
+
428
+ .content-group-header {
429
+ display: flex;
430
+ align-items: center;
431
+ justify-content: space-between;
432
+ font-weight: bold;
433
+ text-decoration: none;
434
+ padding: $default-padding 1px;
435
+ }
436
+
437
+ .content-group-contents {
438
+ display: none;
439
+ }
440
+
441
+ &.expanded {
442
+ .content-group-contents {
443
+ display: block;
444
+ }
445
+
446
+ .content-group-expand {
447
+ @extend .fa-angle-up;
448
+ }
449
+ }
450
+ }
451
+
417
452
  .element-content-editors,
418
453
  .element-ingredient-editors {
419
454
  display: flex;
@@ -324,7 +324,7 @@ module Alchemy
324
324
  end
325
325
 
326
326
  def load_resource
327
- @page = Page.find(params[:id])
327
+ @page = Page.includes(page_includes).find(params[:id])
328
328
  end
329
329
 
330
330
  def pages_from_raw_request
@@ -402,6 +402,10 @@ module Alchemy
402
402
  def set_preview_mode
403
403
  @preview_mode = true
404
404
  end
405
+
406
+ def page_includes
407
+ Alchemy::EagerLoading.page_includes(version: :draft_version)
408
+ end
405
409
  end
406
410
  end
407
411
  end
@@ -104,7 +104,14 @@ module Alchemy
104
104
  # If no index page and no admin users are present we show the "Welcome to Alchemy" page.
105
105
  #
106
106
  def load_index_page
107
- @page ||= Language.current_root_page
107
+ @page ||= begin
108
+ Alchemy::Page.
109
+ contentpages.
110
+ language_roots.
111
+ where(language: Language.current).
112
+ includes(page_includes).
113
+ first
114
+ end
108
115
  render template: "alchemy/welcome", layout: false if signup_required?
109
116
  end
110
117
 
@@ -120,10 +127,13 @@ module Alchemy
120
127
  def load_page
121
128
  page_not_found! unless Language.current
122
129
 
123
- @page ||= Language.current.pages.contentpages.find_by(
124
- urlname: params[:urlname],
125
- language_code: params[:locale] || Language.current.code,
126
- )
130
+ @page ||= begin
131
+ Alchemy::Page.
132
+ contentpages.
133
+ where(language: Language.current).
134
+ includes(page_includes).
135
+ find_by(urlname: params[:urlname])
136
+ end
127
137
  end
128
138
 
129
139
  def enforce_locale
@@ -234,5 +244,9 @@ module Alchemy
234
244
  def page_not_found!
235
245
  not_found_error!("Alchemy::Page not found \"#{request.fullpath}\"")
236
246
  end
247
+
248
+ def page_includes
249
+ Alchemy::EagerLoading.page_includes(version: :public_version)
250
+ end
237
251
  end
238
252
  end
@@ -36,6 +36,29 @@ module Alchemy
36
36
  element.definition.fetch(:ingredients, []).any?
37
37
  end
38
38
 
39
+ # Returns the translated content/ingredient group for displaying in admin editor group headings
40
+ #
41
+ # Translate it in your locale yml file:
42
+ #
43
+ # alchemy:
44
+ # element_groups:
45
+ # foo: Bar
46
+ #
47
+ # Optionally you can scope your ingredient role to an element:
48
+ #
49
+ # alchemy:
50
+ # element_groups:
51
+ # article:
52
+ # foo: Baz
53
+ #
54
+ def translated_group(group)
55
+ Alchemy.t(
56
+ group,
57
+ scope: "element_groups.#{element.name}",
58
+ default: Alchemy.t("element_groups.#{group}", default: group.humanize),
59
+ )
60
+ end
61
+
39
62
  # CSS classes for the element editor partial.
40
63
  def css_classes
41
64
  [
@@ -4,7 +4,10 @@ module Alchemy
4
4
  class PublishPageJob < BaseJob
5
5
  queue_as :default
6
6
 
7
- def perform(page, public_on:)
7
+ def perform(page_id, public_on:)
8
+ page = Alchemy::Page.includes(
9
+ Alchemy::EagerLoading.page_includes(version: :draft_version)
10
+ ).find(page_id)
8
11
  Alchemy::Page::Publisher.new(page).publish!(public_on: public_on)
9
12
  end
10
13
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ # Eager loading parameters for loading pages
5
+ class EagerLoading
6
+ PAGE_VERSIONS = %i[draft_version public_version]
7
+
8
+ class << self
9
+ # Eager loading parameters for {ActiveRecord::Base.includes}
10
+ #
11
+ # Pass this to +includes+ whereever you load an {Alchemy::Page}
12
+ #
13
+ # Alchemy::Page.includes(Alchemy::EagerLoading.page_includes).find_by(urlname: "my-page")
14
+ #
15
+ # @param version [Symbol] Type of page version to eager load
16
+ # @return [Array]
17
+ def page_includes(version: :public_version)
18
+ raise UnsupportedPageVersion unless version.in? PAGE_VERSIONS
19
+
20
+ [
21
+ :tags,
22
+ {
23
+ language: :site,
24
+ version => {
25
+ elements: [
26
+ :page,
27
+ :touchable_pages,
28
+ {
29
+ ingredients: :related_object,
30
+ contents: :essence,
31
+ },
32
+ ],
33
+ },
34
+ },
35
+ ]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -12,7 +12,9 @@ module Alchemy
12
12
 
13
13
  # Copies all currently visible elements to the public version of page
14
14
  #
15
- # Creates a new published version if none exists yet.
15
+ # Creates a new published version if none exists yet and updates
16
+ # the `published_at` timestamp of the page.
17
+ # `published_at` is used as a cache key.
16
18
  #
17
19
  # Sends a publish notification to all registered publish targets
18
20
  #
@@ -32,6 +34,7 @@ module Alchemy
32
34
  end
33
35
  end
34
36
  end
37
+ page.update(published_at: public_on)
35
38
  end
36
39
 
37
40
  Alchemy.publish_targets.each { |p| p.perform_later(page) }
@@ -457,15 +457,10 @@ module Alchemy
457
457
  end
458
458
  end
459
459
 
460
- # Creates a public version of the page.
461
- #
462
- # Sets the +published_at+ value to current time
463
- #
464
- # The +published_at+ attribute is used as +cache_key+.
460
+ # Creates a public version of the page in the background.
465
461
  #
466
462
  def publish!(current_time = Time.current)
467
- update(published_at: current_time)
468
- PublishPageJob.perform_later(self, public_on: current_time)
463
+ PublishPageJob.perform_later(id, public_on: current_time)
469
464
  end
470
465
 
471
466
  # Sets the public_on date on the published version
@@ -46,7 +46,7 @@ module Alchemy
46
46
  end
47
47
 
48
48
  def element_repository
49
- ElementsRepository.new(elements.includes({ contents: :essence }, :tags))
49
+ ElementsRepository.new(elements)
50
50
  end
51
51
 
52
52
  private
@@ -23,15 +23,44 @@
23
23
  html: {id: "element_#{element.id}_form".html_safe, class: 'element-content'} do |f| %>
24
24
 
25
25
  <div id="element_<%= element.id %>_errors" class="element_errors"></div>
26
+
27
+ <!-- Ingredients -->
26
28
  <% if element.has_ingredients_defined? %>
27
29
  <div class="element-ingredient-editors">
28
- <%= render element.ingredients, element_form: f %>
29
- </div>
30
- <% else %>
31
- <div id="element_<%= element.id %>_content" class="element-content-editors">
32
- <%= render element.contents %>
30
+ <%= render element.ingredients.select { |i| !i.definition[:group] }, element_form: f %>
31
+
32
+ <!-- Each ingredient group -->
33
+ <% element.ingredients.select { |i| i.definition[:group] }.group_by { |i| i.definition[:group] }.each do |group, ingredients| %>
34
+ <div class="content-group">
35
+ <%= link_to '#', id: "element_#{element.id}_content_group_#{group.parameterize.underscore}_header", class: 'content-group-header', data: { toggle_content_group: true } do %>
36
+ <%= element.translated_group group %>
37
+ <i class="content-group-expand icon fa-fw fa-angle-down fas"></i>
38
+ <% end %>
39
+ <%= content_tag :div, id: "element_#{element.id}_content_group_#{group.parameterize.underscore}", class: 'content-group-contents' do %>
40
+ <%= render ingredients, element_form: f %>
41
+ <% end %>
42
+ </div>
43
+ <% end %>
33
44
  </div>
34
45
  <% end %>
46
+ <!-- Contents -->
47
+ <div id="element_<%= element.id %>_content" class="element-content-editors">
48
+ <%= render element.contents.select { |c| !c.definition[:group] } %>
49
+
50
+ <!-- Each content group -->
51
+ <% element.contents.select { |c| c.definition[:group] }.group_by { |c| c.definition[:group] }.each do |group, contents| %>
52
+ <div class="content-group">
53
+ <%= link_to '#', id: "element_#{element.id}_content_group_#{group.parameterize.underscore}_header", class: 'content-group-header', data: { toggle_content_group: true } do %>
54
+ <%= element.translated_group group %>
55
+ <i class="content-group-expand icon fa-fw fa-angle-down fas"></i>
56
+ <% end %>
57
+ <%= content_tag :div, id: "element_#{element.id}_content_group_#{group.parameterize.underscore}", class: 'content-group-contents' do %>
58
+ <%= render contents, element_form: f %>
59
+ <% end %>
60
+ </div>
61
+ <% end %>
62
+ </div>
63
+
35
64
  <% if element.taggable? %>
36
65
  <div class="autocomplete_tag_list">
37
66
  <%= f.label :tag_list %>
@@ -11,7 +11,7 @@ module Alchemy
11
11
  # Raised if no default language configuration can be found.
12
12
  def message
13
13
  "No default language configuration found!" \
14
- " Please ensure that you have a 'default_language' defined in Alchemy configuration file."
14
+ " Please ensure that you have a 'default_language' defined in Alchemy configuration file."
15
15
  end
16
16
  end
17
17
 
@@ -19,7 +19,7 @@ module Alchemy
19
19
  # Raised if no default site configuration can be found.
20
20
  def message
21
21
  "No default site configuration found!" \
22
- " Please ensure that you have a 'default_site' defined in Alchemy configuration file."
22
+ " Please ensure that you have a 'default_site' defined in Alchemy configuration file."
23
23
  end
24
24
  end
25
25
 
@@ -90,4 +90,10 @@ module Alchemy
90
90
  "You need to provide a current_user method in your ApplicationController that returns the current authenticated user."
91
91
  end
92
92
  end
93
+
94
+ class UnsupportedPageVersion < StandardError
95
+ def message
96
+ "Unknown Version! Please use one of #{Alchemy::EagerLoading::PAGE_VERSIONS.join(", ")}"
97
+ end
98
+ end
93
99
  end
@@ -16,7 +16,7 @@ module Alchemy::Upgrader::Tasks
16
16
  # eager load all elements that have ingredients defined but no ingredient records yet.
17
17
  all_elements = Alchemy::Element
18
18
  .named(elements_with_ingredients.map { |d| d[:name] })
19
- .includes(contents: :essence)
19
+ .preload(contents: :essence)
20
20
  .left_outer_joins(:ingredients).where(alchemy_ingredients: { id: nil })
21
21
  .to_a
22
22
  elements_with_ingredients.map do |element_definition|
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "6.0.5"
4
+ VERSION = "6.0.6"
5
5
 
6
6
  def self.version
7
7
  VERSION
@@ -35,5 +35,29 @@ namespace :alchemy do
35
35
 
36
36
  puts "Done!"
37
37
  end
38
+
39
+ desc "Generates thumbnails for Alchemy Picture Ingredients (set ELEMENTS=element1,element2 to only generate thumbnails for a subset of elements)."
40
+ task ingredient_picture_thumbnails: :environment do
41
+ ingredient_pictures = Alchemy::Ingredients::Picture.
42
+ joins(:element).
43
+ preload({ related_object: :thumbs }).
44
+ merge(Alchemy::Element.available)
45
+
46
+ if ENV["ELEMENTS"].present?
47
+ ingredient_pictures = ingredient_pictures.merge(
48
+ Alchemy::Element.named(ENV["ELEMENTS"].split(","))
49
+ )
50
+ end
51
+
52
+ puts "Regenerate #{ingredient_pictures.count} ingredient picture thumbnails."
53
+ puts "Please wait..."
54
+
55
+ ingredient_pictures.find_each do |ingredient_picture|
56
+ puts ingredient_picture.picture_url
57
+ puts ingredient_picture.thumbnail_url
58
+ end
59
+
60
+ puts "Done!"
61
+ end
38
62
  end
39
63
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy_cms/admin",
3
- "version": "6.0.5",
3
+ "version": "6.0.6",
4
4
  "description": "AlchemyCMS",
5
5
  "browser": "package/admin.js",
6
6
  "files": [
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.5
4
+ version: 6.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2022-05-11 00:00:00.000000000 Z
16
+ date: 2022-05-30 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: actionmailer
@@ -916,6 +916,7 @@ files:
916
916
  - app/models/alchemy/base_record.rb
917
917
  - app/models/alchemy/content.rb
918
918
  - app/models/alchemy/content/factory.rb
919
+ - app/models/alchemy/eager_loading.rb
919
920
  - app/models/alchemy/element.rb
920
921
  - app/models/alchemy/element/definitions.rb
921
922
  - app/models/alchemy/element/element_contents.rb