alchemy_cms 6.0.0.b1 → 6.0.0.b2

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/alchemy_cms.gemspec +1 -1
  4. data/app/assets/stylesheets/alchemy/archive.scss +14 -0
  5. data/app/controllers/alchemy/admin/attachments_controller.rb +3 -3
  6. data/app/controllers/alchemy/admin/pages_controller.rb +1 -9
  7. data/app/controllers/alchemy/admin/pictures_controller.rb +21 -8
  8. data/app/controllers/alchemy/admin/resources_controller.rb +84 -10
  9. data/app/controllers/alchemy/api/elements_controller.rb +12 -8
  10. data/app/controllers/alchemy/api/pages_controller.rb +4 -2
  11. data/app/models/alchemy/attachment.rb +24 -7
  12. data/app/models/alchemy/element/presenters.rb +18 -1
  13. data/app/models/alchemy/ingredient.rb +5 -0
  14. data/app/models/alchemy/page.rb +10 -1
  15. data/app/models/alchemy/page/page_scopes.rb +4 -0
  16. data/app/models/alchemy/picture.rb +14 -38
  17. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +1 -1
  18. data/app/views/alchemy/admin/attachments/index.html.erb +2 -3
  19. data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -1
  20. data/app/views/alchemy/admin/pages/index.html.erb +2 -9
  21. data/app/views/alchemy/admin/partials/_search_form.html.erb +9 -0
  22. data/app/views/alchemy/admin/pictures/_archive.html.erb +1 -1
  23. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
  24. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +4 -2
  25. data/app/views/alchemy/admin/pictures/index.html.erb +8 -3
  26. data/app/views/alchemy/admin/resources/_filter.html.erb +12 -0
  27. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +14 -17
  28. data/app/views/alchemy/admin/resources/_form.html.erb +2 -0
  29. data/app/views/alchemy/admin/resources/_table_header.html.erb +15 -0
  30. data/app/views/alchemy/admin/resources/index.html.erb +3 -11
  31. data/config/locales/alchemy.en.yml +85 -49
  32. data/lib/alchemy/forms/builder.rb +21 -1
  33. data/lib/alchemy/resource_filter.rb +40 -0
  34. data/lib/alchemy/resources_helper.rb +1 -16
  35. data/lib/alchemy/test_support/shared_ingredient_examples.rb +21 -3
  36. data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +14 -6
  37. data/lib/alchemy/version.rb +1 -1
  38. data/lib/alchemy_cms.rb +1 -0
  39. data/lib/generators/alchemy/menus/templates/node.html.erb +1 -1
  40. data/lib/generators/alchemy/menus/templates/node.html.haml +1 -1
  41. data/lib/generators/alchemy/menus/templates/node.html.slim +1 -1
  42. data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
  43. data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
  44. data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
  45. data/package.json +1 -1
  46. metadata +10 -9
  47. data/app/views/alchemy/admin/attachments/_filter_bar.html.erb +0 -29
  48. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +0 -30
@@ -18,11 +18,31 @@ module Alchemy
18
18
  super
19
19
  end
20
20
 
21
+ # Renders a simple_form input that displays a datepicker
22
+ #
23
+ def datepicker(attribute_name, options = {})
24
+ options[:wrapper] = :alchemy
25
+
26
+ type = options[:as] || :date
27
+ value = options.fetch(:input_html, {}).delete(:value)
28
+ date = value || object.send(attribute_name.to_sym).presence
29
+ date = Time.zone.parse(date) if date.is_a?(String)
30
+
31
+ input_options = {
32
+ type: :text,
33
+ class: type,
34
+ data: { datepicker_type: type },
35
+ value: date&.iso8601,
36
+ }.merge(options[:input_html] || {})
37
+
38
+ input attribute_name, as: :string, input_html: input_options
39
+ end
40
+
21
41
  # Renders a button tag wrapped in a div with 'submit' class.
22
42
  #
23
43
  def submit(label, options = {})
24
44
  options = {
25
- wrapper_html: {class: "submit"},
45
+ wrapper_html: { class: "submit" },
26
46
  }.update(options)
27
47
  template.content_tag("div", options.delete(:wrapper_html)) do
28
48
  template.content_tag("button", label, options.delete(:input_html))
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class ResourceFilter
5
+ attr_reader :name
6
+
7
+ def initialize(filter, resource_name)
8
+ @filter = filter
9
+ @name = filter[:name]
10
+ @resource_name = resource_name
11
+ @values = filter[:values].presence || []
12
+ end
13
+
14
+ def options_for_select
15
+ translated_values.zip(values)
16
+ end
17
+
18
+ def values
19
+ if translated?
20
+ @values.map { |v| v[1] }
21
+ else
22
+ @values
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def translated?
29
+ @values.first.is_a?(Array)
30
+ end
31
+
32
+ def translated_values
33
+ if translated?
34
+ @values.map { |a| a[0] }
35
+ else
36
+ @values.map { |v| Alchemy.t(v.to_sym, scope: ["filters", @resource_name, @name, "values"]) }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -107,12 +107,10 @@ module Alchemy
107
107
  when "boolean"
108
108
  options
109
109
  when "date", "time", "datetime"
110
- date = resource_instance_variable.send(attribute[:name]) || Time.current
111
110
  options.merge(
112
111
  as: "string",
113
112
  input_html: {
114
- "data-datepicker-type" => input_type,
115
- value: date ? date.iso8601 : nil,
113
+ data: { datepicker_type: input_type },
116
114
  },
117
115
  )
118
116
  when "text"
@@ -171,18 +169,5 @@ module Alchemy
171
169
  def resource_has_tags
172
170
  resource_model.respond_to?(:tag_counts) && resource_model.tag_counts.any?
173
171
  end
174
-
175
- def resource_has_filters
176
- resource_model.respond_to?(:alchemy_resource_filters)
177
- end
178
-
179
- def resource_filter_select
180
- resource_model.alchemy_resource_filters.map do |filter_scope|
181
- [
182
- Alchemy.t(filter_scope.to_sym, scope: ["resources", resource_name, "filters"]),
183
- filter_scope,
184
- ]
185
- end
186
- end
187
172
  end
188
173
  end
@@ -28,6 +28,16 @@ RSpec.shared_examples_for "an alchemy ingredient" do
28
28
  end
29
29
 
30
30
  context "with element" do
31
+ before do
32
+ expect(element).to receive(:ingredient_definition_for) do
33
+ {
34
+ settings: {
35
+ linkable: true,
36
+ },
37
+ }.with_indifferent_access
38
+ end
39
+ end
40
+
31
41
  it { is_expected.to eq({ linkable: true }.with_indifferent_access) }
32
42
  end
33
43
  end
@@ -42,15 +52,23 @@ RSpec.shared_examples_for "an alchemy ingredient" do
42
52
  end
43
53
 
44
54
  context "with element" do
45
- it do
46
- is_expected.to eq({
55
+ let(:definition) do
56
+ {
47
57
  role: "headline",
48
58
  type: "Text",
49
59
  default: "Hello World",
50
60
  settings: {
51
61
  linkable: true,
52
62
  },
53
- }.with_indifferent_access)
63
+ }.with_indifferent_access
64
+ end
65
+
66
+ before do
67
+ expect(element).to receive(:ingredient_definition_for) { definition }
68
+ end
69
+
70
+ it "returns ingredient definition" do
71
+ is_expected.to eq(definition)
54
72
  end
55
73
  end
56
74
  end
@@ -10,6 +10,9 @@ module Alchemy::Upgrader::Tasks
10
10
  def create_ingredients
11
11
  Alchemy::Deprecation.silence do
12
12
  elements_with_ingredients = Alchemy::ElementDefinition.all.select { |d| d.key?(:ingredients) }
13
+ if ENV["ONLY"]
14
+ elements_with_ingredients = elements_with_ingredients.select { |d| d[:name].in? ENV["ONLY"].split(",") }
15
+ end
13
16
  # eager load all elements that have ingredients defined but no ingredient records yet.
14
17
  all_elements = Alchemy::Element
15
18
  .named(elements_with_ingredients.map { |d| d[:name] })
@@ -22,21 +25,26 @@ module Alchemy::Upgrader::Tasks
22
25
  puts "-- Creating ingredients for #{elements.count} #{element_definition[:name]}(s)"
23
26
  elements.each do |element|
24
27
  Alchemy::Element.transaction do
25
- element.ingredients = element_definition[:ingredients].map do |ingredient_definition|
28
+ element_definition[:ingredients].each do |ingredient_definition|
26
29
  content = element.content_by_name(ingredient_definition[:role])
27
30
  next unless content
28
31
 
32
+ essence = content.essence
29
33
  ingredient = Alchemy::Ingredient.build(role: ingredient_definition[:role], element: element)
30
- belongs_to_associations = content.essence.class.reflect_on_all_associations(:belongs_to)
34
+ belongs_to_associations = essence.class.reflect_on_all_associations(:belongs_to)
31
35
  if belongs_to_associations.any?
32
- ingredient.related_object = content.essence.public_send(belongs_to_associations.first.name)
36
+ ingredient.related_object = essence.public_send(belongs_to_associations.first.name)
33
37
  else
34
38
  ingredient.value = content.ingredient
35
39
  end
36
- content.destroy!
40
+ data = ingredient.class.stored_attributes.fetch(:data, []).each_with_object({}) do |attr, d|
41
+ d[attr] = essence.public_send(attr)
42
+ end
43
+ ingredient.data = data
37
44
  print "."
38
- ingredient
39
- end.compact
45
+ ingredient.save!
46
+ content.destroy!
47
+ end
40
48
  end
41
49
  end
42
50
  puts "\n"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "6.0.0.b1"
4
+ VERSION = "6.0.0.b2"
5
5
 
6
6
  def self.version
7
7
  VERSION
data/lib/alchemy_cms.rb CHANGED
@@ -54,6 +54,7 @@ require_relative "alchemy/permissions"
54
54
  require_relative "alchemy/resource"
55
55
  require_relative "alchemy/tinymce"
56
56
  require_relative "alchemy/taggable"
57
+ require_relative "alchemy/version"
57
58
 
58
59
  # Require hacks
59
60
  require_relative "kaminari/scoped_pagination_url_helper"
@@ -1,4 +1,4 @@
1
- <%% cache node do %>
1
+ <%% cache [node, @page, @preview_mode] do %>
2
2
  <%%= content_tag :li, class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do %>
3
3
  <%%= link_to_if node.url,
4
4
  node.name,
@@ -1,4 +1,4 @@
1
- - cache node do
1
+ - cache [node, @page, @preview_mode] do
2
2
  = content_tag :li,
3
3
  class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do
4
4
  = link_to_if node.url,
@@ -1,4 +1,4 @@
1
- - cache node do
1
+ - cache [node, @page, @preview_mode] do
2
2
  = content_tag :li,
3
3
  class: ['nav-item', node.children.any? ? 'dropdown' : nil].compact do
4
4
  = link_to_if node.url,
@@ -1,4 +1,4 @@
1
- <%% cache menu do %>
1
+ <%% cache [menu, @page, @preview_mode] do %>
2
2
  <ul class="nav">
3
3
  <%%= render partial: menu.to_partial_path,
4
4
  collection: menu.children.includes(:page, :children),
@@ -1,4 +1,4 @@
1
- - cache menu do
1
+ - cache [menu, @page, @preview_mode] do
2
2
  %ul.nav
3
3
  = render partial: menu.to_partial_path,
4
4
  collection: menu.children.includes(:page, :children),
@@ -1,4 +1,4 @@
1
- - cache menu do
1
+ - cache [menu, @page, @preview_mode] do
2
2
  ul.nav
3
3
  = render partial: menu.to_partial_path,
4
4
  collection: menu.children.includes(:page, :children),
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy_cms/admin",
3
- "version": "0.2.0",
3
+ "version": "6.0.0-b2",
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.0.b1
4
+ version: 6.0.0.b2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -10,10 +10,10 @@ authors:
10
10
  - Hendrik Mans
11
11
  - Carsten Fregin
12
12
  - Martin Meyerhoff
13
- autorequire:
13
+ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2021-07-05 00:00:00.000000000 Z
16
+ date: 2021-08-05 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: actionmailer
@@ -689,14 +689,14 @@ dependencies:
689
689
  requirements:
690
690
  - - "~>"
691
691
  - !ruby/object:Gem::Version
692
- version: '4.0'
692
+ version: '5.0'
693
693
  type: :development
694
694
  prerelease: false
695
695
  version_requirements: !ruby/object:Gem::Requirement
696
696
  requirements:
697
697
  - - "~>"
698
698
  - !ruby/object:Gem::Version
699
- version: '4.0'
699
+ version: '5.0'
700
700
  - !ruby/object:Gem::Dependency
701
701
  name: timecop
702
702
  requirement: !ruby/object:Gem::Requirement
@@ -1013,7 +1013,6 @@ files:
1013
1013
  - app/views/alchemy/admin/attachments/_attachment.html.erb
1014
1014
  - app/views/alchemy/admin/attachments/_file_to_assign.html.erb
1015
1015
  - app/views/alchemy/admin/attachments/_files_list.html.erb
1016
- - app/views/alchemy/admin/attachments/_filter_bar.html.erb
1017
1016
  - app/views/alchemy/admin/attachments/_overlay_file_list.html.erb
1018
1017
  - app/views/alchemy/admin/attachments/_replace_button.html.erb
1019
1018
  - app/views/alchemy/admin/attachments/_tag_list.html.erb
@@ -1131,7 +1130,6 @@ files:
1131
1130
  - app/views/alchemy/admin/pictures/_archive.html.erb
1132
1131
  - app/views/alchemy/admin/pictures/_archive_overlay.html.erb
1133
1132
  - app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb
1134
- - app/views/alchemy/admin/pictures/_filter_bar.html.erb
1135
1133
  - app/views/alchemy/admin/pictures/_form.html.erb
1136
1134
  - app/views/alchemy/admin/pictures/_infos.html.erb
1137
1135
  - app/views/alchemy/admin/pictures/_overlay_picture_list.html.erb
@@ -1145,6 +1143,7 @@ files:
1145
1143
  - app/views/alchemy/admin/pictures/index.js.erb
1146
1144
  - app/views/alchemy/admin/pictures/show.html.erb
1147
1145
  - app/views/alchemy/admin/pictures/update.js.erb
1146
+ - app/views/alchemy/admin/resources/_filter.html.erb
1148
1147
  - app/views/alchemy/admin/resources/_filter_bar.html.erb
1149
1148
  - app/views/alchemy/admin/resources/_form.html.erb
1150
1149
  - app/views/alchemy/admin/resources/_per_page_select.html.erb
@@ -1323,6 +1322,7 @@ files:
1323
1322
  - lib/alchemy/paths.rb
1324
1323
  - lib/alchemy/permissions.rb
1325
1324
  - lib/alchemy/resource.rb
1325
+ - lib/alchemy/resource_filter.rb
1326
1326
  - lib/alchemy/resources_helper.rb
1327
1327
  - lib/alchemy/routing_constraints.rb
1328
1328
  - lib/alchemy/seeder.rb
@@ -1516,8 +1516,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1516
1516
  version: 1.3.1
1517
1517
  requirements:
1518
1518
  - ImageMagick (libmagick), v6.6 or greater.
1519
- rubygems_version: 3.1.4
1520
- signing_key:
1519
+ rubygems_version: 3.1.6
1520
+ signing_key:
1521
1521
  specification_version: 4
1522
1522
  summary: A powerful, userfriendly and flexible CMS for Rails
1523
1523
  test_files: []
1524
+ ...
@@ -1,29 +0,0 @@
1
- <div id="filter_bar">
2
- <h3><%= Alchemy.t('Filter') %></h3>
3
- <%= select_tag(
4
- 'file_type_filter',
5
- options_for_select(
6
- Alchemy::Attachment.file_types_for_select,
7
- search_filter_params[:file_type]
8
- ),
9
- include_blank: Alchemy.t('Show all files'),
10
- data: { remote: !!request.xhr? },
11
- class: 'alchemy_selectbox'
12
- ) %>
13
- </div>
14
-
15
- <script type="text/javascript">
16
- $(function() {
17
- $('#file_type_filter').on('change', function(e) {
18
- var $this = $(this);
19
- var url = '<%= alchemy.admin_attachments_path(search_filter_params.except(:file_type).to_h) %>';
20
- if ($this.data('remote') === true) {
21
- $.get(url, {file_type: $this.val()}, null, 'script');
22
- } else {
23
- delimiter = url.match(/\?/) ? '&' : '?';
24
- Turbolinks.visit(url + delimiter + 'file_type=' + encodeURIComponent($this.val()));
25
- }
26
- return false;
27
- });
28
- });
29
- </script>
@@ -1,30 +0,0 @@
1
- <div id="filter_bar">
2
- <h3><%= Alchemy.t('Filter') %></h3>
3
- <%= select_tag(
4
- 'picture_filter',
5
- options_for_select([
6
- [Alchemy.t(:all_pictures), ''],
7
- [Alchemy.t(:last_upload_only), 'last_upload'],
8
- [Alchemy.t(:recently_uploaded_only), 'recent'],
9
- [Alchemy.t(:without_tag), 'without_tag']
10
- ], search_filter_params[:filter]),
11
- :data => { :remote => !!request.xhr? },
12
- :class => 'alchemy_selectbox'
13
- ) %>
14
- </div>
15
-
16
- <script type="text/javascript">
17
- $(function() {
18
- $('#picture_filter').on('change', function(e) {
19
- var $this = $(this);
20
- var url = '<%= alchemy.admin_pictures_path(search_filter_params.except(:filter).to_h) %>';
21
- if ($this.data('remote') === true) {
22
- $.get(url, {filter: $this.val()}, null, 'script');
23
- } else {
24
- delimiter = url.match(/\?/) ? '&' : '?';
25
- Turbolinks.visit(url + delimiter + 'filter=' + $this.val());
26
- }
27
- return false;
28
- });
29
- });
30
- </script>