alchemy_cms 6.0.5 → 6.0.6

Sign up to get free protection for your applications and to get access to all the features.
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