feat: Passwordless cross-device authentication

- Arkitektur: docs/auth/passwordless-architecture.md
- Backend: iom/quixzoom-auth-service/ (FastAPI + Redis)
- Webb: quixzoom-market-pages/se/login/ (QR-kod + polling)
- App: iom/quixzoom-app/src/features/auth/ (push + deep links)

Flöde: QR-kod → app-godkännande → webb-inloggad
This commit is contained in:
Bernt
2026-07-07 07:11:50 +00:00
parent 4aa984ad74
commit 6989a98d75
61843 changed files with 5491611 additions and 872231 deletions
+5
View File
@@ -0,0 +1,5 @@
import { ValidMetrics, AppQueue } from './app';
export interface GetQueues {
stats: Partial<ValidMetrics>;
queues: AppQueue[];
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=api.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/@types/api.ts"],"names":[],"mappings":""}
+68
View File
@@ -0,0 +1,68 @@
import { Job, JobOptions } from 'bull';
import { Job as JobMq, JobsOptions } from 'bullmq';
import * as Redis from 'ioredis';
import { Status } from '../ui/components/constants';
export declare type JobCleanStatus = 'completed' | 'wait' | 'active' | 'delayed' | 'failed';
export declare type JobStatus = Status;
export declare type JobCounts = Record<JobStatus, number>;
export interface QueueAdapter {
readonly readOnlyMode: boolean;
getClient(): Promise<Redis.Redis>;
getName(): string;
getJob(id: string): Promise<Job | JobMq | undefined | null>;
getJobs(jobStatuses: JobStatus[], start?: number, end?: number): Promise<(Job | JobMq)[]>;
getJobCounts(...jobStatuses: JobStatus[]): Promise<JobCounts>;
clean(queueStatus: JobCleanStatus, graceTimeMs: number): Promise<any>;
setFormatter(field: 'data' | 'returnValue', formatter: (data: any) => any): void;
format(field: 'data' | 'returnValue', data: any): any;
getJobLogs(jobId: string): Promise<string[]>;
}
export interface QueueAdapterOptions {
readOnlyMode: boolean;
}
export interface BullBoardQueue {
queue: QueueAdapter;
}
export interface BullBoardQueues {
[key: string]: BullBoardQueue;
}
export interface ValidMetrics {
total_system_memory: string;
redis_version: string;
used_memory: string;
mem_fragmentation_ratio: string;
connected_clients: string;
blocked_clients: string;
}
export interface AppJob {
id: string | number | undefined;
timestamp: number | null;
processedOn?: number | null;
finishedOn?: number | null;
progress: JobMq['progress'];
attempts: JobMq['attemptsMade'];
failedReason: JobMq['failedReason'];
stacktrace: string[];
opts: JobsOptions | JobOptions;
data: JobMq['data'];
name: JobMq['name'];
delay: number | undefined;
returnValue: string | Record<string | number, any> | null;
}
export interface AppQueue {
name: string;
counts: Record<Status, number>;
jobs: AppJob[];
readOnlyMode: boolean;
}
export declare type SelectedStatuses = Record<AppQueue['name'], Status>;
export interface QueueActions {
promoteJob: (queueName: string) => (job: AppJob) => () => Promise<void>;
retryJob: (queueName: string) => (job: AppJob) => () => Promise<void>;
cleanJob: (queueName: string) => (job: AppJob) => () => Promise<void>;
getJobLogs: (queueName: string) => (job: AppJob) => () => Promise<string[]>;
retryAll: (queueName: string) => () => Promise<void>;
cleanAllDelayed: (queueName: string) => () => Promise<void>;
cleanAllFailed: (queueName: string) => () => Promise<void>;
cleanAllCompleted: (queueName: string) => () => Promise<void>;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=app.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/@types/app.ts"],"names":[],"mappings":""}
+4
View File
@@ -0,0 +1,4 @@
declare module '*.css' {
const resource: Record<string, string>;
export = resource;
}
+2
View File
@@ -0,0 +1,2 @@
"use strict";
//# sourceMappingURL=global.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"global.js","sourceRoot":"","sources":["../../src/@types/global.ts"],"names":[],"mappings":""}
+1
View File
@@ -0,0 +1 @@
export declare type KeyOf<T> = Array<keyof T>;
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=utils.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/@types/utils.ts"],"names":[],"mappings":""}
+1
View File
@@ -0,0 +1 @@
export {};
+18
View File
@@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const dockest_1 = require("dockest");
const { run } = new dockest_1.Dockest({
dumpErrors: true,
jestLib: require('jest'),
logLevel: dockest_1.logLevel.DEBUG,
});
run([
{
serviceName: 'redis',
readinessCheck: async ({ defaultReadinessChecks: { redis } }) => {
await redis();
},
},
// eslint-disable-next-line no-console
]).catch((e) => console.error(e));
//# sourceMappingURL=dockest.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"dockest.js","sourceRoot":"","sources":["../src/dockest.ts"],"names":[],"mappings":";;AAAA,qCAA2C;AAE3C,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,iBAAO,CAAC;IAC1B,UAAU,EAAE,IAAI;IAChB,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;IACxB,QAAQ,EAAE,kBAAQ,CAAC,KAAK;CACzB,CAAC,CAAA;AAEF,GAAG,CAAC;IACF;QACE,WAAW,EAAE,OAAO;QACpB,cAAc,EAAE,KAAK,EAAE,EAAE,sBAAsB,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC9D,MAAM,KAAK,EAAE,CAAA;QACf,CAAC;KACF;IACD,sCAAsC;CACvC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA"}
+8
View File
@@ -0,0 +1,8 @@
import { Express } from 'express-serve-static-core';
import { QueueAdapter } from './@types/app';
export { BullMQAdapter } from './queueAdapters/bullMQ';
export { BullAdapter } from './queueAdapters/bull';
declare const router: Express;
export declare const setQueues: (bullQueues: ReadonlyArray<QueueAdapter>) => void;
export declare const replaceQueues: (bullQueues: ReadonlyArray<QueueAdapter>) => void;
export { router };
+56
View File
@@ -0,0 +1,56 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.router = exports.replaceQueues = exports.setQueues = exports.BullAdapter = exports.BullMQAdapter = void 0;
const express_1 = __importDefault(require("express"));
const path_1 = __importDefault(require("path"));
const cleanAll_1 = require("./routes/cleanAll");
const cleanJob_1 = require("./routes/cleanJob");
const errorHandler_1 = require("./routes/errorHandler");
const index_1 = require("./routes/index");
const jobLogs_1 = require("./routes/jobLogs");
const promoteJob_1 = require("./routes/promoteJob");
const queues_1 = require("./routes/queues");
const retryAll_1 = require("./routes/retryAll");
const retryJob_1 = require("./routes/retryJob");
var bullMQ_1 = require("./queueAdapters/bullMQ");
Object.defineProperty(exports, "BullMQAdapter", { enumerable: true, get: function () { return bullMQ_1.BullMQAdapter; } });
var bull_1 = require("./queueAdapters/bull");
Object.defineProperty(exports, "BullAdapter", { enumerable: true, get: function () { return bull_1.BullAdapter; } });
const bullBoardQueues = {};
const wrapAsync = (fn) => async (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
const router = express_1.default();
exports.router = router;
router.locals.bullBoardQueues = bullBoardQueues;
router.set('view engine', 'ejs');
router.set('views', path_1.default.resolve(__dirname, '../dist/ui'));
router.use('/static', express_1.default.static(path_1.default.resolve(__dirname, '../static')));
router.get(['/', '/queue/:queueName'], index_1.entryPoint);
router.get('/api/queues', wrapAsync(queues_1.queuesHandler));
router.put('/api/queues/:queueName/retry', wrapAsync(retryAll_1.retryAll));
router.put('/api/queues/:queueName/:id/retry', wrapAsync(retryJob_1.retryJob));
router.put('/api/queues/:queueName/:id/clean', wrapAsync(cleanJob_1.cleanJob));
router.put('/api/queues/:queueName/:id/promote', wrapAsync(promoteJob_1.promoteJob));
router.get('/api/queues/:queueName/:id/logs', wrapAsync(jobLogs_1.jobLogs));
router.put('/api/queues/:queueName/clean/:queueStatus', wrapAsync(cleanAll_1.cleanAll));
router.use(errorHandler_1.errorHandler);
const setQueues = (bullQueues) => {
bullQueues.forEach((queue) => {
const name = queue.getName();
bullBoardQueues[name] = { queue };
});
};
exports.setQueues = setQueues;
const replaceQueues = (bullQueues) => {
const queuesToPersist = bullQueues.map((queue) => queue.getName());
Object.keys(bullBoardQueues).forEach((name) => {
if (queuesToPersist.indexOf(name) === -1) {
delete bullBoardQueues[name];
}
});
return exports.setQueues(bullQueues);
};
exports.replaceQueues = replaceQueues;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA6B;AAM7B,gDAAuB;AAEvB,gDAA4C;AAC5C,gDAA4C;AAC5C,wDAAoD;AACpD,0CAA2C;AAC3C,8CAA0C;AAC1C,oDAAgD;AAEhD,4CAA+C;AAC/C,gDAA4C;AAC5C,gDAA4C;AAE5C,iDAAsD;AAA7C,uGAAA,aAAa,OAAA;AACtB,6CAAkD;AAAzC,mGAAA,WAAW,OAAA;AAEpB,MAAM,eAAe,GAAoB,EAAE,CAAA;AAE3C,MAAM,SAAS,GAAG,CAChB,EAA0B,EACF,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CACpD,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;AAEjD,MAAM,MAAM,GAAY,iBAAO,EAAE,CAAA;AAwCxB,wBAAM;AAvCf,MAAM,CAAC,MAAM,CAAC,eAAe,GAAG,eAAe,CAAA;AAE/C,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;AAChC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAA;AAE1D,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,iBAAO,CAAC,MAAM,CAAC,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;AAE3E,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,mBAAmB,CAAC,EAAE,kBAAU,CAAC,CAAA;AAClD,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,SAAS,CAAC,sBAAa,CAAC,CAAC,CAAA;AACnD,MAAM,CAAC,GAAG,CAAC,8BAA8B,EAAE,SAAS,CAAC,mBAAQ,CAAC,CAAC,CAAA;AAC/D,MAAM,CAAC,GAAG,CAAC,kCAAkC,EAAE,SAAS,CAAC,mBAAQ,CAAC,CAAC,CAAA;AACnE,MAAM,CAAC,GAAG,CAAC,kCAAkC,EAAE,SAAS,CAAC,mBAAQ,CAAC,CAAC,CAAA;AACnE,MAAM,CAAC,GAAG,CAAC,oCAAoC,EAAE,SAAS,CAAC,uBAAU,CAAC,CAAC,CAAA;AACvE,MAAM,CAAC,GAAG,CAAC,iCAAiC,EAAE,SAAS,CAAC,iBAAO,CAAC,CAAC,CAAA;AACjE,MAAM,CAAC,GAAG,CAAC,2CAA2C,EAAE,SAAS,CAAC,mBAAQ,CAAC,CAAC,CAAA;AAC5E,MAAM,CAAC,GAAG,CAAC,2BAAY,CAAC,CAAA;AAEjB,MAAM,SAAS,GAAG,CAAC,UAAuC,EAAQ,EAAE;IACzE,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAA;QAE5B,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AANY,QAAA,SAAS,aAMrB;AAEM,MAAM,aAAa,GAAG,CAC3B,UAAuC,EACjC,EAAE;IACR,MAAM,eAAe,GAAa,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;IAE5E,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC5C,IAAI,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;YACxC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAA;SAC7B;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,iBAAS,CAAC,UAAU,CAAC,CAAA;AAC9B,CAAC,CAAA;AAZY,QAAA,aAAa,iBAYzB"}
+1
View File
@@ -0,0 +1 @@
export {};
+211
View File
@@ -0,0 +1,211 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bullmq_1 = require("bullmq");
const supertest_1 = __importDefault(require("supertest"));
const bullBoard = __importStar(require("./index"));
const bullMQ_1 = require("./queueAdapters/bullMQ");
describe('index', () => {
it('should save the interface', () => {
expect(bullBoard).toMatchInlineSnapshot(`
Object {
"BullAdapter": [Function],
"BullMQAdapter": [Function],
"replaceQueues": [Function],
"router": [Function],
"setQueues": [Function],
}
`);
});
});
describe('happy', () => {
const { router, setQueues, replaceQueues } = bullBoard;
it('should be able to set queue', async () => {
const paintQueue = new bullMQ_1.BullMQAdapter(new bullmq_1.Queue('Paint', {
connection: {
host: 'localhost',
port: 6379,
},
}));
setQueues([paintQueue]);
await supertest_1.default(router)
.get('/api/queues')
.expect('Content-Type', /json/)
.expect(200)
.then((res) => {
expect(JSON.parse(res.text)).toMatchInlineSnapshot({
stats: {
blocked_clients: expect.any(String),
connected_clients: expect.any(String),
mem_fragmentation_ratio: expect.any(String),
redis_version: expect.any(String),
total_system_memory: expect.any(String),
used_memory: expect.any(String),
},
}, `
Object {
"queues": Array [
Object {
"counts": Object {
"active": 0,
"completed": 0,
"delayed": 0,
"failed": 0,
"paused": 0,
"waiting": 0,
},
"jobs": Array [],
"name": "Paint",
"readOnlyMode": false,
},
],
"stats": Object {
"blocked_clients": Any<String>,
"connected_clients": Any<String>,
"mem_fragmentation_ratio": Any<String>,
"redis_version": Any<String>,
"total_system_memory": Any<String>,
"used_memory": Any<String>,
},
}
`);
});
});
it('should be able to replace queues', async () => {
const paintQueue = new bullMQ_1.BullMQAdapter(new bullmq_1.Queue('Paint', {
connection: {
host: 'localhost',
port: 6379,
},
}));
const drainQueue = new bullMQ_1.BullMQAdapter(new bullmq_1.Queue('Drain', {
connection: {
host: 'localhost',
port: 6379,
},
}));
const codeQueue = new bullMQ_1.BullMQAdapter(new bullmq_1.Queue('Code', {
connection: {
host: 'localhost',
port: 6379,
},
}));
setQueues([paintQueue, drainQueue]);
replaceQueues([codeQueue]);
await supertest_1.default(router)
.get('/api/queues')
.expect('Content-Type', /json/)
.expect(200)
.then((res) => {
expect(JSON.parse(res.text)).toMatchInlineSnapshot({
stats: {
blocked_clients: expect.any(String),
connected_clients: expect.any(String),
mem_fragmentation_ratio: expect.any(String),
redis_version: expect.any(String),
total_system_memory: expect.any(String),
used_memory: expect.any(String),
},
}, `
Object {
"queues": Array [
Object {
"counts": Object {
"active": 0,
"completed": 0,
"delayed": 0,
"failed": 0,
"paused": 0,
"waiting": 0,
},
"jobs": Array [],
"name": "Code",
"readOnlyMode": false,
},
],
"stats": Object {
"blocked_clients": Any<String>,
"connected_clients": Any<String>,
"mem_fragmentation_ratio": Any<String>,
"redis_version": Any<String>,
"total_system_memory": Any<String>,
"used_memory": Any<String>,
},
}
`);
});
});
it('should be able to replace queues without initial set', async () => {
const codeQueue = new bullMQ_1.BullMQAdapter(new bullmq_1.Queue('Code', {
connection: {
host: 'localhost',
port: 6379,
},
}));
replaceQueues([codeQueue]);
await supertest_1.default(router)
.get('/api/queues')
.expect('Content-Type', /json/)
.expect(200)
.then((res) => {
expect(JSON.parse(res.text)).toMatchInlineSnapshot({
stats: {
blocked_clients: expect.any(String),
connected_clients: expect.any(String),
mem_fragmentation_ratio: expect.any(String),
redis_version: expect.any(String),
total_system_memory: expect.any(String),
used_memory: expect.any(String),
},
}, `
Object {
"queues": Array [
Object {
"counts": Object {
"active": 0,
"completed": 0,
"delayed": 0,
"failed": 0,
"paused": 0,
"waiting": 0,
},
"jobs": Array [],
"name": "Code",
"readOnlyMode": false,
},
],
"stats": Object {
"blocked_clients": Any<String>,
"connected_clients": Any<String>,
"mem_fragmentation_ratio": Any<String>,
"redis_version": Any<String>,
"total_system_memory": Any<String>,
"used_memory": Any<String>,
},
}
`);
});
});
});
//# sourceMappingURL=index.spec.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.spec.js","sourceRoot":"","sources":["../src/index.spec.ts"],"names":[],"mappings":"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"}
+18
View File
@@ -0,0 +1,18 @@
import { Job } from 'bull';
import { Job as JobMq } from 'bullmq';
import { JobCleanStatus, JobCounts, JobStatus, QueueAdapter, QueueAdapterOptions } from '../@types/app';
import * as Redis from 'ioredis';
export declare abstract class BaseAdapter implements QueueAdapter {
readonly readOnlyMode: boolean;
private formatters;
protected constructor(options?: Partial<QueueAdapterOptions>);
setFormatter(field: 'data' | 'returnValue', formatter: (data: any) => any): void;
format(field: 'data' | 'returnValue', data: any): any;
abstract clean(queueStatus: JobCleanStatus, graceTimeMs: number): Promise<void>;
abstract getJob(id: string): Promise<Job | JobMq | undefined | null>;
abstract getJobCounts(...jobStatuses: JobStatus[]): Promise<JobCounts>;
abstract getJobs(jobStatuses: JobStatus[], start?: number, end?: number): Promise<(Job | JobMq)[]>;
abstract getJobLogs(id: string): Promise<string[]>;
abstract getName(): string;
abstract getClient(): Promise<Redis.Redis>;
}
+20
View File
@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseAdapter = void 0;
class BaseAdapter {
constructor(options = {}) {
this.formatters = {};
this.readOnlyMode = options.readOnlyMode === true;
}
setFormatter(field, formatter) {
this.formatters[field] = formatter;
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
format(field, data) {
return typeof this.formatters[field] === 'function'
? this.formatters[field](data)
: data;
}
}
exports.BaseAdapter = BaseAdapter;
//# sourceMappingURL=base.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/queueAdapters/base.ts"],"names":[],"mappings":";;;AAWA,MAAsB,WAAW;IAI/B,YAAsB,UAAwC,EAAE;QAFxD,eAAU,GAAuC,EAAE,CAAA;QAGzD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,KAAK,IAAI,CAAA;IACnD,CAAC;IAEM,YAAY,CACjB,KAA6B,EAC7B,SAA6B;QAE7B,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IACpC,CAAC;IAED,6EAA6E;IACtE,MAAM,CAAC,KAA6B,EAAE,IAAS;QACpD,OAAO,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,UAAU;YACjD,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;YAC9B,CAAC,CAAC,IAAI,CAAA;IACV,CAAC;CAsBF;AA1CD,kCA0CC"}
+14
View File
@@ -0,0 +1,14 @@
import { Job, Queue } from 'bull';
import { JobCleanStatus, JobCounts, JobStatus, QueueAdapterOptions } from '../@types/app';
import { BaseAdapter } from './base';
export declare class BullAdapter extends BaseAdapter {
queue: Queue;
constructor(queue: Queue, options?: Partial<QueueAdapterOptions>);
getClient(): Promise<Queue['client']>;
getName(): string;
clean(jobStatus: JobCleanStatus, graceTimeMs: number): Promise<any>;
getJob(id: string): Promise<Job | undefined | null>;
getJobs(jobStatuses: JobStatus[], start?: number, end?: number): Promise<Job[]>;
getJobCounts(..._jobStatuses: JobStatus[]): Promise<JobCounts>;
getJobLogs(id: string): Promise<string[]>;
}
+34
View File
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BullAdapter = void 0;
const base_1 = require("./base");
class BullAdapter extends base_1.BaseAdapter {
constructor(queue, options = {}) {
super(options);
this.queue = queue;
}
getClient() {
return Promise.resolve(this.queue.client);
}
getName() {
return this.queue.name;
}
clean(jobStatus, graceTimeMs) {
return this.queue.clean(graceTimeMs, jobStatus);
}
getJob(id) {
return this.queue.getJob(id);
}
getJobs(jobStatuses, start, end) {
return this.queue.getJobs(jobStatuses, start, end);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getJobCounts(..._jobStatuses) {
return this.queue.getJobCounts();
}
getJobLogs(id) {
return this.queue.getJobLogs(id).then(({ logs }) => logs);
}
}
exports.BullAdapter = BullAdapter;
//# sourceMappingURL=bull.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"bull.js","sourceRoot":"","sources":["../../src/queueAdapters/bull.ts"],"names":[],"mappings":";;;AAOA,iCAAoC;AAEpC,MAAa,WAAY,SAAQ,kBAAW;IAC1C,YAAmB,KAAY,EAAE,UAAwC,EAAE;QACzE,KAAK,CAAC,OAAO,CAAC,CAAA;QADG,UAAK,GAAL,KAAK,CAAO;IAE/B,CAAC;IAEM,SAAS;QACd,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAC3C,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAA;IACxB,CAAC;IAEM,KAAK,CAAC,SAAyB,EAAE,WAAmB;QACzD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,SAAgB,CAAC,CAAA;IACxD,CAAC;IAEM,MAAM,CAAC,EAAU;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAC9B,CAAC;IAEM,OAAO,CACZ,WAAwB,EACxB,KAAc,EACd,GAAY;QAEZ,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAkB,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;IAC3D,CAAC;IAED,6DAA6D;IACtD,YAAY,CAAC,GAAG,YAAyB;QAC9C,OAAQ,IAAI,CAAC,KAAK,CAAC,YAAY,EAAoC,CAAA;IACrE,CAAC;IAEM,UAAU,CAAC,EAAU;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;IAC3D,CAAC;CACF;AArCD,kCAqCC"}
+15
View File
@@ -0,0 +1,15 @@
import { Job, Queue } from 'bullmq';
import { JobCleanStatus, JobCounts, JobStatus, QueueAdapterOptions } from '../@types/app';
import { BaseAdapter } from './base';
export declare class BullMQAdapter extends BaseAdapter {
private queue;
private readonly LIMIT;
constructor(queue: Queue, options?: Partial<QueueAdapterOptions>);
getClient(): Queue['client'];
getName(): string;
clean(jobStatus: JobCleanStatus, graceTimeMs: number): Promise<void>;
getJob(id: string): Promise<Job | undefined>;
getJobs(jobStatuses: JobStatus[], start?: number, end?: number): Promise<Job[]>;
getJobCounts(...jobStatuses: JobStatus[]): Promise<JobCounts>;
getJobLogs(id: string): Promise<string[]>;
}
+34
View File
@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BullMQAdapter = void 0;
const base_1 = require("./base");
class BullMQAdapter extends base_1.BaseAdapter {
constructor(queue, options = {}) {
super(options);
this.queue = queue;
this.LIMIT = 1000;
}
getClient() {
return this.queue.client;
}
getName() {
return this.queue.name;
}
clean(jobStatus, graceTimeMs) {
return this.queue.clean(graceTimeMs, this.LIMIT, jobStatus);
}
getJob(id) {
return this.queue.getJob(id);
}
getJobs(jobStatuses, start, end) {
return this.queue.getJobs(jobStatuses, start, end);
}
getJobCounts(...jobStatuses) {
return this.queue.getJobCounts(...jobStatuses);
}
getJobLogs(id) {
return this.queue.getJobLogs(id).then(({ logs }) => logs);
}
}
exports.BullMQAdapter = BullMQAdapter;
//# sourceMappingURL=bullMQ.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"bullMQ.js","sourceRoot":"","sources":["../../src/queueAdapters/bullMQ.ts"],"names":[],"mappings":";;;AAOA,iCAAoC;AAEpC,MAAa,aAAc,SAAQ,kBAAW;IAG5C,YACU,KAAY,EACpB,UAAwC,EAAE;QAE1C,KAAK,CAAC,OAAO,CAAC,CAAA;QAHN,UAAK,GAAL,KAAK,CAAO;QAHL,UAAK,GAAG,IAAI,CAAA;IAO7B,CAAC;IAEM,SAAS;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;IAC1B,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAA;IACxB,CAAC;IAEM,KAAK,CAAC,SAAyB,EAAE,WAAmB;QACzD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IAC7D,CAAC;IAEM,MAAM,CAAC,EAAU;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAC9B,CAAC;IAEM,OAAO,CACZ,WAAwB,EACxB,KAAc,EACd,GAAY;QAEZ,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAA;IACpD,CAAC;IAEM,YAAY,CAAC,GAAG,WAAwB;QAC7C,OAAQ,IAAI,CAAC,KAAK,CAAC,YAAY,CAC7B,GAAG,WAAW,CACmB,CAAA;IACrC,CAAC;IAEM,UAAU,CAAC,EAAU;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;IAC3D,CAAC;CACF;AA3CD,sCA2CC"}
+8
View File
@@ -0,0 +1,8 @@
import { RequestHandler } from 'express-serve-static-core';
import { JobCleanStatus } from '../@types/app';
declare type RequestParams = {
queueName: string;
queueStatus: JobCleanStatus;
};
export declare const cleanAll: RequestHandler<RequestParams>;
export {};
+23
View File
@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cleanAll = void 0;
const cleanAll = async (req, res) => {
const { queueName, queueStatus } = req.params;
const { bullBoardQueues } = req.app.locals;
const GRACE_TIME_MS = 5000;
const { queue } = bullBoardQueues[queueName];
if (!queue) {
return res.status(404).send({
error: 'Queue not found',
});
}
else if (queue.readOnlyMode) {
return res.status(405).send({
error: 'Method not allowed on read only queue',
});
}
await queue.clean(queueStatus, GRACE_TIME_MS);
return res.sendStatus(200);
};
exports.cleanAll = cleanAll;
//# sourceMappingURL=cleanAll.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"cleanAll.js","sourceRoot":"","sources":["../../src/routes/cleanAll.ts"],"names":[],"mappings":";;;AAQO,MAAM,QAAQ,GAAkC,KAAK,EAC1D,GAAY,EACZ,GAAa,EACb,EAAE;IACF,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,GAAG,CAAC,MAAM,CAAA;IAC7C,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,MAEnC,CAAA;IAED,MAAM,aAAa,GAAG,IAAI,CAAA;IAE1B,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;IAC5C,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,iBAAiB;SACzB,CAAC,CAAA;KACH;SAAM,IAAI,KAAK,CAAC,YAAY,EAAE;QAC7B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,uCAAuC;SAC/C,CAAC,CAAA;KACH;IAED,MAAM,KAAK,CAAC,KAAK,CAAC,WAAkB,EAAE,aAAa,CAAC,CAAA;IAEpD,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC5B,CAAC,CAAA;AAzBY,QAAA,QAAQ,YAyBpB"}
+2
View File
@@ -0,0 +1,2 @@
import { RequestHandler } from 'express-serve-static-core';
export declare const cleanJob: RequestHandler;
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.cleanJob = void 0;
const cleanJob = async (req, res) => {
const { bullBoardQueues } = req.app.locals;
const { queueName, id } = req.params;
const { queue } = bullBoardQueues[queueName];
if (!queue) {
return res.status(404).send({
error: 'Queue not found',
});
}
else if (queue.readOnlyMode) {
return res.status(405).send({
error: 'Method not allowed on read only queue',
});
}
const job = await queue.getJob(id);
if (!job) {
return res.status(404).send({
error: 'Job not found',
});
}
await job.remove();
return res.sendStatus(204);
};
exports.cleanJob = cleanJob;
//# sourceMappingURL=cleanJob.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"cleanJob.js","sourceRoot":"","sources":["../../src/routes/cleanJob.ts"],"names":[],"mappings":";;;AAGO,MAAM,QAAQ,GAAmB,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC5E,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,MAEnC,CAAA;IACD,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAM,CAAA;IACpC,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;IAE5C,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,iBAAiB;SACzB,CAAC,CAAA;KACH;SAAM,IAAI,KAAK,CAAC,YAAY,EAAE;QAC7B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,uCAAuC;SAC/C,CAAC,CAAA;KACH;IAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAElC,IAAI,CAAC,GAAG,EAAE;QACR,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,eAAe;SACvB,CAAC,CAAA;KACH;IAED,MAAM,GAAG,CAAC,MAAM,EAAE,CAAA;IAElB,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC5B,CAAC,CAAA;AA5BY,QAAA,QAAQ,YA4BpB"}
+2
View File
@@ -0,0 +1,2 @@
import { Request, Response } from 'express-serve-static-core';
export declare function errorHandler(err: Error, _req: Request, res: Response, _next: any): void;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.errorHandler = void 0;
function errorHandler(err, _req, res, _next) {
res.status(500).send({
error: 'Queue error',
message: err.message,
details: err.stack,
});
}
exports.errorHandler = errorHandler;
//# sourceMappingURL=errorHandler.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/routes/errorHandler.ts"],"names":[],"mappings":";;;AAEA,SAAgB,YAAY,CAC1B,GAAU,EACV,IAAa,EACb,GAAa,EACb,KAAU;IAEV,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACnB,KAAK,EAAE,aAAa;QACpB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,OAAO,EAAE,GAAG,CAAC,KAAK;KACnB,CAAC,CAAA;AACJ,CAAC;AAXD,oCAWC"}
+2
View File
@@ -0,0 +1,2 @@
import { RequestHandler } from 'express-serve-static-core';
export declare const entryPoint: RequestHandler;
+11
View File
@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.entryPoint = void 0;
const entryPoint = (req, res) => {
const basePath = req.proxyUrl || req.baseUrl;
res.render('index', {
basePath,
});
};
exports.entryPoint = entryPoint;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":";;;AAEO,MAAM,UAAU,GAAmB,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;IACxE,MAAM,QAAQ,GAAI,GAAW,CAAC,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAA;IAErD,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE;QAClB,QAAQ;KACT,CAAC,CAAA;AACJ,CAAC,CAAA;AANY,QAAA,UAAU,cAMtB"}
+2
View File
@@ -0,0 +1,2 @@
import { RequestHandler } from 'express-serve-static-core';
export declare const jobLogs: RequestHandler;
+23
View File
@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.jobLogs = void 0;
const jobLogs = async (req, res) => {
const { bullBoardQueues } = req.app.locals;
const { queueName, id } = req.params;
const { queue } = bullBoardQueues[queueName];
if (!queue) {
return res.status(404).send({
error: 'Queue not found',
});
}
const job = await queue.getJob(id);
if (!job) {
return res.status(404).send({
error: 'Job not found',
});
}
const logs = await queue.getJobLogs(id);
return res.json(logs);
};
exports.jobLogs = jobLogs;
//# sourceMappingURL=jobLogs.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"jobLogs.js","sourceRoot":"","sources":["../../src/routes/jobLogs.ts"],"names":[],"mappings":";;;AAGO,MAAM,OAAO,GAAmB,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC3E,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,MAEnC,CAAA;IACD,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAM,CAAA;IACpC,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;IAE5C,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,iBAAiB;SACzB,CAAC,CAAA;KACH;IAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAElC,IAAI,CAAC,GAAG,EAAE;QACR,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,eAAe;SACvB,CAAC,CAAA;KACH;IAED,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IAEvC,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACvB,CAAC,CAAA;AAxBY,QAAA,OAAO,WAwBnB"}
+2
View File
@@ -0,0 +1,2 @@
import { RequestHandler } from 'express-serve-static-core';
export declare const promoteJob: RequestHandler;
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.promoteJob = void 0;
const promoteJob = async (req, res) => {
const { bullBoardQueues } = req.app.locals;
const { queueName, id } = req.params;
const { queue } = bullBoardQueues[queueName];
if (!queue) {
return res.status(404).send({
error: 'Queue not found',
});
}
else if (queue.readOnlyMode) {
return res.status(405).send({
error: 'Method not allowed on read only queue',
});
}
const job = await queue.getJob(id);
if (!job) {
return res.status(404).send({
error: 'Job not found',
});
}
await job.promote();
return res.sendStatus(204);
};
exports.promoteJob = promoteJob;
//# sourceMappingURL=promoteJob.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"promoteJob.js","sourceRoot":"","sources":["../../src/routes/promoteJob.ts"],"names":[],"mappings":";;;AAGO,MAAM,UAAU,GAAmB,KAAK,EAC7C,GAAY,EACZ,GAAa,EACb,EAAE;IACF,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,MAEnC,CAAA;IACD,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAM,CAAA;IACpC,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;IAE5C,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,iBAAiB;SACzB,CAAC,CAAA;KACH;SAAM,IAAI,KAAK,CAAC,YAAY,EAAE;QAC7B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,uCAAuC;SAC/C,CAAC,CAAA;KACH;IAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAElC,IAAI,CAAC,GAAG,EAAE;QACR,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,eAAe;SACvB,CAAC,CAAA;KACH;IAED,MAAM,GAAG,CAAC,OAAO,EAAE,CAAA;IAEnB,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC5B,CAAC,CAAA;AA/BY,QAAA,UAAU,cA+BtB"}
+2
View File
@@ -0,0 +1,2 @@
import { RequestHandler } from 'express-serve-static-core';
export declare const queuesHandler: RequestHandler;
+83
View File
@@ -0,0 +1,83 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.queuesHandler = void 0;
const redis_info_1 = require("redis-info");
const metrics = [
'redis_version',
'used_memory',
'mem_fragmentation_ratio',
'connected_clients',
'blocked_clients',
];
const getStats = async ({ queue, }) => {
const redisClient = await queue.getClient();
const redisInfoRaw = await redisClient.info();
const redisInfo = redis_info_1.parse(redisInfoRaw);
const validMetrics = metrics.reduce((acc, metric) => {
if (redisInfo[metric]) {
acc[metric] = redisInfo[metric];
}
return acc;
}, {});
validMetrics.total_system_memory =
redisInfo.total_system_memory || redisInfo.maxmemory;
return validMetrics;
};
const formatJob = (job, queue) => {
const jobProps = job.toJSON();
return {
id: jobProps.id,
timestamp: jobProps.timestamp,
processedOn: jobProps.processedOn,
finishedOn: jobProps.finishedOn,
progress: jobProps.progress,
attempts: jobProps.attemptsMade,
delay: job.opts.delay,
failedReason: jobProps.failedReason,
stacktrace: jobProps.stacktrace ? jobProps.stacktrace.filter(Boolean) : [],
opts: jobProps.opts,
data: queue.format('data', jobProps.data),
name: jobProps.name,
returnValue: queue.format('returnValue', jobProps.returnvalue),
};
};
const statuses = [
'active',
'completed',
'delayed',
'failed',
'paused',
'waiting',
];
const getDataForQueues = async (bullBoardQueues, req) => {
const query = req.query || {};
const pairs = Object.entries(bullBoardQueues);
if (pairs.length == 0) {
return {
stats: {},
queues: [],
};
}
const queues = await Promise.all(pairs.map(async ([name, { queue }]) => {
const counts = await queue.getJobCounts(...statuses);
const status = query[name] === 'latest' ? statuses : query[name];
const jobs = await queue.getJobs(status, 0, 10);
return {
name,
counts: counts,
jobs: jobs.filter(Boolean).map((job) => formatJob(job, queue)),
readOnlyMode: queue.readOnlyMode,
};
}));
const stats = await getStats(pairs[0][1]);
return {
stats,
queues,
};
};
const queuesHandler = async (req, res) => {
const { bullBoardQueues } = req.app.locals;
res.json(await getDataForQueues(bullBoardQueues, req));
};
exports.queuesHandler = queuesHandler;
//# sourceMappingURL=queues.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"queues.js","sourceRoot":"","sources":["../../src/routes/queues.ts"],"names":[],"mappings":"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"}
+2
View File
@@ -0,0 +1,2 @@
import { RequestHandler } from 'express-serve-static-core';
export declare const retryAll: RequestHandler;
+21
View File
@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.retryAll = void 0;
const retryAll = async (req, res) => {
const { queueName } = req.params;
const { bullBoardQueues } = req.app.locals;
const { queue } = bullBoardQueues[queueName];
if (!queue) {
return res.status(404).send({ error: 'queue not found' });
}
else if (queue.readOnlyMode) {
return res.status(405).send({
error: 'Method not allowed on read only queue',
});
}
const jobs = await queue.getJobs(['failed']);
await Promise.all(jobs.map((job) => job.retry()));
return res.sendStatus(200);
};
exports.retryAll = retryAll;
//# sourceMappingURL=retryAll.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"retryAll.js","sourceRoot":"","sources":["../../src/routes/retryAll.ts"],"names":[],"mappings":";;;AAIO,MAAM,QAAQ,GAAmB,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC5E,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,CAAA;IAChC,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,MAEnC,CAAA;IAED,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;IAC5C,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAA;KAC1D;SAAM,IAAI,KAAK,CAAC,YAAY,EAAE;QAC7B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,uCAAuC;SAC/C,CAAC,CAAA;KACH;IAED,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5C,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAEjD,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC5B,CAAC,CAAA;AAnBY,QAAA,QAAQ,YAmBpB"}
+2
View File
@@ -0,0 +1,2 @@
import { RequestHandler } from 'express-serve-static-core';
export declare const retryJob: RequestHandler;
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.retryJob = void 0;
const retryJob = async (req, res) => {
const { bullBoardQueues } = req.app.locals;
const { queueName, id } = req.params;
const { queue } = bullBoardQueues[queueName];
if (!queue) {
return res.status(404).send({
error: 'Queue not found',
});
}
else if (queue.readOnlyMode) {
return res.status(405).send({
error: 'Method not allowed on read only queue',
});
}
const job = await queue.getJob(id);
if (!job) {
return res.status(404).send({
error: 'Job not found',
});
}
await job.retry();
return res.sendStatus(204);
};
exports.retryJob = retryJob;
//# sourceMappingURL=retryJob.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"retryJob.js","sourceRoot":"","sources":["../../src/routes/retryJob.ts"],"names":[],"mappings":";;;AAGO,MAAM,QAAQ,GAAmB,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC5E,MAAM,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,MAEnC,CAAA;IACD,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAM,CAAA;IACpC,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;IAE5C,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,iBAAiB;SACzB,CAAC,CAAA;KACH;SAAM,IAAI,KAAK,CAAC,YAAY,EAAE;QAC7B,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,uCAAuC;SAC/C,CAAC,CAAA;KACH;IAED,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAElC,IAAI,CAAC,GAAG,EAAE;QACR,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,eAAe;SACvB,CAAC,CAAA;KACH;IAED,MAAM,GAAG,CAAC,KAAK,EAAE,CAAA;IAEjB,OAAO,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAA;AAC5B,CAAC,CAAA;AA5BY,QAAA,QAAQ,YA4BpB"}
+5
View File
@@ -0,0 +1,5 @@
/// <reference types="react" />
import { Api } from '../services/Api';
export declare const App: ({ api }: {
api: Api;
}) => JSX.Element;
+37
View File
@@ -0,0 +1,37 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.App = void 0;
const react_1 = __importDefault(require("react"));
const react_router_dom_1 = require("react-router-dom");
const react_toastify_1 = require("react-toastify");
const useScrollTopOnNav_1 = require("../hooks/useScrollTopOnNav");
const useStore_1 = require("../hooks/useStore");
const Header_1 = require("./Header/Header");
const Menu_1 = require("./Menu/Menu");
const QueuePage_1 = require("./QueuePage/QueuePage");
const RedisStats_1 = require("./RedisStats/RedisStats");
const App = ({ api }) => {
var _a, _b, _c, _d, _e;
useScrollTopOnNav_1.useScrollTopOnNav();
const { state, actions, selectedStatuses } = useStore_1.useStore(api);
return (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement(Header_1.Header, null, ((_a = state.data) === null || _a === void 0 ? void 0 : _a.stats) && react_1.default.createElement(RedisStats_1.RedisStats, { stats: (_b = state.data) === null || _b === void 0 ? void 0 : _b.stats })),
react_1.default.createElement("main", null,
react_1.default.createElement("div", null, state.loading ? ('Loading...') : (react_1.default.createElement(react_router_dom_1.Switch, null,
react_1.default.createElement(react_router_dom_1.Route, { path: "/queue/:name", render: ({ match: { params } }) => {
var _a;
const currentQueueName = decodeURIComponent(params.name);
const queue = (_a = state.data) === null || _a === void 0 ? void 0 : _a.queues.find((q) => q.name === currentQueueName);
return (react_1.default.createElement(QueuePage_1.QueuePage, { queue: queue, actions: actions, selectedStatus: selectedStatuses }));
} }),
react_1.default.createElement(react_router_dom_1.Route, { path: "/", exact: true }, !!state.data &&
Array.isArray((_c = state.data) === null || _c === void 0 ? void 0 : _c.queues) &&
state.data.queues.length > 0 && (react_1.default.createElement(react_router_dom_1.Redirect, { to: `/queue/${encodeURIComponent((_d = state.data) === null || _d === void 0 ? void 0 : _d.queues[0].name)}` }))))))),
react_1.default.createElement(Menu_1.Menu, { queues: (_e = state.data) === null || _e === void 0 ? void 0 : _e.queues.map((q) => q.name), selectedStatuses: selectedStatuses }),
react_1.default.createElement(react_toastify_1.ToastContainer, null)));
};
exports.App = App;
//# sourceMappingURL=App.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"App.js","sourceRoot":"","sources":["../../../src/ui/components/App.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,uDAA0D;AAC1D,mDAA+C;AAC/C,kEAA8D;AAC9D,gDAA4C;AAE5C,4CAAwC;AACxC,sCAAkC;AAClC,qDAAiD;AACjD,wDAAoD;AAE7C,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAgB,EAAE,EAAE;;IAC3C,qCAAiB,EAAE,CAAA;IACnB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,mBAAQ,CAAC,GAAG,CAAC,CAAA;IAE1D,OAAO,CACL;QACE,8BAAC,eAAM,QACJ,CAAA,MAAA,KAAK,CAAC,IAAI,0CAAE,KAAK,KAAI,8BAAC,uBAAU,IAAC,KAAK,EAAE,MAAA,KAAK,CAAC,IAAI,0CAAE,KAAK,GAAI,CACvD;QACT;YACE,2CACG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CACf,YAAY,CACb,CAAC,CAAC,CAAC,CACF,8BAAC,yBAAM;gBACL,8BAAC,wBAAK,IACJ,IAAI,EAAC,cAAc,EACnB,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE;;wBAChC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;wBACxD,MAAM,KAAK,GAAG,MAAA,KAAK,CAAC,IAAI,0CAAE,MAAM,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CACnC,CAAA;wBAED,OAAO,CACL,8BAAC,qBAAS,IACR,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,gBAAgB,GAChC,CACH,CAAA;oBACH,CAAC,GACD;gBAEF,8BAAC,wBAAK,IAAC,IAAI,EAAC,GAAG,EAAC,KAAK,UAClB,CAAC,CAAC,KAAK,CAAC,IAAI;oBACX,KAAK,CAAC,OAAO,CAAC,MAAA,KAAK,CAAC,IAAI,0CAAE,MAAM,CAAC;oBACjC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAC9B,8BAAC,2BAAQ,IACP,EAAE,EAAE,UAAU,kBAAkB,CAC9B,MAAA,KAAK,CAAC,IAAI,0CAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAC3B,EAAE,GACH,CACH,CACG,CACD,CACV,CACG,CACD;QACP,8BAAC,WAAI,IACH,MAAM,EAAE,MAAA,KAAK,CAAC,IAAI,0CAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAC7C,gBAAgB,EAAE,gBAAgB,GAClC;QACF,8BAAC,+BAAc,OAAG,CACjB,CACJ,CAAA;AACH,CAAC,CAAA;AAvDY,QAAA,GAAG,OAuDf"}
@@ -0,0 +1,2 @@
import { PropsWithChildren } from 'react';
export declare const Header: ({ children }: PropsWithChildren<any>) => JSX.Element;
+15
View File
@@ -0,0 +1,15 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Header = void 0;
const react_1 = __importDefault(require("react"));
const Header_module_css_1 = __importDefault(require("./Header.module.css"));
const Header = ({ children }) => {
return (react_1.default.createElement("header", { className: Header_module_css_1.default.header },
react_1.default.createElement("div", { className: Header_module_css_1.default.logo }, "\uD83C\uDFAF Bull Dashboard"),
children));
};
exports.Header = Header;
//# sourceMappingURL=Header.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../../../src/ui/components/Header/Header.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAgD;AAChD,4EAAmC;AAE5B,MAAM,MAAM,GAAG,CAAC,EAAE,QAAQ,EAA0B,EAAE,EAAE;IAC7D,OAAO,CACL,0CAAQ,SAAS,EAAE,2BAAC,CAAC,MAAM;QACzB,uCAAK,SAAS,EAAE,2BAAC,CAAC,IAAI,kCAAyB;QAC9C,QAAQ,CACF,CACV,CAAA;AACH,CAAC,CAAA;AAPY,QAAA,MAAM,UAOlB"}
@@ -0,0 +1,14 @@
import React from 'react';
interface HighlightProps {
language: 'json' | 'stacktrace';
children: string | null;
}
export declare class Highlight extends React.Component<HighlightProps> {
private codeRef;
shouldComponentUpdate(nextProps: Readonly<HighlightProps>): boolean;
componentDidMount(): void;
componentDidUpdate(): void;
render(): JSX.Element;
private highlightCode;
}
export {};
@@ -0,0 +1,49 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Highlight = void 0;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const core_1 = __importDefault(require("highlight.js/lib/core"));
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const json_1 = __importDefault(require("highlight.js/lib/languages/json"));
const react_1 = __importDefault(require("react"));
const stacktrace_1 = require("./languages/stacktrace");
core_1.default.registerLanguage('json', json_1.default);
core_1.default.registerLanguage('stacktrace', stacktrace_1.stacktraceJS);
class Highlight extends react_1.default.Component {
constructor() {
super(...arguments);
this.codeRef = react_1.default.createRef();
}
shouldComponentUpdate(nextProps) {
return (nextProps.language !== this.props.language ||
(Array.isArray(this.props.children)
? this.props.children.some((item) => ![].concat(nextProps.children).includes(item))
: nextProps.children !== this.props.children));
}
componentDidMount() {
this.highlightCode();
}
componentDidUpdate() {
this.highlightCode();
}
render() {
const { language } = this.props;
return (react_1.default.createElement("pre", { ref: this.codeRef },
react_1.default.createElement("code", { className: language })));
}
highlightCode() {
var _a;
const node = (_a = this.codeRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('code');
if (node) {
node.textContent = this.props.children;
core_1.default.highlightElement(node);
}
}
}
exports.Highlight = Highlight;
//# sourceMappingURL=Highlight.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Highlight.js","sourceRoot":"","sources":["../../../../src/ui/components/Highlight/Highlight.tsx"],"names":[],"mappings":";;;;;;AAAA,6DAA6D;AAC7D,aAAa;AACb,iEAAwC;AACxC,6DAA6D;AAC7D,aAAa;AACb,2EAAkD;AAClD,kDAAyB;AACzB,uDAAqD;AAErD,cAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,cAAI,CAAC,CAAA;AACnC,cAAI,CAAC,gBAAgB,CAAC,YAAY,EAAE,yBAAY,CAAC,CAAA;AAOjD,MAAa,SAAU,SAAQ,eAAK,CAAC,SAAyB;IAA9D;;QACU,YAAO,GAAG,eAAK,CAAC,SAAS,EAAkB,CAAA;IAsCrD,CAAC;IApCQ,qBAAqB,CAAC,SAAmC;QAC9D,OAAO,CACL,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ;YAC1C,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACjC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CACtB,CAAC,IAAS,EAAE,EAAE,CACZ,CAAE,EAAU,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CACzD;gBACH,CAAC,CAAC,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAChD,CAAA;IACH,CAAC;IAEM,iBAAiB;QACtB,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAEM,kBAAkB;QACvB,IAAI,CAAC,aAAa,EAAE,CAAA;IACtB,CAAC;IAEM,MAAM;QACX,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QAC/B,OAAO,CACL,uCAAK,GAAG,EAAE,IAAI,CAAC,OAAO;YACpB,wCAAM,SAAS,EAAE,QAAQ,GAAI,CACzB,CACP,CAAA;IACH,CAAC;IAEO,aAAa;;QACnB,MAAM,IAAI,GAAG,MAAA,IAAI,CAAC,OAAO,CAAC,OAAO,0CAAE,aAAa,CAAC,MAAM,CAAC,CAAA;QACxD,IAAI,IAAI,EAAE;YACR,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAA;YACtC,cAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAA;SAC5B;IACH,CAAC;CACF;AAvCD,8BAuCC"}
@@ -0,0 +1 @@
export declare function stacktraceJS(): any;
@@ -0,0 +1,51 @@
"use strict";
/*
Language: StacktraceJS
Author: FelixMosh
Description: Node stacktrace highlighter
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.stacktraceJS = void 0;
function stacktraceJS() {
const ERROR = {
className: 'type',
begin: /^\w*Error:\s*/,
relevance: 40,
contains: [
{
className: 'title',
begin: /.*/,
end: /$/,
excludeStart: true,
endsWithParent: true,
},
],
};
const LINE_NUMBER = {
className: 'number',
begin: ':\\d+:\\d+',
relevance: 5,
};
const TRACE_LINE = {
className: 'trace-line',
begin: /^\s*at/,
end: /$/,
keywords: 'at as async prototype anonymous function',
contains: [
{
className: 'code-path',
begin: /\(/,
end: /\)$/,
excludeEnd: true,
excludeBegin: true,
contains: [LINE_NUMBER],
},
],
};
return {
case_insensitive: true,
contains: [ERROR, TRACE_LINE, LINE_NUMBER],
};
}
exports.stacktraceJS = stacktraceJS;
//# sourceMappingURL=stacktrace.js.map
@@ -0,0 +1 @@
{"version":3,"file":"stacktrace.js","sourceRoot":"","sources":["../../../../../src/ui/components/Highlight/languages/stacktrace.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;AAEF,SAAgB,YAAY;IAC1B,MAAM,KAAK,GAAG;QACZ,SAAS,EAAE,MAAM;QACjB,KAAK,EAAE,eAAe;QACtB,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE;YACR;gBACE,SAAS,EAAE,OAAO;gBAClB,KAAK,EAAE,IAAI;gBACX,GAAG,EAAE,GAAG;gBACR,YAAY,EAAE,IAAI;gBAClB,cAAc,EAAE,IAAI;aACrB;SACF;KACF,CAAA;IAED,MAAM,WAAW,GAAG;QAClB,SAAS,EAAE,QAAQ;QACnB,KAAK,EAAE,YAAY;QACnB,SAAS,EAAE,CAAC;KACb,CAAA;IAED,MAAM,UAAU,GAAG;QACjB,SAAS,EAAE,YAAY;QACvB,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,GAAG;QACR,QAAQ,EAAE,0CAA0C;QACpD,QAAQ,EAAE;YACR;gBACE,SAAS,EAAE,WAAW;gBACtB,KAAK,EAAE,IAAI;gBACX,GAAG,EAAE,KAAK;gBACV,UAAU,EAAE,IAAI;gBAChB,YAAY,EAAE,IAAI;gBAClB,QAAQ,EAAE,CAAC,WAAW,CAAC;aACxB;SACF;KACF,CAAA;IAED,OAAO;QACL,gBAAgB,EAAE,IAAI;QACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,CAAC;KAC3C,CAAA;AACH,CAAC;AA3CD,oCA2CC"}
@@ -0,0 +1,2 @@
/// <reference types="react" />
export declare const PromoteIcon: () => JSX.Element;
+11
View File
@@ -0,0 +1,11 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromoteIcon = void 0;
const react_1 = __importDefault(require("react"));
const PromoteIcon = () => (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20" },
react_1.default.createElement("path", { d: "M15 17v-2.99A4 4 0 0 0 11 10H8v5L2 9l6-6v5h3a6 6 0 0 1 6 6v3h-2z" })));
exports.PromoteIcon = PromoteIcon;
//# sourceMappingURL=Promote.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Promote.js","sourceRoot":"","sources":["../../../../src/ui/components/Icons/Promote.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAElB,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,CAC/B,uCAAK,KAAK,EAAC,4BAA4B,EAAC,OAAO,EAAC,WAAW;IACzD,wCAAM,CAAC,EAAC,kEAAkE,GAAG,CACzE,CACP,CAAA;AAJY,QAAA,WAAW,eAIvB"}
+2
View File
@@ -0,0 +1,2 @@
/// <reference types="react" />
export declare const RetryIcon: () => JSX.Element;
+11
View File
@@ -0,0 +1,11 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RetryIcon = void 0;
const react_1 = __importDefault(require("react"));
const RetryIcon = () => (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20" },
react_1.default.createElement("path", { d: "M5 4a2 2 0 0 0-2 2v6H0l4 4 4-4H5V6h7l2-2H5zm10 4h-3l4-4 4 4h-3v6a2 2 0 0 1-2 2H6l2-2h7V8z" })));
exports.RetryIcon = RetryIcon;
//# sourceMappingURL=Retry.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Retry.js","sourceRoot":"","sources":["../../../../src/ui/components/Icons/Retry.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAElB,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,CAC7B,uCAAK,KAAK,EAAC,4BAA4B,EAAC,OAAO,EAAC,WAAW;IACzD,wCAAM,CAAC,EAAC,2FAA2F,GAAG,CAClG,CACP,CAAA;AAJY,QAAA,SAAS,aAIrB"}
+2
View File
@@ -0,0 +1,2 @@
/// <reference types="react" />
export declare const TrashIcon: () => JSX.Element;
+11
View File
@@ -0,0 +1,11 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TrashIcon = void 0;
const react_1 = __importDefault(require("react"));
const TrashIcon = () => (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20" },
react_1.default.createElement("path", { d: "M6 2l2-2h4l2 2h4v2H2V2h4zM3 6h14l-1 14H4L3 6zm5 2v10h1V8H8zm3 0v10h1V8h-1z" })));
exports.TrashIcon = TrashIcon;
//# sourceMappingURL=Trash.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Trash.js","sourceRoot":"","sources":["../../../../src/ui/components/Icons/Trash.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAElB,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,CAC7B,uCAAK,KAAK,EAAC,4BAA4B,EAAC,OAAO,EAAC,WAAW;IACzD,wCAAM,CAAC,EAAC,4EAA4E,GAAG,CACnF,CACP,CAAA;AAJY,QAAA,SAAS,aAIrB"}
@@ -0,0 +1,4 @@
import React from 'react';
export declare const Button: ({ children, className, isActive, ...rest }: React.ClassAttributes<HTMLButtonElement> & React.ButtonHTMLAttributes<HTMLButtonElement> & {
isActive?: boolean | undefined;
}) => JSX.Element;
@@ -0,0 +1,12 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Button = void 0;
const react_1 = __importDefault(require("react"));
const Button_module_css_1 = __importDefault(require("./Button.module.css"));
const classnames_1 = __importDefault(require("classnames"));
const Button = ({ children, className, isActive = false, ...rest }) => (react_1.default.createElement("button", Object.assign({ type: "button" }, rest, { className: classnames_1.default(Button_module_css_1.default.button, className, { [Button_module_css_1.default.isActive]: isActive }) }), children));
exports.Button = Button;
//# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Button.js","sourceRoot":"","sources":["../../../../../src/ui/components/JobCard/Button/Button.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,4EAAmC;AACnC,4DAA2B;AAEpB,MAAM,MAAM,GAAG,CAAC,EACrB,QAAQ,EACR,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,GAAG,IAAI,EAIiB,EAAE,EAAE,CAAC,CAC7B,wDACE,IAAI,EAAC,QAAQ,IACT,IAAI,IACR,SAAS,EAAE,oBAAE,CAAC,2BAAC,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,2BAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC,KAE7D,QAAQ,CACF,CACV,CAAA;AAhBY,QAAA,MAAM,UAgBlB"}
@@ -0,0 +1,12 @@
/// <reference types="react" />
import { AppJob } from '../../../../@types/app';
import { Status } from '../../constants';
interface DetailsProps {
job: AppJob;
status: Status;
actions: {
getJobLogs: () => Promise<string[]>;
};
}
export declare const Details: ({ status, job, actions }: DetailsProps) => JSX.Element | null;
export {};
@@ -0,0 +1,25 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Details = void 0;
const react_1 = __importDefault(require("react"));
const useDetailsTabs_1 = require("../../../hooks/useDetailsTabs");
const Button_1 = require("../Button/Button");
const Details_module_css_1 = __importDefault(require("./Details.module.css"));
const DetailsContent_1 = require("./DetailsContent/DetailsContent");
const Details = ({ status, job, actions }) => {
const { tabs, selectedTab } = useDetailsTabs_1.useDetailsTabs(status);
if (tabs.length === 0) {
return null;
}
return (react_1.default.createElement("div", { className: Details_module_css_1.default.details },
react_1.default.createElement("ul", { className: Details_module_css_1.default.tabActions }, tabs.map((tab) => (react_1.default.createElement("li", { key: tab.title },
react_1.default.createElement(Button_1.Button, { onClick: tab.selectTab, isActive: tab.isActive }, tab.title))))),
react_1.default.createElement("div", { className: Details_module_css_1.default.tabContent },
react_1.default.createElement("div", null,
react_1.default.createElement(DetailsContent_1.DetailsContent, { selectedTab: selectedTab, job: job, actions: actions })))));
};
exports.Details = Details;
//# sourceMappingURL=Details.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Details.js","sourceRoot":"","sources":["../../../../../src/ui/components/JobCard/Details/Details.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAEzB,kEAA8D;AAE9D,6CAAyC;AACzC,8EAAoC;AACpC,oEAAgE;AAQzD,MAAM,OAAO,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAgB,EAAE,EAAE;IAChE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,+BAAc,CAAC,MAAM,CAAC,CAAA;IAEpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;QACrB,OAAO,IAAI,CAAA;KACZ;IAED,OAAO,CACL,uCAAK,SAAS,EAAE,4BAAC,CAAC,OAAO;QACvB,sCAAI,SAAS,EAAE,4BAAC,CAAC,UAAU,IACxB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,sCAAI,GAAG,EAAE,GAAG,CAAC,KAAK;YAChB,8BAAC,eAAM,IAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,IACnD,GAAG,CAAC,KAAK,CACH,CACN,CACN,CAAC,CACC;QACL,uCAAK,SAAS,EAAE,4BAAC,CAAC,UAAU;YAC1B;gBACE,8BAAC,+BAAc,IACb,WAAW,EAAE,WAAW,EACxB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,OAAO,GAChB,CACE,CACF,CACF,CACP,CAAA;AACH,CAAC,CAAA;AA7BY,QAAA,OAAO,WA6BnB"}
@@ -0,0 +1,12 @@
/// <reference types="react" />
import { AppJob } from '../../../../../@types/app';
import { TabsType } from '../../../../hooks/useDetailsTabs';
interface DetailsContentProps {
job: AppJob;
selectedTab: TabsType;
actions: {
getJobLogs: () => Promise<string[]>;
};
}
export declare const DetailsContent: ({ selectedTab, job: { stacktrace, data, returnValue, opts, failedReason }, actions, }: DetailsContentProps) => JSX.Element | null;
export {};
@@ -0,0 +1,25 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DetailsContent = void 0;
const react_1 = __importDefault(require("react"));
const Highlight_1 = require("../../../Highlight/Highlight");
const JobLogs_1 = require("./JobLogs/JobLogs");
const DetailsContent = ({ selectedTab, job: { stacktrace, data, returnValue, opts, failedReason }, actions, }) => {
switch (selectedTab) {
case 'Data':
return (react_1.default.createElement(Highlight_1.Highlight, { language: "json" }, JSON.stringify({ data, returnValue }, null, 2)));
case 'Options':
return (react_1.default.createElement(Highlight_1.Highlight, { language: "json" }, JSON.stringify(opts, null, 2)));
case 'Error':
return (react_1.default.createElement(react_1.default.Fragment, null, stacktrace.length === 0 ? (react_1.default.createElement("div", { className: "error" }, !!failedReason ? failedReason : 'NA')) : (react_1.default.createElement(Highlight_1.Highlight, { language: "stacktrace", key: "stacktrace" }, stacktrace.join('\n')))));
case 'Logs':
return react_1.default.createElement(JobLogs_1.JobLogs, { actions: actions });
default:
return null;
}
};
exports.DetailsContent = DetailsContent;
//# sourceMappingURL=DetailsContent.js.map
@@ -0,0 +1 @@
{"version":3,"file":"DetailsContent.js","sourceRoot":"","sources":["../../../../../../src/ui/components/JobCard/Details/DetailsContent/DetailsContent.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAGzB,4DAAwD;AACxD,+CAA2C;AAUpC,MAAM,cAAc,GAAG,CAAC,EAC7B,WAAW,EACX,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,EAC1D,OAAO,GACa,EAAE,EAAE;IACxB,QAAQ,WAAW,EAAE;QACnB,KAAK,MAAM;YACT,OAAO,CACL,8BAAC,qBAAS,IAAC,QAAQ,EAAC,MAAM,IACvB,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CACrC,CACb,CAAA;QACH,KAAK,SAAS;YACZ,OAAO,CACL,8BAAC,qBAAS,IAAC,QAAQ,EAAC,MAAM,IAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAa,CACvE,CAAA;QACH,KAAK,OAAO;YACV,OAAO,CACL,8DACG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACzB,uCAAK,SAAS,EAAC,OAAO,IAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAO,CACpE,CAAC,CAAC,CAAC,CACF,8BAAC,qBAAS,IAAC,QAAQ,EAAC,YAAY,EAAC,GAAG,EAAC,YAAY,IAC9C,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CACZ,CACb,CACA,CACJ,CAAA;QACH,KAAK,MAAM;YACT,OAAO,8BAAC,iBAAO,IAAC,OAAO,EAAE,OAAO,GAAI,CAAA;QACtC;YACE,OAAO,IAAI,CAAA;KACd;AACH,CAAC,CAAA;AAjCY,QAAA,cAAc,kBAiC1B"}
@@ -0,0 +1,8 @@
/// <reference types="react" />
interface JobLogsProps {
actions: {
getJobLogs: () => Promise<string[]>;
};
}
export declare const JobLogs: ({ actions }: JobLogsProps) => JSX.Element | null;
export {};
@@ -0,0 +1,43 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JobLogs = void 0;
const react_1 = __importStar(require("react"));
const JobLogs_module_css_1 = __importDefault(require("./JobLogs.module.css"));
const JobLogs = ({ actions }) => {
const [logs, setLogs] = react_1.useState([]);
react_1.useEffect(() => {
let mounted = true;
actions.getJobLogs().then((logs) => mounted && setLogs(logs));
return () => {
mounted = false;
};
}, []);
if (!Array.isArray(logs) || !logs.length) {
return null;
}
return (react_1.default.createElement("ul", { className: JobLogs_module_css_1.default.jobLogs }, logs.map((log, idx) => (react_1.default.createElement("li", { key: idx }, log)))));
};
exports.JobLogs = JobLogs;
//# sourceMappingURL=JobLogs.js.map
@@ -0,0 +1 @@
{"version":3,"file":"JobLogs.js","sourceRoot":"","sources":["../../../../../../../src/ui/components/JobCard/Details/DetailsContent/JobLogs/JobLogs.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAkD;AAClD,8EAAoC;AAQ7B,MAAM,OAAO,GAAG,CAAC,EAAE,OAAO,EAAgB,EAAE,EAAE;IACnD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,gBAAQ,CAAW,EAAE,CAAC,CAAA;IAE9C,iBAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,GAAG,IAAI,CAAA;QAClB,OAAO,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;QAC7D,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,KAAK,CAAA;QACjB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;QACxC,OAAO,IAAI,CAAA;KACZ;IAED,OAAO,CACL,sCAAI,SAAS,EAAE,4BAAC,CAAC,OAAO,IACrB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CACtB,sCAAI,GAAG,EAAE,GAAG,IAAG,GAAG,CAAM,CACzB,CAAC,CACC,CACN,CAAA;AACH,CAAC,CAAA;AAtBY,QAAA,OAAO,WAsBnB"}
@@ -0,0 +1,12 @@
/// <reference types="react" />
import { Status } from '../../constants';
interface JobActionsProps {
status: Status;
actions: {
promoteJob: () => Promise<void>;
retryJob: () => Promise<void>;
cleanJob: () => Promise<void>;
};
}
export declare const JobActions: ({ actions, status }: JobActionsProps) => JSX.Element | null;
export {};
@@ -0,0 +1,37 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JobActions = void 0;
const react_1 = __importDefault(require("react"));
const constants_1 = require("../../constants");
const Promote_1 = require("../../Icons/Promote");
const Retry_1 = require("../../Icons/Retry");
const Trash_1 = require("../../Icons/Trash");
const Tooltip_1 = require("../../Tooltip/Tooltip");
const Button_1 = require("../Button/Button");
const JobActions_module_css_1 = __importDefault(require("./JobActions.module.css"));
const buttonTypes = {
promote: { title: 'Promote', Icon: Promote_1.PromoteIcon, actionKey: 'promoteJob' },
clean: { title: 'Clean', Icon: Trash_1.TrashIcon, actionKey: 'cleanJob' },
retry: { title: 'Retry', Icon: Retry_1.RetryIcon, actionKey: 'retryJob' },
};
const statusToButtonsMap = {
[constants_1.STATUSES.failed]: [buttonTypes.retry, buttonTypes.clean],
[constants_1.STATUSES.delayed]: [buttonTypes.promote, buttonTypes.clean],
[constants_1.STATUSES.completed]: [buttonTypes.clean],
[constants_1.STATUSES.waiting]: [buttonTypes.clean],
};
const JobActions = ({ actions, status }) => {
const buttons = statusToButtonsMap[status];
if (!buttons) {
return null;
}
return (react_1.default.createElement("ul", { className: JobActions_module_css_1.default.jobActions }, buttons.map((type) => (react_1.default.createElement("li", { key: type.title },
react_1.default.createElement(Tooltip_1.Tooltip, { title: type.title },
react_1.default.createElement(Button_1.Button, { onClick: actions[type.actionKey], className: JobActions_module_css_1.default.button },
react_1.default.createElement(type.Icon, null))))))));
};
exports.JobActions = JobActions;
//# sourceMappingURL=JobActions.js.map
@@ -0,0 +1 @@
{"version":3,"file":"JobActions.js","sourceRoot":"","sources":["../../../../../src/ui/components/JobCard/JobActions/JobActions.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,+CAAkD;AAClD,iDAAiD;AACjD,6CAA6C;AAC7C,6CAA6C;AAC7C,mDAA+C;AAC/C,6CAAyC;AACzC,oFAAuC;AAiBvC,MAAM,WAAW,GAA+B;IAC9C,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,qBAAW,EAAE,SAAS,EAAE,YAAY,EAAE;IACzE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAS,EAAE,SAAS,EAAE,UAAU,EAAE;IACjE,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAS,EAAE,SAAS,EAAE,UAAU,EAAE;CAClE,CAAA;AAED,MAAM,kBAAkB,GAAiC;IACvD,CAAC,oBAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC;IACzD,CAAC,oBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC;IAC5D,CAAC,oBAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC;IACzC,CAAC,oBAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC;CACxC,CAAA;AAEM,MAAM,UAAU,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,EAAmB,EAAE,EAAE;IACjE,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAC1C,IAAI,CAAC,OAAO,EAAE;QACZ,OAAO,IAAI,CAAA;KACZ;IACD,OAAO,CACL,sCAAI,SAAS,EAAE,+BAAC,CAAC,UAAU,IACxB,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACrB,sCAAI,GAAG,EAAE,IAAI,CAAC,KAAK;QACjB,8BAAC,iBAAO,IAAC,KAAK,EAAE,IAAI,CAAC,KAAK;YACxB,8BAAC,eAAM,IAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,+BAAC,CAAC,MAAM;gBAC3D,8BAAC,IAAI,CAAC,IAAI,OAAG,CACN,CACD,CACP,CACN,CAAC,CACC,CACN,CAAA;AACH,CAAC,CAAA;AAlBY,QAAA,UAAU,cAkBtB"}
@@ -0,0 +1,16 @@
/// <reference types="react" />
import { AppJob } from '../../../@types/app';
import { Status } from '../constants';
interface JobCardProps {
job: AppJob;
status: Status;
readOnlyMode: boolean;
actions: {
promoteJob: () => Promise<void>;
retryJob: () => Promise<void>;
cleanJob: () => Promise<void>;
getJobLogs: () => Promise<string[]>;
};
}
export declare const JobCard: ({ job, status, actions, readOnlyMode, }: JobCardProps) => JSX.Element;
export {};
+31
View File
@@ -0,0 +1,31 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JobCard = void 0;
const react_1 = __importDefault(require("react"));
const Details_1 = require("./Details/Details");
const JobActions_1 = require("./JobActions/JobActions");
const JobCard_module_css_1 = __importDefault(require("./JobCard.module.css"));
const Progress_1 = require("./Progress/Progress");
const Timeline_1 = require("./Timeline/Timeline");
const JobCard = ({ job, status, actions, readOnlyMode, }) => (react_1.default.createElement("div", { className: JobCard_module_css_1.default.card },
react_1.default.createElement("div", { className: JobCard_module_css_1.default.sideInfo },
react_1.default.createElement("span", { title: `#${job.id}` },
"#",
job.id),
react_1.default.createElement(Timeline_1.Timeline, { job: job, status: status })),
react_1.default.createElement("div", { className: JobCard_module_css_1.default.contentWrapper },
react_1.default.createElement("div", { className: JobCard_module_css_1.default.title },
react_1.default.createElement("h4", null,
job.name,
job.attempts > 0 && react_1.default.createElement("span", null,
"attempt #",
job.attempts + 1)),
!readOnlyMode && react_1.default.createElement(JobActions_1.JobActions, { status: status, actions: actions })),
react_1.default.createElement("div", { className: JobCard_module_css_1.default.content },
react_1.default.createElement(Details_1.Details, { status: status, job: job, actions: actions }),
typeof job.progress === 'number' && (react_1.default.createElement(Progress_1.Progress, { percentage: job.progress, status: status, className: JobCard_module_css_1.default.progress }))))));
exports.JobCard = JobCard;
//# sourceMappingURL=JobCard.js.map
@@ -0,0 +1 @@
{"version":3,"file":"JobCard.js","sourceRoot":"","sources":["../../../../src/ui/components/JobCard/JobCard.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAGzB,+CAA2C;AAC3C,wDAAoD;AACpD,8EAAoC;AACpC,kDAA8C;AAC9C,kDAA8C;AAcvC,MAAM,OAAO,GAAG,CAAC,EACtB,GAAG,EACH,MAAM,EACN,OAAO,EACP,YAAY,GACC,EAAE,EAAE,CAAC,CAClB,uCAAK,SAAS,EAAE,4BAAC,CAAC,IAAI;IACpB,uCAAK,SAAS,EAAE,4BAAC,CAAC,QAAQ;QACxB,wCAAM,KAAK,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE;;YAAI,GAAG,CAAC,EAAE,CAAQ;QAC3C,8BAAC,mBAAQ,IAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAI,CAClC;IACN,uCAAK,SAAS,EAAE,4BAAC,CAAC,cAAc;QAC9B,uCAAK,SAAS,EAAE,4BAAC,CAAC,KAAK;YACrB;gBACG,GAAG,CAAC,IAAI;gBACR,GAAG,CAAC,QAAQ,GAAG,CAAC,IAAI;;oBAAgB,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAQ,CAC1D;YACJ,CAAC,YAAY,IAAI,8BAAC,uBAAU,IAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAI,CAC9D;QACN,uCAAK,SAAS,EAAE,4BAAC,CAAC,OAAO;YACvB,8BAAC,iBAAO,IAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,GAAI;YACtD,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CACnC,8BAAC,mBAAQ,IACP,UAAU,EAAE,GAAG,CAAC,QAAQ,EACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,4BAAC,CAAC,QAAQ,GACrB,CACH,CACG,CACF,CACF,CACP,CAAA;AA/BY,QAAA,OAAO,WA+BnB"}
@@ -0,0 +1,7 @@
/// <reference types="react" />
import { Status } from '../../constants';
export declare const Progress: ({ percentage, status, className, }: {
percentage: number;
status: Status;
className?: string | undefined;
}) => JSX.Element;
@@ -0,0 +1,19 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Progress = void 0;
const react_1 = __importDefault(require("react"));
const Progress_module_css_1 = __importDefault(require("./Progress.module.css"));
const classnames_1 = __importDefault(require("classnames"));
const Progress = ({ percentage, status, className, }) => {
return (react_1.default.createElement("svg", { className: classnames_1.default(Progress_module_css_1.default.progress, className), viewBox: "0 0 148 148" },
react_1.default.createElement("circle", { cx: "70", cy: "70", r: "70", fill: "none", stroke: "#EDF2F7", strokeWidth: "8", strokeLinecap: "round", style: { transform: 'translate(4px, 4px)' } }),
react_1.default.createElement("circle", { cx: "70", cy: "70", r: "70", fill: "none", stroke: status === 'failed' ? '#F56565' : '#48BB78', strokeWidth: "8", strokeLinecap: "round", strokeDasharray: "600", strokeDashoffset: 600 - ((600 - 160) * percentage) / 100, style: { transform: 'translate(4px, -4px) rotate(-90deg)' } }),
react_1.default.createElement("text", { textAnchor: "middle", x: "74", y: "88" },
percentage,
"%")));
};
exports.Progress = Progress;
//# sourceMappingURL=Progress.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Progress.js","sourceRoot":"","sources":["../../../../../src/ui/components/JobCard/Progress/Progress.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAEzB,gFAAqC;AACrC,4DAA2B;AAEpB,MAAM,QAAQ,GAAG,CAAC,EACvB,UAAU,EACV,MAAM,EACN,SAAS,GAKV,EAAE,EAAE;IACH,OAAO,CACL,uCAAK,SAAS,EAAE,oBAAE,CAAC,6BAAC,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,OAAO,EAAC,aAAa;QAC9D,0CACE,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAC,IAAI,EACN,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,SAAS,EAChB,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,KAAK,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,GACnC;QACV,0CACE,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAC,IAAI,EACN,IAAI,EAAC,MAAM,EACX,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EACnD,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,eAAe,EAAC,KAAK,EACrB,gBAAgB,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,GAAG,EACxD,KAAK,EAAE,EAAE,SAAS,EAAE,qCAAqC,EAAE,GACnD;QACV,wCAAM,UAAU,EAAC,QAAQ,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI;YACpC,UAAU;gBACN,CACH,CACP,CAAA;AACH,CAAC,CAAA;AAtCY,QAAA,QAAQ,YAsCpB"}
@@ -0,0 +1,7 @@
/// <reference types="react" />
import { AppJob } from '../../../../@types/app';
import { Status } from '../../constants';
export declare const Timeline: ({ job, status, }: {
job: AppJob;
status: Status;
}) => JSX.Element;
@@ -0,0 +1,45 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Timeline = void 0;
const date_fns_1 = require("date-fns");
const react_1 = __importDefault(require("react"));
const Timeline_module_css_1 = __importDefault(require("./Timeline.module.css"));
const formatDate = (ts) => {
if (date_fns_1.isToday(ts)) {
return date_fns_1.format(ts, 'HH:mm:ss');
}
return date_fns_1.getYear(ts) === date_fns_1.getYear(new Date())
? date_fns_1.format(ts, 'MM/dd HH:mm:ss')
: date_fns_1.format(ts, 'MM/dd/yyyy HH:mm:ss');
};
const Timeline = function Timeline({ job, status, }) {
return (react_1.default.createElement("div", { className: Timeline_module_css_1.default.timelineWrapper },
react_1.default.createElement("ul", { className: Timeline_module_css_1.default.timeline },
react_1.default.createElement("li", null,
react_1.default.createElement("small", null, "Added at"),
react_1.default.createElement("time", null, formatDate(job.timestamp || 0))),
!!job.delay && job.delay > 0 && status === 'delayed' && (react_1.default.createElement("li", null,
react_1.default.createElement("small", null, "Delayed for"),
react_1.default.createElement("time", null, date_fns_1.formatDistance(job.timestamp || 0, (job.timestamp || 0) + job.delay, { includeSeconds: true })))),
!!job.processedOn && (react_1.default.createElement("li", null,
react_1.default.createElement("small", null,
job.delay && job.delay > 0 ? 'delayed for ' : '',
date_fns_1.formatDistance(job.processedOn, job.timestamp || 0, {
includeSeconds: true,
})),
react_1.default.createElement("small", null, "Process started at"),
react_1.default.createElement("time", null, formatDate(job.processedOn)))),
!!job.finishedOn && (react_1.default.createElement("li", null,
react_1.default.createElement("small", null, date_fns_1.formatDistance(job.finishedOn, job.processedOn || 0, {
includeSeconds: true,
})),
react_1.default.createElement("small", null,
status === 'failed' ? 'Failed' : 'Finished',
" at"),
react_1.default.createElement("time", null, formatDate(job.finishedOn)))))));
};
exports.Timeline = Timeline;
//# sourceMappingURL=Timeline.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Timeline.js","sourceRoot":"","sources":["../../../../../src/ui/components/JobCard/Timeline/Timeline.tsx"],"names":[],"mappings":";;;;;;AAAA,uCAAmE;AACnE,kDAAyB;AAGzB,gFAAqC;AAIrC,MAAM,UAAU,GAAG,CAAC,EAAa,EAAE,EAAE;IACnC,IAAI,kBAAO,CAAC,EAAE,CAAC,EAAE;QACf,OAAO,iBAAM,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;KAC9B;IAED,OAAO,kBAAO,CAAC,EAAE,CAAC,KAAK,kBAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACxC,CAAC,CAAC,iBAAM,CAAC,EAAE,EAAE,gBAAgB,CAAC;QAC9B,CAAC,CAAC,iBAAM,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAA;AACvC,CAAC,CAAA;AAEM,MAAM,QAAQ,GAAG,SAAS,QAAQ,CAAC,EACxC,GAAG,EACH,MAAM,GAIP;IACC,OAAO,CACL,uCAAK,SAAS,EAAE,6BAAC,CAAC,eAAe;QAC/B,sCAAI,SAAS,EAAE,6BAAC,CAAC,QAAQ;YACvB;gBACE,wDAAuB;gBACvB,4CAAO,UAAU,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,CAAQ,CAC1C;YACJ,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,MAAM,KAAK,SAAS,IAAI,CACvD;gBACE,2DAA0B;gBAC1B,4CACG,yBAAc,CACb,GAAG,CAAC,SAAS,IAAI,CAAC,EAClB,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,EAChC,EAAE,cAAc,EAAE,IAAI,EAAE,CACzB,CACI,CACJ,CACN;YACA,CAAC,CAAC,GAAG,CAAC,WAAW,IAAI,CACpB;gBACE;oBACG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE;oBAChD,yBAAc,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,SAAS,IAAI,CAAC,EAAE;wBACnD,cAAc,EAAE,IAAI;qBACrB,CAAC,CACI;gBACR,kEAAiC;gBACjC,4CAAO,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC,CAAQ,CACvC,CACN;YACA,CAAC,CAAC,GAAG,CAAC,UAAU,IAAI,CACnB;gBACE,6CACG,yBAAc,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,WAAW,IAAI,CAAC,EAAE;oBACpD,cAAc,EAAE,IAAI;iBACrB,CAAC,CACI;gBACR;oBAAQ,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU;0BAAY;gBAC/D,4CAAO,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAQ,CACtC,CACN,CACE,CACD,CACP,CAAA;AACH,CAAC,CAAA;AApDY,QAAA,QAAQ,YAoDpB"}
+6
View File
@@ -0,0 +1,6 @@
/// <reference types="react" />
import { Store } from '../../hooks/useStore';
export declare const Menu: ({ queues, selectedStatuses, }: {
queues: string[] | undefined;
selectedStatuses: Store['selectedStatuses'];
}) => JSX.Element;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Menu = void 0;
const react_1 = __importDefault(require("react"));
const react_router_dom_1 = require("react-router-dom");
const constants_1 = require("../constants");
const Menu_module_css_1 = __importDefault(require("./Menu.module.css"));
const Menu = ({ queues, selectedStatuses, }) => (react_1.default.createElement("aside", { className: Menu_module_css_1.default.aside },
react_1.default.createElement("div", null, "QUEUES"),
react_1.default.createElement("nav", null, !!queues && (react_1.default.createElement("ul", { className: Menu_module_css_1.default.menu }, queues.map((queueName) => (react_1.default.createElement("li", { key: queueName },
react_1.default.createElement(react_router_dom_1.NavLink, { to: `/queue/${encodeURIComponent(queueName)}${!selectedStatuses[queueName] ||
selectedStatuses[queueName] === constants_1.STATUS_LIST[0]
? ''
: `?status=${selectedStatuses[queueName]}`}`, activeClassName: Menu_module_css_1.default.active, title: queueName }, queueName))))))),
react_1.default.createElement("div", { className: Menu_module_css_1.default.appVersion }, process.env.APP_VERSION)));
exports.Menu = Menu;
//# sourceMappingURL=Menu.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Menu.js","sourceRoot":"","sources":["../../../../src/ui/components/Menu/Menu.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,uDAA0C;AAE1C,4CAA0C;AAC1C,wEAAiC;AAE1B,MAAM,IAAI,GAAG,CAAC,EACnB,MAAM,EACN,gBAAgB,GAIjB,EAAE,EAAE,CAAC,CACJ,yCAAO,SAAS,EAAE,yBAAC,CAAC,KAAK;IACvB,oDAAiB;IACjB,2CACG,CAAC,CAAC,MAAM,IAAI,CACX,sCAAI,SAAS,EAAE,yBAAC,CAAC,IAAI,IAClB,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CACzB,sCAAI,GAAG,EAAE,SAAS;QAChB,8BAAC,0BAAO,IACN,EAAE,EAAE,UAAU,kBAAkB,CAAC,SAAS,CAAC,GACzC,CAAC,gBAAgB,CAAC,SAAS,CAAC;gBAC5B,gBAAgB,CAAC,SAAS,CAAC,KAAK,uBAAW,CAAC,CAAC,CAAC;gBAC5C,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,WAAW,gBAAgB,CAAC,SAAS,CAAC,EAC5C,EAAE,EACF,eAAe,EAAE,yBAAC,CAAC,MAAM,EACzB,KAAK,EAAE,SAAS,IAEf,SAAS,CACF,CACP,CACN,CAAC,CACC,CACN,CACG;IACN,uCAAK,SAAS,EAAE,yBAAC,CAAC,UAAU,IAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAO,CACvD,CACT,CAAA;AAjCY,QAAA,IAAI,QAiChB"}
@@ -0,0 +1,11 @@
/// <reference types="react" />
import { AppQueue } from '../../../@types/app';
import { Store } from '../../hooks/useStore';
import { Status } from '../constants';
interface QueueActionProps {
queue: AppQueue;
actions: Store['actions'];
status: Status;
}
export declare const QueueActions: ({ status, actions, queue }: QueueActionProps) => JSX.Element | null;
export {};
@@ -0,0 +1,35 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueueActions = void 0;
const react_1 = __importDefault(require("react"));
const Retry_1 = require("../Icons/Retry");
const Trash_1 = require("../Icons/Trash");
const Button_1 = require("../JobCard/Button/Button");
const QueueActions_module_css_1 = __importDefault(require("./QueueActions.module.css"));
const ACTIONABLE_STATUSES = ['failed', 'delayed', 'completed'];
const isStatusActionable = (status) => ACTIONABLE_STATUSES.includes(status);
const CleanAllButton = ({ onClick }) => (react_1.default.createElement(Button_1.Button, { onClick: onClick, className: QueueActions_module_css_1.default.button },
react_1.default.createElement(Trash_1.TrashIcon, null),
"Clean all"));
const QueueActions = ({ status, actions, queue }) => {
if (!isStatusActionable(status)) {
return null;
}
return (react_1.default.createElement("ul", { className: QueueActions_module_css_1.default.queueActions },
status === 'failed' && (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement("li", null,
react_1.default.createElement(Button_1.Button, { onClick: actions.retryAll(queue.name), className: QueueActions_module_css_1.default.button },
react_1.default.createElement(Retry_1.RetryIcon, null),
"Retry all")),
react_1.default.createElement("li", null,
react_1.default.createElement(CleanAllButton, { onClick: actions.cleanAllFailed(queue.name) })))),
status === 'delayed' && (react_1.default.createElement("li", null,
react_1.default.createElement(CleanAllButton, { onClick: actions.cleanAllDelayed(queue.name) }))),
status === 'completed' && (react_1.default.createElement("li", null,
react_1.default.createElement(CleanAllButton, { onClick: actions.cleanAllCompleted(queue.name) })))));
};
exports.QueueActions = QueueActions;
//# sourceMappingURL=QueueActions.js.map
@@ -0,0 +1 @@
{"version":3,"file":"QueueActions.js","sourceRoot":"","sources":["../../../../src/ui/components/QueueActions/QueueActions.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAIzB,0CAA0C;AAC1C,0CAA0C;AAC1C,qDAAiD;AACjD,wFAAyC;AAQzC,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;AAE9D,MAAM,kBAAkB,GAAG,CAAC,MAAc,EAAW,EAAE,CACrD,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;AAEtC,MAAM,cAAc,GAAG,CAAC,EAAE,OAAO,EAAO,EAAE,EAAE,CAAC,CAC3C,8BAAC,eAAM,IAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,iCAAC,CAAC,MAAM;IAC3C,8BAAC,iBAAS,OAAG;gBAEN,CACV,CAAA;AAEM,MAAM,YAAY,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAoB,EAAE,EAAE;IAC3E,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE;QAC/B,OAAO,IAAI,CAAA;KACZ;IAED,OAAO,CACL,sCAAI,SAAS,EAAE,iCAAC,CAAC,YAAY;QAC1B,MAAM,KAAK,QAAQ,IAAI,CACtB;YACE;gBACE,8BAAC,eAAM,IAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,iCAAC,CAAC,MAAM;oBAChE,8BAAC,iBAAS,OAAG;gCAEN,CACN;YACL;gBACE,8BAAC,cAAc,IAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,GAAI,CAC5D,CACJ,CACJ;QACA,MAAM,KAAK,SAAS,IAAI,CACvB;YACE,8BAAC,cAAc,IAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,GAAI,CAC7D,CACN;QACA,MAAM,KAAK,WAAW,IAAI,CACzB;YACE,8BAAC,cAAc,IAAC,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,GAAI,CAC/D,CACN,CACE,CACN,CAAA;AACH,CAAC,CAAA;AAhCY,QAAA,YAAY,gBAgCxB"}
@@ -0,0 +1,8 @@
/// <reference types="react" />
import { AppQueue } from '../../../@types/app';
import { Store } from '../../hooks/useStore';
export declare const QueuePage: ({ selectedStatus, actions, queue, }: {
queue: AppQueue | undefined;
actions: Store['actions'];
selectedStatus: Store['selectedStatuses'];
}) => JSX.Element;
@@ -0,0 +1,28 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.QueuePage = void 0;
const react_1 = __importDefault(require("react"));
const JobCard_1 = require("../JobCard/JobCard");
const QueueActions_1 = require("../QueueActions/QueueActions");
const StatusMenu_1 = require("../StatusMenu/StatusMenu");
const QueuePage_module_css_1 = __importDefault(require("./QueuePage.module.css"));
const QueuePage = ({ selectedStatus, actions, queue, }) => {
if (!queue) {
return react_1.default.createElement("section", null, "Queue Not found");
}
return (react_1.default.createElement("section", null,
react_1.default.createElement("div", { className: QueuePage_module_css_1.default.stickyHeader },
react_1.default.createElement(StatusMenu_1.StatusMenu, { queue: queue }),
!queue.readOnlyMode && (react_1.default.createElement(QueueActions_1.QueueActions, { queue: queue, actions: actions, status: selectedStatus[queue.name] }))),
queue.jobs.map((job) => (react_1.default.createElement(JobCard_1.JobCard, { key: job.id, job: job, status: selectedStatus[queue.name], actions: {
cleanJob: actions.cleanJob(queue === null || queue === void 0 ? void 0 : queue.name)(job),
promoteJob: actions.promoteJob(queue === null || queue === void 0 ? void 0 : queue.name)(job),
retryJob: actions.retryJob(queue === null || queue === void 0 ? void 0 : queue.name)(job),
getJobLogs: actions.getJobLogs(queue === null || queue === void 0 ? void 0 : queue.name)(job),
}, readOnlyMode: queue === null || queue === void 0 ? void 0 : queue.readOnlyMode })))));
};
exports.QueuePage = QueuePage;
//# sourceMappingURL=QueuePage.js.map
@@ -0,0 +1 @@
{"version":3,"file":"QueuePage.js","sourceRoot":"","sources":["../../../../src/ui/components/QueuePage/QueuePage.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAGzB,gDAA4C;AAC5C,+DAA2D;AAC3D,yDAAqD;AACrD,kFAAsC;AAE/B,MAAM,SAAS,GAAG,CAAC,EACxB,cAAc,EACd,OAAO,EACP,KAAK,GAKN,EAAE,EAAE;IACH,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,iEAAkC,CAAA;KAC1C;IAED,OAAO,CACL;QACE,uCAAK,SAAS,EAAE,8BAAC,CAAC,YAAY;YAC5B,8BAAC,uBAAU,IAAC,KAAK,EAAE,KAAK,GAAI;YAC3B,CAAC,KAAK,CAAC,YAAY,IAAI,CACtB,8BAAC,2BAAY,IACX,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,GAClC,CACH,CACG;QACL,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACvB,8BAAC,iBAAO,IACN,GAAG,EAAE,GAAG,CAAC,EAAE,EACX,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,EAClC,OAAO,EAAE;gBACP,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAC,CAAC,GAAG,CAAC;gBAC5C,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAC,CAAC,GAAG,CAAC;gBAChD,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAC,CAAC,GAAG,CAAC;gBAC5C,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAI,CAAC,CAAC,GAAG,CAAC;aACjD,EACD,YAAY,EAAE,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,YAAY,GACjC,CACH,CAAC,CACM,CACX,CAAA;AACH,CAAC,CAAA;AAzCY,QAAA,SAAS,aAyCrB"}
@@ -0,0 +1,5 @@
/// <reference types="react" />
import { ValidMetrics } from '../../../@types/app';
export declare const RedisStats: ({ stats }: {
stats: Partial<ValidMetrics>;
}) => JSX.Element;
@@ -0,0 +1,52 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisStats = void 0;
const pretty_bytes_1 = __importDefault(require("pretty-bytes"));
const react_1 = __importDefault(require("react"));
const RedisStats_module_css_1 = __importDefault(require("./RedisStats.module.css"));
const RedisLogo = () => (react_1.default.createElement("svg", { width: 42, role: "img", viewBox: "0 0 24 24" },
react_1.default.createElement("path", { fill: "#CBD5E0", d: "M23.99314 6.28305c.012-.244-.307-.458-.949-.694-1.248-.457-7.843-3.082-9.106-3.545-1.263-.462-1.777-.443-3.261.089-1.484.533-8.506 3.287-9.755 3.776-.625.246-.931.473-.92.715v2.426c0 .242.334.498.97.802 1.272.608 8.332 3.461 9.448 3.994 1.116.533 1.9.54 3.313-.196 1.412-.736 8.047-3.465 9.328-4.132.651-.34.939-.604.939-.843 0-.225.001-2.392.001-2.392h-.008zm-15.399 2.296l5.561-.854-1.68 2.463-3.881-1.609zm12.299-2.218l-3.288 1.299-.357.14-3.287-1.299 3.642-1.44 3.29 1.3zm-9.655-2.383l-.538-.992 1.678.656 1.582-.518-.428 1.025 1.612.604-2.079.216-.466 1.12-.752-1.249-2.401-.216 1.792-.646zm-4.143 1.399c1.642 0 2.972.516 2.972 1.152 0 .636-1.331 1.152-2.972 1.152s-2.973-.517-2.973-1.152c0-.636 1.331-1.152 2.973-1.152z" }),
react_1.default.createElement("path", { fill: "#E2E8F0", d: "M23.99314 10.38505c-.011.229-.313.484-.934.809-1.281.667-7.916 3.396-9.328 4.132-1.413.736-2.197.729-3.313.196-1.116-.533-8.176-3.386-9.448-3.994-.635-.303-.959-.56-.97-.801v2.426c0 .242.334.498.97.802 1.272.608 8.332 3.46 9.448 3.993 1.116.534 1.9.541 3.313-.195 1.412-.736 8.047-3.465 9.328-4.132.651-.34.939-.604.939-.843 0-.226.001-2.392.001-2.392-.001-.001-.004 0-.006-.001z" }),
react_1.default.createElement("path", { fill: "#EDF2F7", d: "M23.99414 14.34005c-.01.229-.313.485-.935.81-1.281.667-7.916 3.396-9.328 4.132-1.413.736-2.197.729-3.313.195-1.116-.533-8.176-3.386-9.448-3.993-.635-.304-.959-.56-.97-.802v2.426c0 .242.334.499.97.803 1.272.608 8.333 3.46 9.448 3.993 1.116.534 1.9.541 3.313-.196 1.412-.736 8.047-3.464 9.328-4.132.651-.339.939-.603.939-.842 0-.226.001-2.392.001-2.392-.001-.001-.004-.001-.005-.002z" })));
const getMemoryUsage = (used_memory, total_system_memory) => {
if (used_memory === undefined) {
return '-';
}
const usedMemory = parseInt(used_memory, 10);
if (total_system_memory === undefined) {
return pretty_bytes_1.default(usedMemory);
}
const totalSystemMemory = parseInt(total_system_memory, 10);
return `${((usedMemory / totalSystemMemory) * 100).toFixed(2)}%`;
};
const RedisStats = ({ stats }) => {
const { redis_version, used_memory, total_system_memory, mem_fragmentation_ratio, connected_clients, blocked_clients, } = stats;
return (react_1.default.createElement("div", { className: RedisStats_module_css_1.default.stats },
react_1.default.createElement("div", null,
react_1.default.createElement(RedisLogo, null)),
react_1.default.createElement("div", null,
"Version",
react_1.default.createElement("span", null, redis_version)),
react_1.default.createElement("div", null,
"Memory usage",
react_1.default.createElement("span", null, getMemoryUsage(used_memory, total_system_memory)),
total_system_memory && used_memory ? (react_1.default.createElement("small", null,
pretty_bytes_1.default(parseInt(used_memory)),
" of",
' ',
pretty_bytes_1.default(parseInt(total_system_memory)))) : (react_1.default.createElement("small", { className: "error" }, "Could not retrieve memory stats"))),
react_1.default.createElement("div", null,
"Fragmentation ratio",
react_1.default.createElement("span", null, mem_fragmentation_ratio)),
react_1.default.createElement("div", null,
"Connected clients",
react_1.default.createElement("span", null, connected_clients)),
react_1.default.createElement("div", null,
"Blocked clients",
react_1.default.createElement("span", null, blocked_clients))));
};
exports.RedisStats = RedisStats;
//# sourceMappingURL=RedisStats.js.map
@@ -0,0 +1 @@
{"version":3,"file":"RedisStats.js","sourceRoot":"","sources":["../../../../src/ui/components/RedisStats/RedisStats.tsx"],"names":[],"mappings":";;;;;;AAAA,gEAAsC;AACtC,kDAAyB;AAEzB,oFAAuC;AAEvC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,CACtB,uCAAK,KAAK,EAAE,EAAE,EAAE,IAAI,EAAC,KAAK,EAAC,OAAO,EAAC,WAAW;IAC5C,wCACE,IAAI,EAAC,SAAS,EACd,CAAC,EAAC,utBAAutB,GACztB;IACF,wCACE,IAAI,EAAC,SAAS,EACd,CAAC,EAAC,6XAA6X,GAC/X;IACF,wCACE,IAAI,EAAC,SAAS,EACd,CAAC,EAAC,+XAA+X,GACjY,CACE,CACP,CAAA;AAED,MAAM,cAAc,GAAG,CACrB,WAAyC,EACzC,mBAAyD,EACzD,EAAE;IACF,IAAI,WAAW,KAAK,SAAS,EAAE;QAC7B,OAAO,GAAG,CAAA;KACX;IACD,MAAM,UAAU,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IAE5C,IAAI,mBAAmB,KAAK,SAAS,EAAE;QACrC,OAAO,sBAAW,CAAC,UAAU,CAAC,CAAA;KAC/B;IACD,MAAM,iBAAiB,GAAG,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;IAE3D,OAAO,GAAG,CAAC,CAAC,UAAU,GAAG,iBAAiB,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAA;AAClE,CAAC,CAAA;AAEM,MAAM,UAAU,GAAG,CAAC,EAAE,KAAK,EAAoC,EAAE,EAAE;IACxE,MAAM,EACJ,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,GAChB,GAAG,KAAK,CAAA;IAET,OAAO,CACL,uCAAK,SAAS,EAAE,+BAAC,CAAC,KAAK;QACrB;YACE,8BAAC,SAAS,OAAG,CACT;QAEN;;YAEE,4CAAO,aAAa,CAAQ,CACxB;QAEN;;YAEE,4CAAO,cAAc,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAQ;YAC9D,mBAAmB,IAAI,WAAW,CAAC,CAAC,CAAC,CACpC;gBACG,sBAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;;gBAAK,GAAG;gBAC1C,sBAAW,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CACrC,CACT,CAAC,CAAC,CAAC,CACF,yCAAO,SAAS,EAAC,OAAO,sCAAwC,CACjE,CACG;QAEN;;YAEE,4CAAO,uBAAuB,CAAQ,CAClC;QAEN;;YAEE,4CAAO,iBAAiB,CAAQ,CAC5B;QAEN;;YAEE,4CAAO,eAAe,CAAQ,CAC1B,CACF,CACP,CAAA;AACH,CAAC,CAAA;AAlDY,QAAA,UAAU,cAkDtB"}
@@ -0,0 +1,5 @@
/// <reference types="react" />
import { AppQueue } from '../../../@types/app';
export declare const StatusMenu: ({ queue }: {
queue: AppQueue;
}) => JSX.Element;
@@ -0,0 +1,26 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StatusMenu = void 0;
const react_1 = __importDefault(require("react"));
const react_router_dom_1 = require("react-router-dom");
const constants_1 = require("../constants");
const StatusMenu_module_css_1 = __importDefault(require("./StatusMenu.module.css"));
const StatusMenu = ({ queue }) => {
const { url } = react_router_dom_1.useRouteMatch();
return (react_1.default.createElement("div", { className: StatusMenu_module_css_1.default.statusMenu }, constants_1.STATUS_LIST.map((status) => {
const isLatest = status === constants_1.STATUSES.latest;
const displayStatus = status.toLocaleUpperCase();
return (react_1.default.createElement(react_router_dom_1.NavLink, { to: `${url}${isLatest ? '' : `?status=${status}`}`, activeClassName: StatusMenu_module_css_1.default.active, isActive: (_path, { search }) => {
const query = new URLSearchParams(search);
return (query.get('status') === status ||
(isLatest && query.get('status') === null));
}, key: `${queue.name}-${status}` },
react_1.default.createElement("span", { title: displayStatus }, displayStatus),
queue.counts[status] > 0 && (react_1.default.createElement("span", { className: StatusMenu_module_css_1.default.badge }, queue.counts[status]))));
})));
};
exports.StatusMenu = StatusMenu;
//# sourceMappingURL=StatusMenu.js.map
@@ -0,0 +1 @@
{"version":3,"file":"StatusMenu.js","sourceRoot":"","sources":["../../../../src/ui/components/StatusMenu/StatusMenu.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,uDAAyD;AAEzD,4CAAoD;AACpD,oFAAuC;AAEhC,MAAM,UAAU,GAAG,CAAC,EAAE,KAAK,EAAuB,EAAE,EAAE;IAC3D,MAAM,EAAE,GAAG,EAAE,GAAG,gCAAa,EAAE,CAAA;IAE/B,OAAO,CACL,uCAAK,SAAS,EAAE,+BAAC,CAAC,UAAU,IACzB,uBAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAC1B,MAAM,QAAQ,GAAG,MAAM,KAAK,oBAAQ,CAAC,MAAM,CAAA;QAC3C,MAAM,aAAa,GAAG,MAAM,CAAC,iBAAiB,EAAE,CAAA;QAChD,OAAO,CACL,8BAAC,0BAAO,IACN,EAAE,EAAE,GAAG,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,MAAM,EAAE,EAAE,EAClD,eAAe,EAAE,+BAAC,CAAC,MAAM,EACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;gBAC9B,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;gBACzC,OAAO,CACL,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM;oBAC9B,CAAC,QAAQ,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,CAC3C,CAAA;YACH,CAAC,EACD,GAAG,EAAE,GAAG,KAAK,CAAC,IAAI,IAAI,MAAM,EAAE;YAE9B,wCAAM,KAAK,EAAE,aAAa,IAAG,aAAa,CAAQ;YACjD,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAC3B,wCAAM,SAAS,EAAE,+BAAC,CAAC,KAAK,IAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAQ,CACxD,CACO,CACX,CAAA;IACH,CAAC,CAAC,CACE,CACP,CAAA;AACH,CAAC,CAAA;AA9BY,QAAA,UAAU,cA8BtB"}
@@ -0,0 +1,4 @@
import React from 'react';
export declare const Tooltip: ({ title, children, }: React.PropsWithChildren<{
title: string;
}>) => JSX.Element;
+11
View File
@@ -0,0 +1,11 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Tooltip = void 0;
const react_1 = __importDefault(require("react"));
const Tooltip_module_css_1 = __importDefault(require("./Tooltip.module.css"));
const Tooltip = ({ title, children, }) => (react_1.default.createElement("span", { "data-title": title, className: Tooltip_module_css_1.default.tooltip }, children));
exports.Tooltip = Tooltip;
//# sourceMappingURL=Tooltip.js.map
@@ -0,0 +1 @@
{"version":3,"file":"Tooltip.js","sourceRoot":"","sources":["../../../../src/ui/components/Tooltip/Tooltip.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,8EAAoC;AAE7B,MAAM,OAAO,GAAG,CAAC,EACtB,KAAK,EACL,QAAQ,GACmC,EAAE,EAAE,CAAC,CAChD,sDAAkB,KAAK,EAAE,SAAS,EAAE,4BAAC,CAAC,OAAO,IAC1C,QAAQ,CACJ,CACR,CAAA;AAPY,QAAA,OAAO,WAOnB"}
+14
View File
@@ -0,0 +1,14 @@
import { KeyOf } from '../../@types/utils';
export declare const STATUSES: {
latest: string;
active: string;
waiting: string;
completed: string;
failed: string;
delayed: string;
paused: string;
};
export declare const STATUS_LIST: KeyOf<typeof STATUSES>;
export declare type Status = keyof typeof STATUSES;
export declare type Field = 'attempts' | 'data' | 'id' | 'name' | 'opts' | 'progress' | 'timestamps' | 'delay' | 'failedReason' | 'retry' | 'promote' | 'clean';
export declare const FIELDS: Record<Status, Field[]>;
+60
View File
@@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FIELDS = exports.STATUS_LIST = exports.STATUSES = void 0;
exports.STATUSES = {
latest: 'latest',
active: 'active',
waiting: 'waiting',
completed: 'completed',
failed: 'failed',
delayed: 'delayed',
paused: 'paused',
};
exports.STATUS_LIST = [
exports.STATUSES.latest,
exports.STATUSES.active,
exports.STATUSES.waiting,
exports.STATUSES.completed,
exports.STATUSES.failed,
exports.STATUSES.delayed,
exports.STATUSES.paused,
];
exports.FIELDS = {
active: ['attempts', 'data', 'id', 'name', 'opts', 'progress', 'timestamps'],
completed: [
'attempts',
'data',
'id',
'name',
'opts',
'progress',
'timestamps',
],
delayed: [
'attempts',
'data',
'delay',
'id',
'name',
'opts',
'promote',
'timestamps',
'clean',
],
failed: [
'attempts',
'failedReason',
'data',
'opts',
'id',
'name',
'progress',
'retry',
'timestamps',
'clean',
],
latest: ['attempts', 'data', 'id', 'name', 'opts', 'progress', 'timestamps'],
paused: ['attempts', 'data', 'id', 'name', 'opts', 'timestamps'],
waiting: ['data', 'id', 'name', 'opts', 'timestamps', 'clean'],
};
//# sourceMappingURL=constants.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/ui/components/constants.ts"],"names":[],"mappings":";;;AAEa,QAAA,QAAQ,GAAG;IACtB,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;CACjB,CAAA;AAEY,QAAA,WAAW,GAA2B;IACjD,gBAAQ,CAAC,MAAa;IACtB,gBAAQ,CAAC,MAAM;IACf,gBAAQ,CAAC,OAAO;IAChB,gBAAQ,CAAC,SAAS;IAClB,gBAAQ,CAAC,MAAM;IACf,gBAAQ,CAAC,OAAO;IAChB,gBAAQ,CAAC,MAAM;CAChB,CAAA;AAkBY,QAAA,MAAM,GAA4B;IAC7C,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,CAAC;IAC5E,SAAS,EAAE;QACT,UAAU;QACV,MAAM;QACN,IAAI;QACJ,MAAM;QACN,MAAM;QACN,UAAU;QACV,YAAY;KACb;IACD,OAAO,EAAE;QACP,UAAU;QACV,MAAM;QACN,OAAO;QACP,IAAI;QACJ,MAAM;QACN,MAAM;QACN,SAAS;QACT,YAAY;QACZ,OAAO;KACR;IACD,MAAM,EAAE;QACN,UAAU;QACV,cAAc;QACd,MAAM;QACN,MAAM;QACN,IAAI;QACJ,MAAM;QACN,UAAU;QACV,OAAO;QACP,YAAY;QACZ,OAAO;KACR;IACD,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,CAAC;IAC5E,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC;IAChE,OAAO,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC;CAC/D,CAAA"}
+12
View File
@@ -0,0 +1,12 @@
import { Status } from '../components/constants';
declare const regularItems: readonly ["Data", "Options", "Logs"];
export declare type TabsType = typeof regularItems[number] | 'Error';
export declare function useDetailsTabs(currentStatus: Status): {
tabs: {
title: TabsType;
isActive: boolean;
selectTab: () => void;
}[];
selectedTab: TabsType;
};
export {};
+26
View File
@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useDetailsTabs = void 0;
const react_1 = require("react");
const constants_1 = require("../components/constants");
const regularItems = ['Data', 'Options', 'Logs'];
function useDetailsTabs(currentStatus) {
const [tabs, updateTabs] = react_1.useState([]);
const [selectedTabIdx, setSelectedTabIdx] = react_1.useState(0);
const selectedTab = tabs[selectedTabIdx];
react_1.useEffect(() => {
updateTabs(currentStatus === constants_1.STATUSES.failed
? ['Error', ...regularItems]
: [...regularItems]);
}, [currentStatus]);
return {
tabs: tabs.map((title, index) => ({
title,
isActive: title === selectedTab,
selectTab: () => setSelectedTabIdx(index),
})),
selectedTab,
};
}
exports.useDetailsTabs = useDetailsTabs;
//# sourceMappingURL=useDetailsTabs.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"useDetailsTabs.js","sourceRoot":"","sources":["../../../src/ui/hooks/useDetailsTabs.tsx"],"names":[],"mappings":";;;AAAA,iCAA2C;AAC3C,uDAA0D;AAE1D,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAU,CAAA;AAIzD,SAAgB,cAAc,CAAC,aAAqB;IAClD,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,gBAAQ,CAAa,EAAE,CAAC,CAAA;IACnD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,gBAAQ,CAAC,CAAC,CAAC,CAAA;IACvD,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,CAAA;IAExC,iBAAS,CAAC,GAAG,EAAE;QACb,UAAU,CACR,aAAa,KAAK,oBAAQ,CAAC,MAAM;YAC/B,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,YAAY,CAAC;YAC5B,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,CACtB,CAAA;IACH,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAA;IAEnB,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAChC,KAAK;YACL,QAAQ,EAAE,KAAK,KAAK,WAAW;YAC/B,SAAS,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC;SAC1C,CAAC,CAAC;QACH,WAAW;KACZ,CAAA;AACH,CAAC;AArBD,wCAqBC"}
+1
View File
@@ -0,0 +1 @@
export declare function useInterval(callback: () => void, delay: number | null, deps?: any[]): void;
+25
View File
@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useInterval = void 0;
const react_1 = require("react");
function useInterval(callback, delay, deps = []) {
const savedCallback = react_1.useRef(callback);
// Remember the latest callback if it changes.
react_1.useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
react_1.useEffect(() => {
// Don't schedule if no delay is specified.
if (delay === null) {
return;
}
savedCallback.current();
const id = setInterval(() => savedCallback.current(), delay);
return () => {
clearInterval(id);
};
}, [delay, ...deps]);
}
exports.useInterval = useInterval;
//# sourceMappingURL=useInterval.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"useInterval.js","sourceRoot":"","sources":["../../../src/ui/hooks/useInterval.ts"],"names":[],"mappings":";;;AAAA,iCAAyC;AAEzC,SAAgB,WAAW,CACzB,QAAoB,EACpB,KAAoB,EACpB,OAAc,EAAE;IAEhB,MAAM,aAAa,GAAG,cAAM,CAAC,QAAQ,CAAC,CAAA;IAEtC,8CAA8C;IAC9C,iBAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,OAAO,GAAG,QAAQ,CAAA;IAClC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,uBAAuB;IACvB,iBAAS,CAAC,GAAG,EAAE;QACb,2CAA2C;QAC3C,IAAI,KAAK,KAAK,IAAI,EAAE;YAClB,OAAM;SACP;QAED,aAAa,CAAC,OAAO,EAAE,CAAA;QAEvB,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAA;QAE5D,OAAO,GAAG,EAAE;YACV,aAAa,CAAC,EAAE,CAAC,CAAA;QACnB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAA;AACtB,CAAC;AA3BD,kCA2BC"}
+1
View File
@@ -0,0 +1 @@
export declare function useScrollTopOnNav(): void;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useScrollTopOnNav = void 0;
const react_1 = require("react");
const react_router_dom_1 = require("react-router-dom");
function useScrollTopOnNav() {
const { key } = react_router_dom_1.useLocation();
react_1.useEffect(() => {
window.scrollTo(0, 0);
}, [key]);
}
exports.useScrollTopOnNav = useScrollTopOnNav;
//# sourceMappingURL=useScrollTopOnNav.js.map
@@ -0,0 +1 @@
{"version":3,"file":"useScrollTopOnNav.js","sourceRoot":"","sources":["../../../src/ui/hooks/useScrollTopOnNav.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AACjC,uDAA8C;AAE9C,SAAgB,iBAAiB;IAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,8BAAW,EAAE,CAAA;IAC7B,iBAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACvB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;AACX,CAAC;AALD,8CAKC"}
@@ -0,0 +1,2 @@
import { SelectedStatuses } from '../../@types/app';
export declare function useSelectedStatuses(): SelectedStatuses;
+22
View File
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useSelectedStatuses = void 0;
const react_1 = require("react");
const react_router_dom_1 = require("react-router-dom");
const constants_1 = require("../components/constants");
function useSelectedStatuses() {
const { search, pathname } = react_router_dom_1.useLocation();
const match = react_router_dom_1.useRouteMatch({ path: '/queue/:name' });
const [selectedStatuses, setSelectedStatuses] = react_1.useState({});
react_1.useEffect(() => {
const query = new URLSearchParams(search);
const status = query.get('status') || constants_1.STATUS_LIST[0];
const queue = match ? decodeURIComponent(match === null || match === void 0 ? void 0 : match.params.name) : '';
if (queue) {
setSelectedStatuses({ ...selectedStatuses, [queue]: status });
}
}, [search, pathname]);
return selectedStatuses;
}
exports.useSelectedStatuses = useSelectedStatuses;
//# sourceMappingURL=useSelectedStatuses.js.map
@@ -0,0 +1 @@
{"version":3,"file":"useSelectedStatuses.js","sourceRoot":"","sources":["../../../src/ui/hooks/useSelectedStatuses.ts"],"names":[],"mappings":";;;AAAA,iCAA2C;AAC3C,uDAA6D;AAE7D,uDAA6D;AAE7D,SAAgB,mBAAmB;IACjC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,8BAAW,EAAE,CAAA;IAC1C,MAAM,KAAK,GAAG,gCAAa,CAAmB,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAA;IAEvE,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,gBAAQ,CAAmB,EAAE,CAAC,CAAA;IAE9E,iBAAS,CAAC,GAAG,EAAE;QACb,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;QACzC,MAAM,MAAM,GAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAY,IAAI,uBAAW,CAAC,CAAC,CAAC,CAAA;QAChE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QACjE,IAAI,KAAK,EAAE;YACT,mBAAmB,CAAC,EAAE,GAAG,gBAAgB,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;SAC9D;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEtB,OAAO,gBAAgB,CAAA;AACzB,CAAC;AAhBD,kDAgBC"}
+14
View File
@@ -0,0 +1,14 @@
import * as api from '../../@types/api';
import { QueueActions, SelectedStatuses } from '../../@types/app';
import { Api } from '../services/Api';
declare type State = {
data: null | api.GetQueues;
loading: boolean;
};
export interface Store {
state: State;
actions: QueueActions;
selectedStatuses: SelectedStatuses;
}
export declare const useStore: (api: Api) => Store;
export {};
+46
View File
@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useStore = void 0;
const react_1 = require("react");
const useInterval_1 = require("./useInterval");
const useSelectedStatuses_1 = require("./useSelectedStatuses");
const interval = 5000;
const useStore = (api) => {
const [state, setState] = react_1.useState({
data: null,
loading: true,
});
const selectedStatuses = useSelectedStatuses_1.useSelectedStatuses();
const update = () => api
.getQueues({ status: selectedStatuses })
.then((data) => {
setState({ data, loading: false });
})
// eslint-disable-next-line no-console
.catch((error) => console.error('Failed to poll', error));
useInterval_1.useInterval(update, interval, [selectedStatuses]);
const promoteJob = (queueName) => (job) => () => api.promoteJob(queueName, job.id).then(update);
const retryJob = (queueName) => (job) => () => api.retryJob(queueName, job.id).then(update);
const cleanJob = (queueName) => (job) => () => api.cleanJob(queueName, job.id).then(update);
const retryAll = (queueName) => () => api.retryAll(queueName).then(update);
const cleanAllDelayed = (queueName) => () => api.cleanAllDelayed(queueName).then(update);
const cleanAllFailed = (queueName) => () => api.cleanAllFailed(queueName).then(update);
const cleanAllCompleted = (queueName) => () => api.cleanAllCompleted(queueName).then(update);
const getJobLogs = (queueName) => (job) => () => api.getJobLogs(queueName, job.id);
return {
state,
actions: {
promoteJob,
retryJob,
retryAll,
cleanJob,
cleanAllDelayed,
cleanAllFailed,
cleanAllCompleted,
getJobLogs,
},
selectedStatuses,
};
};
exports.useStore = useStore;
//# sourceMappingURL=useStore.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"useStore.js","sourceRoot":"","sources":["../../../src/ui/hooks/useStore.ts"],"names":[],"mappings":";;;AAAA,iCAAgC;AAIhC,+CAA2C;AAC3C,+DAA2D;AAE3D,MAAM,QAAQ,GAAG,IAAI,CAAA;AAad,MAAM,QAAQ,GAAG,CAAC,GAAQ,EAAS,EAAE;IAC1C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,gBAAQ,CAAQ;QACxC,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,IAAI;KACd,CAAC,CAAA;IAEF,MAAM,gBAAgB,GAAG,yCAAmB,EAAE,CAAA;IAE9C,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,GAAG;SACA,SAAS,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;SACvC,IAAI,CAAC,CAAC,IAAmB,EAAE,EAAE;QAC5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAA;IACpC,CAAC,CAAC;QACF,sCAAsC;SACrC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC,CAAA;IAE7D,yBAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAA;IAEjD,MAAM,UAAU,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,EAAE,CAC9D,GAAG,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAEhD,MAAM,QAAQ,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,EAAE,CAC5D,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAE9C,MAAM,QAAQ,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,EAAE,CAC5D,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAE9C,MAAM,QAAQ,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,GAAG,EAAE,CAC3C,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAEtC,MAAM,eAAe,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,GAAG,EAAE,CAClD,GAAG,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAE7C,MAAM,cAAc,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,GAAG,EAAE,CACjD,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAE5C,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,GAAG,EAAE,CACpD,GAAG,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAE/C,MAAM,UAAU,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,EAAE,CAC9D,GAAG,CAAC,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;IAEnC,OAAO;QACL,KAAK;QACL,OAAO,EAAE;YACP,UAAU;YACV,QAAQ;YACR,QAAQ;YACR,QAAQ;YACR,eAAe;YACf,cAAc;YACd,iBAAiB;YACjB,UAAU;SACX;QACD,gBAAgB;KACjB,CAAA;AACH,CAAC,CAAA;AAzDY,QAAA,QAAQ,YAyDpB"}
+3
View File
@@ -0,0 +1,3 @@
import './index.css';
import './theme.css';
import './toastify.css';
+1
View File
@@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><base href="<%= basePath %>"/><title>Bull Dashboard</title><link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500&display=swap" rel="stylesheet"><script defer="defer" src="<%= basePath %>/static/vendor.a7a5c6b037a450ac3f38.js"></script><script defer="defer" src="<%= basePath %>/static/main.b9ee2f393232badbddf2.js"></script><link href="<%= basePath %>/static/main.776d169b005873942466.css" rel="stylesheet"></head><body><div id="root">Loading...</div></body></html>
+19
View File
@@ -0,0 +1,19 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const react_dom_1 = require("react-dom");
require("./index.css");
require("./theme.css");
require("./toastify.css");
const react_router_dom_1 = require("react-router-dom");
const App_1 = require("./components/App");
const Api_1 = require("./services/Api");
const basePath = ((_a = document.head.querySelector('base')) === null || _a === void 0 ? void 0 : _a.getAttribute('href')) || '';
const api = new Api_1.Api({ basePath });
react_dom_1.render(react_1.default.createElement(react_router_dom_1.BrowserRouter, { basename: basePath },
react_1.default.createElement(App_1.App, { api: api })), document.getElementById('root'));
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.tsx"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AACzB,yCAAkC;AAElC,uBAAoB;AACpB,uBAAoB;AACpB,0BAAuB;AACvB,uDAAgD;AAChD,0CAAsC;AACtC,wCAAoC;AAEpC,MAAM,QAAQ,GAAG,CAAA,MAAA,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,0CAAE,YAAY,CAAC,MAAM,CAAC,KAAI,EAAE,CAAA;AAChF,MAAM,GAAG,GAAG,IAAI,SAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;AAEjC,kBAAM,CACJ,8BAAC,gCAAa,IAAC,QAAQ,EAAE,QAAQ;IAC/B,8BAAC,SAAG,IAAC,GAAG,EAAE,GAAG,GAAI,CACH,EAChB,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAChC,CAAA"}
+21
View File
@@ -0,0 +1,21 @@
import { GetQueues } from '../../@types/api';
import { SelectedStatuses } from '../../@types/app';
export declare class Api {
private axios;
constructor({ basePath }?: {
basePath: string;
});
getQueues({ status, }: {
status: SelectedStatuses;
}): Promise<GetQueues>;
retryAll(queueName: string): Promise<void>;
cleanAllDelayed(queueName: string): Promise<void>;
cleanAllFailed(queueName: string): Promise<void>;
cleanAllCompleted(queueName: string): Promise<void>;
cleanJob(queueName: string, jobId: string | number | undefined): Promise<void>;
retryJob(queueName: string, jobId: string | number | undefined): Promise<void>;
promoteJob(queueName: string, jobId: string | number | undefined): Promise<void>;
getJobLogs(queueName: string, jobId: string | number | undefined): Promise<string[]>;
private handleResponse;
private handleError;
}
+53
View File
@@ -0,0 +1,53 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Api = void 0;
const axios_1 = __importDefault(require("axios"));
const react_toastify_1 = require("react-toastify");
class Api {
constructor({ basePath } = { basePath: '' }) {
this.axios = axios_1.default.create({ baseURL: `${basePath}/api` });
this.axios.interceptors.response.use(this.handleResponse, this.handleError);
}
getQueues({ status, }) {
return this.axios.get(`/queues/`, { params: { ...status } });
}
retryAll(queueName) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/retry`);
}
cleanAllDelayed(queueName) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/clean/delayed`);
}
cleanAllFailed(queueName) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/clean/failed`);
}
cleanAllCompleted(queueName) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/clean/completed`);
}
cleanJob(queueName, jobId) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/${jobId}/clean`);
}
retryJob(queueName, jobId) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/${jobId}/retry`);
}
promoteJob(queueName, jobId) {
return this.axios.put(`/queues/${encodeURIComponent(queueName)}/${jobId}/promote`);
}
getJobLogs(queueName, jobId) {
return this.axios.get(`/queues/${encodeURIComponent(queueName)}/${jobId}/logs`);
}
handleResponse(response) {
return response.data;
}
async handleError(error) {
var _a, _b;
if ((_a = error.response.data) === null || _a === void 0 ? void 0 : _a.error) {
react_toastify_1.toast.error((_b = error.response.data) === null || _b === void 0 ? void 0 : _b.error, { autoClose: 5000 });
}
return Promise.resolve(error.response.data);
}
}
exports.Api = Api;
//# sourceMappingURL=Api.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Api.js","sourceRoot":"","sources":["../../../src/ui/services/Api.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA2D;AAC3D,mDAAsC;AAItC,MAAa,GAAG;IAGd,YAAY,EAAE,QAAQ,KAA2B,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC/D,IAAI,CAAC,KAAK,GAAG,eAAK,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,QAAQ,MAAM,EAAE,CAAC,CAAA;QACzD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAEM,SAAS,CAAC,EACf,MAAM,GAGP;QACC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,CAAA;IAC9D,CAAC;IAEM,QAAQ,CAAC,SAAiB;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,kBAAkB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;IACzE,CAAC;IAEM,eAAe,CAAC,SAAiB;QACtC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,kBAAkB,CAAC,SAAS,CAAC,gBAAgB,CACzD,CAAA;IACH,CAAC;IAEM,cAAc,CAAC,SAAiB;QACrC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,kBAAkB,CAAC,SAAS,CAAC,eAAe,CACxD,CAAA;IACH,CAAC;IAEM,iBAAiB,CAAC,SAAiB;QACxC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,kBAAkB,CAAC,SAAS,CAAC,kBAAkB,CAC3D,CAAA;IACH,CAAC;IAEM,QAAQ,CACb,SAAiB,EACjB,KAAkC;QAElC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,kBAAkB,CAAC,SAAS,CAAC,IAAI,KAAK,QAAQ,CAC1D,CAAA;IACH,CAAC;IAEM,QAAQ,CACb,SAAiB,EACjB,KAAkC;QAElC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,kBAAkB,CAAC,SAAS,CAAC,IAAI,KAAK,QAAQ,CAC1D,CAAA;IACH,CAAC;IAEM,UAAU,CACf,SAAiB,EACjB,KAAkC;QAElC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,kBAAkB,CAAC,SAAS,CAAC,IAAI,KAAK,UAAU,CAC5D,CAAA;IACH,CAAC;IAEM,UAAU,CACf,SAAiB,EACjB,KAAkC;QAElC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CACnB,WAAW,kBAAkB,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO,CACzD,CAAA;IACH,CAAC;IAEO,cAAc,CAAC,QAAuB;QAC5C,OAAO,QAAQ,CAAC,IAAI,CAAA;IACtB,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,KAAkC;;QAC1D,IAAI,MAAA,KAAK,CAAC,QAAQ,CAAC,IAAI,0CAAE,KAAK,EAAE;YAC9B,sBAAK,CAAC,KAAK,CAAC,MAAA,KAAK,CAAC,QAAQ,CAAC,IAAI,0CAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;SAC7D;QAED,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC7C,CAAC;CACF;AArFD,kBAqFC"}