spina-admin-journal 0.5.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/spina_admin_journal_manifest.js +5 -2
  3. data/app/assets/javascripts/spina/admin/journal/application.js +0 -0
  4. data/app/components/spina/admin/journal/affiliations_list_component.rb +32 -0
  5. data/app/components/spina/admin/journal/application_component.rb +11 -0
  6. data/app/components/spina/admin/journal/articles_list_component.rb +54 -0
  7. data/app/components/spina/admin/journal/authors_list_component.rb +37 -0
  8. data/app/components/spina/admin/journal/authorships_list_component.rb +45 -0
  9. data/app/components/spina/admin/journal/empty_list_component.html.haml +1 -0
  10. data/app/components/spina/admin/journal/empty_list_component.rb +14 -0
  11. data/app/components/spina/admin/journal/institutions_list_component.rb +32 -0
  12. data/app/components/spina/admin/journal/issues_list_component.rb +47 -0
  13. data/app/components/spina/admin/journal/licences_list_component.rb +32 -0
  14. data/app/components/spina/admin/journal/list_component.html.haml +10 -0
  15. data/app/components/spina/admin/journal/list_component.rb +22 -0
  16. data/app/components/spina/admin/journal/list_item_component.html.haml +17 -0
  17. data/app/components/spina/admin/journal/list_item_component.rb +23 -0
  18. data/app/components/spina/admin/journal/volumes_list_component.rb +34 -0
  19. data/app/controllers/spina/admin/journal/application_controller.rb +3 -1
  20. data/app/controllers/spina/admin/journal/articles_controller.rb +14 -25
  21. data/app/controllers/spina/admin/journal/authors_controller.rb +15 -28
  22. data/app/controllers/spina/admin/journal/institutions_controller.rb +7 -5
  23. data/app/controllers/spina/admin/journal/issues_controller.rb +17 -24
  24. data/app/controllers/spina/admin/journal/journals_controller.rb +4 -3
  25. data/app/controllers/spina/admin/journal/licences_controller.rb +7 -5
  26. data/app/controllers/spina/admin/journal/volumes_controller.rb +9 -20
  27. data/app/models/spina/parts/admin/journal/page_range.rb +31 -0
  28. data/app/views/spina/admin/hooks/journal/_primary_navigation.html.haml +35 -26
  29. data/app/views/spina/admin/journal/articles/_form.html.haml +23 -24
  30. data/app/views/spina/admin/journal/articles/_form_authors.html.haml +1 -15
  31. data/app/views/spina/admin/journal/articles/_form_details.html.haml +27 -56
  32. data/app/views/spina/admin/journal/articles/index.html.haml +7 -17
  33. data/app/views/spina/admin/journal/authors/_form.html.haml +24 -24
  34. data/app/views/spina/admin/journal/authors/_form_affiliation.html.haml +8 -20
  35. data/app/views/spina/admin/journal/authors/_form_articles.html.haml +1 -18
  36. data/app/views/spina/admin/journal/authors/_form_details.html.haml +2 -6
  37. data/app/views/spina/admin/journal/authors/index.html.haml +7 -15
  38. data/app/views/spina/admin/journal/institutions/_form.html.haml +24 -24
  39. data/app/views/spina/admin/journal/institutions/_form_details.html.haml +2 -8
  40. data/app/views/spina/admin/journal/institutions/_form_view_affiliations.html.haml +1 -10
  41. data/app/views/spina/admin/journal/institutions/index.html.haml +7 -15
  42. data/app/views/spina/admin/journal/issues/_form.html.haml +23 -23
  43. data/app/views/spina/admin/journal/issues/_form_articles.html.haml +1 -14
  44. data/app/views/spina/admin/journal/issues/_form_details.html.haml +13 -28
  45. data/app/views/spina/admin/journal/issues/index.html.haml +7 -16
  46. data/app/views/spina/admin/journal/journals/_form.html.haml +22 -32
  47. data/app/views/spina/admin/journal/licences/_form.html.haml +19 -34
  48. data/app/views/spina/admin/journal/licences/index.html.haml +7 -16
  49. data/app/views/spina/admin/journal/volumes/_form.html.haml +25 -12
  50. data/app/views/spina/admin/journal/volumes/_form_details.html.haml +4 -10
  51. data/app/views/spina/admin/journal/volumes/_form_issues.html.haml +1 -13
  52. data/app/views/spina/admin/journal/volumes/index.html.haml +7 -16
  53. data/app/views/spina/admin/parts/admin/journal/page_ranges/_form.html.haml +6 -0
  54. data/config/locales/en.yml +25 -3
  55. data/config/routes.rb +5 -5
  56. data/db/migrate/20210626153728_create_spina_parts_admin_journal_page_ranges.rb +7 -0
  57. data/lib/spina/admin/journal/engine.rb +18 -0
  58. data/lib/spina/admin/journal/version.rb +1 -1
  59. data/lib/spina/admin/journal.rb +1 -0
  60. metadata +50 -65
  61. data/app/assets/javascripts/spina/admin/journal/application.es6 +0 -72
  62. data/app/views/layouts/spina/admin/journal/articles.html.haml +0 -10
  63. data/app/views/layouts/spina/admin/journal/authors.html.haml +0 -10
  64. data/app/views/layouts/spina/admin/journal/institutions.html.haml +0 -10
  65. data/app/views/layouts/spina/admin/journal/issues.html.haml +0 -10
  66. data/app/views/layouts/spina/admin/journal/journals.html.haml +0 -10
  67. data/app/views/layouts/spina/admin/journal/licences.html.haml +0 -10
  68. data/app/views/layouts/spina/admin/journal/volumes.html.haml +0 -10
  69. data/app/views/spina/admin/journal/affiliations/_affiliation.html.haml +0 -8
  70. data/app/views/spina/admin/journal/application/_empty_list.html.haml +0 -3
  71. data/app/views/spina/admin/journal/articles/_article.html.haml +0 -10
  72. data/app/views/spina/admin/journal/authors/_author.html.haml +0 -8
  73. data/app/views/spina/admin/journal/authorships/_authorship.html.haml +0 -9
  74. data/app/views/spina/admin/journal/institutions/_institution.html.haml +0 -9
  75. data/app/views/spina/admin/journal/issues/_issue.html.haml +0 -9
  76. data/app/views/spina/admin/journal/journals/index.html.haml +0 -27
  77. data/app/views/spina/admin/journal/licences/_licence.html.haml +0 -11
  78. data/app/views/spina/admin/journal/volumes/_volume.html.haml +0 -7
  79. data/vendor/assets/javascripts/spina/admin/journal/html5sortable.js +0 -1295
@@ -24,17 +24,19 @@ module Spina
24
24
  @institution = Institution.new(institution_params)
25
25
 
26
26
  if @institution.save
27
- redirect_to admin_journal_institutions_path, success: t('.saved')
27
+ redirect_to edit_admin_journal_institution_path(@institution), success: t('.saved')
28
28
  else
29
- render :new
29
+ flash.now[:alert] = t('.failed')
30
+ render :new, status: :unprocessable_entity
30
31
  end
31
32
  end
32
33
 
33
34
  def update
34
35
  if @institution.update(institution_params)
35
- redirect_to admin_journal_institutions_path, success: t('.saved')
36
+ redirect_to edit_admin_journal_institution_path(@institution), success: t('.saved')
36
37
  else
37
- render :edit
38
+ flash.now[:alert] = t('.failed')
39
+ render :edit, status: :unprocessable_entity
38
40
  end
39
41
  end
40
42
 
@@ -50,7 +52,7 @@ module Spina
50
52
  private
51
53
 
52
54
  def institution_params
53
- params.require(:admin_journal_institution).permit(:name)
55
+ params.require(:institution).permit(:name)
54
56
  end
55
57
 
56
58
  def set_breadcrumb
@@ -4,6 +4,7 @@ module Spina
4
4
  module Admin
5
5
  module Journal
6
6
  # Controller for {Issue} records.
7
+ # TODO: extract methods to helpers to reduce class length
7
8
  class IssuesController < ApplicationController
8
9
  PARTS_PARAMS = [
9
10
  :name, :title, :type, :content, :filename, :signed_blob_id, :alt, :attachment_id, :image_id,
@@ -25,6 +26,7 @@ module Spina
25
26
  before_action :set_breadcrumb
26
27
  before_action :set_tabs, except: %i[index destroy sort]
27
28
  before_action :set_issue, only: %i[edit update destroy]
29
+ before_action :set_articles, only: %i[edit update]
28
30
  before_action :set_parts_attributes, only: %i[new edit]
29
31
  before_action :build_parts, only: %i[edit]
30
32
 
@@ -44,23 +46,25 @@ module Spina
44
46
  add_breadcrumb t('spina.admin.journal.issues.issue_number', number: @issue.number)
45
47
  end
46
48
 
47
- def create
49
+ def create # rubocop:disable Metrics/AbcSize
48
50
  @issue = Issue.new(issue_params)
49
51
  sister_issues = Issue.where(volume: @issue.volume_id)
50
52
  @issue.number = sister_issues.any? ? sister_issues.sorted_desc.first.number + 1 : 1
51
53
 
52
54
  if @issue.save
53
- redirect_to admin_journal_issues_path, success: t('.saved')
55
+ redirect_to edit_admin_journal_issue_path(@issue), success: t('.saved')
54
56
  else
55
- render :new
57
+ flash.now[:alert] = t('.failed')
58
+ render :new, status: :unprocessable_entity
56
59
  end
57
60
  end
58
61
 
59
62
  def update
60
63
  if @issue.update(issue_params)
61
- redirect_to admin_journal_issues_path, success: t('.saved')
64
+ redirect_to edit_admin_journal_issue_path(@issue), success: t('.saved')
62
65
  else
63
- render :edit
66
+ flash.now[:alert] = t('.failed')
67
+ render :edit, status: :unprocessable_entity
64
68
  end
65
69
  end
66
70
 
@@ -74,16 +78,11 @@ module Spina
74
78
  end
75
79
 
76
80
  def sort
77
- ActiveRecord::Base.transaction do
78
- sort_params.each do |id, new_pos|
79
- # ignore uniqueness validation for now
80
- Issue.find(id.to_i).update_attribute(:number, new_pos.to_i) # rubocop:disable Rails/SkipsModelValidations
81
- end
82
- validate_sort_order
81
+ params[:ids].each.with_index do |id, index|
82
+ Issue.where(id: id).update_all(number: index + 1) # rubocop:disable Rails/SkipsModelValidations
83
83
  end
84
- render json: { success: true, message: t('.sort_success') }
85
- rescue ActiveRecord::RecordInvalid
86
- render json: { success: false, message: t('.sort_error') }
84
+ flash.now[:info] = t('spina.pages.sorting_saved')
85
+ render_flash
87
86
  end
88
87
 
89
88
  private
@@ -92,18 +91,12 @@ module Spina
92
91
  @issue = Issue.find(params[:id])
93
92
  end
94
93
 
95
- def issue_params
96
- params.require(:admin_journal_issue).permit(PARAMS)
97
- end
98
-
99
- def sort_params
100
- params.require(:admin_journal_issues).require(:list).permit!
94
+ def set_articles
95
+ @articles = @issue.articles.sorted_asc
101
96
  end
102
97
 
103
- def validate_sort_order
104
- Issue.where(volume_id: params[:volume_id]).each do |issue|
105
- raise ActiveRecord::RecordInvalid if issue.invalid?
106
- end
98
+ def issue_params
99
+ params.require(:issue).permit(PARAMS)
107
100
  end
108
101
 
109
102
  def set_breadcrumb
@@ -21,7 +21,7 @@ module Spina
21
21
  params.merge("#{locale}_content_attributes": [*PARTS_PARAMS])
22
22
  end
23
23
  PARAMS = [:name, { **CONTENT_PARAMS }].freeze
24
- PARTS = %w[journal_abbreviation logo description documents].freeze
24
+ PARTS = %w[journal_abbreviation logo description documents issn].freeze
25
25
 
26
26
  before_action :set_journal
27
27
  before_action :set_parts_attributes
@@ -35,7 +35,8 @@ module Spina
35
35
  if @journal.update(journal_params)
36
36
  redirect_to edit_admin_journal_journal_path(@journal), success: t('.saved')
37
37
  else
38
- render :edit
38
+ flash.now[:alert] = t('.failed')
39
+ render :edit, status: :unprocessable_entity
39
40
  end
40
41
  end
41
42
 
@@ -65,7 +66,7 @@ module Spina
65
66
  end
66
67
 
67
68
  def journal_params
68
- params.require(:admin_journal_journal).permit(PARAMS)
69
+ params.require(:journal).permit(PARAMS)
69
70
  end
70
71
  end
71
72
  end
@@ -42,17 +42,19 @@ module Spina
42
42
  def create
43
43
  @licence = Licence.new(licence_params)
44
44
  if @licence.save
45
- redirect_to admin_journal_licences_path, success: t('.saved')
45
+ redirect_to edit_admin_journal_licence_path(@licence), success: t('.saved')
46
46
  else
47
- render :new
47
+ flash.now[:alert] = t('.failed')
48
+ render :new, status: :unprocessable_entity
48
49
  end
49
50
  end
50
51
 
51
52
  def update
52
53
  if @licence.update(licence_params)
53
- redirect_to admin_journal_licences_path, success: t('.saved')
54
+ redirect_to edit_admin_journal_licence_path(@licence), success: t('.saved')
54
55
  else
55
- render :edit
56
+ flash.now[:alert] = t('.failed')
57
+ render :edit, status: :unprocessable_entity
56
58
  end
57
59
  end
58
60
 
@@ -68,7 +70,7 @@ module Spina
68
70
  private
69
71
 
70
72
  def licence_params
71
- params.require(:admin_journal_licence).permit(PARAMS)
73
+ params.require(:licence).permit(PARAMS)
72
74
  end
73
75
 
74
76
  def set_breadcrumb
@@ -15,12 +15,16 @@ module Spina
15
15
 
16
16
  def edit; end
17
17
 
18
+ def new
19
+ create
20
+ end
21
+
18
22
  def create # rubocop:disable Metrics/AbcSize
19
23
  @volume = Volume.new
20
24
  @volume.journal_id = Journal.instance.id
21
25
  @volume.number = Volume.any? ? Volume.sorted_desc.first.number + 1 : 1
22
26
  @volume.save!
23
- redirect_to admin_journal_volumes_path, success: t('.created', number: @volume.number)
27
+ redirect_to edit_admin_journal_volume_path(@volume), success: t('.created', number: @volume.number)
24
28
  rescue ActiveRecord::RecordNotUnique
25
29
  # can only happen because of some race condition where two Volumes are created at the same time
26
30
  logger.error 'Error when creating new volume. Retrying...'
@@ -37,30 +41,15 @@ module Spina
37
41
  end
38
42
 
39
43
  def sort
40
- ActiveRecord::Base.transaction do
41
- sort_params.each do |id, new_pos|
42
- # ignore uniqueness validation for now
43
- Volume.find(id.to_i).update_attribute(:number, new_pos.to_i) # rubocop:disable Rails/SkipsModelValidations
44
- end
45
- validate_sort_order
44
+ params[:ids].each.with_index do |id, index|
45
+ Volume.where(id: id).update_all(number: index + 1) # rubocop:disable Rails/SkipsModelValidations
46
46
  end
47
- render json: { success: true, message: t('.sort_success') }
48
- rescue ActiveRecord::RecordInvalid
49
- render json: { success: false, message: t('.sort_error') }
47
+ flash.now[:info] = t('spina.pages.sorting_saved')
48
+ render_flash
50
49
  end
51
50
 
52
51
  private
53
52
 
54
- def sort_params
55
- params.require(:admin_journal_volumes).require(:list).permit!
56
- end
57
-
58
- def validate_sort_order
59
- Volume.where(journal_id: params[:journal_id]).each do |volume|
60
- raise ActiveRecord::RecordInvalid if volume.invalid?
61
- end
62
- end
63
-
64
53
  def set_breadcrumb
65
54
  add_breadcrumb Volume.model_name.human(count: :many), admin_journal_volumes_path
66
55
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spina
4
+ module Parts
5
+ module Admin
6
+ module Journal
7
+ # Part representing a range of pages
8
+ class PageRange < Spina::Parts::Base
9
+ attr_json :first_page, :integer
10
+ attr_json :last_page, :integer
11
+
12
+ validate :valid_range
13
+
14
+ def content
15
+ self
16
+ end
17
+
18
+ def valid_range
19
+ return if first_page.nil? && last_page.nil?
20
+
21
+ if last_page.nil?
22
+ errors.add :last_page, 'must be present'
23
+ elsif last_page < first_page
24
+ errors.add :last_page, 'must be larger than the first page'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,29 +1,38 @@
1
- %li{ class: ('active' if %w[articles issues volumes].include? controller_name) }
2
- = link_to admin_journal_volumes_path do
3
- = icon 'pages'
4
- = ::Spina::Admin::Journal::Journal.instance.has_content?(:journal_abbreviation) ? ::Spina::Admin::Journal::Journal.instance.content(:journal_abbreviation) : ::Spina::Admin::Journal::Journal.instance.name
5
- = icon 'caret-right'
1
+ = render Spina::MainNavigation::SubNavComponent.new(:journal_content) do |nav|
2
+ - nav.icon do
3
+ = heroicon 'document-add', style: :solid, class: 'w-8 h-8 text-white md:mr-3'
4
+ .text-white.font-semibold.hidden{class: 'md:block transform -translate-x-2 ease-in-out duration-300 absolute md:relative opacity-0 transition-all', 'data-navigation-target': 'label'}
5
+ = Spina::Admin::Journal::Journal.instance.name
6
6
 
7
- %ul
8
- %li{ class: ('active' if %w[volumes].include? controller_name) }
9
- = link_to ::Spina::Admin::Journal::Volume.model_name.human(count: :many), admin_journal_volumes_path
10
- %li{ class: ('active' if %w[issues].include? controller_name) }
11
- = link_to ::Spina::Admin::Journal::Issue.model_name.human(count: :many), admin_journal_issues_path
12
- %li{ class: ('active' if %w[articles].include? controller_name) }
13
- = link_to ::Spina::Admin::Journal::Article.model_name.human(count: :many), admin_journal_articles_path
7
+ - nav.links do
8
+ = render Spina::MainNavigation::LinkComponent.new(Spina::Admin::Journal::Volume.model_name.human(count: :many),
9
+ spina.admin_journal_volumes_path,
10
+ active: controller_name == 'volumes')
11
+ = render Spina::MainNavigation::LinkComponent.new(Spina::Admin::Journal::Issue.model_name.human(count: :many),
12
+ spina.admin_journal_issues_path,
13
+ active: controller_name == 'issues')
14
+ = render Spina::MainNavigation::LinkComponent.new(Spina::Admin::Journal::Article.model_name.human(count: :many),
15
+ spina.admin_journal_articles_path,
16
+ active: controller_name == 'articles')
14
17
 
15
- %li{ class: ('active' if %w[journals authors institutions licences].include? controller_name) }
16
- = link_to edit_admin_journal_journal_path(::Spina::Admin::Journal::Journal.instance.id) do
17
- = icon 'dots'
18
- = t 'spina.admin.journal.navigation_title'
19
- = icon 'caret-right'
20
18
 
21
- %ul
22
- %li{ class: ('active' if %w[journals].include? controller_name) }
23
- = link_to ::Spina::Admin::Journal::Journal.model_name.human(count: :one), edit_admin_journal_journal_path(::Spina::Admin::Journal::Journal.instance.id)
24
- %li{ class: ('active' if %w[authors].include? controller_name) }
25
- = link_to ::Spina::Admin::Journal::Author.model_name.human(count: :many), admin_journal_authors_path
26
- %li{ class: ('active' if %w[institutions].include? controller_name) }
27
- = link_to ::Spina::Admin::Journal::Institution.model_name.human(count: :many), admin_journal_institutions_path
28
- %li{ class: ('active' if %w[licences].include? controller_name) }
29
- = link_to ::Spina::Admin::Journal::Licence.model_name.human(count: :many), admin_journal_licences_path
19
+ = render Spina::MainNavigation::SubNavComponent.new(:journal_settings) do |nav|
20
+ - nav.icon do
21
+ = heroicon 'dots-horizontal', style: :solid, class: 'w-8 h-8 text-white md:mr-3'
22
+ .text-white.font-semibold.hidden{class: 'md:block transform -translate-x-2 ease-in-out duration-300 absolute md:relative opacity-0 transition-all', 'data-navigation-target': 'label'}
23
+ = t 'spina.admin.journal.navigation_title'
24
+
25
+ - nav.links do
26
+ = render Spina::MainNavigation::LinkComponent.new(Spina::Admin::Journal::Journal.model_name.human(count: :one),
27
+ spina.edit_admin_journal_journal_path(Spina::Admin::Journal::Journal.instance.id),
28
+ active: controller_name == 'journals')
29
+ = render Spina::MainNavigation::LinkComponent.new(Spina::Admin::Journal::Author.model_name.human(count: :many),
30
+ spina.admin_journal_authors_path,
31
+ active: controller_name == 'authors')
32
+ = render Spina::MainNavigation::LinkComponent.new(Spina::Admin::Journal::Institution.model_name.human(count: :many),
33
+ spina.admin_journal_institutions_path,
34
+ active: controller_name == 'institutions')
35
+ = render Spina::MainNavigation::LinkComponent.new(Spina::Admin::Journal::Licence.model_name.human(count: :many),
36
+ spina.admin_journal_licences_path,
37
+ active: controller_name == 'licences')
38
+
@@ -1,29 +1,28 @@
1
- - if @article.errors.any?
2
- - content_for :notifications do
3
- .notification.notification-danger.animated.fadeInRight
4
- = icon 'exclamation'
5
- .notification-message
6
- = t 'spina.notifications.alert'
7
- %small= @article.errors.full_messages.join('<br />').html_safe
8
- = link_to '#', data: { close_notification: true } do
9
- = icon 'cross'
1
+ %div{ data: { controller: 'tabs',
2
+ tabs: { active: 'cursor-default text-gray-900 bg-spina-dark bg-opacity-10',
3
+ inactive: 'cursor-pointer bg-transparent text-gray-400 border-transparent' } } }
4
+ = render Spina::UserInterface::HeaderComponent.new do |header|
5
+ - header.actions do
6
+ - if @article.persisted?
7
+ = render Spina::UserInterface::DropdownComponent.new do |dropdown|
8
+ - dropdown.button(classes: "btn btn-default px-3") do
9
+ = heroicon('dots-horizontal', style: :solid, class: "w-5 h-5 text-gray-600")
10
10
 
11
- = form_for @article, html: { autocomplete: "off" } do |f|
12
- %header#header
13
- = render partial: 'spina/admin/shared/breadcrumbs'
11
+ - dropdown.menu do
12
+ = button_to t('spina.permanently_delete'), admin_journal_article_path(@article), method: :delete, class: "block w-full text-left px-4 py-2 text-sm leading-5 font-medium text-red-500 cursor-pointer bg-white hover:bg-red-100 hover:bg-opacity-50 hover:text-red-500 focus:outline-none focus:bg-gray-100 focus:text-gray-900", form: {data: { controller: 'confirm', confirm_message: t('.delete_confirmation', title: @article.title) } }
14
13
 
15
- #header_actions
16
- %button.button.button-primary{ type: 'submit', style: 'margin-right: 0', data: { disable_with: t('spina.pages.saving') } }
17
- = icon 'check'
14
+ = button_tag type: :submit, form: dom_id(@article), class: 'btn btn-primary', data: { controller: 'button', action: 'button#loading', loading_message: t('spina.ui.saving')} do
15
+ = heroicon('check', style: :solid, class: 'w-5 h-5 mr-1 -ml-2')
18
16
  = t '.save'
19
17
 
20
- = link_to t('spina.cancel'), admin_journal_articles_path, class: 'button', style: 'margin-right: 0;'
18
+ - header.navigation do
19
+ %nav.-mb-3.mt-4
20
+ %ul.inline-flex.w-auto.rounded-md.bg-white
21
+ - @tabs.each do |tab|
22
+ %button.block.px-3.leading-relaxed.py-1.hover:text-gray-800.rounded-md.text-gray-400.font-medium.text-sm.flex.items-center.whitespace-nowrap{ type: 'button', data: { action: 'tabs#show', 'tabs-target': 'button', 'pane-id': "#{tab}" } }
23
+ = t ".#{tab}"
21
24
 
22
- %nav#secondary.tabs
23
- %ul
24
- - @tabs.each_with_index do |tab, i|
25
- %li{ class: ('active' if i == 0) }
26
- = link_to t(".#{tab}"), "##{tab}"
27
-
28
- #details.tab-content.active= render 'form_details', f: f
29
- #authors.tab-content= render 'form_authors', f: f
25
+ .p-4.md:p-8
26
+ - @tabs.each_with_index do |tab, i|
27
+ %div{ 'data-tabs-target': 'pane', id: tab, hidden: i != 0 }
28
+ = render "form_#{tab}"
@@ -1,15 +1 @@
1
- .sort-message
2
- .table-container
3
- %table.table
4
- %thead
5
- %tr
6
- %th= ::Spina::Admin::Journal::Affiliation.human_attribute_name :position
7
- %th= ::Spina::Admin::Journal::Affiliation.human_attribute_name :name
8
- %th= ::Spina::Admin::Journal::Affiliation.human_attribute_name :institution
9
- %th= t '.number_of_articles'
10
- %th
11
- %tbody.html5sortable{ data: { id: @article.id, sorted_collection: 'admin_journal_authorships', sort_url: !@article.id.nil? && sort_admin_journal_authors_url(@article) } }
12
- - if @article.authorships.any?
13
- = render @article.authorships.sorted_within_article
14
- - else
15
- = render 'empty_list', message: t('.no_authors')
1
+ = render Spina::Admin::Journal::AuthorshipsListComponent.new(authorships: @article.authorships.sorted_within_article, sortable: true)
@@ -1,62 +1,33 @@
1
- .page-form
2
- .page-form-group
3
- .page-form-label
4
- = ::Spina::Admin::Journal::Issue.model_name.human count: :one
5
- .page-form-content
6
- = f.collection_select :issue_id, ::Spina::Admin::Journal::Issue.sorted_desc, :id, ->(issue) { t '.volume_issue', volume_number: issue.volume.number, issue_number: issue.number }
7
- .page-form-group
8
- .page-form-label
9
- = ::Spina::Admin::Journal::Article.human_attribute_name :number
10
- %small= t '.unchangeable'
11
- .page-form-content
12
- = f.number_field :number, disabled: true
13
- .page-form-group
14
- .page-form-label
15
- = ::Spina::Admin::Journal::Article.human_attribute_name :title
16
- .page-form-content
17
- = f.text_field :title
18
- .page-form-group
19
- .page-form-label
20
- = Spina::Admin::Journal::Article.human_attribute_name :status
21
- .page-form-content
22
- = f.select :status, Spina::Admin::Journal::Article.statuses.keys.map { |key| [key.humanize, key] }
23
- .page-form-group
24
- .page-form-label
25
- = Spina::Admin::Journal::Article.human_attribute_name :licence
26
- .page-form-content
27
- = f.collection_select :licence_id, Spina::Admin::Journal::Licence.sorted, :id, :name, prompt: true
28
- .page-form-group
29
- .page-form-label
30
- = ::Spina::Admin::Journal::Author.model_name.human count: :many
31
- .page-form-content
32
- .well{ style: 'margin: 0' }
33
- .table-container
34
- %table.table{ style: 'margin: 0' }
35
- %tbody.collection-check-boxes
36
- = f.collection_check_boxes :affiliation_ids, Spina::Admin::Journal::Affiliation.sorted, :id, :name do |builder|
37
- %tr
38
- %td{ style: "padding-left: 16px" }
39
- .form-checkbox
40
- = builder.check_box
41
- = builder.label
42
- .page-form-group
43
- .page-form-label
44
- = ::Spina::Admin::Journal::Article.human_attribute_name :url
45
- .page-form-content
46
- = f.text_field :url
47
- .page-form-group
48
- .page-form-label
49
- = ::Spina::Admin::Journal::Article.human_attribute_name :doi
50
- .page-form-content
51
- = f.text_field :doi
1
+ = form_with model: [spina, :admin_journal, @article], id: dom_id(@article), html: { autocomplete: 'off' } do |f|
2
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Issue.model_name.human(count: :one)) do
3
+ = f.collection_select :issue_id, ::Spina::Admin::Journal::Issue.sorted_desc, :id, ->(issue) { t '.volume_issue', volume_number: issue.volume.number, issue_number: issue.number }
4
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Article.human_attribute_name(:number),
5
+ description: t('.unchangeable')) do
6
+ = f.number_field :number, disabled: true
7
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Article.human_attribute_name(:title)) do
8
+ = render Spina::Forms::TextFieldComponent.new(f, :title)
9
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Article.human_attribute_name(:status)) do
10
+ = f.select :status, Spina::Admin::Journal::Article.statuses.keys.map { |key| [key.humanize, key] }
11
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Article.human_attribute_name(:licence)) do
12
+ = f.collection_select :licence_id, Spina::Admin::Journal::Licence.sorted, :id, :name, prompt: true
13
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Author.model_name.human(count: :many)) do
14
+ %table.table{ style: 'margin: 0' }
15
+ %tbody.collection-check-boxes
16
+ = f.collection_check_boxes :affiliation_ids, Spina::Admin::Journal::Affiliation.sorted, :id, :name do |builder|
17
+ %tr
18
+ %td{ style: "padding-left: 16px" }
19
+ .form-checkbox
20
+ = builder.check_box
21
+ = builder.label
22
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Article.human_attribute_name(:url)) do
23
+ = render Spina::Forms::TextFieldComponent.new(f, :url)
24
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Article.human_attribute_name(:doi)) do
25
+ = render Spina::Forms::TextFieldComponent.new(f, :doi)
52
26
 
53
27
  = f.fields_for :"#{@locale}_content", @parts do |ff|
54
- = ff.hidden_field :type, value: ff.object.class.name
28
+ = ff.hidden_field :type, value: ff.object.class
55
29
  = ff.hidden_field :title
56
30
  = ff.hidden_field :name
57
31
 
58
- .page-form-group.page-part{ data: { name: ff.object.name } }
59
- = render "spina/admin/parts/#{parts_partial_namespace(ff.object.class.name)}/form", f: ff
32
+ = render "spina/admin/parts/#{parts_partial_namespace(ff.object.class.to_s)}/form", f: ff
60
33
 
61
- - unless @article.new_record?
62
- .pull-right= link_to t('spina.permanently_delete'), admin_journal_article_path(@article), method: :delete, data: { confirm: t('.delete_confirmation', title: @article.title) }, class: 'button button-link button-danger'
@@ -1,19 +1,9 @@
1
- - content_for(:header_actions) do
2
- = link_to new_admin_journal_article_path, class: 'button button-primary' do
3
- = icon 'plus'
4
- = t '.new'
1
+ = render Spina::UserInterface::HeaderComponent.new do |header|
2
+ - header.actions do
3
+ .ml-3
4
+ = link_to new_admin_journal_article_path, class: 'btn btn-primary w-full' do
5
+ = heroicon 'plus', style: :solid, class: 'w-7 h-7 -m1-2'
6
+ = t '.new'
5
7
 
6
- .well
7
- .table-container
8
- %table.table
9
- %thead
10
- %tr
11
- %th= ::Spina::Admin::Journal::Volume.human_attribute_name :number
12
- %th= ::Spina::Admin::Journal::Issue.human_attribute_name :number
13
- %th= ::Spina::Admin::Journal::Article.human_attribute_name :number
14
- %th= ::Spina::Admin::Journal::Issue.human_attribute_name :date
15
- %th= ::Spina::Admin::Journal::Article.human_attribute_name :title
16
- %th
8
+ = render Spina::Admin::Journal::ArticlesListComponent.new(articles: @articles)
17
9
 
18
- %tbody
19
- = render @articles.any? ? @articles : 'empty_list', message: t('.empty')
@@ -1,29 +1,29 @@
1
- - if @author.errors.any?
2
- - content_for :notifications do
3
- .notification.notification-danger.animated.fadeInRight
4
- = icon 'exclamation'
5
- .notification-message
6
- = t 'spina.notifications.alert'
7
- %small= @author.errors.full_messages.join('<br />').html_safe
8
- = link_to '#', data: {close_notification: true} do
9
- = icon 'cross'
1
+ %div{ data: { controller: 'tabs',
2
+ tabs: { active: 'cursor-default text-gray-900 bg-spina-dark bg-opacity-10',
3
+ inactive: 'cursor-pointer bg-transparent text-gray-400 border-transparent' } } }
4
+ = render Spina::UserInterface::HeaderComponent.new do |header|
5
+ - header.actions do
6
+ - if @author.persisted?
7
+ = render Spina::UserInterface::DropdownComponent.new do |dropdown|
8
+ - dropdown.button(classes: "btn btn-default px-3") do
9
+ = heroicon('dots-horizontal', style: :solid, class: "w-5 h-5 text-gray-600")
10
10
 
11
- = form_for @author, html: {autocomplete: "off"} do |f|
12
- %header#header
13
- = render partial: 'spina/admin/shared/breadcrumbs'
11
+ - dropdown.menu do
12
+ = button_to t('spina.permanently_delete'), admin_journal_author_path(@author), method: :delete, class: "block w-full text-left px-4 py-2 text-sm leading-5 font-medium text-red-500 cursor-pointer bg-white hover:bg-red-100 hover:bg-opacity-50 hover:text-red-500 focus:outline-none focus:bg-gray-100 focus:text-gray-900", form: {data: { controller: 'confirm', confirm_message: t('.delete_confirmation', name: @author.primary_affiliation.name) } }
14
13
 
15
- #header_actions
16
- %button.button.button-primary{type: 'submit', style: 'margin-right: 0', data: {disable_with: t('spina.pages.saving')}}
17
- = icon 'check'
14
+ = button_tag type: :submit, form: dom_id(@author), class: 'btn btn-primary', data: { controller: 'button', action: 'button#loading', loading_message: t('spina.ui.saving')} do
15
+ = heroicon('check', style: :solid, class: 'w-5 h-5 mr-1 -ml-2')
18
16
  = t '.save'
19
17
 
20
- .button{style: 'margin-right: 0'}= link_to t('spina.cancel'), admin_journal_authors_path
18
+ - header.navigation do
19
+ %nav.-mb-3.mt-4
20
+ %ul.inline-flex.w-auto.rounded-md.bg-white
21
+ - @tabs.each do |tab|
22
+ %button.block.px-3.leading-relaxed.py-1.hover:text-gray-800.rounded-md.text-gray-400.font-medium.text-sm.flex.items-center.whitespace-nowrap{ type: 'button', data: { action: 'tabs#show', 'tabs-target': 'button', 'pane-id': "#{tab}" } }
23
+ = t ".#{tab}"
21
24
 
22
- %nav#secondary.tabs
23
- %ul
24
- - @tabs.each_with_index do |tab, i|
25
- %li{ class: ('active' if i == 0) }
26
- = link_to t(".#{tab}"), "##{tab}"
27
-
28
- #details.tab-content.active= render 'form_details', f: f
29
- #articles.tab-content= render 'form_articles', f: f
25
+ .p-4.md:p-8
26
+ = form_with model: [spina, :admin_journal, @author], id: dom_id(@author), html: { autocomplete: 'off' } do |f|
27
+ - @tabs.each_with_index do |tab, i|
28
+ %div{ 'data-tabs-target': 'pane', id: tab, hidden: i != 0 }
29
+ = render "form_#{tab}", f: f
@@ -1,20 +1,8 @@
1
- .page-form-group
2
- .page-form-label
3
- = ::Spina::Admin::Journal::Affiliation.human_attribute_name :first_name
4
- .page-form-content
5
- = ff.text_field :first_name
6
- .page-form-group
7
- .page-form-label
8
- = ::Spina::Admin::Journal::Affiliation.human_attribute_name :surname
9
- .page-form-content
10
- = ff.text_field :surname
11
- .page-form-group
12
- .page-form-label
13
- = ::Spina::Admin::Journal::Affiliation.human_attribute_name :institution
14
- .page-form-content
15
- = ff.collection_select :institution_id, ::Spina::Admin::Journal::Institution.sorted, :id, :name
16
- .page-form-group
17
- .page-form-label
18
- = t '.primary'
19
- .page-form-content
20
- = radio_button_tag 'admin_journal_author[primary_affiliation_index]', ff.index, ff.object.status == 'primary'
1
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Affiliation.human_attribute_name(:first_name)) do
2
+ = render Spina::Forms::TextFieldComponent.new(ff, :first_name)
3
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Affiliation.human_attribute_name(:surname)) do
4
+ = render Spina::Forms::TextFieldComponent.new(ff, :surname)
5
+ = render Spina::Forms::GroupComponent.new(label: Spina::Admin::Journal::Affiliation.human_attribute_name(:institution)) do
6
+ = ff.collection_select :institution_id, Spina::Admin::Journal::Institution.sorted, :id, :name
7
+ = render Spina::Forms::GroupComponent.new(label: t('.primary')) do
8
+ = radio_button_tag 'author[primary_affiliation_index]', ff.index, ff.object.status == 'primary'
@@ -1,18 +1 @@
1
- .table-container
2
- %table.table
3
- %thead
4
- %tr
5
- %th= ::Spina::Admin::Journal::Volume.human_attribute_name :number
6
- %th= ::Spina::Admin::Journal::Issue.human_attribute_name :number
7
- %th= ::Spina::Admin::Journal::Article.human_attribute_name :number
8
- %th= ::Spina::Admin::Journal::Issue.human_attribute_name :date
9
- %th= ::Spina::Admin::Journal::Article.human_attribute_name :title
10
- %th
11
- %tbody
12
- - if @author.affiliations.any?
13
- -# render empty list if no affiliation has any articles
14
- = render 'empty_list', message: t('.no_articles') if @author.affiliations.reduce(true) do |memo, affiliation|
15
- = render affiliation.articles
16
- - memo && !affiliation.articles.any?
17
- - else
18
- = render 'empty_list', message: t('.no_articles')
1
+ = render Spina::Admin::Journal::ArticlesListComponent.new(articles: @author.affiliations.reduce([]) { |memo, affiliation| memo << affiliation.articles.to_a }.flatten )