agendash 4.0.0 → 6.0.1
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/LICENSE.md +25 -0
- package/README.md +109 -200
- package/dist/AgendashController.d.ts +50 -0
- package/dist/AgendashController.js +176 -0
- package/dist/AgendashController.js.map +1 -0
- package/dist/csp.d.ts +1 -0
- package/dist/csp.js +15 -0
- package/dist/csp.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/middlewares/express.d.ts +22 -0
- package/dist/middlewares/express.js +119 -0
- package/dist/middlewares/express.js.map +1 -0
- package/dist/middlewares/fastify.d.ts +18 -0
- package/dist/middlewares/fastify.js +129 -0
- package/dist/middlewares/fastify.js.map +1 -0
- package/dist/middlewares/hapi.d.ts +28 -0
- package/dist/middlewares/hapi.js +198 -0
- package/dist/middlewares/hapi.js.map +1 -0
- package/dist/middlewares/koa.d.ts +25 -0
- package/dist/middlewares/koa.js +139 -0
- package/dist/middlewares/koa.js.map +1 -0
- package/dist/types.d.ts +154 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +77 -62
- package/public/assets/index-CIdOb8D1.css +5 -0
- package/public/assets/index-Ct6Ovrls.js +17 -0
- package/public/index.html +10 -52
- package/Dockerfile +0 -23
- package/History.md +0 -118
- package/LICENSE +0 -21
- package/all-jobs.png +0 -0
- package/app.js +0 -23
- package/bin/agendash-standalone-fastify.js +0 -61
- package/bin/agendash-standalone-hapi.js +0 -60
- package/bin/agendash-standalone-koa.js +0 -56
- package/bin/agendash-standalone.js +0 -64
- package/create-job.png +0 -0
- package/entrypoint.sh +0 -5
- package/lib/controllers/agendash.js +0 -341
- package/lib/csp.js +0 -28
- package/lib/middlewares/README.md +0 -59
- package/lib/middlewares/express.js +0 -80
- package/lib/middlewares/fastify.js +0 -77
- package/lib/middlewares/hapi.js +0 -101
- package/lib/middlewares/koa.js +0 -77
- package/mobile-ui-sm.png +0 -0
- package/mobile-ui-xs.png +0 -0
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/app/assets/ArgensdashV2Logo.svg +0 -18
- package/public/app/css/styles.css +0 -233
- package/public/app/js/confirmDelete.js +0 -40
- package/public/app/js/confirmDeleteMulti.js +0 -45
- package/public/app/js/confirmRequeue.js +0 -40
- package/public/app/js/confirmRequeueMulti.js +0 -45
- package/public/app/js/confirms.js +0 -8
- package/public/app/js/jobdetail.js +0 -48
- package/public/app/js/joblist.js +0 -248
- package/public/app/js/main.js +0 -283
- package/public/app/js/newJob.js +0 -89
- package/public/app/js/sidebar.js +0 -121
- package/public/app/js/topbar.js +0 -95
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/site.webmanifest +0 -1
- package/search.png +0 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## License
|
|
2
|
+
(The MIT License)
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2013 Ryan Schmukler <ryan@slingingcode.com>
|
|
5
|
+
|
|
6
|
+
Copyright (c) 2022-2026 Simon Tretter <s.tretter@gmail.com>
|
|
7
|
+
|
|
8
|
+
Contributors: Mikael Korpela, Alexis Tyler, Vasyl Boroviak, Haris Sulaiman, Loris Guignard
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
11
|
+
this software and associated documentation files (the 'Software'), to deal in
|
|
12
|
+
the Software without restriction, including without limitation the rights to
|
|
13
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
14
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
15
|
+
subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
22
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
23
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
24
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
25
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,253 +1,162 @@
|
|
|
1
1
|
# Agendash
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A modern dashboard for [Agenda](https://github.com/agenda/agenda) job scheduler.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+

|
|
6
6
|
|
|
7
|
-
|
|
7
|
+

|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- Schedule a new job from the UI.
|
|
11
|
-
- Dive in to see more details about the job, like the json data.
|
|
12
|
-
- Requeue a job. Clone the data and run immediately.
|
|
13
|
-
- Delete jobs. Useful for cleaning up old completed jobs.
|
|
14
|
-
- Search jobs by name and metadata. Supports querying by Mongo Object Id.
|
|
15
|
-
- Pagination
|
|
16
|
-
- Responsive UI
|
|
9
|
+
## Installation
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
### Screenshots
|
|
21
|
-
|
|
22
|
-
#### Dashboard
|
|
23
|
-
|
|
24
|
-

|
|
25
|
-
|
|
26
|
-
---
|
|
27
|
-
|
|
28
|
-
#### Create jobs
|
|
29
|
-
|
|
30
|
-

|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
#### Search by name, metadata, job status
|
|
35
|
-
|
|
36
|
-

|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
#### Responsive UI
|
|
41
|
-
|
|
42
|
-

|
|
43
|
-
|
|
44
|
-

|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
# Troubleshooting
|
|
49
|
-
|
|
50
|
-
### Index for sorting
|
|
51
|
-
|
|
52
|
-
It may be required to create the following index for faster sorting (see [#24](https://github.com/agenda/agendash/issues/24))
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
db.agendaJobs.ensureIndex({
|
|
56
|
-
"nextRunAt" : -1,
|
|
57
|
-
"lastRunAt" : -1,
|
|
58
|
-
"lastFinishedAt" : -1
|
|
59
|
-
}, "agendash")
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
# Roadmap
|
|
65
|
-
|
|
66
|
-
- [ ] Get more test coverage
|
|
67
|
-
- [ ] Add middlewares for fastify, and other express-like libraries
|
|
68
|
-
- [ ] You decide! Submit a feature request
|
|
69
|
-
|
|
70
|
-
### Install
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
npm install --save agendash
|
|
11
|
+
```bash
|
|
12
|
+
npm install agendash agenda @agendajs/mongo-backend
|
|
74
13
|
```
|
|
75
14
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
### Middleware usage
|
|
79
|
-
|
|
80
|
-
#### Express
|
|
15
|
+
## Quick Start
|
|
81
16
|
|
|
82
|
-
|
|
83
|
-
make Agendash available on your site at the `/dash` path. Note: Do not try to mount Agendash
|
|
84
|
-
at the root level like `app.use('/', Agendash(agenda))`.
|
|
17
|
+
### Express
|
|
85
18
|
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
|
|
19
|
+
```typescript
|
|
20
|
+
import express from 'express';
|
|
21
|
+
import { Agenda } from 'agenda';
|
|
22
|
+
import { MongoBackend } from '@agendajs/mongo-backend';
|
|
23
|
+
import { expressMiddleware } from 'agendash';
|
|
89
24
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
25
|
+
const app = express();
|
|
26
|
+
const agenda = new Agenda({
|
|
27
|
+
backend: new MongoBackend({ address: 'mongodb://localhost:27017/agenda' })
|
|
28
|
+
});
|
|
94
29
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// var agenda = new Agenda({mongo: myMongoClient})
|
|
30
|
+
// Mount agendash at /dash
|
|
31
|
+
app.use('/dash', expressMiddleware(agenda));
|
|
98
32
|
|
|
99
|
-
app.
|
|
33
|
+
app.listen(3000, () => {
|
|
34
|
+
console.log('Dashboard: http://localhost:3000/dash');
|
|
35
|
+
});
|
|
36
|
+
```
|
|
100
37
|
|
|
101
|
-
|
|
38
|
+
### Fastify
|
|
102
39
|
|
|
103
|
-
|
|
104
|
-
|
|
40
|
+
```typescript
|
|
41
|
+
import Fastify from 'fastify';
|
|
42
|
+
import { Agenda } from 'agenda';
|
|
43
|
+
import { MongoBackend } from '@agendajs/mongo-backend';
|
|
44
|
+
import { fastifyPlugin } from 'agendash';
|
|
105
45
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
```js
|
|
111
|
-
app.use(
|
|
112
|
-
"/dash",
|
|
113
|
-
function (req, res, next) {
|
|
114
|
-
if (!req.user || !req.user.is_admin) {
|
|
115
|
-
res.send(401);
|
|
116
|
-
} else {
|
|
117
|
-
next();
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
Agendash(agenda)
|
|
121
|
-
);
|
|
122
|
-
```
|
|
46
|
+
const fastify = Fastify();
|
|
47
|
+
const agenda = new Agenda({
|
|
48
|
+
backend: new MongoBackend({ address: 'mongodb://localhost:27017/agenda' })
|
|
49
|
+
});
|
|
123
50
|
|
|
124
|
-
|
|
125
|
-
|
|
51
|
+
// Register agendash at /dash
|
|
52
|
+
fastify.register(fastifyPlugin(agenda), { prefix: '/dash' });
|
|
126
53
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
Agendash(agenda, {
|
|
131
|
-
middleware: "connect",
|
|
132
|
-
})
|
|
133
|
-
);
|
|
54
|
+
fastify.listen({ port: 3000 }, () => {
|
|
55
|
+
console.log('Dashboard: http://localhost:3000/dash');
|
|
56
|
+
});
|
|
134
57
|
```
|
|
135
58
|
|
|
136
|
-
|
|
59
|
+
### Koa
|
|
137
60
|
|
|
138
|
-
|
|
61
|
+
```typescript
|
|
62
|
+
import Koa from 'koa';
|
|
63
|
+
import Router from 'koa-router';
|
|
64
|
+
import { Agenda } from 'agenda';
|
|
65
|
+
import { MongoBackend } from '@agendajs/mongo-backend';
|
|
66
|
+
import { koaMiddleware } from 'agendash';
|
|
139
67
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
```
|
|
68
|
+
const app = new Koa();
|
|
69
|
+
const agenda = new Agenda({
|
|
70
|
+
backend: new MongoBackend({ address: 'mongodb://localhost:27017/agenda' })
|
|
71
|
+
});
|
|
145
72
|
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
);
|
|
73
|
+
// Mount agendash at /dash
|
|
74
|
+
const { router, middleware } = koaMiddleware(agenda, '/dash');
|
|
75
|
+
app.use(middleware);
|
|
76
|
+
app.use(router.routes());
|
|
77
|
+
app.use(router.allowedMethods());
|
|
151
78
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
host: "localhost",
|
|
79
|
+
app.listen(3000, () => {
|
|
80
|
+
console.log('Dashboard: http://localhost:3000/dash');
|
|
155
81
|
});
|
|
156
|
-
await server.register(require("@hapi/inert"));
|
|
157
|
-
await server.register(
|
|
158
|
-
Agendash(agenda, {
|
|
159
|
-
middleware: "hapi",
|
|
160
|
-
})
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
await server.start();
|
|
164
82
|
```
|
|
165
83
|
|
|
166
|
-
|
|
84
|
+
### Hapi
|
|
167
85
|
|
|
168
|
-
|
|
86
|
+
```typescript
|
|
87
|
+
import Hapi from '@hapi/hapi';
|
|
88
|
+
import { Agenda } from 'agenda';
|
|
89
|
+
import { MongoBackend } from '@agendajs/mongo-backend';
|
|
90
|
+
import { hapiPlugin } from 'agendash';
|
|
169
91
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
92
|
+
const agenda = new Agenda({
|
|
93
|
+
backend: new MongoBackend({ address: 'mongodb://localhost:27017/agenda' })
|
|
94
|
+
});
|
|
173
95
|
|
|
174
|
-
|
|
175
|
-
const agenda = new Agenda().database(
|
|
176
|
-
"mongodb://127.0.0.1/agendaDb",
|
|
177
|
-
"agendaJobs"
|
|
178
|
-
);
|
|
96
|
+
const server = Hapi.server({ port: 3000 });
|
|
179
97
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
middleware: "koa",
|
|
98
|
+
await server.register({
|
|
99
|
+
plugin: hapiPlugin(agenda),
|
|
100
|
+
options: { basePath: '/dash' }
|
|
184
101
|
});
|
|
185
|
-
for (const middleware of middlewares) {
|
|
186
|
-
app.use(middleware);
|
|
187
|
-
}
|
|
188
102
|
|
|
189
|
-
await
|
|
103
|
+
await server.start();
|
|
104
|
+
console.log('Dashboard: http://localhost:3000/dash');
|
|
190
105
|
```
|
|
191
106
|
|
|
192
|
-
|
|
107
|
+
## Security
|
|
193
108
|
|
|
194
|
-
|
|
109
|
+
**Important:** The Agendash dashboard provides full access to view, create, requeue, and delete jobs. You should **always protect it with authentication** before deploying to production.
|
|
195
110
|
|
|
196
|
-
|
|
197
|
-
npm i fastify
|
|
198
|
-
```
|
|
111
|
+
Example with basic auth (Express):
|
|
199
112
|
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
"mongodb://127.0.0.1/agendaDb",
|
|
203
|
-
"agendaJobs"
|
|
204
|
-
);
|
|
113
|
+
```typescript
|
|
114
|
+
import basicAuth from 'express-basic-auth';
|
|
205
115
|
|
|
206
|
-
|
|
207
|
-
|
|
116
|
+
// Protect the dashboard with basic auth
|
|
117
|
+
app.use('/dash', basicAuth({
|
|
118
|
+
users: { 'admin': 'secure-password' },
|
|
119
|
+
challenge: true
|
|
120
|
+
}));
|
|
208
121
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
agenda,
|
|
212
|
-
{ middleware: "fastify" }
|
|
213
|
-
);
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
await fastify.listen(3002);
|
|
122
|
+
// Then mount agendash
|
|
123
|
+
app.use('/dash', expressMiddleware(agenda));
|
|
217
124
|
```
|
|
218
125
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
126
|
+
For production environments, consider using:
|
|
127
|
+
- Session-based authentication with your existing auth system
|
|
128
|
+
- OAuth/SSO integration
|
|
129
|
+
- IP-based access control (e.g., only accessible from internal network)
|
|
130
|
+
- A reverse proxy with authentication (e.g., nginx with auth_basic)
|
|
222
131
|
|
|
223
|
-
|
|
132
|
+
**Never expose the dashboard to the public internet without authentication.**
|
|
224
133
|
|
|
225
|
-
|
|
226
|
-
./node_modules/.bin/agendash --db=mongodb://localhost/agendaDb --collection=agendaCollection --port=3002
|
|
227
|
-
```
|
|
134
|
+
## Features
|
|
228
135
|
|
|
229
|
-
|
|
136
|
+
- **Job Overview**: View all jobs organized by name with status counts
|
|
137
|
+
- **Job States**: See jobs by state (scheduled, queued, running, completed, failed, repeating)
|
|
138
|
+
- **Agenda Status**: Live view of running/queued/locked jobs and configuration
|
|
139
|
+
- **Filtering**: Filter jobs by name, state, or search within job data
|
|
140
|
+
- **Job Management**: Create, requeue, and delete jobs
|
|
141
|
+
- **Bulk Operations**: Multi-select jobs for bulk requeue or delete
|
|
142
|
+
- **Job Details**: View job data, timestamps, and failure information
|
|
143
|
+
- **Auto-refresh**: Dashboard refreshes automatically with countdown indicator
|
|
144
|
+
- **Mobile Responsive**: Works on desktop and mobile devices
|
|
230
145
|
|
|
231
|
-
|
|
232
|
-
./node_modules/.bin/agendash --db=mongodb://localhost/agendaDb
|
|
233
|
-
```
|
|
146
|
+
## Development
|
|
234
147
|
|
|
235
|
-
|
|
148
|
+
To run agendash in development mode with hot reloading:
|
|
236
149
|
|
|
237
150
|
```bash
|
|
238
|
-
|
|
151
|
+
# From the agendash package directory
|
|
152
|
+
pnpm dev
|
|
239
153
|
```
|
|
240
154
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
155
|
+
This starts a development server with:
|
|
156
|
+
- Vite dev server for frontend hot reloading
|
|
157
|
+
- Express API server
|
|
158
|
+
- In-memory MongoDB (no external database required)
|
|
244
159
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
```bash
|
|
248
|
-
docker run -p 3000:3000 \
|
|
249
|
-
--env MONGODB_URI=mongo://myUser:myPass@myHost/myDb \
|
|
250
|
-
--env COLLECTION=myAgendaCollection agenda/agendash
|
|
251
|
-
```
|
|
160
|
+
## License
|
|
252
161
|
|
|
253
|
-
|
|
162
|
+
MIT
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Agenda, AgendaStatus } from 'agenda';
|
|
2
|
+
import type { AgendashController as IAgendashController, ApiQueryParams, ApiResponse, CreateJobRequest, CreateJobResponse, DeleteResponse, RequeueResponse, PauseResponse, ResumeResponse } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Agendash Controller - Core logic for dashboard operations
|
|
5
|
+
*
|
|
6
|
+
* Uses the database-agnostic Agenda API (v6) for all operations:
|
|
7
|
+
* - agenda.queryJobs() for filtering, pagination, state computation
|
|
8
|
+
* - agenda.getJobsOverview() for statistics
|
|
9
|
+
* - agenda.cancel() for deletion
|
|
10
|
+
*/
|
|
11
|
+
export declare class AgendashController implements IAgendashController {
|
|
12
|
+
private agenda;
|
|
13
|
+
constructor(agenda: Agenda);
|
|
14
|
+
/**
|
|
15
|
+
* Transform a job from the new API format to the frontend format
|
|
16
|
+
*/
|
|
17
|
+
private transformJob;
|
|
18
|
+
/**
|
|
19
|
+
* Transform overview from new API format to frontend format
|
|
20
|
+
*/
|
|
21
|
+
private transformOverview;
|
|
22
|
+
/**
|
|
23
|
+
* Get jobs with overview and filtering
|
|
24
|
+
*/
|
|
25
|
+
getJobs(params: ApiQueryParams): Promise<ApiResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* Requeue jobs by creating new instances
|
|
28
|
+
*/
|
|
29
|
+
requeueJobs(ids: string[]): Promise<RequeueResponse>;
|
|
30
|
+
/**
|
|
31
|
+
* Delete jobs by ID
|
|
32
|
+
*/
|
|
33
|
+
deleteJobs(ids: string[]): Promise<DeleteResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Create a new job
|
|
36
|
+
*/
|
|
37
|
+
createJob(options: CreateJobRequest): Promise<CreateJobResponse>;
|
|
38
|
+
/**
|
|
39
|
+
* Get running stats from the Agenda processor
|
|
40
|
+
*/
|
|
41
|
+
getStats(fullDetails?: boolean): Promise<AgendaStatus>;
|
|
42
|
+
/**
|
|
43
|
+
* Pause jobs by ID (disables them so they won't run)
|
|
44
|
+
*/
|
|
45
|
+
pauseJobs(ids: string[]): Promise<PauseResponse>;
|
|
46
|
+
/**
|
|
47
|
+
* Resume jobs by ID (re-enables them so they can run)
|
|
48
|
+
*/
|
|
49
|
+
resumeJobs(ids: string[]): Promise<ResumeResponse>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agendash Controller - Core logic for dashboard operations
|
|
3
|
+
*
|
|
4
|
+
* Uses the database-agnostic Agenda API (v6) for all operations:
|
|
5
|
+
* - agenda.queryJobs() for filtering, pagination, state computation
|
|
6
|
+
* - agenda.getJobsOverview() for statistics
|
|
7
|
+
* - agenda.cancel() for deletion
|
|
8
|
+
*/
|
|
9
|
+
export class AgendashController {
|
|
10
|
+
agenda;
|
|
11
|
+
constructor(agenda) {
|
|
12
|
+
this.agenda = agenda;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Transform a job from the new API format to the frontend format
|
|
16
|
+
*/
|
|
17
|
+
transformJob(job) {
|
|
18
|
+
return {
|
|
19
|
+
job: {
|
|
20
|
+
_id: String(job._id),
|
|
21
|
+
name: job.name,
|
|
22
|
+
data: job.data,
|
|
23
|
+
priority: job.priority,
|
|
24
|
+
nextRunAt: job.nextRunAt,
|
|
25
|
+
lastRunAt: job.lastRunAt,
|
|
26
|
+
lastFinishedAt: job.lastFinishedAt,
|
|
27
|
+
lockedAt: job.lockedAt,
|
|
28
|
+
failedAt: job.failedAt,
|
|
29
|
+
failCount: job.failCount,
|
|
30
|
+
failReason: job.failReason,
|
|
31
|
+
repeatInterval: job.repeatInterval,
|
|
32
|
+
repeatTimezone: job.repeatTimezone,
|
|
33
|
+
disabled: job.disabled
|
|
34
|
+
},
|
|
35
|
+
running: job.state === 'running',
|
|
36
|
+
scheduled: job.state === 'scheduled',
|
|
37
|
+
queued: job.state === 'queued',
|
|
38
|
+
completed: job.state === 'completed',
|
|
39
|
+
failed: job.state === 'failed',
|
|
40
|
+
repeating: job.state === 'repeating',
|
|
41
|
+
paused: job.disabled === true
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Transform overview from new API format to frontend format
|
|
46
|
+
*/
|
|
47
|
+
transformOverview(overviews) {
|
|
48
|
+
// Calculate totals for "All Jobs" entry
|
|
49
|
+
const totals = overviews.reduce((acc, o) => ({
|
|
50
|
+
total: acc.total + o.total,
|
|
51
|
+
running: acc.running + o.running,
|
|
52
|
+
scheduled: acc.scheduled + o.scheduled,
|
|
53
|
+
queued: acc.queued + o.queued,
|
|
54
|
+
completed: acc.completed + o.completed,
|
|
55
|
+
failed: acc.failed + o.failed,
|
|
56
|
+
repeating: acc.repeating + o.repeating,
|
|
57
|
+
paused: acc.paused + o.paused
|
|
58
|
+
}), { total: 0, running: 0, scheduled: 0, queued: 0, completed: 0, failed: 0, repeating: 0, paused: 0 });
|
|
59
|
+
const allJobsEntry = {
|
|
60
|
+
displayName: 'All Jobs',
|
|
61
|
+
...totals
|
|
62
|
+
};
|
|
63
|
+
const jobOverviews = overviews.map((o) => ({
|
|
64
|
+
displayName: o.name,
|
|
65
|
+
total: o.total,
|
|
66
|
+
running: o.running,
|
|
67
|
+
scheduled: o.scheduled,
|
|
68
|
+
queued: o.queued,
|
|
69
|
+
completed: o.completed,
|
|
70
|
+
failed: o.failed,
|
|
71
|
+
repeating: o.repeating,
|
|
72
|
+
paused: o.paused
|
|
73
|
+
}));
|
|
74
|
+
return [allJobsEntry, ...jobOverviews];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get jobs with overview and filtering
|
|
78
|
+
*/
|
|
79
|
+
async getJobs(params) {
|
|
80
|
+
const { name, state, search, skip = 0, limit = 50 } = params;
|
|
81
|
+
const [overview, result] = await Promise.all([
|
|
82
|
+
this.agenda.getJobsOverview(),
|
|
83
|
+
this.agenda.queryJobs({
|
|
84
|
+
name: name || undefined,
|
|
85
|
+
state: state,
|
|
86
|
+
search: search || undefined,
|
|
87
|
+
skip,
|
|
88
|
+
limit,
|
|
89
|
+
sort: { nextRunAt: 'desc' }
|
|
90
|
+
})
|
|
91
|
+
]);
|
|
92
|
+
const transformedJobs = result.jobs.map((job) => this.transformJob(job));
|
|
93
|
+
const transformedOverview = this.transformOverview(overview);
|
|
94
|
+
const totalPages = Math.ceil(result.total / limit) || 1;
|
|
95
|
+
return {
|
|
96
|
+
overview: transformedOverview,
|
|
97
|
+
jobs: transformedJobs,
|
|
98
|
+
total: result.total,
|
|
99
|
+
totalPages
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Requeue jobs by creating new instances
|
|
104
|
+
*/
|
|
105
|
+
async requeueJobs(ids) {
|
|
106
|
+
if (!ids || ids.length === 0) {
|
|
107
|
+
return { requeuedCount: 0 };
|
|
108
|
+
}
|
|
109
|
+
const { jobs } = await this.agenda.queryJobs({ ids });
|
|
110
|
+
let requeuedCount = 0;
|
|
111
|
+
for (const job of jobs) {
|
|
112
|
+
await this.agenda.now(job.name, job.data);
|
|
113
|
+
requeuedCount++;
|
|
114
|
+
}
|
|
115
|
+
return { requeuedCount };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Delete jobs by ID
|
|
119
|
+
*/
|
|
120
|
+
async deleteJobs(ids) {
|
|
121
|
+
if (!ids || ids.length === 0) {
|
|
122
|
+
return { deleted: false, deletedCount: 0 };
|
|
123
|
+
}
|
|
124
|
+
const deletedCount = await this.agenda.cancel({ ids });
|
|
125
|
+
return {
|
|
126
|
+
deleted: deletedCount > 0,
|
|
127
|
+
deletedCount
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create a new job
|
|
132
|
+
*/
|
|
133
|
+
async createJob(options) {
|
|
134
|
+
const { jobName, jobSchedule, jobRepeatEvery, jobData } = options;
|
|
135
|
+
if (!jobName) {
|
|
136
|
+
throw new Error('jobName is required');
|
|
137
|
+
}
|
|
138
|
+
if (jobRepeatEvery) {
|
|
139
|
+
await this.agenda.every(jobRepeatEvery, jobName, jobData);
|
|
140
|
+
}
|
|
141
|
+
else if (jobSchedule) {
|
|
142
|
+
await this.agenda.schedule(jobSchedule, jobName, jobData);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
await this.agenda.now(jobName, jobData);
|
|
146
|
+
}
|
|
147
|
+
return { created: true };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get running stats from the Agenda processor
|
|
151
|
+
*/
|
|
152
|
+
async getStats(fullDetails = false) {
|
|
153
|
+
return this.agenda.getRunningStats(fullDetails);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Pause jobs by ID (disables them so they won't run)
|
|
157
|
+
*/
|
|
158
|
+
async pauseJobs(ids) {
|
|
159
|
+
if (!ids || ids.length === 0) {
|
|
160
|
+
return { pausedCount: 0 };
|
|
161
|
+
}
|
|
162
|
+
const pausedCount = await this.agenda.disable({ ids });
|
|
163
|
+
return { pausedCount };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Resume jobs by ID (re-enables them so they can run)
|
|
167
|
+
*/
|
|
168
|
+
async resumeJobs(ids) {
|
|
169
|
+
if (!ids || ids.length === 0) {
|
|
170
|
+
return { resumedCount: 0 };
|
|
171
|
+
}
|
|
172
|
+
const resumedCount = await this.agenda.enable({ ids });
|
|
173
|
+
return { resumedCount };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=AgendashController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgendashController.js","sourceRoot":"","sources":["../src/AgendashController.ts"],"names":[],"mappings":"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"}
|
package/dist/csp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const cspHeader: string;
|
package/dist/csp.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Security Policy configuration for Agendash
|
|
3
|
+
* Since we now bundle all frontend assets with Vite, we only need 'self'
|
|
4
|
+
*/
|
|
5
|
+
const CSP = {
|
|
6
|
+
'default-src': ["'self'"],
|
|
7
|
+
'script-src': ["'self'"],
|
|
8
|
+
'style-src': ["'self'", "'unsafe-inline'"],
|
|
9
|
+
'font-src': ["'self'"],
|
|
10
|
+
'img-src': ["'self'", 'data:']
|
|
11
|
+
};
|
|
12
|
+
export const cspHeader = Object.entries(CSP)
|
|
13
|
+
.map(([type, values]) => `${type} ${values.join(' ')}`)
|
|
14
|
+
.join('; ');
|
|
15
|
+
//# sourceMappingURL=csp.js.map
|
package/dist/csp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csp.js","sourceRoot":"","sources":["../src/csp.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,GAAG,GAA6B;IACrC,aAAa,EAAE,CAAC,QAAQ,CAAC;IACzB,YAAY,EAAE,CAAC,QAAQ,CAAC;IACxB,WAAW,EAAE,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAC1C,UAAU,EAAE,CAAC,QAAQ,CAAC;IACtB,SAAS,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;KAC1C,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;KACtD,IAAI,CAAC,IAAI,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agendash - Dashboard for Agenda job scheduler
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { AgendashController } from './AgendashController.js';
|
|
7
|
+
export * from './types.js';
|
|
8
|
+
export { cspHeader } from './csp.js';
|
|
9
|
+
export { createExpressMiddleware } from './middlewares/express.js';
|
|
10
|
+
export { createKoaMiddleware, createKoaMiddlewareAsync } from './middlewares/koa.js';
|
|
11
|
+
export { createFastifyPlugin } from './middlewares/fastify.js';
|
|
12
|
+
export { createHapiPlugin } from './middlewares/hapi.js';
|