vue_delayed_job_dashboard 0.1.2 → 0.1.3

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
  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