agendash 3.1.0 → 4.0.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.
package/History.md ADDED
@@ -0,0 +1,118 @@
1
+ # 4.0.0
2
+
3
+ - Drop support for node 12. Add support for node 18 and MongoDB 5.0.
4
+ - Fastify upgraded to v4. #215
5
+ - Various UI fixes. #212 #203
6
+ - Vulnerability fixes. #220
7
+ - Requeue and Delete job fixes. #226 #227
8
+
9
+ # 3.1.0
10
+
11
+ - Add Content-Security-Policy header to all server implementations
12
+
13
+ # 3.0.0
14
+
15
+ - BREAKING: Drop support for MongoDB v3.4, only >=v3.6 is supported now.
16
+ - BREAKING: Drop support for node 10, but added node 16 support.
17
+ - feat: add `fastify` support #194
18
+ - fix: a lot of rendering issues
19
+ - fix: newer version of `mongodb` compatibility #193
20
+
21
+ This file won't mention contributors anymore. Because all contributors are listed on the [main page](https://github.com/agenda/agendash) now. Thanks, GitHub!
22
+
23
+ # 2.1.0 - JSON validation when creating jobs
24
+
25
+ - feat: Add json validator message when createJob #169 (thanks @love8587)
26
+
27
+ # 2.0.0 - First public release of v2 as Agendash proper
28
+
29
+ Complete rewrite of Agendash in Vue.js!
30
+
31
+ Supports Node.js 10 and up.
32
+
33
+ # 2.0.0-beta0.8.2 / 2020-12-04 - As agendash2, in parallel repository https://github.com/agenda/agendash-v2
34
+
35
+ - fix: search by job name, small side bar design fix and toggle improvements (thanks @simllll)
36
+ - fix: joblist reset fix (thanks @simllll)
37
+ - fix: improve design on desktop + close sidebar on mobile when clicked on something (thanks @simllll)
38
+ - feat: enable options.query as number (thanks @Enubia @simllll)
39
+ - feat: multiselect checkboxes (thanks @Enubia @simllll)
40
+
41
+ # 2.0.0-beta0.1.0 / 2020-04-30 - First public release of Agendash2 in parallel repository https://github.com/agenda/agendash-v2
42
+
43
+ - New frontend written from scratch in Vue.js
44
+ - Add search
45
+ - Add pagination
46
+ - Change default refresh interval to 60 seconds
47
+
48
+ # 1.0.0 / 2019-02-25
49
+
50
+ - Add Hapi v17 middleware, drop support for Node.js v6 & v7 (#81) by umens (**BREAKING**)
51
+ - Support Agenda version 2 by alexkwolfe (**BREAKING**)
52
+
53
+ # 0.5.0 / 2019-02-25
54
+
55
+ - Update dependencies (#69, #70) (**BREAKING**)
56
+ - Agenda `>=0.7.0 <1.0.0` → `^1.0.3` and thus require MongoDB v3+
57
+ - async `^1.0.0` → `^2.6.0`
58
+ - Drop support for Node.js v4 and v5 (might still work but we're stopping testing these) (**BREAKING**)
59
+ - Switch testing with Mocha to [Ava](https://www.npmjs.com/package/ava) (#70)
60
+ - Docker support (#54) by WoLfulus
61
+ - Fix 404 errors when deleting and re-queuing jobs (#61) by koresar
62
+
63
+ # 0.4.0 / 2016-10-27
64
+
65
+ - (simison) Agenda dependency version `<1.0.0` to avoid breaking dependency.
66
+ - (loris) Fix #24 - Added indexes for faster queries.
67
+ - Fix #28 - Removed dependency on Mongo Driver.
68
+ - Added API tests with mocha and supertest. No frontend tests.
69
+
70
+ # 0.3.2 / 2016-06-30
71
+
72
+ - (HugoCornu) Fix #19 "Schedule Job" - Don't repeat job if user didn't want it repeated
73
+
74
+ # 0.3.1 / 2016-04-12
75
+
76
+ - (simison) Add engines key to package.json
77
+
78
+ # 0.3.0 / 2016-04-04
79
+
80
+ - (bh-chaker) Schedule Job Feature - create new jobs from the UI
81
+ - Limit to 200 jobs on page, no UI for configuration
82
+
83
+ # 0.2.1 / 2016-03-25
84
+
85
+ - (vziukas) Recurring job count and labels
86
+ - Fixed "queued" label colors
87
+
88
+ # 0.2.0 / 2016-03-18
89
+
90
+ - (vziukas) Configurable title
91
+ - Middleware option moved to "options" object
92
+
93
+ # 0.1.1 / 2016-03-17
94
+
95
+ - (vziukas) multiple instances of agendash can each have a separate agenda
96
+
97
+ # 0.1.0 / 2016-03-15
98
+
99
+ - (rapidia) remove "arrow function" syntax for non-chrome browsers
100
+ - (ebourmalo) Fix the middleware usage and use a proper structure
101
+
102
+ # 0.0.5 / 2016-02-24
103
+
104
+ - Batch requeue and delete
105
+ - Select All and Select None
106
+
107
+ # 0.0.4 / 2016-02-24
108
+
109
+ - Select multiple jobs
110
+
111
+ # 0.0.2 / 2016-02-23
112
+
113
+ - version bump so npm will update docs
114
+ - Added screenshots
115
+
116
+ # 0.0.1 / 2016-02-23
117
+
118
+ - Initial Release
@@ -54,7 +54,7 @@ fastify.register(
54
54
  })
55
55
  );
56
56
 
57
- fastify.listen(program.port, function () {
57
+ fastify.listen({ port: program.port }, function () {
58
58
  console.log(
59
59
  `Agendash started http://localhost:${program.port}${program.path}`
60
60
  );
@@ -42,7 +42,7 @@ module.exports = function (agenda, options) {
42
42
 
43
43
  if (options.query && options.property) {
44
44
  if (options.isObjectId) {
45
- preMatch[options.property] = ObjectId(options.query);
45
+ preMatch[options.property] = new ObjectId(options.query);
46
46
  } else if (/^\d+$/.test(options.query)) {
47
47
  preMatch[options.property] = Number.parseInt(options.query, 10);
48
48
  } else {
@@ -61,6 +61,7 @@ module.exports = function (agenda, options) {
61
61
  { $match: preMatch },
62
62
  {
63
63
  $sort: {
64
+ repeatInterval: -1,
64
65
  nextRunAt: -1,
65
66
  lastRunAt: -1,
66
67
  lastFinishedAt: -1,
@@ -284,7 +285,7 @@ module.exports = function (agenda, options) {
284
285
  const collection = agenda._collection.collection || agenda._collection;
285
286
  const jobs = await collection
286
287
  .find({
287
- _id: { $in: jobIds.map((jobId) => ObjectId(jobId)) },
288
+ _id: { $in: jobIds.map((jobId) => new ObjectId(jobId)) },
288
289
  })
289
290
  .toArray();
290
291
  if (jobs.length === 0) {
@@ -306,7 +307,7 @@ module.exports = function (agenda, options) {
306
307
  }
307
308
 
308
309
  return agenda.cancel({
309
- _id: { $in: jobIds.map((jobId) => ObjectId(jobId)) },
310
+ _id: { $in: jobIds.map((jobId) => new ObjectId(jobId)) },
310
311
  });
311
312
  };
312
313
 
@@ -4,7 +4,7 @@ const csp = require("../csp");
4
4
  module.exports = (agendash) => (instance, opts, done) => {
5
5
  const { api, requeueJobs, deleteJobs, createJob } = agendash;
6
6
 
7
- instance.register(require("fastify-static"), {
7
+ instance.register(require("@fastify/static"), {
8
8
  root: path.join(__dirname, "../../public"),
9
9
  });
10
10
 
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "agendash",
3
- "version": "3.1.0",
3
+ "version": "4.0.0",
4
4
  "description": "A modern dashboard for Agenda.js with Pagination and Search capabilities",
5
5
  "main": "app.js",
6
6
  "bin": "bin/agendash-standalone.js",
7
7
  "engines": {
8
- "node": ">=10.0.0"
8
+ "node": ">=14.0.0"
9
9
  },
10
10
  "scripts": {
11
11
  "test": "run-p lint ava",
@@ -38,19 +38,19 @@
38
38
  ],
39
39
  "dependencies": {
40
40
  "agenda": "^4.2.1",
41
- "body-parser": "^1.15.0",
41
+ "body-parser": "^1.19.2",
42
42
  "commander": "^2.9.0",
43
- "express": "^4.0.0",
43
+ "express": "^4.17.3",
44
44
  "mongodb": "*",
45
45
  "semver": "^7.3.4"
46
46
  },
47
47
  "devDependencies": {
48
+ "@fastify/static": "^6.5.0",
48
49
  "@hapi/hapi": "^20.2.1",
49
50
  "@hapi/inert": "^6.0.5",
50
51
  "ava": "3.15.0",
51
52
  "eslint": "7.19.0",
52
- "fastify": "^3.24.0",
53
- "fastify-static": "^4.5.0",
53
+ "fastify": "^4.9.2",
54
54
  "koa": "2.13.1",
55
55
  "koa-bodyparser": "4.3.0",
56
56
  "koa-router": "10.0.0",
@@ -122,8 +122,20 @@ code {
122
122
  margin: 0 2px;
123
123
  }
124
124
 
125
+ .job-detail-dialog {
126
+ max-width: calc(100vw - 1.75rem * 2);
127
+ }
128
+ .modal-body > * {
129
+ flex: 0 1 auto;
130
+ }
131
+ .modal-body {
132
+ display: flex;
133
+ flex-flow: column;
134
+ max-height: calc(100vh - 195px);
135
+ }
136
+
125
137
  .json-editor {
126
- height: 150px;
138
+ flex: 1 1 auto;
127
139
  }
128
140
  .card-responsive-title-container {
129
141
  display: flex;
@@ -13,7 +13,7 @@ const jobDetail = Vue.component("job-detail", {
13
13
  template: `
14
14
  <div class="modal fade" id="modalData" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
15
15
  <!-- Modal -->
16
- <div class="modal-dialog" role="document">
16
+ <div class="modal-dialog job-detail-dialog" role="document">
17
17
  <div class="modal-content">
18
18
  <div class="modal-header">
19
19
  <h5 class="modal-title" id="exampleModalLabel">Job Data - {{job.job.name}}</h5>
@@ -4,10 +4,10 @@ const jobList = Vue.component("job-list", {
4
4
  currentSort: "name",
5
5
  currentSortDir: "asc",
6
6
  }),
7
- props: ["jobs", "pagesize", "pagenumber", "sendClean", "loading"],
7
+ props: ["jobs", "pagesize", "pagenumber", "totalPages", "sendClean", "loading"],
8
8
  computed: {
9
9
  sortedJobs: function () {
10
- return this.jobs.sort((a, b) => {
10
+ var sortedJobs = this.jobs.sort((a, b) => {
11
11
  let displayA, displayB;
12
12
  if (this.currentSort === "name") {
13
13
  displayA = a.job[this.currentSort]
@@ -26,6 +26,12 @@ const jobList = Vue.component("job-list", {
26
26
  if (displayA > displayB) return 1 * modifier;
27
27
  return 0;
28
28
  });
29
+
30
+ /** Show recurring jobs first */
31
+ return Array.prototype.concat(
32
+ sortedJobs.filter(job => job.repeating === true),
33
+ sortedJobs.filter(job => job.repeating === false),
34
+ )
29
35
  },
30
36
  },
31
37
  watch: {
@@ -226,14 +232,17 @@ const jobList = Vue.component("job-list", {
226
232
  <nav aria-label="Page navigation example">
227
233
  <ul class="pagination">
228
234
  <li class="page-item" :class="pagenumber === 1 ? 'disabled': ''"><a class="page-link" @click="$emit('pagechange', 'prev')">Previous</a></li>
229
- <!-- <li class="page-item" :class="pagenumber === 1 ? 'disabled': ''"><a class="page-link" @click="$emit('pagechange', 'prev')">{{pagenumber -1}}</a></li>
230
- <li class="page-item active"><a class="page-link">{{pagenumber}}</a></li>
231
- <li class="page-item"><a style="cursor:pointer;" class="page-link" @click="$emit('pagechange', 'next')">{{pagenumber +1}}</a></li> -->
232
- <li class="page-item"><a style="cursor:pointer;" class="page-link" @click="$emit('pagechange', 'next')">Next</a></li>
235
+ <li class="page-item" :class="pagenumber >= totalPages ? 'disabled': ''"> <a style="cursor:pointer;" class="page-link" @click="$emit('pagechange', 'next')">Next</a> </li>
233
236
  </ul>
234
237
  </nav>
235
238
  </div>
236
239
  </div>
240
+
241
+ <div class="row">
242
+ <div class="col d-flex justify-content-center">
243
+ Page: {{pagenumber}} / {{totalPages}}
244
+ </div>
245
+ </div>
237
246
  </div>
238
247
  `,
239
248
  });
@@ -2,9 +2,10 @@ const app = Vue.component("app", {
2
2
  data: () => ({
3
3
  jobs: [],
4
4
  overview: [],
5
- refresh: 60,
5
+ refresh: 30,
6
6
  showDetail: false,
7
7
  pagenumber: 1,
8
+ totalPages: 0,
8
9
  showConfirm: false,
9
10
  showConfirmMulti: false,
10
11
  showConfirmRequeue: false,
@@ -13,7 +14,7 @@ const app = Vue.component("app", {
13
14
  jobData: {},
14
15
  deletec: false,
15
16
  requeuec: false,
16
- pagesize: 15,
17
+ pagesize: 50,
17
18
  sendClean: false,
18
19
  createc: false,
19
20
  property: "",
@@ -66,14 +67,19 @@ const app = Vue.component("app", {
66
67
  this.showNewJob = true;
67
68
  },
68
69
  searchForm(name, search, property, limit, skip, refresh, state, object) {
69
- (this.pagesize = limit ? limit : this.pagesize),
70
- (this.name = name),
71
- (this.search = search),
72
- (this.property = property),
73
- (this.skip = skip),
74
- (this.refresh = refresh),
75
- (this.state = state),
76
- (this.object = object ? object : this.object),
70
+ this.pagesize = limit ? limit : this.pagesize
71
+ this.name = name
72
+ this.search = search
73
+ this.property = property
74
+ this.skip = skip
75
+ this.refresh = refresh
76
+ this.state = state
77
+ this.object = object ? object : this.object
78
+
79
+ // Form changed, reset the pagination state
80
+ this.pagenumber = 1
81
+ this.totalPages = 1
82
+
77
83
  this.fetchData(
78
84
  this.name,
79
85
  this.search,
@@ -120,9 +126,9 @@ const app = Vue.component("app", {
120
126
  name = "",
121
127
  search = "",
122
128
  property = "",
123
- limit = 15,
129
+ limit = 50,
124
130
  skip = 0,
125
- refresh = 60,
131
+ refresh = 30,
126
132
  state = "",
127
133
  object
128
134
  ) {
@@ -143,6 +149,7 @@ const app = Vue.component("app", {
143
149
  this.object = object;
144
150
  this.overview = data.overview;
145
151
  this.loading = false;
152
+ this.totalPages = data.totalPages;
146
153
  },
147
154
  () => {
148
155
  this.loading = false;
@@ -229,7 +236,7 @@ const app = Vue.component("app", {
229
236
  >
230
237
  </sidebar>
231
238
  </div>
232
- <main role="main" class="col-md-10 ml-sm-auto col-lg-10 px-4">
239
+ <main role="main" class="col-md-10 ml-sm-auto col-lg-10 px-4 pt-3 pb-5">
233
240
  <div class="col-12">
234
241
  <topbar v-on:search-form="searchForm"
235
242
  :name='name'
@@ -249,6 +256,7 @@ const app = Vue.component("app", {
249
256
  v-on:pagechange="pagechange"
250
257
  :pagesize="pagesize"
251
258
  :pagenumber='pagenumber'
259
+ :totalPages='totalPages'
252
260
  :skip="skip"
253
261
  :jobs="jobs"
254
262
  :sendClean='sendClean'
@@ -63,7 +63,7 @@ const sidebar = Vue.component("sidebar", {
63
63
  },
64
64
  },
65
65
  template: `
66
- <div class="col sidebar">
66
+ <div class="col sidebar pt-4">
67
67
  <div class="row">
68
68
  <div class="col ">
69
69
  <button data-toggle="modal" data-target="#modalNewJob" @click="$emit('new-job')" data-placement="top" title="Add a new job" class="btn btn-block btn-outline-success"><i class="oi oi-plus IcoInButton"></i> New Job</button>
@@ -4,9 +4,9 @@ const topbar = Vue.component("topbar", {
4
4
  // search: '',
5
5
  // property: 'data.id',
6
6
  // name: '',
7
- limit: 15,
7
+ limit: 50,
8
8
  skip: 0,
9
- refresh: 60,
9
+ refresh: 30,
10
10
  // state: '',
11
11
  object: false,
12
12
  stateobject: [