effective_committees 0.4.3 → 0.5.1

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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/effective/committees_controller.rb +12 -2
  3. data/app/datatables/admin/effective_committee_files_datatable.rb +2 -2
  4. data/app/datatables/admin/effective_committee_folders_datatable.rb +2 -2
  5. data/app/datatables/admin/effective_committee_members_datatable.rb +8 -2
  6. data/app/datatables/admin/effective_committees_datatable.rb +6 -3
  7. data/app/datatables/effective_committee_members_datatable.rb +3 -0
  8. data/app/datatables/effective_committees_activity_datatable.rb +42 -0
  9. data/app/datatables/effective_committees_datatable.rb +2 -1
  10. data/app/models/concerns/effective_committees_user.rb +24 -0
  11. data/app/models/effective/committee_file.rb +4 -1
  12. data/app/views/admin/committee_files/_form.html.haml +3 -18
  13. data/app/views/admin/committee_files/_form_committee_file.html.haml +18 -0
  14. data/app/views/admin/committee_folders/_form.html.haml +8 -22
  15. data/app/views/admin/committee_folders/_form_committee_folder.html.haml +17 -0
  16. data/app/views/admin/committee_members/_form.html.haml +3 -37
  17. data/app/views/admin/committee_members/_form_committee_member.html.haml +37 -0
  18. data/app/views/admin/committees/_fields.html.haml +4 -4
  19. data/app/views/admin/committees/_form.html.haml +7 -6
  20. data/app/views/admin/committees/_form_committee.html.haml +1 -3
  21. data/app/views/effective/committee_folders/_committee_folder.html.haml +30 -23
  22. data/app/views/effective/committee_folders/show.html.haml +13 -0
  23. data/app/views/effective/committee_members/_form.html.haml +5 -5
  24. data/app/views/effective/committees/_committee.html.haml +23 -26
  25. data/app/views/effective/committees/_dashboard.html.haml +2 -18
  26. data/app/views/effective/committees/_dashboard_activity.html.haml +34 -0
  27. data/app/views/effective/committees/_form_committee.html.haml +1 -1
  28. data/app/views/effective/committees/activity.html.haml +19 -0
  29. data/app/views/effective/committees/index.html.haml +23 -26
  30. data/app/views/effective/committees/show.html.haml +13 -0
  31. data/app/views/effective/committees/volunteers_and_committees.html.haml +14 -0
  32. data/config/locales/effective_committees.en.yml +1 -1
  33. data/config/routes.rb +5 -1
  34. data/db/migrate/101_create_effective_committees.rb +3 -0
  35. data/lib/effective_committees/version.rb +1 -1
  36. metadata +11 -3
  37. data/app/views/effective/committees/my_committees.html.haml +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 104dc7680378fa73b91bd1d46dbc850322a082964d9a99cdbe0d0d49d434f84e
4
- data.tar.gz: 216d28fd5efabaf608d07766bd33068db2198f8b92d7afc8f5d8189679a6b2ef
3
+ metadata.gz: effc4579e15d6bbbf45ffb1113ebb129a0d809b9e600da98c3b10c5a70e2d385
4
+ data.tar.gz: 25ffa06fe7742f83f08fbac7c79521aa3b2155deb2639fa36559164bfc243c14
5
5
  SHA512:
6
- metadata.gz: 6dcdea843b50069451c4d224bfab85a2f9ed57af9a2e1cfd3741cdefd70bcf9036419da031a8c82ae95e71c4f6674acbf6e0937183d81436abe26dcff151150f
7
- data.tar.gz: 53f044a8752b22d9bda868c8156be5820e3a507bc261e35f74b0990c3f8398c11eb49b1d2cf89283c66994e538aff37ddba46d4230a4250bbdd44640bb36ab4f
6
+ metadata.gz: 1593abb4700a2d23026405da7a7acfb82e042eac5a856bb84efb37afcbb7592817bcb53ab0f5870a10965258d905f9d06deaecd2af976adac4c244e6736417f5
7
+ data.tar.gz: 9bc7a3f7dc8aed23178a8e8d11704e09b470bd782e13a947de3bf2f6f13f1530ec71d6e636499bf4f07b71b7c3a9d97a01ec49f195a39b3726e7303100013540
@@ -6,16 +6,26 @@ module Effective
6
6
  log_page_views(if: -> { EffectiveCommittees.log_page_views? })
7
7
 
8
8
  resource_scope -> { Effective::Committee.all.deep }
9
+ page_title "More Activity", only: [:activity]
9
10
 
10
11
  def index
11
- @committees = resource_scope.for_index
12
- @page_title = EffectiveResources.et('effective_committees.name')
12
+ @committees = resource_scope.for_dashboard
13
+ @page_title = "My #{EffectiveResources.et('effective_committees.name')}"
13
14
 
14
15
  EffectiveResources.authorize!(self, :index, Effective::Committee)
15
16
 
16
17
  render 'index'
17
18
  end
18
19
 
20
+ def volunteers_and_committees
21
+ @committees = resource_scope.for_index
22
+ @page_title = "Volunteers and Committees"
23
+
24
+ EffectiveResources.authorize!(self, :index, Effective::Committee)
25
+ end
26
+
27
+ # activity
28
+
19
29
  private
20
30
 
21
31
  def permitted_params
@@ -7,9 +7,9 @@ module Admin
7
7
  col :id, visible: false
8
8
 
9
9
  col :committee
10
- col :committee_folder
10
+ col :committee_folder, label: "Folder"
11
11
  col :file
12
- col :title
12
+ col :title, visible: false
13
13
  col :notes
14
14
 
15
15
  actions_col
@@ -12,9 +12,9 @@ module Admin
12
12
 
13
13
  col :title, label: 'Folder'
14
14
  col :slug, visible: false
15
- col :body
15
+ col :body, visible: false
16
16
 
17
- col :committee_files, label: 'Files'
17
+ col :committee_files, label: 'Files', visible: false
18
18
  col :committee_files_count, label: 'Files Count', visible: false
19
19
 
20
20
  actions_col
@@ -1,13 +1,15 @@
1
1
  module Admin
2
2
  class EffectiveCommitteeMembersDatatable < Effective::Datatable
3
3
  datatable do
4
+ length 100
5
+
4
6
  col :id, visible: false
5
7
  col :user_id, visible: false
6
8
 
7
9
  col :committee
8
10
  col :user
9
11
 
10
- if defined?(EffectiveMemberships)
12
+ if current_user.class.try(:effective_memberships_owner?)
11
13
  col(:member_number, label: 'Member #', sort: false) do |committee_member|
12
14
  committee_member.user.try(:membership).try(:number)
13
15
  end.search do |collection, term|
@@ -34,7 +36,11 @@ module Admin
34
36
  col :roles, search: roles_collection
35
37
  end
36
38
 
37
- actions_col
39
+ actions_col do |committee_member|
40
+ if EffectiveResources.authorized?(self, :impersonate, committee_member.user)
41
+ dropdown_link_to("Impersonate", "/admin/users/#{committee_member.user_id}/impersonate", data: { confirm: "Really impersonate #{committee_member.user}?", method: :post, remote: true })
42
+ end
43
+ end
38
44
  end
39
45
 
40
46
  collection do
@@ -1,6 +1,9 @@
1
1
  module Admin
2
2
  class EffectiveCommitteesDatatable < Effective::Datatable
3
3
  datatable do
4
+ length 100
5
+ order :title
6
+
4
7
  col :updated_at, visible: false
5
8
  col :created_at, visible: false
6
9
 
@@ -13,7 +16,7 @@ module Admin
13
16
  col :display_on_index, label: "Display on #{committees_name_label} page"
14
17
  col :display_on_dashboard
15
18
 
16
- col(:committee_members, label: committee_members_label) do |committee|
19
+ col(:committee_members, label: committee_members_label, visible: false) do |committee|
17
20
  committee.committee_members.select(&:active?).sort_by(&:to_s).map do |member|
18
21
  content_tag(:div, class: 'col-resource_item') do
19
22
  label = link_to(member.to_s, "/admin/users/#{member.user_id}/edit")
@@ -33,8 +36,8 @@ module Admin
33
36
  col :committee_files_count, label: 'Files Count', visible: false
34
37
 
35
38
  actions_col do |committee|
36
- dropdown_link_to("View #{committee_label}", effective_committees.committee_path(committee), target: '_blank')
37
- dropdown_clipboard_copy(committee.emails, label: "Copy all email addresses")
39
+ dropdown_link_to("Open dashboard", effective_committees.committee_path(committee), target: '_blank')
40
+ dropdown_clipboard_copy(committee.emails, label: "Copy emails")
38
41
  end
39
42
 
40
43
  end
@@ -1,5 +1,8 @@
1
1
  class EffectiveCommitteeMembersDatatable < Effective::Datatable
2
2
  datatable do
3
+ length 100
4
+ order :user
5
+
3
6
  col :id, visible: false
4
7
 
5
8
  col :committee
@@ -0,0 +1,42 @@
1
+ # For the /committees/activity More Activity page
2
+ # Displays all the logged changes for this user's committees
3
+ class EffectiveCommitteesActivityDatatable < Effective::Datatable
4
+ datatable do
5
+ order :id, :desc
6
+
7
+ col :updated_at, label: 'Date'
8
+ col :id, visible: false
9
+
10
+ col :user, label: 'Changed by', search: :string, sort: false
11
+ col :changes_to, label: committee_label, search: current_user.committees
12
+ col :associated, visible: false
13
+
14
+ col :message, sort: false do |log|
15
+ message = (log.message || '').gsub("\n", '<br>')
16
+ associated_type = log.associated_type.gsub('Effective::', '').gsub('ActiveStorage::', '')
17
+
18
+ if log.associated_id == attributes[:changes_to_id] && log.associated_type == attributes[:changes_to_type]
19
+ message
20
+ else
21
+ "#{associated_type} #{log.associated_to_s} - #{message}"
22
+ end
23
+
24
+ end.search do |collection, term, column, sql_column|
25
+ ilike = effective_resource.ilike
26
+ collection.where("associated_type #{ilike} ? OR associated_to_s #{ilike} ? OR message #{ilike} ?", "%#{term}%", "%#{term}%", "%#{term}%")
27
+ end
28
+
29
+ col :details, visible: false, sort: false do |log|
30
+ tableize_hash(log.details)
31
+ end
32
+
33
+ actions_col
34
+ end
35
+
36
+ collection do
37
+ EffectiveLogging.Log.logged_changes.deep
38
+ .where(changes_to_type: 'Effective::Committee', changes_to_id: current_user.committees.map(&:id))
39
+ .where.not(associated_type: 'ActiveStorage::Attachment')
40
+ end
41
+
42
+ end
@@ -1,6 +1,7 @@
1
1
  # Dashboard Committees
2
2
  class EffectiveCommitteesDatatable < Effective::Datatable
3
3
  datatable do
4
+ length 100
4
5
  order :title
5
6
 
6
7
  col :id, visible: false
@@ -10,7 +11,7 @@ class EffectiveCommitteesDatatable < Effective::Datatable
10
11
  col(:committee_members, label: committee_members_label, visible: false) do |committee|
11
12
  committee.committee_members.select(&:active?).sort_by(&:to_s).map do |member|
12
13
  content_tag(:div, class: 'col-resource_item') do
13
- label = link_to(member.to_s, "/admin/users/#{member.user_id}/edit")
14
+ label = member.to_s
14
15
  badge = badge(member.category) if member.category.present?
15
16
 
16
17
  [label, badge].compact.join(' ').html_safe
@@ -45,4 +45,28 @@ module EffectiveCommitteesUser
45
45
  committee_members.select { |cm| cm.active? && !cm.marked_for_destruction? }.map { |cm| cm.committee }
46
46
  end
47
47
 
48
+ # When activity is for sequential uploaded files, group them together like: "12 files were added to Board of Directors - April 2025 Meeting"
49
+ def committees_recent_activity(limit: 100)
50
+ logs = EffectiveLogging.Log.logged_changes.deep
51
+ .where(changes_to_type: 'Effective::Committee', changes_to_id: committees.map(&:id))
52
+ .order(created_at: :desc)
53
+
54
+ # Recent activity should be for folders being created and files being uploaded/replaced
55
+ logs = logs.select do |log|
56
+ folder_created = (log.associated_type == 'Effective::CommitteeFolder' && log.message == 'Created')
57
+ file_changed = (log.associated_type == 'Effective::CommitteeFile' && (log.message == 'Created' || log.details.dig(:changes, 'File').present?))
58
+ folder_created || file_changed
59
+ end
60
+
61
+ # Returns an Array of Arrays where some are 1 length groups
62
+ # Others are multiple length groups of file changes to one folder
63
+ logs = logs.slice_when do |a, b|
64
+ (a.changes_to_id != b.changes_to_id) ||
65
+ (a.associated_type != b.associated_type) ||
66
+ (b.associated_type == "Effective::CommitteeFolder") ||
67
+ (a.associated.try(:committee_folder_id) != b.associated.try(:committee_folder_id))
68
+ end
69
+
70
+ logs.take(limit)
71
+ end
48
72
  end
@@ -15,6 +15,9 @@ module Effective
15
15
  title :string
16
16
  notes :text
17
17
 
18
+ file_id :integer
19
+ file_created_at :datetime
20
+
18
21
  timestamps
19
22
  end
20
23
 
@@ -23,7 +26,7 @@ module Effective
23
26
  end
24
27
 
25
28
  before_validation(if: -> { file.attached? }) do
26
- self.title ||= file.filename.to_s
29
+ assign_attributes(title: file.filename.to_s, file_id: file.attachment.blob.id, file_created_at: file.attachment.blob.created_at)
27
30
  end
28
31
 
29
32
  scope :deep, -> { with_attached_file.includes(:committee, :committee_folder) }
@@ -1,18 +1,3 @@
1
- = effective_form_with(model: [:admin, committee_file], engine: true) do |f|
2
- - f.object.committee_type ||= Effective::Committee.name
3
-
4
- = f.hidden_field :committee_type
5
- = f.hidden_field :committee_id
6
-
7
- - if inline_datatable? && inline_datatable.attributes[:committee_folder_id].present?
8
- = f.hidden_field :committee_folder_id
9
- - elsif inline_datatable?
10
- = f.select :committee_folder_id, Effective::CommitteeFolder.deep.where(committee: committee_file.committee_id)
11
- - else
12
- = f.select :committee_id, Effective::Committee.sorted.all
13
- = f.select :committee_folder_id, Effective::CommitteeFolder.sorted.all
14
-
15
- = f.file_field :file
16
- = f.text_area :notes
17
-
18
- = f.submit
1
+ = tabs do
2
+ = tab 'File Details' do
3
+ = render 'admin/committee_files/form_committee_file', committee_file: committee_file
@@ -0,0 +1,18 @@
1
+ = effective_form_with(model: [:admin, committee_file], engine: true) do |f|
2
+ - f.object.committee_type ||= Effective::Committee.name
3
+
4
+ = f.hidden_field :committee_type
5
+ = f.hidden_field :committee_id
6
+
7
+ - if inline_datatable? && inline_datatable.attributes[:committee_folder_id].present?
8
+ = f.hidden_field :committee_folder_id
9
+ - elsif inline_datatable?
10
+ = f.select :committee_folder_id, Effective::CommitteeFolder.deep.where(committee: committee_file.committee_id), label: "Folder"
11
+ - else
12
+ = f.select :committee_id, Effective::Committee.sorted.all
13
+ = f.select :committee_folder_id, Effective::CommitteeFolder.sorted.all, label: "Folder"
14
+
15
+ = f.file_field :file
16
+ = f.text_area :notes
17
+
18
+ = effective_submit(f)
@@ -1,22 +1,8 @@
1
- = effective_form_with(model: [:admin, committee_folder], engine: true) do |f|
2
- - if inline_datatable?
3
- = f.hidden_field :committee_id
4
- = f.hidden_field :committee_type
5
- - else
6
- = f.select :committee, { committees_label => Effective::Committee.sorted }, polymorphic: true
7
-
8
- = f.text_field :title
9
-
10
- = acts_as_slugged_fields(f, url: (effective_committees.commitee_url(f.object) rescue nil))
11
-
12
- - if defined?(EffectiveArticleEditor)
13
- = f.article_editor :body, hint: "Displayed on the #{committee_folder_label} page"
14
- - else
15
- = f.rich_text_area :body, hint: "Displayed on the #{commitee_fodler_label} page"
16
-
17
- = f.submit
18
-
19
- - if committee_folder.persisted?
20
- %h2 #{committee_folder} Files
21
- - datatable = Admin::EffectiveCommitteeFilesDatatable.new(committee_folder: committee_folder, committee: committee_folder.committee)
22
- = render_inline_datatable(datatable)
1
+ = tabs do
2
+ - if committee_folder.persisted?
3
+ = tab 'Folder Files' do
4
+ - datatable = Admin::EffectiveCommitteeFilesDatatable.new(committee_folder: committee_folder, committee: committee_folder.committee)
5
+ = render_inline_datatable(datatable)
6
+
7
+ = tab 'Folder Details' do
8
+ = render 'admin/committee_folders/form_committee_folder', committee_folder: committee_folder
@@ -0,0 +1,17 @@
1
+ = effective_form_with(model: [:admin, committee_folder], engine: true) do |f|
2
+ - if inline_datatable?
3
+ = f.hidden_field :committee_id
4
+ = f.hidden_field :committee_type
5
+ - else
6
+ = f.select :committee, { committees_label => Effective::Committee.sorted }, polymorphic: true
7
+
8
+ = f.text_field :title
9
+
10
+ = acts_as_slugged_fields(f, url: (effective_committees.commitee_url(f.object) rescue nil))
11
+
12
+ - if defined?(EffectiveArticleEditor)
13
+ = f.article_editor :body, hint: "Displayed on the #{committee_folder_label} page"
14
+ - else
15
+ = f.rich_text_area :body, hint: "Displayed on the #{committee_folder_label} page"
16
+
17
+ = effective_submit(f)
@@ -1,37 +1,3 @@
1
- = effective_form_with(model: [:admin, committee_member], engine: true) do |f|
2
- - f.object.user_type ||= current_user.class.name
3
- - f.object.committee_type ||= Effective::Committee.name
4
-
5
- = f.hidden_field :user_type
6
- = f.hidden_field :user_id
7
-
8
- = f.hidden_field :committee_type
9
- = f.hidden_field :committee_id
10
-
11
- - ajax_url = (effective_resources.users_effective_ajax_index_path unless Rails.env.test?)
12
-
13
- - if f.object.new_record?
14
- - if inline_datatable? && inline_datatable.attributes[:committee_id].present?
15
- = f.select :user_ids, current_user.class.all, label: 'Add user(s)', required: true, ajax_url: ajax_url, hint: "Add one or more #{committee_member_label.downcase}"
16
-
17
- - if inline_datatable? && inline_datatable.attributes[:user_id].present?
18
- = f.select :committee_ids, Effective::Committee.sorted.all, label: "Add #{commitee_label}(s)", hint: "Add one or more #{commitees_label.downcase}"
19
-
20
- - unless inline_datatable?
21
- = f.select :committee_id, Effective::Committee.sorted.all
22
- = f.select :user_ids, current_user.class.sorted, label: 'User(s)', required: true, ajax_url: ajax_url, hint: "Add one or more #{committee_member_label.downcase}"
23
-
24
- - if f.object.persisted?
25
- = f.static_field :committee
26
- = f.static_field :user, label: committee_member_label
27
-
28
- = f.text_field :category
29
-
30
- .row
31
- .col= f.date_field :start_on, hint: 'optional start date'
32
- .col= f.date_field :end_on, hint: 'optional end date'
33
-
34
- - if EffectiveCommittees.use_effective_roles
35
- = f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
36
-
37
- = f.submit
1
+ = tabs do
2
+ = tab "#{committee_member_label} Details" do
3
+ = render 'admin/committee_members/form_committee_member', committee_member: committee_member
@@ -0,0 +1,37 @@
1
+ = effective_form_with(model: [:admin, committee_member], engine: true) do |f|
2
+ - f.object.user_type ||= current_user.class.name
3
+ - f.object.committee_type ||= Effective::Committee.name
4
+
5
+ = f.hidden_field :user_type
6
+ = f.hidden_field :user_id
7
+
8
+ = f.hidden_field :committee_type
9
+ = f.hidden_field :committee_id
10
+
11
+ - ajax_url = (effective_resources.users_effective_ajax_index_path unless Rails.env.test?)
12
+
13
+ - if f.object.new_record?
14
+ - if inline_datatable? && inline_datatable.attributes[:committee_id].present?
15
+ = f.select :user_ids, current_user.class.all, label: 'Select user(s)', required: true, ajax_url: ajax_url
16
+
17
+ - if inline_datatable? && inline_datatable.attributes[:user_id].present?
18
+ = f.select :committee_ids, Effective::Committee.sorted.all, label: "Select #{commitee_label}(s)"
19
+
20
+ - unless inline_datatable?
21
+ = f.select :committee_id, Effective::Committee.sorted.all
22
+ = f.select :user_ids, current_user.class.sorted, label: 'User(s)', required: true, ajax_url: ajax_url, hint: "Add one or more #{committee_member_label.downcase}"
23
+
24
+ - if f.object.persisted?
25
+ = f.static_field :committee
26
+ = f.static_field :user, label: committee_member_label
27
+
28
+ = f.text_field :category
29
+
30
+ .row
31
+ .col= f.date_field :start_on
32
+ .col= f.date_field :end_on, hint: 'End dating will remove access'
33
+
34
+ - if EffectiveCommittees.use_effective_roles
35
+ = f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
36
+
37
+ = effective_submit(f)
@@ -2,10 +2,10 @@
2
2
 
3
3
  = acts_as_slugged_fields(f, url: (effective_committees.committee_url(f.object) rescue nil))
4
4
 
5
- = f.check_box :display_on_index, label: "Display on the #{committees_name_label} page"
6
- = f.check_box :display_on_dashboard, label: "Display to #{committee_members_label.downcase} on their dashboard"
5
+ = f.check_box :display_on_index, label: "Show on the member-only #{link_to "Volunteers and Committees", effective_committees.volunteers_and_committees_path} page"
6
+ = f.check_box :display_on_dashboard, label: "Show on the <a href='/committees'>My #{committee_label.pluralize}</a> page".html_safe
7
7
 
8
8
  - if defined?(EffectiveArticleEditor)
9
- = f.article_editor :body, hint: "Displayed on the #{committee_label} page"
9
+ = f.article_editor :body, hint: "Shown on the #{committee_label} page."
10
10
  - else
11
- = f.rich_text_area :body, hint: "Displayed on the #{committee_label} page"
11
+ = f.rich_text_area :body, hint: "Shown on the #{committee_label} page."
@@ -1,20 +1,21 @@
1
1
  = tabs do
2
- = tab(committee_label) do
3
- = render 'admin/committees/form_committee', committee: committee
4
-
5
2
  - if committee.persisted?
6
3
  = tab(Effective::CommitteeMember) do
7
4
  .text-right.mb-3
8
- = clipboard_copy(committee.emails, label: "Copy all email addresses")
5
+ = clipboard_copy(committee.emails, label: "Copy emails")
9
6
 
10
7
  - datatable = Admin::EffectiveCommitteeMembersDatatable.new(committee: committee)
11
8
  = render_inline_datatable(datatable)
12
9
 
13
- = tab 'Folders' do
10
+ = tab "#{committee_label} Details" do
11
+ = render 'admin/committees/form_committee', committee: committee
12
+
13
+ - if committee.persisted?
14
+ = tab "#{committee_label} Folders" do
14
15
  - datatable = Admin::EffectiveCommitteeFoldersDatatable.new(committee: committee)
15
16
  = render_inline_datatable(datatable)
16
17
 
17
- = tab 'Files' do
18
+ = tab "#{committee_label} Files" do
18
19
  - datatable = Admin::EffectiveCommitteeFilesDatatable.new(committee: committee)
19
20
  = render_inline_datatable(datatable)
20
21
 
@@ -1,6 +1,4 @@
1
1
  = effective_form_with(model: [:admin, committee], engine: true) do |f|
2
2
  = render 'admin/committees/fields', f: f
3
3
 
4
- = f.submit do
5
- = f.save 'Save'
6
- = f.save 'Save and View', class: 'btn btn-secondary'
4
+ = effective_submit(f)
@@ -1,36 +1,43 @@
1
1
  = render('layout') do
2
2
  %nav{'aria-label': 'breadcrumb'}
3
3
  %ol.breadcrumb
4
- - if EffectiveResources.authorized?(self, :index, Effective::Committee)
5
- %li.breadcrumb-item= link_to("All #{committees_label}", effective_committees.committees_path)
6
- - elsif EffectiveResources.authorized?(self, :my_committees, Effective::Committee)
7
- %li.breadcrumb-item= link_to("My #{committees_label}", effective_committees.my_committees_path)
8
- - else
9
- %li.breadcrumb-item= link_to("Home", root_path)
10
-
4
+ %li.breadcrumb-item= link_to("My Dashboard", return_to_dashboard_path)
5
+ %li.breadcrumb-item= link_to("My #{committees_label}", effective_committees.committees_path)
11
6
  %li.breadcrumb-item= link_to(committee_folder.committee, effective_committees.committee_path(committee_folder.committee))
12
7
  %li.breadcrumb-item.active{'aria-current': 'page'}= committee_folder
13
8
 
14
9
  .effective-committee-folder
10
+ %h1= committee_folder
11
+
15
12
  - if committee_folder.rich_text_body.present?
16
13
  .mb-4= committee_folder.rich_text_body.to_s
17
14
 
18
- %table.table.table-striped
19
- %thead
20
- %tr
21
- %th File
22
- %th Date Added
23
- %th Description
15
+ .my-4
24
16
 
25
- - committee_folder.committee_files.each do |file|
26
- %tr
27
- %td
28
- - if file.file.attached?
29
- = link_to(icon('download') + ' ' + file.to_s, url_for(file.file), target: '_blank')
30
- - else
31
- = file.to_s
17
+ %h3 Files
18
+ .card
19
+ .card-body
20
+ - if committee_folder.committee_files.present?
21
+ %table.table.table-sm.table-striped
22
+ %thead
23
+ %tr
24
+ %th
25
+ %th File
26
+ %th.d-none.d-lg-table-cell Date
27
+ %th.d-none.d-lg-table-cell Size
28
+ %th.d-none.d-lg-table-cell Note
32
29
 
33
- %td= file.created_at.strftime('%F')
34
- %td= file.notes
30
+ - committee_folder.committee_files.each_with_index do |file, index|
31
+ %tr
32
+ %td= index+1
33
+ %td
34
+ - if file.file.attached?
35
+ = link_to(file.to_s, url_for(file.file), target: '_blank')
36
+ - else
37
+ = file.to_s
35
38
 
36
- %p Displaying #{pluralize(committee_folder.committee_files.length, 'file')}
39
+ %td.d-none.d-lg-table-cell= file.created_at.strftime('%F')
40
+ %td.d-none.d-lg-table-cell= number_to_human_size(file.file.byte_size)
41
+ %td.d-none.d-lg-table-cell= file.notes
42
+ - else
43
+ %p No files.
@@ -0,0 +1,13 @@
1
+ - resource = (@_effective_resource || Effective::Resource.new(controller_path))
2
+ - @resource = instance_variable_get('@' + resource.name) if resource.name
3
+
4
+ - if @resource
5
+ .resource-buttons
6
+ = render_resource_buttons(@resource, show: false)
7
+
8
+ = render_resource_partial(@resource)
9
+
10
+ .my-4
11
+
12
+ -# .form-actions
13
+ -# = link_to 'Continue', return_to_dashboard_path, class: 'btn btn-primary mb-4'
@@ -11,8 +11,8 @@
11
11
  = f.select :committee, { committees_label => Effective::Committee.sorted }, polymorphic: true
12
12
 
13
13
  .row
14
- .col= f.date_field :start_on, hint: 'optional start date'
15
- .col= f.date_field :end_on, hint: 'optional end date'
14
+ .col= f.date_field :start_on
15
+ .col= f.date_field :end_on, hint: 'End dating will remove access'
16
16
 
17
17
  - if EffectiveCommittees.use_effective_roles
18
18
  = f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
@@ -33,8 +33,8 @@
33
33
  = f.text_field :category
34
34
 
35
35
  .row
36
- .col= f.date_field :start_on, hint: 'optional start date'
37
- .col= f.date_field :end_on, hint: 'optional end date'
36
+ .col= f.date_field :start_on
37
+ .col= f.date_field :end_on, hint: 'End dating will remove access'
38
38
 
39
39
  - if EffectiveCommittees.use_effective_roles
40
40
  = f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
@@ -42,4 +42,4 @@
42
42
  = f.fields_for :user, f.object.user do |fu|
43
43
  = render 'effective/committee_members/user_fields', f: fu
44
44
 
45
- = f.submit
45
+ = effective_submit(f)
@@ -1,24 +1,34 @@
1
1
  = render('layout') do
2
2
  %nav{'aria-label': 'breadcrumb'}
3
3
  %ol.breadcrumb
4
- - if EffectiveResources.authorized?(self, :index, Effective::Committee)
5
- %li.breadcrumb-item= link_to("All #{committees_label}", effective_committees.committees_path)
6
- - elsif EffectiveResources.authorized?(self, :my_committees, Effective::Committee)
7
- %li.breadcrumb-item= link_to("My #{committees_label}", effective_committees.my_committees_path)
8
- - else
9
- %li.breadcrumb-item= link_to("Home", root_path)
10
-
4
+ %li.breadcrumb-item= link_to("My Dashboard", return_to_dashboard_path)
5
+ %li.breadcrumb-item= link_to("My #{committees_label}", effective_committees.committees_path)
11
6
  %li.breadcrumb-item.active{'aria-current': 'page'}= committee
12
7
 
13
8
  .effective-committee
9
+ %h1= committee
10
+
14
11
  - if committee.rich_text_body.present?
15
- .mb-4= committee.rich_text_body.to_s
12
+ = committee.rich_text_body.to_s
16
13
 
17
- .mb-4
18
- = collapse("Show #{committee_members_label.downcase}") do
19
- - members = committee.committee_members.select(&:active?).sort_by(&:to_s)
14
+ .my-4
15
+
16
+ .row
17
+ .col-lg
18
+ %h3 Folders
19
+
20
+ .card
21
+ .list-group.list-group-flush
22
+ - if committee.committee_folders.present?
23
+ - committee.committee_folders.each do |folder|
24
+ = link_to folder.to_s, effective_committees.committee_committee_folder_path(committee, folder), class: 'list-group-item list-group-action'
25
+ - else
26
+ .list-group-item No files or folders.
20
27
 
21
- %p= pluralize(members.length, committee_member_label.downcase)
28
+ .col-lg
29
+ %h3= committee_members_label
30
+
31
+ - members = committee.committee_members.select(&:active?).sort_by(&:to_s)
22
32
 
23
33
  %ul
24
34
  - members.each do |member|
@@ -27,17 +37,4 @@
27
37
  - if member.category.present?
28
38
  = badge(member.category)
29
39
 
30
- %table.table.table-striped
31
- %thead
32
- %tr
33
- %th Folder
34
- %th Files
35
- %th Description
36
-
37
- - committee.committee_folders.each do |folder|
38
- %tr
39
- %td= link_to(icon('folder') + ' ' + folder.to_s, effective_committees.committee_committee_folder_path(committee, folder))
40
- %td= pluralize(folder.committee_files.length, 'file')
41
- %td= folder.body.to_s
42
-
43
- %p Displaying #{pluralize(committee.committee_folders.length, 'folder')}
40
+ -# TODO add recent activity here
@@ -1,20 +1,4 @@
1
1
  %h2= committees_label
2
+ %p You can download files and view recent activity for your #{committees_label}.
2
3
 
3
- - if current_user.committees.present?
4
- %p
5
- You have access to #{pluralize(current_user.committees.length, committee_label.downcase)}.
6
-
7
- - if EffectiveResources.authorized?(self, :index, Effective::Committee)
8
- Please
9
- = link_to('click here', effective_committees.committees_path)
10
- to view all #{committees_label.downcase}.
11
- - elsif EffectiveResources.authorized?(self, :my_committees, Effective::Committee)
12
- Please
13
- = link_to('click here', effective_committees.my_committees_path)
14
- to view your #{committees_label.downcase}.
15
-
16
- - datatable = EffectiveResources.best('EffectiveCommitteesDatatable').new(self, namespace: :effective)
17
- = render_datatable(datatable, simple: true)
18
-
19
- - else
20
- %p You aren't assigned to any #{committees_label.downcase}. When you are, we'll show them here.
4
+ = link_to("My #{committees_label}", effective_committees.committees_path, class: "btn btn-primary")
@@ -0,0 +1,34 @@
1
+ %h3 Recent Activity
2
+
3
+ - if current_user.committees.present?
4
+ %ul
5
+ - current_user.committees_recent_activity(limit: 10).each do |logs|
6
+ - log = logs.first
7
+
8
+ - committee = log.changes_to
9
+ - link_to_committee = link_to(committee, effective_committees.committee_path(committee))
10
+
11
+ - committee_folder = log.associated.try(:committee_folder) || log.associated
12
+ - link_to_committee_folder = link_to(committee_folder, effective_committees.committee_committee_folder_path(committee, committee_folder))
13
+
14
+ -# TODO - this errors out if it isn't on the dashboard
15
+ -# link_to_file = link_to(log.associated, main_app.url_for(log.associated.try(:file)))
16
+
17
+ - if logs.length == 1 && log.associated_type == 'Effective::CommitteeFolder'
18
+ %li Folder #{link_to_committee_folder} was added to #{link_to_committee}.
19
+
20
+ - elsif logs.length == 1 && log.associated_type == 'Effective::CommitteeFile'
21
+ %li File {filename} was added to #{link_to_committee} &rarr; #{link_to_committee_folder}.
22
+ -# %li File #{link_to_file} was added to #{link_to_committee} &rarr; #{link_to_committee_folder}.
23
+
24
+ - elsif logs.length > 1 && logs.all? { |log| log.associated_type == 'Effective::CommitteeFile' }
25
+ %li #{logs.length} files were added to #{link_to_committee} &rarr; #{link_to_committee_folder}.
26
+
27
+ - else
28
+ - raise("Unexpected logs: #{logs.inspect}")
29
+
30
+ -# TODO - make the index better before linking it
31
+ -#%p= link_to('View more activity', effective_committees.activity_committees_path)
32
+
33
+ - else
34
+ %p There's no activity to display. When there is, we'll show it here.
@@ -3,7 +3,7 @@
3
3
  = effective_form_with(model: committee, url: url) do |f|
4
4
  = render 'effective/committees/fields', f: f
5
5
 
6
- = f.submit
6
+ = effective_submit(f)
7
7
 
8
8
  - if committee.persisted?
9
9
  %h2= committee_members_label
@@ -0,0 +1,19 @@
1
+ - committees = @committees.sorted
2
+
3
+ = render('layout') do
4
+ %nav{'aria-label': 'breadcrumb'}
5
+ %ol.breadcrumb
6
+ %li.breadcrumb-item= link_to("Home", root_path)
7
+ %li.breadcrumb-item.active{'aria-current': 'page'}= @page_title
8
+
9
+ %h1= @page_title
10
+
11
+ - if committees.blank?
12
+ %p There are no #{committees_label.downcase} to display.
13
+ - else
14
+ - datatable = EffectiveResources.best('EffectiveCommitteesActivityDatatable').new(self, namespace: :effective)
15
+ = render_datatable(datatable, inline: true)
16
+ .my-4
17
+
18
+ .form-actions
19
+ = link_to 'Continue', return_to_dashboard_path, class: 'btn btn-primary mb-4'
@@ -1,37 +1,34 @@
1
- - committees = @committees.sorted
1
+ - committees = @committees.sorted.where(id: current_user.committees)
2
2
 
3
3
  = render('layout') do
4
4
  %nav{'aria-label': 'breadcrumb'}
5
5
  %ol.breadcrumb
6
- %li.breadcrumb-item= link_to("Home", root_path)
7
- %li.breadcrumb-item.active{'aria-current': 'page'}= @page_title
6
+ %li.breadcrumb-item= link_to("My Dashboard", return_to_dashboard_path)
7
+ %li.breadcrumb-item.active{'aria-current': 'page'} My #{committees_label}
8
8
 
9
- %h1= @page_title
9
+ .effective-committees
10
10
 
11
- - if committees.blank?
12
- %p There are no #{committees_label.downcase} to display.
13
- - else
14
- %p
15
- = succeed('.') do
16
- There are #{pluralize(committees.length, committee_label.downcase)} and
17
- = pluralize(Effective::CommitteeMember.pluck(:user_id).uniq.length, committee_member_label.downcase)
11
+ %h1 My #{committees_label}
18
12
 
19
- .effective-committees
20
- - committees.each do |committee|
21
- %h3= committee
13
+ .my-4
22
14
 
23
- - members = committee.committee_members.select(&:active?).sort_by(&:to_s)
24
- %ul
25
- - members.each do |member|
26
- %li
27
- = member.user.to_s
28
- - if member.category.present?
29
- = badge(member.category)
15
+ .row
16
+ .col-lg
17
+ - if committees.blank?
18
+ %p There are no #{committees_label.downcase} to display.
30
19
 
31
- - if members.blank?
32
- %li No #{committee_members_label.downcase}
20
+ - else
21
+ - committees.each do |committee|
22
+ .mb-5
23
+ %h3= link_to(committee.to_s, effective_committees.committee_path(committee), style: "text-decoration: none;")
33
24
 
34
- .my-4
25
+ - if committee.committee_folders.present?
26
+ .card
27
+ .list-group.list-grou-flush
28
+ - committee.committee_folders.each do |folder|
29
+ = link_to(folder.to_s, effective_committees.committee_committee_folder_path(committee, folder), class: 'list-group-item list-group-action')
30
+ - else
31
+ %p No files or folders.
35
32
 
36
- .form-actions
37
- = link_to 'Continue', return_to_dashboard_path, class: 'btn btn-primary mb-4'
33
+ .col-lg
34
+ = render 'effective/committees/dashboard_activity'
@@ -0,0 +1,13 @@
1
+ - resource = (@_effective_resource || Effective::Resource.new(controller_path))
2
+ - @resource = instance_variable_get('@' + resource.name) if resource.name
3
+
4
+ - if @resource
5
+ .resource-buttons
6
+ = render_resource_buttons(@resource, show: false)
7
+
8
+ = render_resource_partial(@resource)
9
+
10
+ .my-4
11
+
12
+ -# .form-actions
13
+ -# = link_to 'Continue', return_to_dashboard_path, class: 'btn btn-primary mb-4'
@@ -0,0 +1,14 @@
1
+ = render('layout') do
2
+ - @committees.each do |committee|
3
+ %h3= committee
4
+
5
+ - members = committee.committee_members.select(&:active?).sort_by(&:to_s)
6
+ %ul
7
+ - members.each do |member|
8
+ %li
9
+ = member.user.to_s
10
+ - if member.category.present?
11
+ = badge(member.category)
12
+
13
+ - if members.blank?
14
+ %li No #{committee_members_label.downcase}
@@ -1,6 +1,6 @@
1
1
  en:
2
2
  effective_committees:
3
- name: 'Effective Committees'
3
+ name: 'Committees'
4
4
  acronym: 'Committees'
5
5
 
6
6
  activerecord:
data/config/routes.rb CHANGED
@@ -8,10 +8,13 @@ EffectiveCommittees::Engine.routes.draw do
8
8
  # Public routes
9
9
  scope module: 'effective' do
10
10
  resources :committees, only: [:index, :show] do
11
+ get 'activity', on: :collection
12
+
11
13
  resources :committee_folders, only: [:show]
12
14
  end
13
15
 
14
- get 'my-committees', to: 'committees#my_committees'
16
+ get 'volunteers-and-committees', to: 'committees#volunteers_and_committees', as: 'volunteers_and_committees'
17
+ get 'volunteers_and_committees', to: 'committees#volunteers_and_committees'
15
18
 
16
19
  resources :committee_members, except: [:show]
17
20
  end
@@ -24,3 +27,4 @@ EffectiveCommittees::Engine.routes.draw do
24
27
  end
25
28
 
26
29
  end
30
+
@@ -66,6 +66,9 @@ class CreateEffectiveCommittees < ActiveRecord::Migration[6.0]
66
66
 
67
67
  t.integer :committee_folder_id
68
68
 
69
+ t.integer :file_id
70
+ t.datetime :file_created_at
71
+
69
72
  t.string :title
70
73
  t.text :notes
71
74
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveCommittees
2
- VERSION = '0.4.3'.freeze
2
+ VERSION = '0.5.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_committees
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-26 00:00:00.000000000 Z
11
+ date: 2025-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -191,6 +191,7 @@ files:
191
191
  - app/datatables/admin/effective_committee_members_datatable.rb
192
192
  - app/datatables/admin/effective_committees_datatable.rb
193
193
  - app/datatables/effective_committee_members_datatable.rb
194
+ - app/datatables/effective_committees_activity_datatable.rb
194
195
  - app/datatables/effective_committees_datatable.rb
195
196
  - app/helpers/effective_committees_helper.rb
196
197
  - app/models/concerns/effective_committees_user.rb
@@ -199,24 +200,31 @@ files:
199
200
  - app/models/effective/committee_folder.rb
200
201
  - app/models/effective/committee_member.rb
201
202
  - app/views/admin/committee_files/_form.html.haml
203
+ - app/views/admin/committee_files/_form_committee_file.html.haml
202
204
  - app/views/admin/committee_folders/_form.html.haml
205
+ - app/views/admin/committee_folders/_form_committee_folder.html.haml
203
206
  - app/views/admin/committee_members/_form.html.haml
207
+ - app/views/admin/committee_members/_form_committee_member.html.haml
204
208
  - app/views/admin/committee_members/_user_fields.html.haml
205
209
  - app/views/admin/committees/_fields.html.haml
206
210
  - app/views/admin/committees/_form.html.haml
207
211
  - app/views/admin/committees/_form_committee.html.haml
208
212
  - app/views/effective/committee_folders/_committee_folder.html.haml
209
213
  - app/views/effective/committee_folders/_layout.html.haml
214
+ - app/views/effective/committee_folders/show.html.haml
210
215
  - app/views/effective/committee_members/_form.html.haml
211
216
  - app/views/effective/committee_members/_user_fields.html.haml
212
217
  - app/views/effective/committees/_committee.html.haml
213
218
  - app/views/effective/committees/_dashboard.html.haml
219
+ - app/views/effective/committees/_dashboard_activity.html.haml
214
220
  - app/views/effective/committees/_fields.html.haml
215
221
  - app/views/effective/committees/_form.html.haml
216
222
  - app/views/effective/committees/_form_committee.html.haml
217
223
  - app/views/effective/committees/_layout.html.haml
224
+ - app/views/effective/committees/activity.html.haml
218
225
  - app/views/effective/committees/index.html.haml
219
- - app/views/effective/committees/my_committees.html.haml
226
+ - app/views/effective/committees/show.html.haml
227
+ - app/views/effective/committees/volunteers_and_committees.html.haml
220
228
  - config/effective_committees.rb
221
229
  - config/locales/effective_committees.en.yml
222
230
  - config/routes.rb
@@ -1,47 +0,0 @@
1
- - committees = @committees.sorted.where(id: current_user.committees)
2
-
3
- = render('layout') do
4
- %nav{'aria-label': 'breadcrumb'}
5
- %ol.breadcrumb
6
- - if EffectiveResources.authorized?(self, :index, Effective::Committee)
7
- %li.breadcrumb-item= link_to("All #{committees_label}", effective_committees.committees_path)
8
- - else
9
- %li.breadcrumb-item= link_to("Home", root_path)
10
-
11
- %li.breadcrumb-item.active{'aria-current': 'page'} My #{committees_label}
12
-
13
- - if committees.blank?
14
- %p There are no #{committees_label.downcase} to display.
15
-
16
- - if committees.present?
17
- %p You have access to #{pluralize(committees.length, committee_label.downcase)}: #{committees.to_sentence}
18
-
19
- .effective-committees
20
- - committees.each do |committee|
21
- .card
22
- .card-body
23
- = link_to(icon('folder') + ' ' + committee.to_s, effective_committees.committee_path(committee))
24
-
25
- = collapse("Show #{committee_members_label.downcase}", card_class: 'card card-body mt-4 mx-4', link_class: 'btn btn-link float-right') do
26
- - members = committee.committee_members.select(&:active?).sort_by(&:to_s)
27
-
28
- %p= pluralize(members.length, committee_member_label.downcase)
29
-
30
- %ul
31
- - members.each do |member|
32
- %li
33
- = member.user.to_s
34
- - if member.category.present?
35
- = badge(member.category)
36
-
37
- %table.table.table-striped.mt-3.ml-4
38
- - committee.committee_folders.each do |folder|
39
- %tr
40
- %td= link_to(icon('folder') + ' ' + folder.to_s, effective_committees.committee_committee_folder_path(committee, folder))
41
- %td= pluralize(folder.committee_files.length, 'file')
42
- %td= folder.body
43
-
44
- .my-4
45
-
46
- .form-actions
47
- = link_to 'Continue', return_to_dashboard_path, class: 'btn btn-primary mb-4'