rails_execution 0.1.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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/Gemfile +8 -0
  4. data/Gemfile.lock +129 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +35 -0
  7. data/Rakefile +3 -0
  8. data/app/assets/images/executions/approved.png +0 -0
  9. data/app/assets/images/executions/favicon.png +0 -0
  10. data/app/assets/images/executions/logo.png +0 -0
  11. data/app/assets/images/executions/rejected.png +0 -0
  12. data/app/assets/images/executions/robot.png +0 -0
  13. data/app/assets/javascripts/executions/ace.min.js +1 -0
  14. data/app/assets/javascripts/executions/ace.modes.ruby.min.js +1 -0
  15. data/app/assets/javascripts/executions/ace.theme-solarized_dark.min.js +1 -0
  16. data/app/assets/javascripts/executions/base.js +1 -0
  17. data/app/assets/javascripts/executions/bootstrap.5.2.1.min.js +6 -0
  18. data/app/assets/javascripts/executions/chart.min.js +13 -0
  19. data/app/assets/javascripts/executions/comments.js +43 -0
  20. data/app/assets/javascripts/executions/easymde.min.js +7 -0
  21. data/app/assets/javascripts/executions/events.js +8 -0
  22. data/app/assets/javascripts/executions/highlight.min.js +1198 -0
  23. data/app/assets/javascripts/executions/highlight.ruby.min.js +51 -0
  24. data/app/assets/javascripts/executions/jquery-3.6.1.min.js +2 -0
  25. data/app/assets/javascripts/executions/marked.min.js +6 -0
  26. data/app/assets/javascripts/executions/rails.js +565 -0
  27. data/app/assets/javascripts/executions/select2.min.js +2 -0
  28. data/app/assets/stylesheets/executions/base.css +3 -0
  29. data/app/assets/stylesheets/executions/bootstrap-icons.css +1869 -0
  30. data/app/assets/stylesheets/executions/comments.css +14 -0
  31. data/app/assets/stylesheets/executions/easymde.min.css +7 -0
  32. data/app/assets/stylesheets/executions/fonts.css +4 -0
  33. data/app/assets/stylesheets/executions/highlight.min.css +9 -0
  34. data/app/assets/stylesheets/executions/modify.scss +278 -0
  35. data/app/assets/stylesheets/executions/select2.min.css +1 -0
  36. data/app/controllers/rails_execution/base_controller.rb +16 -0
  37. data/app/controllers/rails_execution/comments_controller.rb +34 -0
  38. data/app/controllers/rails_execution/dashboards_controller.rb +27 -0
  39. data/app/controllers/rails_execution/tasks_controller.rb +175 -0
  40. data/app/helpers/rails_execution/base_helper.rb +14 -0
  41. data/app/helpers/rails_execution/policy_helper.rb +64 -0
  42. data/app/helpers/rails_execution/rendering_helper.rb +94 -0
  43. data/app/models/rails_execution/activity.rb +8 -0
  44. data/app/models/rails_execution/comment.rb +8 -0
  45. data/app/models/rails_execution/task.rb +71 -0
  46. data/app/models/rails_execution/task_review.rb +14 -0
  47. data/app/views/layouts/execution.html.haml +16 -0
  48. data/app/views/rails_execution/comments/_comment.html.haml +23 -0
  49. data/app/views/rails_execution/comments/create.js.haml +6 -0
  50. data/app/views/rails_execution/comments/update.js.haml +2 -0
  51. data/app/views/rails_execution/dashboards/charts/_insights.html.haml +27 -0
  52. data/app/views/rails_execution/dashboards/home.html.haml +24 -0
  53. data/app/views/rails_execution/dashboards/insights.json.jbuilder +8 -0
  54. data/app/views/rails_execution/shared/_flash.html.haml +7 -0
  55. data/app/views/rails_execution/shared/_header.html.haml +13 -0
  56. data/app/views/rails_execution/shared/_paging.html.haml +35 -0
  57. data/app/views/rails_execution/tasks/_actions.html.haml +12 -0
  58. data/app/views/rails_execution/tasks/_activities.html.haml +22 -0
  59. data/app/views/rails_execution/tasks/_attachment_file_fields.html.haml +3 -0
  60. data/app/views/rails_execution/tasks/_attachment_files.html.haml +12 -0
  61. data/app/views/rails_execution/tasks/_comments.html.haml +15 -0
  62. data/app/views/rails_execution/tasks/_form.html.haml +55 -0
  63. data/app/views/rails_execution/tasks/_form_scripts.html.haml +34 -0
  64. data/app/views/rails_execution/tasks/_new_comment.html.haml +8 -0
  65. data/app/views/rails_execution/tasks/_reviewers.html.haml +23 -0
  66. data/app/views/rails_execution/tasks/_script_content.html.haml +15 -0
  67. data/app/views/rails_execution/tasks/_show_scripts.html.haml +27 -0
  68. data/app/views/rails_execution/tasks/_status.html.haml +19 -0
  69. data/app/views/rails_execution/tasks/_task.html.haml +18 -0
  70. data/app/views/rails_execution/tasks/_tips.html.haml +18 -0
  71. data/app/views/rails_execution/tasks/closed.html.haml +12 -0
  72. data/app/views/rails_execution/tasks/completed.html.haml +12 -0
  73. data/app/views/rails_execution/tasks/edit.html.haml +3 -0
  74. data/app/views/rails_execution/tasks/index.html.haml +12 -0
  75. data/app/views/rails_execution/tasks/new.html.haml +3 -0
  76. data/app/views/rails_execution/tasks/show.html.haml +38 -0
  77. data/config/routes.rb +26 -0
  78. data/lib/generators/rails_execution/file_upload_generator.rb +18 -0
  79. data/lib/generators/rails_execution/install_generator.rb +36 -0
  80. data/lib/generators/rails_execution/templates/config.rb.tt +63 -0
  81. data/lib/generators/rails_execution/templates/file_reader.rb.tt +14 -0
  82. data/lib/generators/rails_execution/templates/file_uploader.rb.tt +11 -0
  83. data/lib/generators/rails_execution/templates/install.rb.tt +48 -0
  84. data/lib/rails_execution/app_model.rb +14 -0
  85. data/lib/rails_execution/config.rb +73 -0
  86. data/lib/rails_execution/engine.rb +24 -0
  87. data/lib/rails_execution/error.rb +6 -0
  88. data/lib/rails_execution/files/reader.rb +49 -0
  89. data/lib/rails_execution/files/uploader.rb +42 -0
  90. data/lib/rails_execution/services/approvement.rb +41 -0
  91. data/lib/rails_execution/services/execution.rb +87 -0
  92. data/lib/rails_execution/services/executor.rb +24 -0
  93. data/lib/rails_execution/services/paging.rb +35 -0
  94. data/lib/rails_execution/services/syntax_checker.rb +38 -0
  95. data/lib/rails_execution/version.rb +5 -0
  96. data/lib/rails_execution.rb +24 -0
  97. metadata +157 -0
@@ -0,0 +1,94 @@
1
+ module RailsExecution
2
+ module RenderingHelper
3
+
4
+ def render_user_info(user, avatar_size: '40x40')
5
+ content_tag :div, class: 'user-info' do
6
+ concat render_owner_avatar(user, size: avatar_size)
7
+ concat render_owner_name(user)
8
+ end
9
+ end
10
+
11
+ def render_owner_avatar(owner, size: '32x32')
12
+ return nil if owner.blank?
13
+
14
+ avatar_url = RailsExecution.configuration.owner_avatar.call(owner)
15
+ return nil if avatar_url.blank?
16
+
17
+ image_tag avatar_url, size: size, class: 'bd-placeholder-img flex-shrink-0 me-2 rounded'
18
+ end
19
+
20
+ def render_owner_name(owner)
21
+ return nil if owner.blank?
22
+ return nil if RailsExecution.configuration.owner_name_method.blank?
23
+
24
+ content_tag :span, owner.public_send(RailsExecution.configuration.owner_name_method)
25
+ end
26
+
27
+ def render_notification_message(mode, message)
28
+ case mode
29
+ when 'alert'
30
+ content_tag :div, class: 'alert alert-warning align-items-center' do
31
+ concat content_tag(:i, nil, class: 'bi bi-x-octagon mr-2')
32
+ concat content_tag(:span, message, class: 'ms-2')
33
+ end
34
+ when 'notice'
35
+ content_tag :div, class: 'alert alert-success align-items-center' do
36
+ concat content_tag(:i, nil, class: 'bi bi-check-circle mr-2')
37
+ concat content_tag(:span, message, class: 'ms-2')
38
+ end
39
+ end
40
+ end
41
+
42
+ def task_reviewed_status(task)
43
+ @task_reviewed_status ||= {}
44
+ @task_reviewed_status[task] ||= task.task_reviews.find_by(owner_id: current_owner&.id)&.status&.inquiry
45
+ end
46
+
47
+ def re_page_actions(&block)
48
+ content_for :page_actions do
49
+ content_tag :span, class: 'ms-2' do
50
+ capture(&block)
51
+ end
52
+ end
53
+ end
54
+
55
+ def re_card_content(id: nil, &block)
56
+ content_tag :div, id: id, class: 'my-3 p-3 bg-body rounded shadow-sm' do
57
+ capture(&block)
58
+ end
59
+ end
60
+
61
+ def re_render_paging(relation)
62
+ render partial: 'rails_execution/shared/paging', locals: { page: relation.re_current_page, total_pages: relation.re_total_pages }
63
+ end
64
+
65
+ def re_attachment_file_acceptable_types
66
+ ::RailsExecution.configuration.acceptable_file_types.keys.join(',')
67
+ end
68
+
69
+ def re_get_file_name(url)
70
+ URI(url).path.split('/').last
71
+ end
72
+
73
+ def re_badge_color(status)
74
+ color = status_to_color(status.to_s.downcase.to_sym)
75
+ content_tag :small, status.to_s.titleize, class: "fw-light badge rounded-pill text-bg-#{color}"
76
+ end
77
+
78
+ private
79
+
80
+ def status_to_color(text)
81
+ {
82
+ bad: 'danger',
83
+ good: 'success',
84
+ closed: 'danger',
85
+ created: 'primary',
86
+ rejected: 'danger',
87
+ approved: 'success',
88
+ reviewing: 'secondary',
89
+ completed: 'success',
90
+ }[text] || 'secondary'
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,8 @@
1
+ class RailsExecution::Activity < RailsExecution::AppModel
2
+
3
+ belongs_to :task
4
+
5
+ validates :task, presence: true
6
+ validates :message, presence: true
7
+
8
+ end
@@ -0,0 +1,8 @@
1
+ class RailsExecution::Comment < RailsExecution::AppModel
2
+
3
+ belongs_to :task
4
+
5
+ validates :task, presence: true
6
+ validates :content, presence: true
7
+
8
+ end
@@ -0,0 +1,71 @@
1
+ class RailsExecution::Task < RailsExecution::AppModel
2
+
3
+ PROCESSING_STATUSES = %w(created reviewing approved rejected)
4
+
5
+ has_many :activities, class_name: 'RailsExecution::Activity'
6
+ has_many :comments, class_name: 'RailsExecution::Comment'
7
+ has_many :task_reviews, class_name: 'RailsExecution::TaskReview'
8
+ attr_accessor :reviewer_ids
9
+
10
+ validates :title, presence: true
11
+ validates :status, presence: true
12
+
13
+ enum status: {
14
+ created: 'created',
15
+ reviewing: 'reviewing',
16
+ approved: 'approved',
17
+ rejected: 'rejected',
18
+ completed: 'completed',
19
+ closed: 'closed',
20
+ }, _prefix: :is
21
+
22
+ enum syntax_status: {
23
+ bad: 'bad',
24
+ good: 'good',
25
+ }, _prefix: true
26
+
27
+ scope :processing, -> { where(status: PROCESSING_STATUSES) }
28
+
29
+ before_update :re_assign_status
30
+ after_commit :create_activity, on: :create, if: :owner
31
+
32
+ def in_processing?
33
+ PROCESSING_STATUSES.include?(self.status)
34
+ end
35
+
36
+ def assign_reviewers(ids)
37
+ ids.each do |id|
38
+ next if id.blank?
39
+
40
+ task_review = self.task_reviews.find_or_initialize_by({
41
+ owner_id: id,
42
+ owner_type: ::RailsExecution.configuration.owner_model.to_s,
43
+ })
44
+ task_review.status ||= :reviewing
45
+ end
46
+ end
47
+
48
+ def reviewer_ids
49
+ self.task_reviews.pluck(:owner_id)
50
+ end
51
+
52
+ def add_files(attachments, current_owner)
53
+ ::RailsExecution.configuration.file_uploader.new(self, attachments, owner: current_owner).call
54
+ end
55
+
56
+ private
57
+
58
+ def create_activity
59
+ self.activities.create(owner: self.owner, message: 'Created the task')
60
+ end
61
+
62
+ def re_assign_status
63
+ return if self.is_completed? || self.is_closed?
64
+
65
+ if self.is_approved? && self.script_changed?
66
+ self.status = :reviewing
67
+ self.task_reviews.update_all(status: :reviewing)
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,14 @@
1
+ class RailsExecution::TaskReview < RailsExecution::AppModel
2
+
3
+ belongs_to :task
4
+
5
+ validates :task, presence: true
6
+ validates :status, presence: true
7
+
8
+ enum status: {
9
+ reviewing: 'reviewing',
10
+ approved: 'approved',
11
+ rejected: 'rejected',
12
+ }, _prefix: :is
13
+
14
+ end
@@ -0,0 +1,16 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Rails Execution
5
+ %meta{ name: :viewport, content: 'width=device-width, initial-scale=1' }
6
+ = csrf_meta_tags
7
+ = favicon_link_tag 'executions/favicon.png'
8
+ = stylesheet_link_tag 'https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css'
9
+ = stylesheet_link_tag 'executions/base'
10
+ = javascript_include_tag 'executions/base'
11
+
12
+ %body.bg-light.fw-light.pb-5
13
+ = render partial: 'rails_execution/shared/header'
14
+ %main.container
15
+ = render partial: 'rails_execution/shared/flash'
16
+ = yield
@@ -0,0 +1,23 @@
1
+ - comment_key = comment.cache_key.parameterize(separator: '_').remove('-')
2
+
3
+ .media.media-comment.d-flex{ id: comment_key }
4
+ = render_owner_avatar(comment.owner, size: '50x50')
5
+ .media-body.rounded.shadow-sm.g-bg-secondary.g-pa-15.w-100
6
+ - if comment.owner == current_owner
7
+ = link_to '#edit-comment', class: 'edit-comment' do
8
+ %i.bi.bi-gear.fs-5.text-dark
9
+ .review-comment-content
10
+ .g-mb-15.mb-2
11
+ .user-info.g-color-gray-dark-v1.mb-0= render_owner_name(comment.owner)
12
+ .fs-13.text-muted= comment.created_at.strftime('%Y/%m/%d %H:%M')
13
+ %p.content-markdown= comment.content
14
+ %p.content-html.normal-text
15
+ .edit-comment-form.hidden
16
+ = form_for comment, url: task_comment_path(current_task, comment, comment_key: comment_key), remote: true do |f|
17
+ = f.text_area :content, { id: "#{comment_key}_content" }
18
+ .mt-3.text-end
19
+ %a.btn.btn-outline-default.text-danger.cancel-edit-mode{ href: '#cancel-edit-form' } Cancel
20
+ = f.submit 'Update', class: 'btn btn-outline-success'
21
+
22
+ :javascript
23
+ window.comments.renderMarkdown("##{comment_key}");
@@ -0,0 +1,6 @@
1
+ - if @new_comment.errors.empty?
2
+ window.location.href = '#{task_path(current_task)}';
3
+ - else
4
+ $("#new-comment").replaceWith("#{j render(partial: 'rails_execution/tasks/new_comment', locals: { comment: @new_comment, alert: @alert })}");
5
+ hljs.highlightAll();
6
+ window.comments.initAddNewComment('comment_content');
@@ -0,0 +1,2 @@
1
+ $("##{params[:comment_key]}").replaceWith("#{j render(partial: 'comment', locals: { comment: @comment })}");
2
+ hljs.highlightAll();
@@ -0,0 +1,27 @@
1
+ = re_card_content do
2
+ %h5.section-title Insights
3
+ %canvas{ id: :insights_chart, height: 300 }
4
+
5
+ :javascript
6
+ $.get("#{insights_dashboards_path(:json)}", function(data) {
7
+ new Chart(document.getElementById('insights_chart').getContext('2d'), {
8
+ type: 'line',
9
+ data: data,
10
+ options: {
11
+ responsive: true,
12
+ plugins: {
13
+ legend: false,
14
+ },
15
+ layout: {
16
+ padding: 20,
17
+ },
18
+ scales: {
19
+ y: {
20
+ min: 0,
21
+ ticks: { stepSize: 1 },
22
+ grid: { display: false },
23
+ },
24
+ },
25
+ },
26
+ });
27
+ });
@@ -0,0 +1,24 @@
1
+ = re_card_content do
2
+ %h5.section-title Overview
3
+ .row
4
+ .col
5
+ .card.text-center
6
+ .card-header= link_to 'In Processing', tasks_path
7
+ .card-body
8
+ %span.fs-2.fw-lighter= @in_processing_count
9
+ %span tasks
10
+ .col
11
+ .card.text-center
12
+ .card-header= link_to 'Completed', completed_tasks_path
13
+ .card-body
14
+ %span.fs-2.fw-lighter= @tasks_count['completed'].to_i
15
+ %span tasks
16
+ .col
17
+ .card.text-center
18
+ .card-header= link_to 'Closed', closed_tasks_path
19
+ .card-body
20
+ %span.fs-2.fw-lighter= @tasks_count['closed'].to_i
21
+ %span tasks
22
+
23
+ - if show_insights_chart?
24
+ = render partial: 'rails_execution/dashboards/charts/insights'
@@ -0,0 +1,8 @@
1
+ json.labels @tasks_by_week.keys.map { |year, week| Date.commercial(year, week, 1).strftime('Week: %d/%m') }
2
+ json.datasets [{
3
+ label: 'Created tasks',
4
+ data: @tasks_by_week.values,
5
+ borderWidth: 1,
6
+ borderColor: 'rgba(255, 99, 132, 1)',
7
+ backgroundColor: 'rgba(255, 99, 132, 0.2)',
8
+ }]
@@ -0,0 +1,7 @@
1
+ #flash-messages
2
+ - flash.each do |key, message|
3
+ = render_notification_message(key, message)
4
+ :javascript
5
+ setTimeout(function() {
6
+ $('#flash-messages .alert').slideUp();
7
+ }, 3000);
@@ -0,0 +1,13 @@
1
+ %header.p-3.mb-3.border-bottom.bg-white
2
+ .container
3
+ .d-flex.flex-wrap.align-items-center.justify-content-center.justify-content-lg-start
4
+ = link_to root_path, class: 'd-flex align-items-center mb-2 mb-lg-0 text-dark text-decoration-none' do
5
+ = image_tag 'executions/logo.png', size: '30x30'
6
+ %ul.nav.col-12.col-lg-auto.me-lg-auto.mb-2.justify-content-center.mb-md-0.ms-3
7
+ %li= link_to 'Dashboard', root_path, class: "nav-link px-2 link-#{ current_page?(root_path) ? 'secondary' : 'dark' }"
8
+ %li= link_to 'Processing', tasks_path, class: "nav-link px-2 link-#{ current_page?(tasks_path) ? 'secondary' : 'dark' }"
9
+ %li= link_to 'Completed', completed_tasks_path, class: "nav-link px-2 link-#{ current_page?(completed_tasks_path) ? 'secondary' : 'dark' }"
10
+ %li= link_to 'Closed', closed_tasks_path, class: "nav-link px-2 link-#{ current_page?(closed_tasks_path) ? 'secondary' : 'dark' }"
11
+ .col-md-3.text-end
12
+ = yield :page_actions
13
+ = link_to 'New Task', new_task_path, class: 'btn btn-outline-primary ms-2', disabled: !can_create_task?
@@ -0,0 +1,35 @@
1
+ - return if total_pages <= 1
2
+ - original_params = params.permit!.to_h
3
+
4
+ - gap_number = 2
5
+ - page_numbers = (1..total_pages).to_a
6
+ - begin_paging = (1..(1 + gap_number)).to_a
7
+ - middle_paging = page_numbers & ((page - gap_number)..(page + gap_number)).to_a
8
+ - end_paging = page_numbers & ((total_pages - gap_number)..total_pages).to_a
9
+
10
+ - if begin_paging.last < middle_paging.first.pred
11
+ - begin_paging[-1] = 'gap1'
12
+ - if middle_paging.last < end_paging.first.pred
13
+ - end_paging[0] = 'gap2'
14
+ - page_numbers = begin_paging + middle_paging + end_paging
15
+
16
+ %nav.execution-paging
17
+ %ul.pagination.justify-content-center
18
+ - if page > 1
19
+ %li.page-item
20
+ = link_to original_params.merge(page: page.pred), class: 'page-link' do
21
+ %i.bi.bi-chevron-left
22
+
23
+ - page_numbers.uniq.each do |page_num|
24
+ - if page == page_num
25
+ - item_css = 'active'
26
+ - elsif page_num.to_s.start_with?('gap')
27
+ - page_num, item_css = '...', 'disabled'
28
+
29
+ %li.page-item{ class: item_css }
30
+ = link_to page_num, original_params.merge(page: page_num), class: 'page-link'
31
+
32
+ - if page < total_pages
33
+ %li.page-item
34
+ = link_to original_params.merge(page: page.next), class: 'page-link' do
35
+ %i.bi.bi-chevron-right
@@ -0,0 +1,12 @@
1
+ - unless current_task.is_completed?
2
+ = re_card_content do
3
+ .text-center
4
+ - if can_execute_task?(current_task)
5
+ = link_to 'Execute NOW!!!', execute_task_path(current_task), class: 'btn btn-primary', method: :patch, data: { confirm: 'Are you sure?' }
6
+ - else
7
+ %p.text-danger.mb-0.fw-bold
8
+ %i.bi.bi-x-octagon.me-1
9
+ Not ready to Execute!
10
+ %span.fs-13.text-muted.fw-lighter.mb-0
11
+ %i.bi.bi-megaphone
12
+ = how_to_executable(current_task)
@@ -0,0 +1,22 @@
1
+ - if task_logs.any?
2
+ = re_card_content do
3
+ %h5.section-title Logs
4
+ %ul.list-unstyled#task-logs
5
+ - task_logs.each do |task_log|
6
+ %li.fs-13.row.mb-3
7
+ .col.text-muted
8
+ %i.bi.bi-journal-text
9
+ = re_get_file_name(task_log)
10
+ .col-3.text-end= link_to 'Download', task_log, target: :_blank, class: 'text-muted click2download'
11
+
12
+ = re_card_content id: 'activities-section' do
13
+ %h5.section-title Activities
14
+ %ul.list-unstyled
15
+ - current_task.activities.descending.preload(:owner).each do |activitiy|
16
+ %li.row
17
+ .col
18
+ = render_user_info(activitiy.owner, avatar_size: '20x20')
19
+ %p.normal-text.mt-1= activitiy.message
20
+ .col-3.text-end.activitiy-time
21
+ %span.fs13px.text-muted= activitiy.created_at.strftime('%Y/%m/%d')
22
+ %p.text-muted= activitiy.created_at.strftime('%H:%M')
@@ -0,0 +1,3 @@
1
+ %li.row.mb-2
2
+ .col= text_field :attachments, :name, { class: 'form-control file-name', placeholder: 'Name', name: "attachments[0][name]" }
3
+ .col-6.overflow-hidden= file_field :attachments, :file, { class: 'form-control file-upload', accept: re_attachment_file_acceptable_types, name: "attachments[0][file]" }
@@ -0,0 +1,12 @@
1
+ - if RailsExecution.configuration.file_upload && task_attachment_files.any?
2
+ = re_card_content do
3
+ %h5.section-title.mb-3 Attachment files
4
+ %ul.list-unstyled.mt-3
5
+ - task_attachment_files.each do |name, url|
6
+ %li.row.normal-text
7
+ .col
8
+ %i.bi.fs-3.text-muted{ class: "bi-file-text bi-filetype-#{url.split('.').last}" }
9
+ = name
10
+ .col-3.text-end
11
+ %p.mb-0= link_to 'Download', url, class: 'text-muted'
12
+ %small Filename: #{re_get_file_name(url)}
@@ -0,0 +1,15 @@
1
+ = render partial: 'new_comment', locals: { comment: (new_comment || current_task.comments.new) }
2
+ = render current_task.comments.ascending
3
+
4
+ :javascript
5
+ hljs.highlightAll();
6
+ window.comments.initAddNewComment('comment_content');
7
+
8
+ $(document).on('click', '.media-comment a.edit-comment', function() {
9
+ window.comments.clickEditComment(this);
10
+ return false;
11
+ });
12
+ $(document).on('click', '.media-comment a.cancel-edit-mode', function() {
13
+ window.comments.cancelEditMode(this);
14
+ return false;
15
+ });
@@ -0,0 +1,55 @@
1
+ = form_for task, html: { enctype: 'multipart/form-data' } do |f|
2
+ .row
3
+ - if task.errors.any?
4
+ .col-12.text-danger.small.mt-3= task.errors.full_messages.join("\n")
5
+
6
+ .col
7
+ .mb-3.mt-4= f.text_field :title, { class: 'form-control', placeholder: 'Title', required: true }
8
+ .mb-3.mt-4= f.text_area :description, { class: 'form-control', placeholder: 'Description', rows: 10 }
9
+ - if show_form_sidebar?(task)
10
+ .col-4
11
+ - unless in_solo_mode?
12
+ %h5.mb-2.mt-4.section-title Reviewers
13
+ #reviewers.mb-3
14
+ - if reviewers.any?
15
+ = f.collection_select :task_review_ids, reviewers, :id, :name, { selected: task.reviewer_ids }, { multiple: true, class: 'select2 col-12' }
16
+ - else
17
+ %p.small.text-muted Nobody can add
18
+
19
+ - if RailsExecution.configuration.file_upload
20
+ %h5.mb-2.mt-4.section-title Attachment files
21
+ %ul.list-unstyled.mt-3
22
+ - task_attachment_files.each do |name, url|
23
+ %li.row.normal-text
24
+ .col
25
+ %i.bi.fs-3.text-muted{ class: "bi-file-text bi-filetype-#{url.split('.').last}" }
26
+ = name
27
+ .col-6.text-end
28
+ %p.mb-0= link_to 'Download', url, class: 'text-muted'
29
+ %small Filename: #{re_get_file_name(url)}
30
+ #attachment_files.mb-3
31
+ %ul.list-unstyled= render partial: 'attachment_file_fields'
32
+
33
+ .mt-3.text-center
34
+ %hr.smoothly
35
+ = link_to 'More file', '#add-more-file', data: { fields_html: render(partial: 'attachment_file_fields') }, class: 'btn text-primary', id: 'js-add-more-file'
36
+
37
+
38
+ - if task.new_record? || task.in_processing?
39
+ .col-md-12.mb-3.mt-3
40
+ .row
41
+ .col
42
+ %h5.section-title Script
43
+ .col.text-end= render partial: 'tips'
44
+ = f.text_area :script, { class: 'form-control hidden', rows: 3, id: 'main-script' }
45
+ #script-editor-container
46
+ #script-editor= task.script
47
+ = link_to '#full-screen', class: 'btn', id: 'click2full' do
48
+ %i.bi.bi-arrows-fullscreen
49
+ %i.bi.bi-arrows-angle-contract
50
+
51
+ .mb-3.mt-3.text-end
52
+ %hr
53
+ = f.submit (task.new_record? ? 'Create' : 'Update'), class: 'btn btn-success'
54
+
55
+ = render partial: 'form_scripts', locals: { task: task }
@@ -0,0 +1,34 @@
1
+ :javascript
2
+ $('#task_task_review_ids').select2({});
3
+ new EasyMDE({
4
+ element: document.getElementById('task_description'),
5
+ status: false,
6
+ showIcons: ['code'],
7
+ placeholder: "Type description here...",
8
+ renderingConfig: {
9
+ codeSyntaxHighlighting: true,
10
+ }
11
+ });
12
+
13
+ - if task.new_record? || task.in_processing?
14
+ :javascript
15
+ var editor = ace.edit("script-editor", { printMarginColumn: false });
16
+ var RubyMode = ace.require("ace/mode/ruby").Mode;
17
+ editor.setTheme("ace/theme/solarized_dark");
18
+ editor.session.setMode(new RubyMode());
19
+ editor.renderer.setPadding(15);
20
+ editor.renderer.setShowPrintMargin(false);
21
+ editor.getSession().on("change", function () {
22
+ $("#main-script").val(editor.getValue());
23
+ });
24
+
25
+ $('#click2full').click(function() {
26
+ $('#script-editor-container').toggleClass('fullscreen');
27
+ return false;
28
+ });
29
+
30
+ $('#js-add-more-file').click(function() {
31
+ AddMoreFile();
32
+ return false;
33
+ });
34
+
@@ -0,0 +1,8 @@
1
+ #new-comment
2
+ = re_card_content do
3
+ = form_for comment || current_task.comments.new, url: task_comments_path(current_task), remote: true do |f|
4
+ = f.text_area :content, { rows: 3 }
5
+ .mt-3
6
+ .text-start.text-danger= alert
7
+ .text-end= f.submit 'Comment', class: 'btn btn-outline-success'
8
+
@@ -0,0 +1,23 @@
1
+ - if display_reviewers?(current_task)
2
+ = re_card_content do
3
+ %h5.section-title Reviewers
4
+ %ul.list-unstyled.mt-3
5
+ - if reviewing_accounts.empty?
6
+ %li.mt-2.small.text-muted.text-center Nobody!
7
+ - else
8
+ - reviewing_accounts.each do |task_review|
9
+ %li.mt-2
10
+ .row
11
+ .col= render_user_info(task_review.owner, avatar_size: '20x20')
12
+ .col-3.text-end= re_badge_color(task_review.status)
13
+
14
+ - if display_decide?(current_task)
15
+ = re_card_content do
16
+ %h5.section-title What is your decision?
17
+ .row.mt-3
18
+ .col= render_user_info(current_owner, avatar_size: '20x20')
19
+ .col-6.text-end
20
+ - unless task_reviewed_status(current_task)&.rejected?
21
+ = link_to 'Reject', reject_task_path(current_task), method: :patch, data: { confirm: 'Are you sure?' }, class: 'btn btn-sm btn-danger'
22
+ - unless task_reviewed_status(current_task)&.approved?
23
+ = link_to 'Approve', approve_task_path(current_task), method: :patch, data: { confirm: 'Are you sure?' }, class: 'btn btn-sm btn-success'
@@ -0,0 +1,15 @@
1
+ = re_card_content do
2
+ - if current_task.script.blank?
3
+ %p.text-center.text-muted.mt-3
4
+ %i.bi.bi-quote.fs-5
5
+ Script is empty!
6
+ - else
7
+ %h5.section-title.mb-3 Script
8
+ #task-detail
9
+ = link_to '#full-screen', class: 'btn', id: 'click2full' do
10
+ %i.bi.bi-arrows-fullscreen
11
+ %i.bi.bi-arrows-angle-contract
12
+ #script-editor.collapsed= current_task.script
13
+ = link_to '#detail', class: 'btn', id: 'click2detail' do
14
+ %i.bi.bi-arrow-bar-down.me-2
15
+ Click to detail
@@ -0,0 +1,27 @@
1
+ - if current_task.script.present?
2
+ :javascript
3
+ window.editor = ace.edit("script-editor", {
4
+ wrap: true,
5
+ readOnly: true,
6
+ printMarginColumn: false,
7
+ });
8
+ var RubyMode = ace.require("ace/mode/ruby").Mode;
9
+ editor.setTheme("ace/theme/solarized_dark");
10
+ editor.session.setMode(new RubyMode());
11
+
12
+ $('#click2detail').click(function() {
13
+ this.remove();
14
+ $('#script-editor').removeClass('collapsed');
15
+ window.editor.resize();
16
+ return false;
17
+ })
18
+ $('#click2full').click(function() {
19
+ $('#task-detail').toggleClass('fullscreen');
20
+ window.editor.resize();
21
+ return false;
22
+ })
23
+
24
+ - if current_task.description.present?
25
+ :javascript
26
+ $('#description-html').html(marked.parse($('#description-markdown').html()));
27
+ hljs.highlightAll();
@@ -0,0 +1,19 @@
1
+ = re_card_content do
2
+ %h5.section-title All checks
3
+ %ul.list-unstyled.mt-3
4
+ %li.mt-2.row
5
+ .col
6
+ .user-info
7
+ = image_tag 'executions/robot.png', size: '20x20', class: 'bd-placeholder-img flex-shrink-0 me-2 rounded'
8
+ %span Task status
9
+ .col-3.text-end= re_badge_color(current_task.status)
10
+ %li.mt-2.row
11
+ .col
12
+ .user-info
13
+ = image_tag 'executions/robot.png', size: '20x20', class: 'bd-placeholder-img flex-shrink-0 me-2 rounded'
14
+ %span Syntax
15
+ .col-3.text-end
16
+ - if current_task.syntax_status_good?
17
+ %i.fs-5.bi.bi-check-lg.text-success
18
+ - else
19
+ %i.fs-5.bi.bi-exclamation-triangle.text-danger
@@ -0,0 +1,18 @@
1
+ %li.border-bottom.d-flex.pt-2.pb-2{ class: "task-is-#{task.status}" }
2
+ .p-2.pt-3
3
+ %span.fs-4.text-muted ##{task.id}
4
+ .p-2
5
+ = link_to task_path(task) do
6
+ = render_owner_avatar(task.owner, size: '50x50')
7
+ .p-2
8
+ = link_to task_path(task) do
9
+ %p.mb-0.text-black
10
+ = task.title.truncate(100)
11
+ - if task.syntax_status_good?
12
+ %i.bi.bi-check2.text-success
13
+ - elsif task.syntax_status_bad?
14
+ %i.bi.bi-exclamation-octagon.text-danger
15
+ %span.small.text-muted created on #{time_ago_in_words(task.created_at)} by #{render_owner_name(task.owner)}
16
+ .p-2.ms-auto.text-end
17
+ %span.me-1= task.comments.size
18
+ %i.bi.bi-chat-left-dots