vue_delayed_job_dashboard 0.1.2 → 0.1.3

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
  SHA1:
3
- metadata.gz: 48f4fa220093d565e3e111f261b0e91ed7ed6b20
4
- data.tar.gz: e8886096e1bc75e96959eebcf2abd1a20dfb0506
3
+ metadata.gz: abd7f26728d3056a3dd0f352b44bb71e5efceb4c
4
+ data.tar.gz: d050e8d92a3aa7dbcccd3cdc2a8aa71faa4d72c7
5
5
  SHA512:
6
- metadata.gz: 6fa9f09a8913719a29ab2b7d9fbde7540afb7cee50b0bcf8b22f5b2983f4b016329d34f2d284e528997699a99f50666782b16a809fc2a39ea6c46a2de0e982ac
7
- data.tar.gz: 272ed1b5a6c948cbf1eb57a281a4a604e87c5b54b24685ddaf38d389189b751ded0cd7a0875c7af1442285514687af8b95a7ec706c9ba61b06344e59fb86929e
6
+ metadata.gz: 44200b594ae11cf96984fddaa9b559003470e0915b3597f9e05da7962503f75cb7ca9409cbaee6bd5bb5fa8cf06a6e1421574fad9ef2c5d0b88ad18733cd91ae
7
+ data.tar.gz: 8299052b51f98f6ffa0a8120c5ec7f0ea462908a84003c50fab8379bd7aa4c1f798449e1269107f3a0f83d0db067f210a0fe0499b45e9a691821a3751501705c
data/README.md CHANGED
@@ -28,6 +28,20 @@ Add the following line to top of `route.rb`
28
28
  mount VueDelayedJobDashboard::WebApplication => '/delayed_job'
29
29
  ```
30
30
 
31
+ vue_delayed_job_dashboard will require basic authentication by default. Add the following configuration to environment variable.
32
+
33
+ ```ruby
34
+ ENV["VUE_DELAYED_JOB_USERNAME"] = "username"
35
+ ENV["VUE_DELAYED_JOB_PASSWORD"] = "password"
36
+ ```
37
+
38
+ ## TODO
39
+
40
+ - Add unit tests
41
+ - Add pagination
42
+ - Stats
43
+ - Add authentication [DONE]
44
+
31
45
  ## Development
32
46
 
33
47
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,5 @@
1
+ require "vue_delayed_job_dashboard/web/app"
2
+
3
+ VueDelayedJobDashboard::WebApplication.use Rack::Auth::Basic do |username, password|
4
+ username == ENV["VUE_DELAYED_JOB_USERNAME"] && password == ENV["VUE_DELAYED_JOB_PASSWORD"]
5
+ end
@@ -1,3 +1,3 @@
1
1
  module VueDelayedJobDashboard
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require 'sinatra/base'
2
+ require 'vue_delayed_job_dashboard/web/filter'
2
3
 
3
4
  module VueDelayedJobDashboard
4
5
  class WebApplication < Sinatra::Base
@@ -36,21 +37,21 @@ module VueDelayedJobDashboard
36
37
  haml :working, escape_html: false
37
38
  end
38
39
 
39
- get '/jobs.json' do
40
+ get '/jobs_info.json' do
40
41
  content_type :json
42
+ total = VueDelayedJobDashboard::Filter.for(Delayed::Job, params[:filter]).page(0).per(params[:per_page]).total_pages
41
43
 
42
- case params["filter"]
43
- when "pending"
44
- @jobs = Delayed::Job.where(locked_at: nil, attempts: 0).order(created_at: :desc)
45
- when "failed"
46
- @jobs = Delayed::Job.where.not(failed_at: nil).order(created_at: :desc)
47
- when "working"
48
- @jobs = Delayed::Job.where.not(locked_at: nil).order(created_at: :desc)
49
- when "enqueued"
50
- @jobs = Delayed::Job.order(created_at: :desc)
51
- end
44
+ {
45
+ total_jobs: VueDelayedJobDashboard::Filter.for(Delayed::Job, params[:filter]).count,
46
+ total_pages: total
47
+ }.to_json
48
+ end
49
+
50
+ get '/jobs.json' do
51
+ content_type :json
52
52
 
53
- @jobs = Delayed::Job.order(created_at: :desc) if @jobs.nil?
53
+ @jobs = Delayed::Job.page(params[:page]).per(params[:per_page]).order(created_at: :desc)
54
+ @jobs = VueDelayedJobDashboard::Filter.for(@jobs, params[:filter])
54
55
 
55
56
  @jobs_json = @jobs.as_json
56
57
  @jobs_json.each_with_index do |job, index|
@@ -0,0 +1,18 @@
1
+ module VueDelayedJobDashboard
2
+ class Filter
3
+ def self.for(jobs, filter)
4
+ case filter
5
+ when "pending"
6
+ jobs.where(locked_at: nil, attempts: 0)
7
+ when "failed"
8
+ jobs.where.not(failed_at: nil)
9
+ when "working"
10
+ jobs.where.not(locked_at: nil)
11
+ when "enqueued"
12
+ jobs
13
+ when nil || ""
14
+ jobs
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,16 @@
1
1
  <template>
2
2
  <div>
3
+ <div class="block">
4
+ <el-pagination
5
+ layout="total, sizes, prev, pager, next"
6
+ @size-change="handleSizeChange"
7
+ @current-change="handleCurrentChange"
8
+ :page-sizes="pageSizes"
9
+ :page-size="perPage"
10
+ :total="totalJobs">
11
+ </el-pagination>
12
+ </div>
13
+
3
14
  <el-table
4
15
  :data="jobs"
5
16
  v-loading.body="loading"
@@ -52,6 +63,17 @@
52
63
  </el-table-column>
53
64
  </el-table>
54
65
 
66
+ <div class="block">
67
+ <el-pagination
68
+ layout="total, sizes, prev, pager, next"
69
+ @size-change="handleSizeChange"
70
+ @current-change="handleCurrentChange"
71
+ :page-sizes="pageSizes"
72
+ :page-size="perPage"
73
+ :total="totalJobs">
74
+ </el-pagination>
75
+ </div>
76
+
55
77
  <el-dialog title="Object Payload" v-model="dialogVisible" size="small">
56
78
  <pre>{{jobDetailHandler}}</pre>
57
79
  <span slot="footer" class="dialog-footer">
@@ -65,34 +87,75 @@
65
87
  const moment = require('moment');
66
88
 
67
89
  export default {
68
- props: ["mydata"],
69
90
  data () {
70
91
  return {
71
92
  jobs: [],
72
93
  dialogVisible: false,
73
94
  jobDetailHandler: "",
74
95
  jobDetailId: "",
75
- loading: true
76
-
96
+ loading: true,
97
+ currentPage: 0,
98
+ perPage: 4,
99
+ totalJobs: 0,
100
+ totalPages: 0,
101
+ pageSizes: [4, 6, 8, 10]
77
102
  }
78
103
  },
104
+
79
105
  created () {
80
- let path = window.location.pathname;
81
- if (path.includes("pending")) {
82
- this.loadJobs({ params: { filter: "pending" } });
83
- } else if (path.includes("failed")) {
84
- this.loadJobs({ params: { filter: "failed" } });
85
- } else if (path.includes("working")) {
86
- this.loadJobs({ params: { filter: "working" } });
87
- } else if (path.includes("enqueued")) {
88
- this.loadJobs({ params: { filter: "enqueued" } });
89
- }
90
- else {
91
- this.loadJobs({ params: {} });
92
- }
106
+ this.loadPageInfo();
107
+ this.loadJobsForCurrentPage();
93
108
  },
94
109
 
95
110
  methods: {
111
+ getJobType() {
112
+ const path = window.location.pathname;
113
+ if (path.includes("pending")) {
114
+ return "pending"
115
+ } else if (path.includes("failed")) {
116
+ return "failed"
117
+ } else if (path.includes("working")) {
118
+ return "working"
119
+ } else if (path.includes("enqueued")) {
120
+ return "enqueued"
121
+ }
122
+ else {
123
+ return ""
124
+ }
125
+ },
126
+
127
+ loadJobsForCurrentPage() {
128
+ const filter = this.getJobType();
129
+ this.loadJobs({
130
+ params: {
131
+ filter: filter,
132
+ page: this.currentPage,
133
+ per_page: this.perPage
134
+ }
135
+ });
136
+ },
137
+
138
+ loadPageInfo(){
139
+ const queries = { params: { filter: this.getJobType(), r_page: this.perPage } };
140
+ this.$http.get("/delayed_job/jobs_info.json", queries).then(response => {
141
+ const res = response.body;
142
+ this.totalPages = res.total_pages;
143
+ this.totalJobs = res.total_jobs;
144
+ }, response => {
145
+ });
146
+ },
147
+
148
+ handleSizeChange(val){
149
+ this.perPage = val;
150
+ this.loadPageInfo();
151
+ this.loadJobsForCurrentPage();
152
+ },
153
+
154
+ handleCurrentChange(val) {
155
+ this.currentPage = val;
156
+ this.loadJobsForCurrentPage();
157
+ },
158
+
96
159
  handleClickDialog(index, jobs){
97
160
  this.jobDetailHandler = jobs[index].payload_object;
98
161
  this.jobDetailId = jobs[index].id;
@@ -51443,11 +51443,11 @@ var Component = __webpack_require__(140)(
51443
51443
  /* template */
51444
51444
  __webpack_require__(202),
51445
51445
  /* scopeId */
51446
- "data-v-fd1f72f0",
51446
+ "data-v-96b7533e",
51447
51447
  /* cssModules */
51448
51448
  null
51449
51449
  )
51450
- Component.options.__file = "/Users/mac/Desktop/opensources/vue_delayed_job_dashboard/lib/vue_delayed_job_dashboard/web/priv/App.vue"
51450
+ Component.options.__file = "/Users/mac/Desktop/opensources/delayed_job_dashboard/lib/vue_delayed_job_dashboard/web/priv/App.vue"
51451
51451
  if (Component.esModule && Object.keys(Component.esModule).some(function (key) {return key !== "default" && key !== "__esModule"})) {console.error("named exports are not supported in *.vue files.")}
51452
51452
  if (Component.options.functional) {console.error("[vue-loader] App.vue: functional components are not supported with templates, they should use render functions.")}
51453
51453
 
@@ -51458,9 +51458,9 @@ if (false) {(function () {
51458
51458
  if (!hotAPI.compatible) return
51459
51459
  module.hot.accept()
51460
51460
  if (!module.hot.data) {
51461
- hotAPI.createRecord("data-v-fd1f72f0", Component.options)
51461
+ hotAPI.createRecord("data-v-96b7533e", Component.options)
51462
51462
  } else {
51463
- hotAPI.reload("data-v-fd1f72f0", Component.options)
51463
+ hotAPI.reload("data-v-96b7533e", Component.options)
51464
51464
  }
51465
51465
  })()}
51466
51466
 
@@ -54516,38 +54516,96 @@ Object.defineProperty(exports, "__esModule", {
54516
54516
  //
54517
54517
  //
54518
54518
  //
54519
+ //
54520
+ //
54521
+ //
54522
+ //
54523
+ //
54524
+ //
54525
+ //
54526
+ //
54527
+ //
54528
+ //
54529
+ //
54530
+ //
54531
+ //
54532
+ //
54533
+ //
54534
+ //
54535
+ //
54536
+ //
54537
+ //
54538
+ //
54539
+ //
54540
+ //
54519
54541
 
54520
54542
  var moment = __webpack_require__(0);
54521
54543
 
54522
54544
  exports.default = {
54523
- props: ["mydata"],
54524
54545
  data: function data() {
54525
54546
  return {
54526
54547
  jobs: [],
54527
54548
  dialogVisible: false,
54528
54549
  jobDetailHandler: "",
54529
54550
  jobDetailId: "",
54530
- loading: true
54531
-
54551
+ loading: true,
54552
+ currentPage: 0,
54553
+ perPage: 4,
54554
+ totalJobs: 0,
54555
+ totalPages: 0,
54556
+ pageSizes: [4, 6, 8, 10]
54532
54557
  };
54533
54558
  },
54534
54559
  created: function created() {
54535
- var path = window.location.pathname;
54536
- if (path.includes("pending")) {
54537
- this.loadJobs({ params: { filter: "pending" } });
54538
- } else if (path.includes("failed")) {
54539
- this.loadJobs({ params: { filter: "failed" } });
54540
- } else if (path.includes("working")) {
54541
- this.loadJobs({ params: { filter: "working" } });
54542
- } else if (path.includes("enqueued")) {
54543
- this.loadJobs({ params: { filter: "enqueued" } });
54544
- } else {
54545
- this.loadJobs({ params: {} });
54546
- }
54560
+ this.loadPageInfo();
54561
+ this.loadJobsForCurrentPage();
54547
54562
  },
54548
54563
 
54549
54564
 
54550
54565
  methods: {
54566
+ getJobType: function getJobType() {
54567
+ var path = window.location.pathname;
54568
+ if (path.includes("pending")) {
54569
+ return "pending";
54570
+ } else if (path.includes("failed")) {
54571
+ return "failed";
54572
+ } else if (path.includes("working")) {
54573
+ return "working";
54574
+ } else if (path.includes("enqueued")) {
54575
+ return "enqueued";
54576
+ } else {
54577
+ return "";
54578
+ }
54579
+ },
54580
+ loadJobsForCurrentPage: function loadJobsForCurrentPage() {
54581
+ var filter = this.getJobType();
54582
+ this.loadJobs({
54583
+ params: {
54584
+ filter: filter,
54585
+ page: this.currentPage,
54586
+ per_page: this.perPage
54587
+ }
54588
+ });
54589
+ },
54590
+ loadPageInfo: function loadPageInfo() {
54591
+ var _this = this;
54592
+
54593
+ var queries = { params: { filter: this.getJobType(), r_page: this.perPage } };
54594
+ this.$http.get("/delayed_job/jobs_info.json", queries).then(function (response) {
54595
+ var res = response.body;
54596
+ _this.totalPages = res.total_pages;
54597
+ _this.totalJobs = res.total_jobs;
54598
+ }, function (response) {});
54599
+ },
54600
+ handleSizeChange: function handleSizeChange(val) {
54601
+ this.perPage = val;
54602
+ this.loadPageInfo();
54603
+ this.loadJobsForCurrentPage();
54604
+ },
54605
+ handleCurrentChange: function handleCurrentChange(val) {
54606
+ this.currentPage = val;
54607
+ this.loadJobsForCurrentPage();
54608
+ },
54551
54609
  handleClickDialog: function handleClickDialog(index, jobs) {
54552
54610
  this.jobDetailHandler = jobs[index].payload_object;
54553
54611
  this.jobDetailId = jobs[index].id;
@@ -54581,13 +54639,13 @@ exports.default = {
54581
54639
  return moment(row.created_at).format('MMMM Do YYYY, h:mm:ss a');
54582
54640
  },
54583
54641
  loadJobs: function loadJobs(queries) {
54584
- var _this = this;
54642
+ var _this2 = this;
54585
54643
 
54586
54644
  this.$http.get("/delayed_job/jobs.json", queries).then(function (response) {
54587
- _this.jobs = response.body;
54588
- _this.loading = false;
54645
+ _this2.jobs = response.body;
54646
+ _this2.loading = false;
54589
54647
  }, function (response) {
54590
- _this.loading = false;
54648
+ _this2.loading = false;
54591
54649
  });
54592
54650
  }
54593
54651
  }
@@ -56534,7 +56592,7 @@ exports = module.exports = __webpack_require__(17)(undefined);
56534
56592
 
56535
56593
 
56536
56594
  // module
56537
- exports.push([module.i, "\na[data-v-fd1f72f0] {\n text-decoration: none;\n}\n", ""]);
56595
+ exports.push([module.i, "\na[data-v-96b7533e] {\n text-decoration: none;\n}\n", ""]);
56538
56596
 
56539
56597
  // exports
56540
56598
 
@@ -63432,7 +63490,7 @@ var Component = __webpack_require__(140)(
63432
63490
  /* cssModules */
63433
63491
  null
63434
63492
  )
63435
- Component.options.__file = "/Users/mac/Desktop/opensources/vue_delayed_job_dashboard/lib/vue_delayed_job_dashboard/web/priv/JobsList.vue"
63493
+ Component.options.__file = "/Users/mac/Desktop/opensources/delayed_job_dashboard/lib/vue_delayed_job_dashboard/web/priv/JobsList.vue"
63436
63494
  if (Component.esModule && Object.keys(Component.esModule).some(function (key) {return key !== "default" && key !== "__esModule"})) {console.error("named exports are not supported in *.vue files.")}
63437
63495
  if (Component.options.functional) {console.error("[vue-loader] JobsList.vue: functional components are not supported with templates, they should use render functions.")}
63438
63496
 
@@ -63443,9 +63501,9 @@ if (false) {(function () {
63443
63501
  if (!hotAPI.compatible) return
63444
63502
  module.hot.accept()
63445
63503
  if (!module.hot.data) {
63446
- hotAPI.createRecord("data-v-234775bd", Component.options)
63504
+ hotAPI.createRecord("data-v-48df34f8", Component.options)
63447
63505
  } else {
63448
- hotAPI.reload("data-v-234775bd", Component.options)
63506
+ hotAPI.reload("data-v-48df34f8", Component.options)
63449
63507
  }
63450
63508
  })()}
63451
63509
 
@@ -63457,7 +63515,20 @@ module.exports = Component.exports
63457
63515
  /***/ (function(module, exports, __webpack_require__) {
63458
63516
 
63459
63517
  module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
63460
- return _c('div', [_c('el-table', {
63518
+ return _c('div', [_c('div', {
63519
+ staticClass: "block"
63520
+ }, [_c('el-pagination', {
63521
+ attrs: {
63522
+ "layout": "total, sizes, prev, pager, next",
63523
+ "page-sizes": _vm.pageSizes,
63524
+ "page-size": _vm.perPage,
63525
+ "total": _vm.totalJobs
63526
+ },
63527
+ on: {
63528
+ "size-change": _vm.handleSizeChange,
63529
+ "current-change": _vm.handleCurrentChange
63530
+ }
63531
+ })], 1), _vm._v(" "), _c('el-table', {
63461
63532
  directives: [{
63462
63533
  name: "loading",
63463
63534
  rawName: "v-loading.body",
@@ -63542,6 +63613,19 @@ module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c
63542
63613
  }, [_vm._v("\n Show\n ")])]
63543
63614
  }]
63544
63615
  ])
63616
+ })], 1), _vm._v(" "), _c('div', {
63617
+ staticClass: "block"
63618
+ }, [_c('el-pagination', {
63619
+ attrs: {
63620
+ "layout": "total, sizes, prev, pager, next",
63621
+ "page-sizes": _vm.pageSizes,
63622
+ "page-size": _vm.perPage,
63623
+ "total": _vm.totalJobs
63624
+ },
63625
+ on: {
63626
+ "size-change": _vm.handleSizeChange,
63627
+ "current-change": _vm.handleCurrentChange
63628
+ }
63545
63629
  })], 1), _vm._v(" "), _c('el-dialog', {
63546
63630
  attrs: {
63547
63631
  "title": "Object Payload",
@@ -63572,7 +63656,7 @@ module.exports.render._withStripped = true
63572
63656
  if (false) {
63573
63657
  module.hot.accept()
63574
63658
  if (module.hot.data) {
63575
- require("vue-hot-reload-api").rerender("data-v-234775bd", module.exports)
63659
+ require("vue-hot-reload-api").rerender("data-v-48df34f8", module.exports)
63576
63660
  }
63577
63661
  }
63578
63662
 
@@ -63638,7 +63722,7 @@ module.exports.render._withStripped = true
63638
63722
  if (false) {
63639
63723
  module.hot.accept()
63640
63724
  if (module.hot.data) {
63641
- require("vue-hot-reload-api").rerender("data-v-fd1f72f0", module.exports)
63725
+ require("vue-hot-reload-api").rerender("data-v-96b7533e", module.exports)
63642
63726
  }
63643
63727
  }
63644
63728
 
@@ -63653,13 +63737,13 @@ var content = __webpack_require__(175);
63653
63737
  if(typeof content === 'string') content = [[module.i, content, '']];
63654
63738
  if(content.locals) module.exports = content.locals;
63655
63739
  // add the styles to the DOM
63656
- var update = __webpack_require__(204)("4a4e7eb5", content, false);
63740
+ var update = __webpack_require__(204)("304edec2", content, false);
63657
63741
  // Hot Module Replacement
63658
63742
  if(false) {
63659
63743
  // When the styles change, update the <style> tags
63660
63744
  if(!content.locals) {
63661
- module.hot.accept("!!../../../../node_modules/css-loader/index.js!../../../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-fd1f72f0\",\"scoped\":true,\"hasInlineConfig\":false}!../../../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./App.vue", function() {
63662
- var newContent = require("!!../../../../node_modules/css-loader/index.js!../../../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-fd1f72f0\",\"scoped\":true,\"hasInlineConfig\":false}!../../../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./App.vue");
63745
+ module.hot.accept("!!../../../../node_modules/css-loader/index.js!../../../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-96b7533e\",\"scoped\":true,\"hasInlineConfig\":false}!../../../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./App.vue", function() {
63746
+ var newContent = require("!!../../../../node_modules/css-loader/index.js!../../../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-96b7533e\",\"scoped\":true,\"hasInlineConfig\":false}!../../../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./App.vue");
63663
63747
  if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
63664
63748
  update(newContent);
63665
63749
  });
@@ -1,2 +1,3 @@
1
1
  require "vue_delayed_job_dashboard/version"
2
+ require "vue_delayed_job_dashboard/authentication"
2
3
  require "vue_delayed_job_dashboard/web/app"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vue_delayed_job_dashboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Long Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-09 00:00:00.000000000 Z
11
+ date: 2017-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -62,8 +62,10 @@ files:
62
62
  - README.md
63
63
  - Rakefile
64
64
  - lib/vue_delayed_job_dashboard.rb
65
+ - lib/vue_delayed_job_dashboard/authentication.rb
65
66
  - lib/vue_delayed_job_dashboard/version.rb
66
67
  - lib/vue_delayed_job_dashboard/web/app.rb
68
+ - lib/vue_delayed_job_dashboard/web/filter.rb
67
69
  - lib/vue_delayed_job_dashboard/web/priv/App.vue
68
70
  - lib/vue_delayed_job_dashboard/web/priv/JobsList.vue
69
71
  - lib/vue_delayed_job_dashboard/web/priv/app.js