integral 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +4 -3
  3. data/app/assets/javascripts/integral/backend.js +86 -2
  4. data/app/assets/javascripts/integral/support/character_counter.js +13 -8
  5. data/app/assets/javascripts/integral/support/list.coffee +1 -0
  6. data/app/assets/javascripts/integral/support/record_selector.coffee +2 -0
  7. data/app/assets/javascripts/integral/support/slug_generator.coffee +1 -0
  8. data/app/assets/stylesheets/integral/backend.sass +34 -23
  9. data/app/assets/stylesheets/integral/backend/_foundation_settings.scss +2 -2
  10. data/app/assets/stylesheets/integral/backend/dashboard-layout.scss +27 -63
  11. data/app/assets/stylesheets/integral/backend/devise.sass +2 -3
  12. data/app/assets/stylesheets/integral/backend/materialize-tags.sass +1 -0
  13. data/app/assets/stylesheets/integral/backend/modules/dropdown_pane_notifications.scss +150 -0
  14. data/app/assets/stylesheets/integral/backend/modules/dropdown_pane_profile.scss +59 -0
  15. data/app/assets/stylesheets/integral/backend/shared.sass +41 -2
  16. data/app/assets/stylesheets/integral/frontend/layout.sass +10 -0
  17. data/app/assets/stylesheets/integral/support/media-query-indicator.sass +4 -4
  18. data/app/controllers/integral/backend/activities_controller.rb +21 -27
  19. data/app/controllers/integral/backend/base_controller.rb +87 -37
  20. data/app/controllers/integral/backend/images_controller.rb +26 -8
  21. data/app/controllers/integral/backend/lists_controller.rb +2 -14
  22. data/app/controllers/integral/backend/notification_subscriptions_controller.rb +23 -0
  23. data/app/controllers/integral/backend/pages_controller.rb +0 -4
  24. data/app/controllers/integral/backend/posts_controller.rb +0 -4
  25. data/app/controllers/integral/backend/settings_controller.rb +4 -0
  26. data/app/controllers/integral/backend/static_pages_controller.rb +6 -0
  27. data/app/controllers/integral/backend/users_controller.rb +43 -24
  28. data/app/controllers/integral/blog_controller.rb +12 -0
  29. data/app/controllers/integral/categories_controller.rb +17 -3
  30. data/app/controllers/integral/tags_controller.rb +5 -2
  31. data/app/decorators/integral/base_decorator.rb +16 -0
  32. data/app/decorators/integral/image_decorator.rb +2 -2
  33. data/app/decorators/integral/list_decorator.rb +1 -13
  34. data/app/decorators/integral/notification/notification_decorator.rb +74 -0
  35. data/app/decorators/integral/page_decorator.rb +1 -13
  36. data/app/decorators/integral/post_decorator.rb +1 -2
  37. data/app/decorators/integral/user_decorator.rb +1 -13
  38. data/app/decorators/integral/version_decorator.rb +8 -4
  39. data/app/helpers/integral/backend/base_helper.rb +97 -31
  40. data/app/jobs/integral/application_job.rb +1 -0
  41. data/app/jobs/integral/newsletter_signup_job.rb +0 -2
  42. data/app/mailers/integral/devise_mailer.rb +6 -0
  43. data/app/models/concerns/integral/notification/subscribable.rb +67 -0
  44. data/app/models/integral/application_record.rb +9 -0
  45. data/app/models/integral/category.rb +9 -0
  46. data/app/models/integral/image.rb +40 -3
  47. data/app/models/integral/list.rb +10 -2
  48. data/app/models/integral/list_item.rb +14 -14
  49. data/app/models/integral/list_item_connection.rb +6 -0
  50. data/app/models/integral/notification/notification.rb +28 -0
  51. data/app/models/integral/notification/subscription.rb +14 -0
  52. data/app/models/integral/page.rb +15 -8
  53. data/app/models/integral/post.rb +11 -13
  54. data/app/models/integral/user.rb +45 -2
  55. data/app/policies/integral/base_policy.rb +7 -12
  56. data/app/policies/integral/page_policy.rb +1 -0
  57. data/app/policies/integral/version_policy.rb +0 -8
  58. data/app/views/devise/invitations/edit.haml +1 -4
  59. data/app/views/devise/mailer/invitation_instructions.inky-haml +20 -0
  60. data/app/views/integral/backend/activities/grid/_dropdown_actions.haml +1 -0
  61. data/app/views/integral/backend/activities/grid/_row_content.haml +13 -0
  62. data/app/views/integral/backend/activities/index.haml +7 -13
  63. data/app/views/integral/backend/activities/shared/_grid.haml +35 -20
  64. data/app/views/integral/backend/activities/shared/index.haml +12 -12
  65. data/app/views/integral/backend/activities/shared/show.haml +7 -7
  66. data/app/views/integral/backend/activities/show.haml +1 -1
  67. data/app/views/integral/backend/categories/_modal.haml +2 -3
  68. data/app/views/integral/backend/images/_form.haml +13 -25
  69. data/app/views/integral/backend/images/edit.haml +1 -9
  70. data/app/views/integral/backend/images/grid/_dropdown_actions.haml +5 -0
  71. data/app/views/integral/backend/images/grid/_row_content.haml +5 -0
  72. data/app/views/integral/backend/images/index.haml +11 -17
  73. data/app/views/integral/backend/images/list.haml +11 -0
  74. data/app/views/integral/backend/images/show.haml +26 -0
  75. data/app/views/integral/backend/lists/_form.haml +6 -19
  76. data/app/views/integral/backend/lists/_item_modal.haml +3 -3
  77. data/app/views/integral/backend/lists/_manager.haml +11 -13
  78. data/app/views/integral/backend/lists/edit.haml +6 -20
  79. data/app/views/integral/backend/lists/grid/_dropdown_actions.haml +9 -0
  80. data/app/views/integral/backend/lists/grid/_row_content.haml +3 -0
  81. data/app/views/integral/backend/lists/index.haml +11 -17
  82. data/app/views/integral/backend/lists/list.haml +11 -0
  83. data/app/views/integral/backend/lists/show.haml +30 -0
  84. data/app/views/integral/backend/notifications/_notification.haml +21 -0
  85. data/app/views/integral/backend/pages/_form.haml +19 -43
  86. data/app/views/integral/backend/pages/edit.haml +4 -12
  87. data/app/views/integral/backend/pages/grid/_dropdown_actions.haml +11 -0
  88. data/app/views/integral/backend/pages/grid/_row_content.haml +5 -0
  89. data/app/views/integral/backend/pages/index.haml +6 -6
  90. data/app/views/integral/backend/pages/list.haml +12 -19
  91. data/app/views/integral/backend/pages/show.haml +19 -35
  92. data/app/views/integral/backend/posts/_form.haml +18 -56
  93. data/app/views/integral/backend/posts/edit.haml +4 -14
  94. data/app/views/integral/backend/posts/grid/_dropdown_actions.haml +10 -0
  95. data/app/views/integral/backend/posts/grid/_row_content.haml +6 -0
  96. data/app/views/integral/backend/posts/index.haml +6 -6
  97. data/app/views/integral/backend/posts/list.haml +11 -18
  98. data/app/views/integral/backend/posts/new.haml +0 -1
  99. data/app/views/integral/backend/posts/show.haml +18 -41
  100. data/app/views/integral/backend/shared/_breadcrumbs.haml +7 -4
  101. data/app/views/integral/backend/shared/_image_preview.haml +10 -3
  102. data/app/views/integral/backend/shared/_image_selector.haml +1 -1
  103. data/app/views/integral/backend/shared/_notification_subscription_toggle.haml +22 -0
  104. data/app/views/integral/backend/shared/action_bar/_index.haml +9 -0
  105. data/app/views/integral/backend/shared/action_bar/_show.haml +3 -0
  106. data/app/views/integral/backend/shared/cards/_at_a_glance.haml +3 -3
  107. data/app/views/integral/backend/shared/cards/_categories.haml +27 -28
  108. data/app/views/integral/backend/shared/cards/_object.haml +1 -1
  109. data/app/views/integral/backend/shared/cards/_recent_activity.haml +12 -12
  110. data/app/views/integral/backend/shared/cards/_recent_resources.haml +17 -0
  111. data/app/views/integral/backend/shared/cards/_top_post_authors.haml +14 -15
  112. data/app/views/integral/backend/shared/cards/_welcome.haml +24 -25
  113. data/app/views/integral/backend/shared/{_empty_grid.haml → grid/_empty.haml} +0 -0
  114. data/app/views/integral/backend/shared/grid/_form.haml +9 -0
  115. data/app/views/integral/backend/shared/grid/_grid.haml +21 -0
  116. data/app/views/integral/backend/shared/{_pagination.haml → grid/_pagination.haml} +0 -0
  117. data/app/views/integral/backend/shared/grid/_row_layout.haml +8 -0
  118. data/app/views/integral/backend/shared/record_selector/_collection.haml +1 -0
  119. data/app/views/integral/backend/shared/record_selector/_modal.haml +9 -10
  120. data/app/views/integral/backend/static_pages/dashboard.haml +6 -7
  121. data/app/views/integral/backend/users/_form.haml +34 -46
  122. data/app/views/integral/backend/users/grid/_dropdown_actions.haml +17 -0
  123. data/app/views/integral/backend/users/grid/_row_content.haml +8 -0
  124. data/app/views/integral/backend/users/index.haml +6 -6
  125. data/app/views/integral/backend/users/list.haml +10 -16
  126. data/app/views/integral/backend/users/show.haml +10 -1
  127. data/app/views/integral/categories/show.haml +3 -3
  128. data/app/views/integral/posts/_article_footer.haml +1 -1
  129. data/app/views/integral/posts/_card.haml +1 -1
  130. data/app/views/integral/posts/_most_read_section.haml +1 -1
  131. data/app/views/integral/posts/_post.haml +1 -1
  132. data/app/views/integral/posts/templates/default.haml +1 -1
  133. data/app/views/integral/shared/sidebar/_item.haml +1 -1
  134. data/app/views/layouts/integral/backend.html.haml +24 -5
  135. data/app/views/layouts/integral/backend/_create_dropdown.haml +1 -30
  136. data/app/views/layouts/integral/backend/_main_menu_items.haml +1 -101
  137. data/config/initializers/devise.rb +1 -1
  138. data/config/locales/en.yml +60 -2
  139. data/config/routes.rb +2 -0
  140. data/db/migrate/20200407022636_create_integral_notifications.rb +25 -0
  141. data/db/migrate/20200421223602_add_status_to_integral_users.rb +5 -0
  142. data/db/seeds.rb +15 -11
  143. data/lib/integral.rb +1 -0
  144. data/lib/integral/acts_as_integral.rb +115 -0
  145. data/lib/integral/acts_as_listable.rb +1 -1
  146. data/lib/integral/engine.rb +9 -0
  147. data/lib/integral/grids/activities_grid.rb +0 -1
  148. data/lib/integral/grids/lists_grid.rb +1 -0
  149. data/lib/integral/grids/posts_grid.rb +5 -1
  150. data/lib/integral/grids/users_grid.rb +5 -0
  151. data/lib/integral/list_renderer.rb +5 -1
  152. data/lib/integral/router.rb +20 -4
  153. data/lib/integral/version.rb +1 -1
  154. data/spec/factories.rb +15 -1
  155. metadata +45 -39
  156. data/app/decorators/integral/category_version_decorator.rb +0 -7
  157. data/app/decorators/integral/image_version_decorator.rb +0 -7
  158. data/app/decorators/integral/list_version_decorator.rb +0 -7
  159. data/app/decorators/integral/page_version_decorator.rb +0 -7
  160. data/app/decorators/integral/post_version_decorator.rb +0 -7
  161. data/app/decorators/integral/user_version_decorator.rb +0 -7
  162. data/app/views/devise/mailer/invitation_instructions.html.erb +0 -13
  163. data/app/views/integral/backend/activities/_grid.haml +0 -22
  164. data/app/views/integral/backend/images/_grid.haml +0 -16
  165. data/app/views/integral/backend/lists/_grid.haml +0 -14
  166. data/app/views/integral/backend/pages/_grid.haml +0 -46
  167. data/app/views/integral/backend/posts/_grid.haml +0 -51
  168. data/app/views/integral/backend/shared/_grid.haml +0 -18
  169. data/app/views/integral/backend/shared/cards/_recent_pages.haml +0 -19
  170. data/app/views/integral/backend/shared/cards/_recent_posts.haml +0 -18
  171. data/app/views/integral/backend/shared/cards/_recent_users.haml +0 -19
  172. data/app/views/integral/backend/users/_grid.haml +0 -36
@@ -1,101 +1 @@
1
- %li
2
- = link_to backend_dashboard_url do
3
- = icon('home')
4
- %span= t('integral.navigation.dashboard')
5
-
6
- - if policy(Integral::Page).index?
7
- %li
8
- = link_to backend_pages_url do
9
- = icon('file')
10
- %span= t('integral.navigation.pages')
11
- %ul
12
- %li= t('integral.navigation.pages')
13
- %li
14
- = link_to backend_pages_url do
15
- %span= t('integral.navigation.dashboard')
16
-
17
- - if policy(Integral::Page).create?
18
- %li
19
- = link_to new_backend_page_url do
20
- %span= t('integral.actions.create')
21
- %li
22
- = link_to list_backend_pages_url do
23
- %span= t('integral.navigation.listing')
24
-
25
-
26
- - if policy(Integral::Post).index? && Integral.blog_enabled?
27
- %li
28
- = link_to backend_posts_url do
29
- = icon('rss')
30
- %span= t('integral.navigation.posts')
31
- %ul
32
- %li= t('integral.navigation.posts')
33
- %li
34
- = link_to backend_posts_url do
35
- %span= t('integral.navigation.dashboard')
36
- - if policy(Integral::Post).create?
37
- %li
38
- = link_to new_backend_post_url do
39
- %span= t('integral.actions.create')
40
- %li
41
- = link_to list_backend_posts_url do
42
- %span= t('integral.navigation.listing')
43
-
44
- - if policy(Integral::List).index?
45
- %li
46
- = link_to backend_lists_url do
47
- = icon('list')
48
- %span= t('integral.navigation.lists')
49
- %ul
50
- %li= t('integral.navigation.lists')
51
- %li
52
- = link_to backend_lists_url do
53
- %span= t('integral.navigation.dashboard')
54
- - if policy(Integral::List).create?
55
- %li
56
- = link_to new_backend_list_url do
57
- %span= t('integral.actions.create')
58
-
59
- - if policy(Integral::Image).manager?
60
- %li
61
- = link_to backend_img_index_url do
62
- = icon('picture-o')
63
- %span= t('integral.navigation.images')
64
- %ul
65
- %li= t('integral.navigation.images')
66
- %li
67
- = link_to backend_img_index_url do
68
- %span= t('integral.navigation.dashboard')
69
- - if policy(Integral::Image).create?
70
- %li
71
- = link_to new_backend_img_url do
72
- %span= t('integral.actions.create')
73
-
74
- - if policy(current_user).manager?
75
- %li
76
- = link_to backend_users_url do
77
- = icon('users')
78
- %span=t('integral.navigation.users')
79
- %ul
80
- %li= t('integral.navigation.users')
81
- %li
82
- = link_to backend_users_url do
83
- %span= t('integral.navigation.dashboard')
84
- %li
85
- = link_to new_backend_user_url do
86
- %span= t('integral.actions.create')
87
- %li
88
- = link_to list_backend_users_url do
89
- %span= t('integral.navigation.listing')
90
-
91
- - if policy(Integral::Version).manager?
92
- %li
93
- = link_to backend_activities_url do
94
- = icon('crosshairs')
95
- %span=t('integral.navigation.activities')
96
-
97
- - if current_user.admin?
98
- %li
99
- = link_to backend_settings_url do
100
- = icon('cog')
101
- %span=t('integral.navigation.settings')
1
+ = render_main_menu
@@ -13,7 +13,7 @@ Devise.setup do |config|
13
13
  config.mailer_sender = Proc.new { "#{Integral::Settings.website_title} <#{Integral::Settings.contact_email}>" }
14
14
 
15
15
  # Configure the class responsible to send e-mails.
16
- # config.mailer = 'Devise::Mailer'
16
+ config.mailer = 'Integral::DeviseMailer'
17
17
 
18
18
  # ==> ORM configuration
19
19
  # Load and configure the ORM. Supports :active_record (default) and
@@ -15,6 +15,44 @@ en:
15
15
  default: "%A, %d %B %Y"
16
16
  long: "%H:%M %d/%m/%Y"
17
17
 
18
+ datetime:
19
+ distance_in_words:
20
+ short:
21
+ half_a_minute: "30s"
22
+ less_than_x_seconds:
23
+ one: "1s"
24
+ other: "%{count}s"
25
+ x_seconds:
26
+ one: "1s"
27
+ other: "%{count}s"
28
+ less_than_x_minutes:
29
+ one: "~1m"
30
+ other: "~%{count}m"
31
+ x_minutes:
32
+ one: "1m"
33
+ other: "%{count}m"
34
+ about_x_hours:
35
+ one: "~1h"
36
+ other: "~%{count}h "
37
+ x_days:
38
+ one: "1d"
39
+ other: "%{count}d"
40
+ about_x_months:
41
+ one: "~1mn"
42
+ other: "~%{count}mn"
43
+ x_months:
44
+ one: "1mn"
45
+ other: "%{count}mn"
46
+ about_x_years:
47
+ one: "~1y"
48
+ other: "~%{count}y"
49
+ over_x_years:
50
+ one: "1y"
51
+ other: "%{count}y"
52
+ almost_x_years:
53
+ one: "~1y"
54
+ other: "~%{count}y"
55
+
18
56
  errors:
19
57
  generic: Unfortunately there was a problem. Please try again later.
20
58
  unauthorized: You are not authorized to perform this action.
@@ -55,6 +93,8 @@ en:
55
93
  confirmation:
56
94
  deletion: If you delete this item it will be gone forever. Are you sure you want to proceed?
57
95
  clone: Are you sure you want to clone this item?
96
+ block: Are you sure you want to block this user?
97
+ unblock: Are you sure you want to unblock this user?
58
98
  new_page: Add new page
59
99
  new_post: Add new post
60
100
  edit_profile: Edit profile
@@ -63,6 +103,8 @@ en:
63
103
  view_main_site: View main site
64
104
  view_on_site: View on site
65
105
  publish: Publish
106
+ block: Block
107
+ unblock: Unblock
66
108
  create: Create
67
109
  clone: Clone
68
110
  save: Save
@@ -95,6 +137,9 @@ en:
95
137
  select_image: Select Image..
96
138
  select_type: Select Type..
97
139
  unsaved_changes: Changes that you made may not be saved.
140
+ tooltips:
141
+ unsubscribe: Unsubscribe from notifications.
142
+ subscribe: Subscribe to notifications.
98
143
  placeholders:
99
144
  description: Description
100
145
  title: Title
@@ -102,6 +147,9 @@ en:
102
147
  draft: Draft
103
148
  published: Published
104
149
  archived: Archived
150
+ blocked: Blocked
151
+ pending: Pending
152
+ active: Active
105
153
  records:
106
154
  attributes:
107
155
  category: Category
@@ -143,7 +191,7 @@ en:
143
191
  actions: Actions
144
192
  activity: Activity
145
193
  activity_log: Activity Log
146
- profile: My Profile
194
+ profile: My profile
147
195
  quick_links: Quick Links
148
196
  activities: Activities
149
197
  home: Home
@@ -161,7 +209,7 @@ en:
161
209
  new: New
162
210
  edit: Edit
163
211
  log_out: Logout
164
- my_account: Account & Profile
212
+ my_account: Account & profile
165
213
  settings: Settings
166
214
  listing: Listing
167
215
 
@@ -368,6 +416,8 @@ en:
368
416
  title: 'Image listing'
369
417
  no_images_available: 'No images available. Try uploading some!'
370
418
  new_image: 'New image'
419
+ edit:
420
+ title: Edit Image
371
421
  users:
372
422
  available_locales:
373
423
  en: English
@@ -424,6 +474,8 @@ en:
424
474
  list:
425
475
  title: This is only used for internal reference.
426
476
  description: This is only used for internal reference.
477
+ user:
478
+ notify_me: Subscribe to be notified whenever there is a change to any resource. Otherwise be notified about followed resources only.
427
479
  inputs:
428
480
  file:
429
481
  button_label: 'File'
@@ -473,6 +525,12 @@ en:
473
525
  create: 'Invite %{model}'
474
526
 
475
527
  devise:
528
+ invitations:
529
+ edit:
530
+ title: Set your password
531
+ failure:
532
+ user:
533
+ blocked: User account is no longer active.
476
534
  passwords:
477
535
  edit:
478
536
  title: Change your password
@@ -1,3 +1,5 @@
1
1
  Integral::Engine.routes.draw do
2
2
  Integral::Router.load
3
3
  end
4
+
5
+ ActiveSupport::Notifications.instrument 'integral.routes_loaded'
@@ -0,0 +1,25 @@
1
+ class CreateIntegralNotifications < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :integral_users, :notify_me, :boolean, default: true
4
+
5
+ create_table :integral_notifications do |t|
6
+ t.integer :recipient_id
7
+ t.integer :actor_id
8
+ t.datetime :read_at
9
+ t.string :action
10
+ # (automated index name is too long)
11
+ t.references :subscribable, polymorphic: true, index: { name: 'index_integral_notifications_on_subscribable_type_id' }
12
+
13
+ t.timestamps null: false
14
+ end
15
+
16
+ create_table :integral_notification_subscriptions do |t|
17
+ t.integer :user_id
18
+ t.string :state
19
+ # (automated index name is too long)
20
+ t.references :subscribable, polymorphic: true, index: { name: 'index_integral_subscriptions_on_subscribable_type_id' }
21
+
22
+ t.timestamps null: false
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ class AddStatusToIntegralUsers < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :integral_users, :status, :integer, default: 0
4
+ end
5
+ end
@@ -18,7 +18,9 @@ Integral::Role.create!(name: 'PostManager')
18
18
  Integral::Role.create!(name: 'ListManager')
19
19
 
20
20
  # Demo User
21
- user = Integral::User.create!({ name: 'Integrico', email: 'user@integralrails.com', password: 'password', role_ids: Integral::Role.ids, admin: true })
21
+ user = Integral::User.create!({ name: 'Integrico', email: 'user@integralrails.com', password: 'password', role_ids: Integral::Role.ids, admin: true, status: 1 })
22
+
23
+ return if Rails.env.test? # Test DB should start with blank slate ... although roles and initial user are required
22
24
 
23
25
  # Demo Page
24
26
  host = URI.parse(Rails.application.routes.default_url_options[:host] || 'http://localhost:3000')
@@ -33,16 +35,18 @@ Integral::Page.create!(title: 'Integral CMS - Demo Page',
33
35
  body: renderer.render('integral/pages/_demo', layout: false),
34
36
  status: 1)
35
37
 
36
- # Demo Post
37
- category = Integral::Category.create!(title: 'Uncategorised', description: "Posts which we haven't yet categorized but are sure to grab your attention", slug: 'uncategorized')
38
- Integral::Post.create!(title: 'Integral CMS - Demo Post',
39
- description:'Integral CMS demo post. Integral is a rails content management system (CMS) which gives developers the ability to create a modern website with all the bells and whistles without the hassle.',
40
- body: File.read(File.join(Integral::Engine.root.join('public', 'integral', 'ckeditor_demo_content.html'))),
41
- slug: 'integral-demo',
42
- user: user,
43
- tag_list: 'integral-cms,example-tag',
44
- status: 1,
45
- category: category)
38
+ if Integral.blog_enabled?
39
+ # Demo Post
40
+ category = Integral::Category.create!(title: 'Uncategorised', description: "Posts which we haven't yet categorized but are sure to grab your attention", slug: 'uncategorized')
41
+ Integral::Post.create!(title: 'Integral CMS - Demo Post',
42
+ description:'Integral CMS demo post. Integral is a rails content management system (CMS) which gives developers the ability to create a modern website with all the bells and whistles without the hassle.',
43
+ body: File.read(File.join(Integral::Engine.root.join('public', 'integral', 'ckeditor_demo_content.html'))),
44
+ slug: 'integral-demo',
45
+ user: user,
46
+ tag_list: 'integral-cms,example-tag',
47
+ status: 1,
48
+ category: category)
49
+ end
46
50
 
47
51
  # Main Menu
48
52
  Integral::List.create!({ title: 'Main Menu', list_items: [
@@ -15,6 +15,7 @@ require 'integral/grids/lists_grid'
15
15
  require 'integral/grids/posts_grid'
16
16
  require 'integral/grids/images_grid'
17
17
  require 'integral/acts_as_listable'
18
+ require 'integral/acts_as_integral'
18
19
  require 'integral/widgets/recent_posts'
19
20
  require 'integral/widgets/swiper_list'
20
21
  require 'integral/content_renderer'
@@ -0,0 +1,115 @@
1
+ module Integral
2
+ # Handles adding Integral behaviour to a class
3
+ module ActsAsIntegral
4
+ DEFAULT_OPTIONS ={ notifications: { enabled: true },
5
+ cards: { at_a_glance: true, },
6
+ backend_main_menu: { enabled: true, order: 11 },
7
+ backend_create_menu: { enabled: true, order: 1 }}.freeze
8
+ class << self
9
+ attr_writer :backend_main_menu_items
10
+ attr_writer :backend_create_menu_items
11
+ attr_writer :backend_at_a_glance_card_items
12
+ end
13
+
14
+ # Accessor for backend main menu items
15
+ def self.backend_main_menu_items
16
+ @backend_main_menu_items ||= []
17
+ end
18
+
19
+ # Accessor for backend create menu items
20
+ def self.backend_create_menu_items
21
+ @backend_create_menu_items ||= []
22
+ end
23
+
24
+ # Accessor for at a glance card items
25
+ def self.backend_at_a_glance_card_items
26
+ @backend_at_a_glance_card_items ||= []
27
+ end
28
+
29
+ # Adds item to main backend dashboard at a glance chart
30
+ # @param [Class] item
31
+ def self.add_backend_at_a_glance_card_item(item)
32
+ backend_at_a_glance_card_items << item unless duplicate_menu_item?(item, backend_at_a_glance_card_items)
33
+ end
34
+
35
+ # Adds item to create menu, expects Hash or Class
36
+ def self.add_backend_create_menu_item(item)
37
+ backend_create_menu_items << item unless duplicate_menu_item?(item, backend_create_menu_items)
38
+ end
39
+
40
+ # Adds item to main menu, expects Hash or Class
41
+ def self.add_backend_main_menu_item(item)
42
+ backend_main_menu_items << item unless duplicate_menu_item?(item, backend_main_menu_items)
43
+ end
44
+
45
+ # Checks for existing duplicates in menu. Useful in development when app reloads
46
+ def self.duplicate_menu_item?(item, menu)
47
+ duplicate_found = if item.class == Class
48
+ menu.map(&:to_s).include?(item.to_s)
49
+ else
50
+ menu.select { |item| item.is_a?(Hash) }.map {|item| item[:id] }.include?(item[:id])
51
+ end
52
+
53
+ if duplicate_found
54
+ Rails.logger.error("ActsAsIntegral: Item '#{item.to_s}' not added to menu as it already exists.")
55
+ true
56
+ else
57
+ false
58
+ end
59
+ end
60
+
61
+ ActiveSupport.on_load(:active_record) do
62
+ # ActiveRecord::Base extension
63
+ class ActiveRecord::Base
64
+ # Adds integral behaviour to models
65
+ def self.acts_as_integral(options = {})
66
+ class << self
67
+ attr_accessor :integral_options
68
+
69
+ # @return [Hash] hash representing the class, used to render within the main menu
70
+ def integral_backend_main_menu_item
71
+ {
72
+ icon: integral_icon,
73
+ order: integral_options.dig(:backend_main_menu, :order),
74
+ label: model_name.human.pluralize,
75
+ url: url_helpers.send("backend_#{model_name.route_key}_url"),
76
+ # authorize: proc { policy(self).index? }, can't use this as self is in wrong context
77
+ authorize_class: self,
78
+ authorize_action: :index,
79
+ list_items: [
80
+ { label: I18n.t('integral.navigation.dashboard'), url: url_helpers.send("backend_#{model_name.route_key}_url"), authorize_class: self, authorize_action: :index },
81
+ { label: I18n.t('integral.actions.create'), url: url_helpers.send("new_backend_#{model_name.singular_route_key}_url"), authorize_class: self, authorize_action: :new },
82
+ { label: I18n.t('integral.navigation.listing'), url: url_helpers.send("list_backend_#{model_name.route_key}_url"), authorize_class: self, authorize_action: :list },
83
+ ]
84
+ }
85
+ end
86
+
87
+ # @return [Hash] hash representing the class, used to render within the create menu
88
+ def integral_backend_create_menu_item
89
+ {
90
+ icon: integral_icon,
91
+ order: integral_options.dig(:backend_create_menu, :order),
92
+ label: model_name.human,
93
+ url: url_helpers.send("new_backend_#{model_name.singular_route_key}_url"),
94
+ # authorize: proc { policy(self).index? }, can't use this as self is in wrong context
95
+ authorize_class: self,
96
+ authorize_action: :new,
97
+ }
98
+ end
99
+
100
+ def url_helpers
101
+ Integral::Engine.routes.url_helpers
102
+ end
103
+ end
104
+
105
+ self.integral_options = Integral::ActsAsIntegral::DEFAULT_OPTIONS.deep_merge(options)
106
+ Integral::ActsAsIntegral.add_backend_create_menu_item(self) if integral_options.dig(:backend_create_menu, :enabled)
107
+ Integral::ActsAsIntegral.add_backend_main_menu_item(self) if integral_options.dig(:backend_main_menu, :enabled)
108
+ Integral::ActsAsIntegral.add_backend_at_a_glance_card_item(self) if integral_options.dig(:cards, :at_a_glance)
109
+
110
+ include Integral::Notification::Subscribable if integral_options.dig(:notifications, :enabled)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -16,7 +16,7 @@ module Integral
16
16
  class ActiveRecord::Base
17
17
  # Adds listable behaviour to objects
18
18
  def self.acts_as_listable(_options = {})
19
- Integral::ActsAsListable.objects << self
19
+ Integral::ActsAsListable.objects << self unless Integral::ActsAsListable.objects.map(&:name).include?(self.name)
20
20
 
21
21
  # @return [Hash] instance as a list item
22
22
  # Keys include: id, title, subtitle, image, description, url