panoptic 0.1.3 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92d310e17406ea0681469b5f4f4ff1d456b9d24ad4c89d4498adc87643f9ed8c
4
- data.tar.gz: 9e2faccbac6daf2820c63202adc28292918934e596462443b046be5d4b874c72
3
+ metadata.gz: 0c9c24666cf21962529d267d1432b25fb3b2ba813ec8997c5a50373da1b76f2b
4
+ data.tar.gz: 72eae4c018c7585f2abf3ec7968c94e9ccf223783d3f730e75d5796ff06b2f7b
5
5
  SHA512:
6
- metadata.gz: b596a1d4224631ffb6f1e619958bbed94c20c4bfcb6c64fd967045efd40d785be72d2393b1317dc239866be6ba35952eebbf3eeac22e02cc270626475f325328
7
- data.tar.gz: b07d2227e30e712aedaeb5d1213991fba6cb5e467f67466795c3b1fd8d10a92e9fa5c9a98e86f6afc2a71bd2ac4de963c3a5de2a49a3f74494973c666227d4ba
6
+ metadata.gz: 248f586bdf987718900bd83c4e9989b2f6b617853637e2a9ac690b94723e01cd5659126a01c812ee4ba7584ebfaa87778a1e3208cb6be442f415e348dfe6a1bc
7
+ data.tar.gz: 5e58e532a16725fc88dfc90f1a7321a20fc4730957a31db28e5e14952381ac5192c1afda78547395b1de833b5cbef45750cacd0effe1e5b822402b1afddfc866
data/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  # Panoptic
2
- Short description and motivation.
3
2
 
4
- ## Usage
5
- How to use my plugin.
3
+ [![Gem Version](https://badge.fury.io/rb/panoptic.svg)](https://badge.fury.io/rb/panoptic)
4
+
5
+ Panoptic is a web interface for the [SolidQueue](https://github.com/basecamp/solid_queue) queuing backend.
6
+
7
+ ![](./images/demo.png)
8
+
9
+ While MissionControl is getting ready for release, this gem offers a visual interface for testing purposes with SolidQueue.
6
10
 
7
11
  ## Installation
8
12
  Add this line to your application's Gemfile:
@@ -11,18 +15,23 @@ Add this line to your application's Gemfile:
11
15
  gem "panoptic"
12
16
  ```
13
17
 
14
- And then execute:
15
- ```bash
16
- $ bundle
17
- ```
18
+ Then mount the engine in your `config/routes.rb` file
18
19
 
19
- Or install it yourself as:
20
- ```bash
21
- $ gem install panoptic
20
+ ```ruby
21
+ mount Panoptic::Engine => "/panoptic"
22
22
  ```
23
23
 
24
- ## Contributing
25
- Contribution directions go here.
24
+ ## Usage
25
+
26
+ Once the gem is installed and the Engine mounted, visit your engine route to access Panoptic. For now, it offers three views:
27
+ - Processes
28
+ - Queues
29
+ - A first version of the jobs view
30
+
31
+ In the near future, the following features could be implemented:
32
+ - Pause and clear queues
33
+ - Advanced jobs view, with filters for executed, failed and scheduled jobs
34
+ - Search and retries
26
35
 
27
36
  ## License
28
37
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,4 +1,5 @@
1
1
  module Panoptic
2
2
  class ApplicationController < ActionController::Base
3
+ include Pagy::Backend
3
4
  end
4
5
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panoptic
4
+ class Jobs::FailedController < ApplicationController
5
+ layout "panoptic/jobs", only: :index
6
+
7
+ def index
8
+ @pagy, @jobs = pagy(
9
+ Panoptic::FailedJob.order(created_at: :asc)
10
+ )
11
+ end
12
+
13
+ def show
14
+ @job = Panoptic::FailedJob.find(params[:id])
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panoptic
4
+ class Jobs::ScheduledController < ApplicationController
5
+ layout "panoptic/jobs"
6
+
7
+ def index
8
+ # TODO: use the `scheduled` scope available in SolidQueue next release
9
+ @pagy, @jobs = pagy(
10
+ SolidQueue::Job.joins(:scheduled_execution).order(created_at: :asc)
11
+ )
12
+
13
+ render "panoptic/jobs/index"
14
+ end
15
+ end
16
+ end
@@ -2,8 +2,6 @@
2
2
 
3
3
  module Panoptic
4
4
  class JobsController < ApplicationController
5
- include Pagy::Backend
6
-
7
5
  def index
8
6
  @pagy, @jobs = pagy(SolidQueue::Job.order(created_at: :asc))
9
7
  end
@@ -1,5 +1,7 @@
1
1
  module Panoptic
2
2
  module ApplicationHelper
3
3
  include Pagy::Frontend
4
+ include BreadcrumbsHelper
5
+ include DateTimeHelper
4
6
  end
5
7
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panoptic
4
+ module BreadcrumbsHelper
5
+ def breadcrumb_items
6
+ @breadcrumb_items ||= []
7
+ end
8
+
9
+ def breadcrumbs
10
+ tag.nav(aria: { label: "breadcrumb" }) do
11
+ tag.ol(class: "breadcrumb") do
12
+ breadcrumb_items.map do |item|
13
+ concat tag.li(item, class: "breadcrumb-item")
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panoptic
4
+ module DateTimeHelper
5
+ def safe_time_tag(date_or_time, *args, &block)
6
+ return "-" unless date_or_time
7
+
8
+ time_tag(date_or_time, *args, &block)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Panoptic
4
+ class FailedJob < SolidQueue::Job
5
+ # TODO: use the `failed` scope available in SolidQueue next release
6
+ default_scope { joins(:failed_execution) }
7
+
8
+ def enqueued_at
9
+ Time.parse(arguments["enqueued_at"])
10
+ end
11
+
12
+ def exception_class
13
+ failed_execution.error["exception_class"]
14
+ end
15
+
16
+ def exception_message
17
+ failed_execution.error["message"]
18
+ end
19
+
20
+ def stacktrace
21
+ failed_execution.error["backtrace"]
22
+ end
23
+ end
24
+ end
@@ -7,11 +7,11 @@
7
7
 
8
8
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
9
9
  </head>
10
- <body>
10
+ <body class="pb-4">
11
11
  <%= render "shared/navbar" %>
12
12
 
13
13
  <main class="container mt-2">
14
- <%= yield %>
14
+ <%= content_for?(:content) ? yield(:content) : yield %>
15
15
  </main>
16
16
 
17
17
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>
@@ -0,0 +1,27 @@
1
+ <% content_for(:content) do %>
2
+ <h1>Jobs</h1>
3
+
4
+ <ul class="nav nav-underline">
5
+ <li class="nav-item">
6
+ <%= link_to "All", jobs_path, class: class_names("nav-link", "active": current_page?(jobs_path)) %>
7
+ </li>
8
+ <li class="nav-item">
9
+ <%= link_to "Scheduled", scheduled_jobs_path, class: class_names("nav-link", "active": current_page?(scheduled_jobs_path)) %>
10
+ </li>
11
+ <li class="nav-item">
12
+ <%= link_to "Failed", failed_jobs_path, class: class_names("nav-link", "active": current_page?(failed_jobs_path)) %>
13
+ </li>
14
+ </ul>
15
+
16
+ <div class="d-flex justify-content-end">
17
+ <%== pagy_info(@pagy) %>
18
+ </div>
19
+
20
+ <%= yield %>
21
+
22
+ <div class="d-flex justify-content-center">
23
+ <%== pagy_bootstrap_nav(@pagy) if @pagy.pages > 1 %>
24
+ </div>
25
+ <% end %>
26
+
27
+ <%= render template: "layouts/panoptic/application" %>
@@ -2,7 +2,6 @@
2
2
  <th scope="row"><%= job.id %></th>
3
3
  <td scope="col"><%= job.class_name %></td>
4
4
  <td scope="col"><%= job.queue_name %></td>
5
- <td scope="col"><%= job.arguments %></td>
6
- <td scope="col"><% job.scheduled_at %></td>
7
- <td scope="col"><% job.finished_at %></td>
5
+ <td scope="col"><%= safe_time_tag job.scheduled_at %></td>
6
+ <td scope="col"><%= safe_time_tag job.finished_at %></td>
8
7
  </tr>
@@ -0,0 +1,10 @@
1
+ <tr>
2
+ <th scope="row"><%= job.id %></th>
3
+ <td scope="col"><%= job.class_name %></td>
4
+ <td scope="col"><%= job.queue_name %></td>
5
+ <td scope="col" class="font-monospace"><%= job.exception_class %></td>
6
+ <td scope="col"><%= safe_time_tag job.enqueued_at %></td>
7
+ <td scope="col">
8
+ <%= link_to "Details", failed_job_path(job) %>
9
+ </td>
10
+ </tr>
@@ -0,0 +1,16 @@
1
+ <table class="table">
2
+ <thead>
3
+ <tr>
4
+ <th scope="col">#</th>
5
+ <th scope="col">Class</th>
6
+ <th scope="col">Queue</th>
7
+ <th scope="col">Exception</th>
8
+ <th scope="col">Enqueued</th>
9
+ <th scope="col"></th>
10
+ </tr>
11
+ </thead>
12
+
13
+ <tbody>
14
+ <%= render partial: "job", collection: @jobs %>
15
+ </tbody>
16
+ </table>
@@ -0,0 +1,24 @@
1
+ <% breadcrumb_items.push link_to("Jobs", jobs_path) %>
2
+ <% breadcrumb_items.push link_to("Failed", failed_jobs_path) %>
3
+ <% breadcrumb_items.push @job.id %>
4
+ <%= breadcrumbs %>
5
+
6
+ <h1><%= @job.class_name %></h1>
7
+
8
+ <div class="alert alert-danger" role="alert">
9
+ <h4 class="alert-heading"><%= @job.exception_class %></h4>
10
+ <p class="font-monospace mb-0">
11
+ <%= @job.exception_message %>
12
+ </p>
13
+ </div>
14
+
15
+ <div class="card" >
16
+ <div class="card-header">
17
+ Stacktrace
18
+ </div>
19
+ <ul class="list-group list-group-flush font-monospace text-xs">
20
+ <% @job.stacktrace.each do |trace| %>
21
+ <li class="list-group-item"><%= trace %></li>
22
+ <% end %>
23
+ </ul>
24
+ </div>
@@ -1,26 +1,15 @@
1
- <h1>Jobs</h1>
2
-
3
- <div class="d-flex justify-content-end">
4
- <%== pagy_info(@pagy) %>
5
- </div>
6
-
7
1
  <table class="table">
8
2
  <thead>
9
3
  <tr>
10
4
  <th scope="col">#</th>
11
5
  <th scope="col">Class</th>
12
6
  <th scope="col">Queue</th>
13
- <th scope="col">Arguments</th>
14
- <th scope="col">Scheduled at</th>
15
- <th scope="col">Finished at</th>
7
+ <th scope="col">Scheduled</th>
8
+ <th scope="col">Finished</th>
16
9
  </tr>
17
10
  </thead>
18
11
 
19
12
  <tbody>
20
- <%= render partial: "job", collection: @jobs %>
13
+ <%= render partial: "panoptic/jobs/job", collection: @jobs %>
21
14
  </tbody>
22
15
  </table>
23
-
24
- <div class="d-flex justify-content-center">
25
- <%== pagy_bootstrap_nav(@pagy) if @pagy.pages > 1 %>
26
- </div>
data/config/routes.rb CHANGED
@@ -2,5 +2,13 @@ Panoptic::Engine.routes.draw do
2
2
  root to: "processes#index"
3
3
 
4
4
  resources :queues, only: [:index]
5
- resources :jobs, only: [:index]
5
+
6
+ scope "jobs" do
7
+ get "all", to: "jobs#index", as: "jobs"
8
+
9
+ scope module: "jobs" do
10
+ resources :scheduled, only: :index, as: :scheduled_jobs
11
+ resources :failed, only: [:index, :show], as: :failed_jobs
12
+ end
13
+ end
6
14
  end
@@ -1,3 +1,3 @@
1
1
  module Panoptic
2
- VERSION = "0.1.3"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: panoptic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vincent Rolea
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-28 00:00:00.000000000 Z
11
+ date: 2023-12-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -59,20 +59,28 @@ executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
- - MIT-LICENSE
63
62
  - README.md
64
63
  - Rakefile
65
64
  - app/controllers/panoptic/application_controller.rb
65
+ - app/controllers/panoptic/jobs/failed_controller.rb
66
+ - app/controllers/panoptic/jobs/scheduled_controller.rb
66
67
  - app/controllers/panoptic/jobs_controller.rb
67
68
  - app/controllers/panoptic/processes_controller.rb
68
69
  - app/controllers/panoptic/queues_controller.rb
69
70
  - app/helpers/panoptic/application_helper.rb
71
+ - app/helpers/panoptic/breadcrumbs_helper.rb
72
+ - app/helpers/panoptic/date_time_helper.rb
70
73
  - app/jobs/panoptic/application_job.rb
71
74
  - app/mailers/panoptic/application_mailer.rb
72
75
  - app/models/panoptic/application_record.rb
76
+ - app/models/panoptic/failed_job.rb
73
77
  - app/models/panoptic/process.rb
74
78
  - app/views/layouts/panoptic/application.html.erb
79
+ - app/views/layouts/panoptic/jobs.html.erb
75
80
  - app/views/panoptic/jobs/_job.html.erb
81
+ - app/views/panoptic/jobs/failed/_job.html.erb
82
+ - app/views/panoptic/jobs/failed/index.html.erb
83
+ - app/views/panoptic/jobs/failed/show.html.erb
76
84
  - app/views/panoptic/jobs/index.html.erb
77
85
  - app/views/panoptic/processes/_process.html.erb
78
86
  - app/views/panoptic/processes/index.html.erb
data/MIT-LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright Vincent Rolea
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.