que-view 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1ced9639e99e58168c4b6e6a43c95f25e7a8dc0e44da579cc3e5bff4260afac
4
- data.tar.gz: 035f401a2e5afe417100ecb908ca54e99d467a7af3822a698af734e27bfbee1c
3
+ metadata.gz: a54cde016dccd6207b38924f717a5aeb3ea9ccae0eef215f848c2621c8af4945
4
+ data.tar.gz: 0d44f6c8e723e8533c8f640b58996a2b25b7d444115c761e95879c6a91ca3331
5
5
  SHA512:
6
- metadata.gz: 38a0e562ee5553257cdddffceb963b87b659cc57fd04fc8c78c0a1b6e6c7863d4c86287f0fc03e6df30bbd8823c758b0b78607c56fd39a04fb345649aad72aee
7
- data.tar.gz: 7466ab6634be76c84a3587eb800f82fbe7cb355eba7914cae29cd4bcf66054ff519b14d11d3a9be3c5927eb9011486e0d78d287ff7b7ada6ca758a5d77943dc6
6
+ metadata.gz: 72bde7eb6e7d6a2ae64e380eedb7f8ce45eb609116a017e71dc1af0ea7acdb5df7293cfb5015474b6d0793570b9062ca735e95878ea1e65e570dd95f0ba4f3d3
7
+ data.tar.gz: 659f6cfb80c3bb746f2f0088638e3e6f8d7acd63cc47ab0584df44762a9b18266736fd80bb4820c0a91d0e1b12b3262f7209c7321c7cf867b3ca9f2ee7c7eae9
data/README.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # Que::View
2
2
  Rails engine inspired by [Que::Web](https://github.com/statianzo/que-web) for [Que](https://github.com/que-rb/que) job queue.
3
3
  SQL queries came from Que::Web, some styling from there too.
4
- Benefits for using this one: independent from Sinatra (que-web based on Sinatra)
4
+
5
+ Benefits for using this one:
6
+ - no Sinatra (que-web based on Sinatra),
7
+ - no Foundation for styles,
8
+ - no jQuery,
9
+ - Que::Web was last updated 2 years ago.
10
+
11
+ <img width="1735" alt="Снимок экрана 2024-02-21 в 15 10 35" src="https://github.com/kortirso/que-view/assets/6195394/cd2812c7-abb0-48d9-92d5-4dbef93bcd9e">
12
+ <img width="1735" alt="Снимок экрана 2024-02-21 в 15 11 12" src="https://github.com/kortirso/que-view/assets/6195394/8af01e7f-a002-4ef1-aeff-f96fd27c639f">
13
+
5
14
 
6
15
  ## Installation
7
16
 
@@ -48,8 +57,10 @@ Add this line to assets/config/manifest.js
48
57
 
49
58
  - [X] rescheduling jobs
50
59
  - [X] deleting jobs
51
- - [ ] better styles for UI
52
- - [ ] rendering running jobs
60
+ - [X] better styles for UI
61
+ - [X] rendering running jobs
62
+ - [ ] searching/filtering through jobs by name, queue
63
+ - [X] pagination for jobs list page
53
64
  - [ ] tests
54
65
 
55
66
  ## License
@@ -20,6 +20,11 @@
20
20
  font-family: 'Source Sans Pro';
21
21
  }
22
22
 
23
+ html, body {
24
+ padding: 0;
25
+ margin: 0;
26
+ }
27
+
23
28
  .row {
24
29
  display: flex;
25
30
  flex-direction: row;
@@ -48,11 +53,11 @@ table th {
48
53
  }
49
54
 
50
55
  table tbody tr:nth-of-type(2n), table tbody tr:hover {
51
- background: #DDD;
56
+ background: #EEE;
52
57
  }
53
58
 
54
59
  table tbody tr:nth-of-type(2n):hover {
55
- background: #CCC;
60
+ background: #DDD;
56
61
  }
57
62
 
58
63
  table p {
@@ -114,3 +119,76 @@ table p {
114
119
  padding: .25rem .5rem;
115
120
  margin-right: .5rem;
116
121
  }
122
+
123
+ .pagination {
124
+ margin: 1rem auto;
125
+ }
126
+
127
+ .pagination .pagination-link {
128
+ margin: 0 .5rem 0 0;
129
+ padding: .25rem .5rem;
130
+ background: #fde68a;
131
+ border: 1px solid #fcd34d;
132
+ border-radius: .25rem;
133
+ text-decoration: none;
134
+ }
135
+
136
+ .pagination .pagination-link.disabled {
137
+ background: #fef3c7;
138
+ }
139
+
140
+ .pagination .total-pages {
141
+ margin: 0 .5rem 0 0;
142
+ padding: .25rem .5rem;
143
+ }
144
+
145
+ .navigation {
146
+ display: flex;
147
+ padding: .5rem 1rem;
148
+ background: #52525b;
149
+ color: #fff;
150
+ }
151
+
152
+ .navigation h1 {
153
+ margin: 0 2rem 0 0;
154
+ }
155
+
156
+ .navigation h1 a {
157
+ text-decoration: none;
158
+ color: #fff;
159
+ }
160
+
161
+ .navigation .navigation-section {
162
+ flex: 1;
163
+ display: flex;
164
+ justify-content: space-between;
165
+ align-items: center;
166
+ }
167
+
168
+ .navigation .navigation-section ul {
169
+ margin: 0;
170
+ padding: 0;
171
+ list-style: none;
172
+ display: flex;
173
+ }
174
+
175
+ .navigation .navigation-section ul.version li {
176
+ margin-left: 1rem;
177
+ }
178
+
179
+ .navigation .navigation-section ul li a {
180
+ display: inline-block;
181
+ padding: .5rem;
182
+ text-decoration: none;
183
+ color: #fff;
184
+ }
185
+
186
+ .navigation .navigation-section ul li.active a {
187
+ text-decoration: underline;
188
+ }
189
+
190
+ @media screen and (max-width: 768px) {
191
+ .row {
192
+ flex-direction: column;
193
+ }
194
+ }
@@ -9,7 +9,7 @@ module Que
9
9
 
10
10
  def index
11
11
  @jobs = find_jobs(params[:status])
12
- @jobs_amount = find_jobs_amount(params[:status])
12
+ paginate
13
13
  end
14
14
 
15
15
  def show; end
@@ -48,6 +48,19 @@ module Que
48
48
 
49
49
  private
50
50
 
51
+ def paginate
52
+ return if %w[failing scheduled].exclude?(params[:status])
53
+ return unless @jobs.any?
54
+
55
+ @pagination = Que::View::Pagination.new(
56
+ params: {
57
+ page: page,
58
+ per_page: params[:per_page] || PER_PAGE,
59
+ count: find_jobs_total_amount(params[:status])
60
+ }
61
+ )
62
+ end
63
+
51
64
  def find_job
52
65
  @job = ::Que::View.fetch_job(params[:id])[0]
53
66
  return if @job
@@ -57,13 +70,14 @@ module Que
57
70
 
58
71
  def find_jobs(status)
59
72
  case status&.to_sym
73
+ when :running then ::Que::View.fetch_running_jobs(search)
60
74
  when :failing then ::Que::View.fetch_failing_jobs(PER_PAGE, offset, search)
61
75
  when :scheduled then ::Que::View.fetch_scheduled_jobs(PER_PAGE, offset, search)
62
76
  else []
63
77
  end
64
78
  end
65
79
 
66
- def find_jobs_amount(status)
80
+ def find_jobs_total_amount(status)
67
81
  ::Que::View.fetch_dashboard_stats(search)[0][status&.to_sym]
68
82
  end
69
83
 
@@ -96,13 +110,13 @@ module Que
96
110
  sanitised
97
111
  end
98
112
 
99
- def page
100
- (params[:page] || 1).to_i
101
- end
102
-
103
113
  def offset
104
114
  (page - 1) * PER_PAGE
105
115
  end
116
+
117
+ def page
118
+ (params[:page] || 1).to_i
119
+ end
106
120
  end
107
121
  end
108
122
  end
@@ -7,6 +7,27 @@
7
7
  <%= stylesheet_link_tag 'que/view/application', media: 'all' %>
8
8
  </head>
9
9
  <body>
10
+ <nav class="navigation" role="navigation">
11
+ <h1><%= link_to 'Que View', root_path %></h1>
12
+ <section class="navigation-section">
13
+ <ul>
14
+ <li class="<%= 'active' if params[:status] == 'running' %>">
15
+ <%= link_to 'Running', jobs_path(status: 'running') %>
16
+ </li>
17
+ <li class="<%= 'active' if params[:status] == 'scheduled' %>">
18
+ <%= link_to 'Scheduled', jobs_path(status: 'scheduled') %>
19
+ </li>
20
+ <li class="<%= 'active' if params[:status] == 'failing' %>">
21
+ <%= link_to 'Failing', jobs_path(status: 'failing') %>
22
+ </li>
23
+ </ul>
24
+ <ul class="version">
25
+ <li>Que <%= Que::VERSION %></li>
26
+ <li>Que View <%= Que::View::VERSION %></li>
27
+ <li><%= Time.now.utc.strftime("%Y-%m-%d %H:%M:%S") %></li>
28
+ </ul>
29
+ </section>
30
+ </nav>
10
31
  <%= yield %>
11
32
  </body>
12
33
  </html>
@@ -1,13 +1,32 @@
1
- <div class="row">
2
- <% if @jobs.size.positive? %>
1
+ <% if @jobs.any? %>
2
+ <% if @pagination %>
3
+ <div class="row pagination">
4
+ <% if @pagination.previous_page? %>
5
+ <%= link_to 'First', jobs_path(status: params[:status], page: 1), class: 'pagination-link' %>
6
+ <%= link_to '< Previous', jobs_path(status: params[:status], page: @pagination.previous_page), class: 'pagination-link' %>
7
+ <% else %>
8
+ <p class="pagination-link disabled">First</p>
9
+ <p class="pagination-link disabled">&#60; Previous</p>
10
+ <% end %>
11
+ <p class="total-pages"><%= "Page #{@pagination.page} of #{@pagination.total_pages}" %></p>
12
+ <% if @pagination.next_page? %>
13
+ <%= link_to 'Next >', jobs_path(status: params[:status], page: @pagination.next_page), class: 'pagination-link' %>
14
+ <%= link_to 'Last', jobs_path(status: params[:status], page: @pagination.total_pages), class: 'pagination-link' %>
15
+ <% else %>
16
+ <p class="pagination-link disabled">Next &#62;</p>
17
+ <p class="pagination-link disabled">Last </p>
18
+ <% end %>
19
+ </div>
20
+ <% end %>
21
+ <div class="row">
3
22
  <table cellspacing="0">
4
23
  <thead>
5
24
  <tr>
6
25
  <th>ID</th>
7
26
  <th>Run at</th>
8
27
  <th>Job</th>
9
- <th>Arguments</th>
10
28
  <th>Queue</th>
29
+ <th>Arguments</th>
11
30
  <% if params[:status] == 'failing' %>
12
31
  <th>Failures</th>
13
32
  <th>Error</th>
@@ -21,7 +40,7 @@
21
40
  <% @jobs.each do |job| %>
22
41
  <tr>
23
42
  <td><%= link_to job[:id], job_path(job[:id]) %></td>
24
- <td><%= job[:run_at].utc %></td>
43
+ <td><%= job[:run_at].strftime("%Y-%m-%d %H:%M:%S") %></td>
25
44
  <td><%= humanized_job_class(job) %></td>
26
45
  <td><%= job[:queue] %></td>
27
46
  <td>
@@ -34,20 +53,24 @@
34
53
  <td><%= format_error(job) %></td>
35
54
  <% end %>
36
55
  <% if %w[failing scheduled].include?(params[:status]) %>
37
- <td class="actions">
38
- <%= button_to 'Run', job_path(job[:id]), class: 'btn-danger', method: :patch, onclick: "return confirm('Are you sure you wish to reschedule job?')" %>
39
- <%= button_to 'Delete', job_path(job[:id]), class: 'btn-danger', method: :delete, onclick: "return confirm('Are you sure you wish to delete job?')" %>
56
+ <td>
57
+ <div class="actions">
58
+ <%= button_to 'Run', job_path(job[:id]), class: 'btn-danger', method: :patch, onclick: "return confirm('Are you sure you wish to reschedule job?')" %>
59
+ <%= button_to 'Delete', job_path(job[:id]), class: 'btn-danger', method: :delete, onclick: "return confirm('Are you sure you wish to delete job?')" %>
60
+ </div>
40
61
  </td>
41
62
  <% end %>
42
63
  </tr>
43
64
  <% end %>
44
65
  </tbody>
45
66
  </table>
46
- <% else %>
67
+ </div>
68
+ <% else %>
69
+ <div class="row">
47
70
  <p>No jobs found</p>
48
- <% end %>
49
- </div>
50
- <% if %w[failing scheduled].include?(params[:status]) && @jobs_amount.positive? %>
71
+ </div>
72
+ <% end %>
73
+ <% if @pagination&.count&.positive? %>
51
74
  <div class="row">
52
75
  <%= button_to 'Run All', reschedule_all_jobs_path(status: params[:status]), class: 'btn-danger', method: :post, onclick: "return confirm('Are you sure you wish to reschedule all jobs?')" %>
53
76
  <%= button_to 'Delete All', destroy_all_jobs_path(status: params[:status]), class: 'btn-danger', method: :delete, onclick: "return confirm('Are you sure you wish to delete all jobs?')" %>
@@ -20,7 +20,7 @@
20
20
  </tr>
21
21
  <tr>
22
22
  <th>Run at</th>
23
- <td><%= @job[:run_at].utc %></td>
23
+ <td><%= @job[:run_at].strftime("%Y-%m-%d %H:%M:%S") %></td>
24
24
  </tr>
25
25
  <tr>
26
26
  <th>Failures</th>
data/lib/que/view/dsl.rb CHANGED
@@ -8,6 +8,10 @@ module Que
8
8
  execute(fetch_dashboard_stats_sql(...))
9
9
  end
10
10
 
11
+ def fetch_running_jobs(...)
12
+ Que.job_states
13
+ end
14
+
11
15
  def fetch_failing_jobs(...)
12
16
  execute(fetch_failing_jobs_sql(...))
13
17
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Que
4
+ module View
5
+ class Pagination
6
+ attr_reader :page, :count, :per_page
7
+
8
+ def initialize(params: {})
9
+ @page = params[:page]
10
+ @count = params[:count]
11
+ @per_page = params[:per_page]
12
+ end
13
+
14
+ def offset
15
+ return 0 if page == 1
16
+
17
+ per_page * (page.to_i - 1)
18
+ end
19
+
20
+ def next_page
21
+ page + 1 unless last_page?
22
+ end
23
+
24
+ def next_page?
25
+ page < total_pages
26
+ end
27
+
28
+ def previous_page
29
+ page - 1 unless first_page?
30
+ end
31
+
32
+ def previous_page?
33
+ page > 1
34
+ end
35
+
36
+ def last_page?
37
+ page == total_pages
38
+ end
39
+
40
+ def first_page?
41
+ page == 1
42
+ end
43
+
44
+ def total_pages
45
+ (count / per_page.to_f).ceil
46
+ end
47
+ end
48
+ end
49
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Que
4
4
  module View
5
- VERSION = '0.2.3'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
data/lib/que/view.rb CHANGED
@@ -6,13 +6,14 @@ require 'que/view/version'
6
6
  require 'que/view/engine'
7
7
  require 'que/view/configuration'
8
8
  require 'que/view/dsl'
9
+ require 'que/view/pagination'
9
10
 
10
11
  module Que
11
12
  module View
12
13
  extend self
13
14
  extend Forwardable
14
15
 
15
- # Public: Configure emailbutler.
16
+ # Public: Configure que view.
16
17
  #
17
18
  # Que::View.configure do |config|
18
19
  # end
@@ -26,15 +27,15 @@ module Que
26
27
  @configuration ||= Configuration.new
27
28
  end
28
29
 
29
- # Public: Default per thread emailbutler instance if configured.
30
+ # Public: Default per thread que view instance if configured.
30
31
  # Returns Que::View::DSL instance.
31
32
  def instance
32
33
  Thread.current[:que_view_instance] ||= DSL.new
33
34
  end
34
35
 
35
36
  # Public: All the methods delegated to instance. These should match the interface of Que::View::DSL.
36
- def_delegators :instance,
37
- :fetch_dashboard_stats, :fetch_failing_jobs, :fetch_scheduled_jobs, :fetch_job,
37
+ def_delegators :instance, :fetch_dashboard_stats,
38
+ :fetch_running_jobs, :fetch_failing_jobs, :fetch_scheduled_jobs, :fetch_job,
38
39
  :delete_failing_jobs, :delete_scheduled_jobs, :delete_job,
39
40
  :reschedule_scheduled_jobs, :reschedule_failing_jobs, :reschedule_job
40
41
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: que-view
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bogdanov Anton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-01 00:00:00.000000000 Z
11
+ date: 2024-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: que
@@ -175,6 +175,7 @@ files:
175
175
  - lib/que/view/configuration.rb
176
176
  - lib/que/view/dsl.rb
177
177
  - lib/que/view/engine.rb
178
+ - lib/que/view/pagination.rb
178
179
  - lib/que/view/version.rb
179
180
  homepage: https://github.com/kortirso/que-view
180
181
  licenses: