plum-e2e 1.1.1 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -70
- package/backend/Dockerfile +4 -2
- package/backend/_scaffold/utils/browser.ts +1 -0
- package/backend/app.js +4 -2
- package/backend/config/scripts/generate-report.js +38 -30
- package/{.prettierignore → backend/entrypoint.sh} +7 -6
- package/backend/package-lock.json +453 -10
- package/backend/package.json +5 -2
- package/backend/prisma/migrations/20260614000000_init/migration.sql +35 -0
- package/backend/prisma/migrations/20260614000001_add_project/migration.sql +8 -0
- package/backend/prisma/migrations/migration_lock.toml +3 -0
- package/backend/prisma/schema.prisma +53 -0
- package/backend/routes/backup.routes.js +50 -0
- package/backend/routes/cron.routes.js +9 -60
- package/backend/routes/reports.routes.js +39 -6
- package/backend/routes/settings.routes.js +43 -0
- package/backend/server.js +52 -1
- package/backend/services/backupService.js +88 -0
- package/backend/services/cronService.js +68 -78
- package/backend/{routes/schedules.routes.js → services/prisma.js} +3 -13
- package/backend/services/reportService.js +48 -20
- package/backend/services/settingsService.js +36 -0
- package/bin/plum.js +216 -34
- package/docker-compose.yml +24 -0
- package/frontend/.svelte-kit/adapter-node/.vite/manifest.json +190 -0
- package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
- package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/Button.cBruH0aD.css +17 -0
- package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
- package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.BVnUajEa.css +17 -0
- package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
- package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
- package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
- package/frontend/.svelte-kit/adapter-node/chunks/Badge.js +30 -0
- package/frontend/.svelte-kit/adapter-node/chunks/Button.js +32 -0
- package/frontend/.svelte-kit/adapter-node/chunks/attributes.js +34 -0
- package/frontend/.svelte-kit/adapter-node/chunks/client.js +59 -0
- package/{backend/services/scheduleService.js → frontend/.svelte-kit/adapter-node/chunks/equality.js} +13 -16
- package/frontend/.svelte-kit/adapter-node/chunks/escaping.js +36 -0
- package/frontend/.svelte-kit/adapter-node/chunks/exports.js +247 -0
- package/frontend/.svelte-kit/adapter-node/chunks/index.js +1135 -0
- package/frontend/.svelte-kit/adapter-node/chunks/internal.js +695 -0
- package/frontend/.svelte-kit/adapter-node/chunks/reports.js +57 -0
- package/frontend/.svelte-kit/adapter-node/entries/fallbacks/error.svelte.js +44 -0
- package/frontend/.svelte-kit/adapter-node/entries/pages/_layout.svelte.js +181 -0
- package/frontend/.svelte-kit/adapter-node/entries/pages/_page.svelte.js +164 -0
- package/frontend/.svelte-kit/adapter-node/entries/pages/reports/_page.svelte.js +141 -0
- package/frontend/.svelte-kit/adapter-node/entries/pages/reports/_slug_/_page.svelte.js +42 -0
- package/frontend/.svelte-kit/adapter-node/entries/pages/scheduled-tests/_page.svelte.js +179 -0
- package/frontend/.svelte-kit/adapter-node/index.js +3144 -0
- package/frontend/.svelte-kit/adapter-node/internal.js +30 -0
- package/frontend/.svelte-kit/adapter-node/manifest-full.js +77 -0
- package/frontend/.svelte-kit/adapter-node/manifest.js +81 -0
- package/frontend/.svelte-kit/adapter-node/nodes/0.js +25 -0
- package/frontend/.svelte-kit/adapter-node/nodes/1.js +25 -0
- package/frontend/.svelte-kit/adapter-node/nodes/2.js +25 -0
- package/frontend/.svelte-kit/adapter-node/nodes/3.js +25 -0
- package/frontend/.svelte-kit/adapter-node/nodes/4.js +25 -0
- package/frontend/.svelte-kit/adapter-node/nodes/5.js +25 -0
- package/frontend/.svelte-kit/ambient.d.ts +240 -0
- package/frontend/.svelte-kit/generated/client/app.js +51 -0
- package/frontend/.svelte-kit/generated/client/matchers.js +18 -0
- package/frontend/.svelte-kit/generated/client/nodes/0.js +18 -0
- package/frontend/.svelte-kit/generated/client/nodes/1.js +18 -0
- package/frontend/.svelte-kit/generated/client/nodes/2.js +18 -0
- package/frontend/.svelte-kit/generated/client/nodes/3.js +18 -0
- package/frontend/.svelte-kit/generated/client/nodes/4.js +18 -0
- package/frontend/.svelte-kit/generated/client/nodes/5.js +18 -0
- package/frontend/.svelte-kit/generated/client-optimized/app.js +51 -0
- package/frontend/.svelte-kit/generated/client-optimized/matchers.js +18 -0
- package/frontend/.svelte-kit/generated/client-optimized/nodes/0.js +18 -0
- package/frontend/.svelte-kit/generated/client-optimized/nodes/1.js +18 -0
- package/frontend/.svelte-kit/generated/client-optimized/nodes/2.js +18 -0
- package/frontend/.svelte-kit/generated/client-optimized/nodes/3.js +18 -0
- package/frontend/.svelte-kit/generated/client-optimized/nodes/4.js +18 -0
- package/frontend/.svelte-kit/generated/client-optimized/nodes/5.js +18 -0
- package/frontend/.svelte-kit/generated/root.js +20 -0
- package/frontend/.svelte-kit/generated/root.svelte +83 -0
- package/frontend/.svelte-kit/generated/server/internal.js +65 -0
- package/frontend/.svelte-kit/non-ambient.d.ts +42 -0
- package/frontend/.svelte-kit/output/client/.vite/manifest.json +289 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/0.CnXRuPt4.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/2.CGnCsn5q.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/3.BVnUajEa.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/4.DBhBrHFz.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/5.D93VAB-w.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/Button.cBruH0aD.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.BVnUajEa.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/B0bn91RF.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/B1kE5jmt.js +23 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BKz6FZdB.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Be4iUAB0.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BpaMqo9O.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Bt3-Z7H1.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CHV2KnPr.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CJ8q7g9Y.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Cit9MuSg.js +20 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CwBTqcbj.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DBk3zeq4.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DFJLQFic.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DTUE7kkY.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/IYPwzKs_.js +20 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/oc0we5Us.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/chunks/rVEKg0Ak.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/entry/app.C2MbX06K.js +19 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/entry/start.GiBry-lw.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/nodes/0.BsCYK-Tn.js +21 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/nodes/1.N4gjrCnX.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/nodes/2.D9yQNzK8.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/nodes/3.CBC5WvNb.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/nodes/4.BU6UZHSE.js +19 -0
- package/frontend/.svelte-kit/output/client/_app/immutable/nodes/5.Dzzfrntl.js +18 -0
- package/frontend/.svelte-kit/output/client/_app/version.json +1 -0
- package/frontend/.svelte-kit/output/client/favicon.png +0 -0
- package/frontend/.svelte-kit/output/server/.vite/manifest.json +190 -0
- package/frontend/.svelte-kit/output/server/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
- package/frontend/.svelte-kit/output/server/_app/immutable/assets/Button.cBruH0aD.css +17 -0
- package/frontend/.svelte-kit/output/server/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
- package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.BVnUajEa.css +17 -0
- package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
- package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
- package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
- package/frontend/.svelte-kit/output/server/chunks/Badge.js +30 -0
- package/frontend/.svelte-kit/output/server/chunks/Button.js +32 -0
- package/frontend/.svelte-kit/output/server/chunks/attributes.js +34 -0
- package/frontend/.svelte-kit/output/server/chunks/client.js +59 -0
- package/frontend/.svelte-kit/output/server/chunks/equality.js +31 -0
- package/frontend/.svelte-kit/output/server/chunks/escaping.js +36 -0
- package/frontend/.svelte-kit/output/server/chunks/exports.js +247 -0
- package/frontend/.svelte-kit/output/server/chunks/index.js +1135 -0
- package/frontend/.svelte-kit/output/server/chunks/internal.js +695 -0
- package/frontend/.svelte-kit/output/server/chunks/reports.js +57 -0
- package/frontend/.svelte-kit/output/server/entries/fallbacks/error.svelte.js +44 -0
- package/frontend/.svelte-kit/output/server/entries/pages/_layout.svelte.js +181 -0
- package/frontend/.svelte-kit/output/server/entries/pages/_page.svelte.js +164 -0
- package/frontend/.svelte-kit/output/server/entries/pages/reports/_page.svelte.js +141 -0
- package/frontend/.svelte-kit/output/server/entries/pages/reports/_slug_/_page.svelte.js +42 -0
- package/frontend/.svelte-kit/output/server/entries/pages/scheduled-tests/_page.svelte.js +179 -0
- package/frontend/.svelte-kit/output/server/index.js +3144 -0
- package/frontend/.svelte-kit/output/server/internal.js +30 -0
- package/frontend/.svelte-kit/output/server/manifest-full.js +77 -0
- package/frontend/.svelte-kit/output/server/manifest.js +77 -0
- package/frontend/.svelte-kit/output/server/nodes/0.js +25 -0
- package/frontend/.svelte-kit/output/server/nodes/1.js +25 -0
- package/frontend/.svelte-kit/output/server/nodes/2.js +25 -0
- package/frontend/.svelte-kit/output/server/nodes/3.js +25 -0
- package/frontend/.svelte-kit/output/server/nodes/4.js +25 -0
- package/frontend/.svelte-kit/output/server/nodes/5.js +25 -0
- package/frontend/.svelte-kit/tsconfig.json +49 -0
- package/frontend/build/client/_app/immutable/assets/0.CnXRuPt4.css +17 -0
- package/frontend/build/client/_app/immutable/assets/0.CnXRuPt4.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/0.CnXRuPt4.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/2.CGnCsn5q.css +17 -0
- package/frontend/build/client/_app/immutable/assets/2.CGnCsn5q.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/2.CGnCsn5q.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/3.BVnUajEa.css +17 -0
- package/frontend/build/client/_app/immutable/assets/3.BVnUajEa.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/3.BVnUajEa.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/4.DBhBrHFz.css +17 -0
- package/frontend/build/client/_app/immutable/assets/4.DBhBrHFz.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/4.DBhBrHFz.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/5.D93VAB-w.css +17 -0
- package/frontend/build/client/_app/immutable/assets/5.D93VAB-w.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/5.D93VAB-w.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/Badge.DLLowvEA.css +17 -0
- package/frontend/build/client/_app/immutable/assets/Badge.DLLowvEA.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/Badge.DLLowvEA.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/Button.cBruH0aD.css +17 -0
- package/frontend/build/client/_app/immutable/assets/Button.cBruH0aD.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/Button.cBruH0aD.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/_layout.D7eM-6MV.css +17 -0
- package/frontend/build/client/_app/immutable/assets/_layout.D7eM-6MV.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/_layout.D7eM-6MV.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.BVnUajEa.css +17 -0
- package/frontend/build/client/_app/immutable/assets/_page.BVnUajEa.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.BVnUajEa.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.CGnCsn5q.css +17 -0
- package/frontend/build/client/_app/immutable/assets/_page.CGnCsn5q.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.CGnCsn5q.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.DBhBrHFz.css +17 -0
- package/frontend/build/client/_app/immutable/assets/_page.DBhBrHFz.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.DBhBrHFz.css.gz +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.DOqo0UR4.css +17 -0
- package/frontend/build/client/_app/immutable/assets/_page.DOqo0UR4.css.br +0 -0
- package/frontend/build/client/_app/immutable/assets/_page.DOqo0UR4.css.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/B0bn91RF.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/B0bn91RF.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/B0bn91RF.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/B1kE5jmt.js +23 -0
- package/frontend/build/client/_app/immutable/chunks/B1kE5jmt.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/B1kE5jmt.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/BKz6FZdB.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/BKz6FZdB.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/BKz6FZdB.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/Be4iUAB0.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/Be4iUAB0.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/Be4iUAB0.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/BpaMqo9O.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/BpaMqo9O.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/BpaMqo9O.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/Bt3-Z7H1.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/Bt3-Z7H1.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/Bt3-Z7H1.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/CHV2KnPr.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/CHV2KnPr.js.br +18 -0
- package/frontend/build/client/_app/immutable/chunks/CHV2KnPr.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/CJ8q7g9Y.js +18 -0
- package/{resources/comments-format.text → frontend/build/client/_app/immutable/chunks/CJ8q7g9Y.js.br} +0 -0
- package/frontend/build/client/_app/immutable/chunks/CJ8q7g9Y.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/Cit9MuSg.js +20 -0
- package/frontend/build/client/_app/immutable/chunks/Cit9MuSg.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/Cit9MuSg.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/CwBTqcbj.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/CwBTqcbj.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/CwBTqcbj.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/DBk3zeq4.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/DBk3zeq4.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/DBk3zeq4.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/DFJLQFic.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/DFJLQFic.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/DFJLQFic.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/DTUE7kkY.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/DTUE7kkY.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/DTUE7kkY.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/IYPwzKs_.js +20 -0
- package/frontend/build/client/_app/immutable/chunks/IYPwzKs_.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/IYPwzKs_.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/oc0we5Us.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/oc0we5Us.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/oc0we5Us.js.gz +0 -0
- package/frontend/build/client/_app/immutable/chunks/rVEKg0Ak.js +18 -0
- package/frontend/build/client/_app/immutable/chunks/rVEKg0Ak.js.br +0 -0
- package/frontend/build/client/_app/immutable/chunks/rVEKg0Ak.js.gz +0 -0
- package/frontend/build/client/_app/immutable/entry/app.C2MbX06K.js +19 -0
- package/frontend/build/client/_app/immutable/entry/app.C2MbX06K.js.br +0 -0
- package/frontend/build/client/_app/immutable/entry/app.C2MbX06K.js.gz +0 -0
- package/frontend/build/client/_app/immutable/entry/start.GiBry-lw.js +18 -0
- package/frontend/build/client/_app/immutable/entry/start.GiBry-lw.js.br +18 -0
- package/frontend/build/client/_app/immutable/entry/start.GiBry-lw.js.gz +0 -0
- package/frontend/build/client/_app/immutable/nodes/0.BsCYK-Tn.js +21 -0
- package/frontend/build/client/_app/immutable/nodes/0.BsCYK-Tn.js.br +0 -0
- package/frontend/build/client/_app/immutable/nodes/0.BsCYK-Tn.js.gz +0 -0
- package/frontend/build/client/_app/immutable/nodes/1.N4gjrCnX.js +18 -0
- package/frontend/build/client/_app/immutable/nodes/1.N4gjrCnX.js.br +0 -0
- package/frontend/build/client/_app/immutable/nodes/1.N4gjrCnX.js.gz +0 -0
- package/frontend/build/client/_app/immutable/nodes/2.D9yQNzK8.js +18 -0
- package/frontend/build/client/_app/immutable/nodes/2.D9yQNzK8.js.br +0 -0
- package/frontend/build/client/_app/immutable/nodes/2.D9yQNzK8.js.gz +0 -0
- package/frontend/build/client/_app/immutable/nodes/3.CBC5WvNb.js +18 -0
- package/frontend/build/client/_app/immutable/nodes/3.CBC5WvNb.js.br +0 -0
- package/frontend/build/client/_app/immutable/nodes/3.CBC5WvNb.js.gz +0 -0
- package/frontend/build/client/_app/immutable/nodes/4.BU6UZHSE.js +19 -0
- package/frontend/build/client/_app/immutable/nodes/4.BU6UZHSE.js.br +0 -0
- package/frontend/build/client/_app/immutable/nodes/4.BU6UZHSE.js.gz +0 -0
- package/frontend/build/client/_app/immutable/nodes/5.Dzzfrntl.js +18 -0
- package/frontend/build/client/_app/immutable/nodes/5.Dzzfrntl.js.br +0 -0
- package/frontend/build/client/_app/immutable/nodes/5.Dzzfrntl.js.gz +0 -0
- package/frontend/build/client/_app/version.json +1 -0
- package/frontend/build/client/_app/version.json.br +0 -0
- package/frontend/build/client/_app/version.json.gz +0 -0
- package/frontend/build/client/favicon.png +0 -0
- package/frontend/build/env.js +111 -0
- package/frontend/build/handler.js +1511 -0
- package/frontend/build/index.js +362 -0
- package/frontend/build/server/chunks/0-BFfqmlsS.js +26 -0
- package/frontend/build/server/chunks/0-BFfqmlsS.js.map +17 -0
- package/frontend/build/server/chunks/1-hso3H4Ax.js +26 -0
- package/frontend/build/server/chunks/1-hso3H4Ax.js.map +17 -0
- package/frontend/build/server/chunks/2-BSZWXCWp.js +26 -0
- package/frontend/build/server/chunks/2-BSZWXCWp.js.map +17 -0
- package/frontend/build/server/chunks/3-BYumY9dv.js +26 -0
- package/frontend/build/server/chunks/3-BYumY9dv.js.map +17 -0
- package/frontend/build/server/chunks/4-2UUrCVtM.js +26 -0
- package/frontend/build/server/chunks/4-2UUrCVtM.js.map +17 -0
- package/frontend/build/server/chunks/5-C2_y_fwT.js +26 -0
- package/frontend/build/server/chunks/5-C2_y_fwT.js.map +17 -0
- package/frontend/build/server/chunks/Badge-CC4U7C0c.js +30 -0
- package/frontend/build/server/chunks/Badge-CC4U7C0c.js.map +17 -0
- package/frontend/build/server/chunks/Button-BLkPicwS.js +33 -0
- package/frontend/build/server/chunks/Button-BLkPicwS.js.map +17 -0
- package/frontend/build/server/chunks/_layout.svelte-Bfxcj9C6.js +183 -0
- package/frontend/build/server/chunks/_layout.svelte-Bfxcj9C6.js.map +17 -0
- package/frontend/build/server/chunks/_page.svelte-DEK6UvaI.js +45 -0
- package/frontend/build/server/chunks/_page.svelte-DEK6UvaI.js.map +17 -0
- package/frontend/build/server/chunks/_page.svelte-DScVdHOq.js +142 -0
- package/frontend/build/server/chunks/_page.svelte-DScVdHOq.js.map +17 -0
- package/frontend/build/server/chunks/_page.svelte-Ns7w2sZt.js +180 -0
- package/frontend/build/server/chunks/_page.svelte-Ns7w2sZt.js.map +17 -0
- package/frontend/build/server/chunks/_page.svelte-s6ZIOitT.js +165 -0
- package/frontend/build/server/chunks/_page.svelte-s6ZIOitT.js.map +17 -0
- package/frontend/build/server/chunks/attributes-BeaNKpgU.js +34 -0
- package/frontend/build/server/chunks/attributes-BeaNKpgU.js.map +17 -0
- package/frontend/build/server/chunks/client-C9IaEwNo.js +52 -0
- package/frontend/build/server/chunks/client-C9IaEwNo.js.map +17 -0
- package/frontend/build/server/chunks/error.svelte-HKBv5sQT.js +45 -0
- package/frontend/build/server/chunks/error.svelte-HKBv5sQT.js.map +17 -0
- package/frontend/build/server/chunks/escaping-CqgfEcN3.js +36 -0
- package/frontend/build/server/chunks/escaping-CqgfEcN3.js.map +17 -0
- package/frontend/build/server/chunks/exports-OxlCJ8yE.js +192 -0
- package/frontend/build/server/chunks/exports-OxlCJ8yE.js.map +17 -0
- package/frontend/build/server/chunks/index-CjHlq1kt.js +1076 -0
- package/frontend/build/server/chunks/index-CjHlq1kt.js.map +17 -0
- package/frontend/build/server/chunks/reports-D3ZeYSmi.js +56 -0
- package/frontend/build/server/chunks/reports-D3ZeYSmi.js.map +17 -0
- package/frontend/build/server/index.js +5015 -0
- package/frontend/build/server/index.js.map +17 -0
- package/frontend/build/server/manifest.js +84 -0
- package/frontend/build/server/manifest.js.map +17 -0
- package/frontend/build/shims.js +49 -0
- package/frontend/package-lock.json +2 -2
- package/frontend/package.json +1 -1
- package/frontend/src/lib/api/reports.js +38 -27
- package/frontend/src/lib/api/schedules.js +9 -25
- package/frontend/src/lib/api/settings.js +48 -0
- package/frontend/src/lib/components/layout/Nav.svelte +2 -1
- package/frontend/src/lib/components/layout/RunnerPanel.svelte +160 -21
- package/frontend/src/lib/components/ui/Terminal.svelte +2 -2
- package/frontend/src/lib/stores/runner.js +9 -0
- package/frontend/src/routes/+page.svelte +10 -3
- package/frontend/src/routes/reports/+page.svelte +342 -51
- package/frontend/src/routes/reports/[slug]/+page.svelte +2 -0
- package/frontend/src/routes/scheduled-tests/+page.svelte +247 -11
- package/frontend/src/routes/settings/+page.svelte +410 -0
- package/package.json +6 -2
- package/.claude/settings.local.json +0 -27
- package/.husky/pre-commit +0 -2
- package/.prettierrc +0 -15
- package/.vscode/settings.json +0 -10
- package/backend/config/scripts/create-settings.js +0 -53
- package/license-config.json +0 -37
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const manifest = (() => {
|
|
19
|
+
function __memo(fn) {
|
|
20
|
+
let value;
|
|
21
|
+
return () => value ??= (value = fn());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
appDir: "_app",
|
|
26
|
+
appPath: "_app",
|
|
27
|
+
assets: new Set(["favicon.png"]),
|
|
28
|
+
mimeTypes: {".png":"image/png"},
|
|
29
|
+
_: {
|
|
30
|
+
client: {start:"_app/immutable/entry/start.GiBry-lw.js",app:"_app/immutable/entry/app.C2MbX06K.js",imports:["_app/immutable/entry/start.GiBry-lw.js","_app/immutable/chunks/Cit9MuSg.js","_app/immutable/chunks/B0bn91RF.js","_app/immutable/entry/app.C2MbX06K.js","_app/immutable/chunks/B0bn91RF.js","_app/immutable/chunks/DFJLQFic.js","_app/immutable/chunks/CwBTqcbj.js","_app/immutable/chunks/Be4iUAB0.js","_app/immutable/chunks/CHV2KnPr.js"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},
|
|
31
|
+
nodes: [
|
|
32
|
+
__memo(() => import('./chunks/0-BFfqmlsS.js')),
|
|
33
|
+
__memo(() => import('./chunks/1-hso3H4Ax.js')),
|
|
34
|
+
__memo(() => import('./chunks/2-BSZWXCWp.js')),
|
|
35
|
+
__memo(() => import('./chunks/3-BYumY9dv.js')),
|
|
36
|
+
__memo(() => import('./chunks/4-2UUrCVtM.js')),
|
|
37
|
+
__memo(() => import('./chunks/5-C2_y_fwT.js'))
|
|
38
|
+
],
|
|
39
|
+
routes: [
|
|
40
|
+
{
|
|
41
|
+
id: "/",
|
|
42
|
+
pattern: /^\/$/,
|
|
43
|
+
params: [],
|
|
44
|
+
page: { layouts: [0,], errors: [1,], leaf: 2 },
|
|
45
|
+
endpoint: null
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "/reports",
|
|
49
|
+
pattern: /^\/reports\/?$/,
|
|
50
|
+
params: [],
|
|
51
|
+
page: { layouts: [0,], errors: [1,], leaf: 3 },
|
|
52
|
+
endpoint: null
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "/reports/[slug]",
|
|
56
|
+
pattern: /^\/reports\/([^/]+?)\/?$/,
|
|
57
|
+
params: [{"name":"slug","optional":false,"rest":false,"chained":false}],
|
|
58
|
+
page: { layouts: [0,], errors: [1,], leaf: 4 },
|
|
59
|
+
endpoint: null
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "/scheduled-tests",
|
|
63
|
+
pattern: /^\/scheduled-tests\/?$/,
|
|
64
|
+
params: [],
|
|
65
|
+
page: { layouts: [0,], errors: [1,], leaf: 5 },
|
|
66
|
+
endpoint: null
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
prerendered_routes: new Set([]),
|
|
70
|
+
matchers: async () => {
|
|
71
|
+
|
|
72
|
+
return { };
|
|
73
|
+
},
|
|
74
|
+
server_assets: {}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
78
|
+
|
|
79
|
+
const prerendered = new Set([]);
|
|
80
|
+
|
|
81
|
+
const base = "";
|
|
82
|
+
|
|
83
|
+
export { base, manifest, prerendered };
|
|
84
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This file is part of Plum.
|
|
3
|
+
|
|
4
|
+
Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU General Public License as published by
|
|
6
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
(at your option) any later version.
|
|
8
|
+
|
|
9
|
+
Plum is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
{"version":3,"file":"manifest.js","sources":["../../.svelte-kit/adapter-node/manifest.js"],"sourcesContent":["export const manifest = (() => {\nfunction __memo(fn) {\n\tlet value;\n\treturn () => value ??= (value = fn());\n}\n\nreturn {\n\tappDir: \"_app\",\n\tappPath: \"_app\",\n\tassets: new Set([\"favicon.png\"]),\n\tmimeTypes: {\".png\":\"image/png\"},\n\t_: {\n\t\tclient: {start:\"_app/immutable/entry/start.GiBry-lw.js\",app:\"_app/immutable/entry/app.C2MbX06K.js\",imports:[\"_app/immutable/entry/start.GiBry-lw.js\",\"_app/immutable/chunks/Cit9MuSg.js\",\"_app/immutable/chunks/B0bn91RF.js\",\"_app/immutable/entry/app.C2MbX06K.js\",\"_app/immutable/chunks/B0bn91RF.js\",\"_app/immutable/chunks/DFJLQFic.js\",\"_app/immutable/chunks/CwBTqcbj.js\",\"_app/immutable/chunks/Be4iUAB0.js\",\"_app/immutable/chunks/CHV2KnPr.js\"],stylesheets:[],fonts:[],uses_env_dynamic_public:false},\n\t\tnodes: [\n\t\t\t__memo(() => import('./nodes/0.js')),\n\t\t\t__memo(() => import('./nodes/1.js')),\n\t\t\t__memo(() => import('./nodes/2.js')),\n\t\t\t__memo(() => import('./nodes/3.js')),\n\t\t\t__memo(() => import('./nodes/4.js')),\n\t\t\t__memo(() => import('./nodes/5.js'))\n\t\t],\n\t\troutes: [\n\t\t\t{\n\t\t\t\tid: \"/\",\n\t\t\t\tpattern: /^\\/$/,\n\t\t\t\tparams: [],\n\t\t\t\tpage: { layouts: [0,], errors: [1,], leaf: 2 },\n\t\t\t\tendpoint: null\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/reports\",\n\t\t\t\tpattern: /^\\/reports\\/?$/,\n\t\t\t\tparams: [],\n\t\t\t\tpage: { layouts: [0,], errors: [1,], leaf: 3 },\n\t\t\t\tendpoint: null\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/reports/[slug]\",\n\t\t\t\tpattern: /^\\/reports\\/([^/]+?)\\/?$/,\n\t\t\t\tparams: [{\"name\":\"slug\",\"optional\":false,\"rest\":false,\"chained\":false}],\n\t\t\t\tpage: { layouts: [0,], errors: [1,], leaf: 4 },\n\t\t\t\tendpoint: null\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"/scheduled-tests\",\n\t\t\t\tpattern: /^\\/scheduled-tests\\/?$/,\n\t\t\t\tparams: [],\n\t\t\t\tpage: { layouts: [0,], errors: [1,], leaf: 5 },\n\t\t\t\tendpoint: null\n\t\t\t}\n\t\t],\n\t\tprerendered_routes: new Set([]),\n\t\tmatchers: async () => {\n\t\t\t\n\t\t\treturn { };\n\t\t},\n\t\tserver_assets: {}\n\t}\n}\n})();\n\nexport const prerendered = new Set([]);\n\nexport const base = \"\";"],"names":[],"mappings":"AAAY,MAAC,QAAQ,GAAG,CAAC,MAAM;AAC/B,SAAS,MAAM,CAAC,EAAE,EAAE;AACpB,CAAC,IAAI,KAAK;AACV,CAAC,OAAO,MAAM,KAAK,MAAM,KAAK,GAAG,EAAE,EAAE,CAAC;AACtC;;AAEA,OAAO;AACP,CAAC,MAAM,EAAE,MAAM;AACf,CAAC,OAAO,EAAE,MAAM;AAChB,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC;AACjC,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC;AAChC,CAAC,CAAC,EAAE;AACJ,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,wCAAwC,CAAC,GAAG,CAAC,sCAAsC,CAAC,OAAO,CAAC,CAAC,wCAAwC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,sCAAsC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,mCAAmC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC;AACjf,EAAE,KAAK,EAAE;AACT,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC,CAAC;AACvC,GAAG,MAAM,CAAC,MAAM,OAAO,wBAAc,CAAC;AACtC,GAAG;AACH,EAAE,MAAM,EAAE;AACV,GAAG;AACH,IAAI,EAAE,EAAE,GAAG;AACX,IAAI,OAAO,EAAE,MAAM;AACnB,IAAI,MAAM,EAAE,EAAE;AACd,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;AAClD,IAAI,QAAQ,EAAE;AACd,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,UAAU;AAClB,IAAI,OAAO,EAAE,gBAAgB;AAC7B,IAAI,MAAM,EAAE,EAAE;AACd,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;AAClD,IAAI,QAAQ,EAAE;AACd,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,iBAAiB;AACzB,IAAI,OAAO,EAAE,0BAA0B;AACvC,IAAI,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC3E,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;AAClD,IAAI,QAAQ,EAAE;AACd,IAAI;AACJ,GAAG;AACH,IAAI,EAAE,EAAE,kBAAkB;AAC1B,IAAI,OAAO,EAAE,wBAAwB;AACrC,IAAI,MAAM,EAAE,EAAE;AACd,IAAI,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;AAClD,IAAI,QAAQ,EAAE;AACd;AACA,GAAG;AACH,EAAE,kBAAkB,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC;AACjC,EAAE,QAAQ,EAAE,YAAY;AACxB;AACA,GAAG,OAAO,IAAI;AACd,EAAE,CAAC;AACH,EAAE,aAAa,EAAE;AACjB;AACA;AACA,CAAC;;AAEW,MAAC,WAAW,GAAG,IAAI,GAAG,CAAC,EAAE;;AAEzB,MAAC,IAAI,GAAG;;;;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import buffer from 'node:buffer';
|
|
19
|
+
import { webcrypto } from 'node:crypto';
|
|
20
|
+
|
|
21
|
+
// `buffer.File` was added in Node 18.13.0 while the `File` global was added in Node 20.0.0
|
|
22
|
+
const File = /** @type {import('node:buffer') & { File?: File}} */ (buffer).File;
|
|
23
|
+
|
|
24
|
+
/** @type {Record<string, any>} */
|
|
25
|
+
const globals = {
|
|
26
|
+
crypto: webcrypto,
|
|
27
|
+
File
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// exported for dev/preview and node environments
|
|
31
|
+
/**
|
|
32
|
+
* Make various web APIs available as globals:
|
|
33
|
+
* - `crypto`
|
|
34
|
+
* - `File`
|
|
35
|
+
*/
|
|
36
|
+
function installPolyfills() {
|
|
37
|
+
for (const name in globals) {
|
|
38
|
+
if (name in globalThis) continue;
|
|
39
|
+
|
|
40
|
+
Object.defineProperty(globalThis, name, {
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true,
|
|
43
|
+
writable: true,
|
|
44
|
+
value: globals[name]
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
installPolyfills();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plum-frontend",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "plum-frontend",
|
|
9
|
-
"version": "
|
|
9
|
+
"version": "1.2.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"socket.io-client": "^4.8.1"
|
|
12
12
|
},
|
package/frontend/package.json
CHANGED
|
@@ -15,29 +15,12 @@
|
|
|
15
15
|
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
/*
|
|
19
|
-
This file is part of Plum.
|
|
20
|
-
|
|
21
|
-
Plum is free software: you can redistribute it and/or modify
|
|
22
|
-
it under the terms of the GNU General Public License as published by
|
|
23
|
-
the Free Software Foundation, either version 3 of the License, or
|
|
24
|
-
(at your option) any later version.
|
|
25
|
-
|
|
26
|
-
Plum is distributed in the hope that it will be useful,
|
|
27
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
28
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
29
|
-
GNU General Public License for more details.
|
|
30
|
-
|
|
31
|
-
You should have received a copy of the GNU General Public License
|
|
32
|
-
along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
18
|
const BASE = 'http://localhost:3001';
|
|
36
19
|
|
|
37
20
|
export async function fetchReports() {
|
|
38
21
|
const res = await fetch(`${BASE}/reports`);
|
|
39
22
|
const { reports } = await res.json();
|
|
40
|
-
return reports.map(
|
|
23
|
+
return reports.map((r) => ({ ...r, date: new Date(r.createdAt).toLocaleString() }));
|
|
41
24
|
}
|
|
42
25
|
|
|
43
26
|
export async function fetchLatestReport() {
|
|
@@ -50,19 +33,47 @@ export function reportUrl(fileName) {
|
|
|
50
33
|
return `/reports/${encodeURIComponent(fileName)}`;
|
|
51
34
|
}
|
|
52
35
|
|
|
36
|
+
// Parses metadata out of a report filename.
|
|
37
|
+
// Format: {STATUS}_cucumber_report_{trigger}_{tags}_runners_{n}_{timestamp}.json
|
|
38
|
+
export function parseReport(fileName) {
|
|
39
|
+
const m = fileName.match(
|
|
40
|
+
/^(PASS|FAIL)_cucumber_report_(.+?)_(\([^)]+\))_runners_(\d+)_(\d{4}_\d{2}_\d{2}T[\d_]+Z)\.json$/
|
|
41
|
+
);
|
|
42
|
+
if (!m) return null;
|
|
43
|
+
const [, status, triggerType, tags, runners, tsRaw] = m;
|
|
44
|
+
const isoStr = tsRaw.replace(
|
|
45
|
+
/^(\d{4})_(\d{2})_(\d{2})T(\d{2})_(\d{2})_(\d{2})_(\d+)Z$/,
|
|
46
|
+
'$1-$2-$3T$4:$5:$6.$7Z'
|
|
47
|
+
);
|
|
48
|
+
return {
|
|
49
|
+
status,
|
|
50
|
+
triggerType,
|
|
51
|
+
tags,
|
|
52
|
+
runners: parseInt(runners, 10),
|
|
53
|
+
date: new Date(isoStr).toLocaleString()
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
53
57
|
export async function fetchReportDetail(fileName) {
|
|
54
58
|
const res = await fetch(`${BASE}/reports/${encodeURIComponent(fileName)}/detail`);
|
|
55
59
|
if (!res.ok) throw new Error('Report not found');
|
|
56
60
|
return res.json();
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
export function
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
);
|
|
63
|
-
if (!
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
export async function deleteReport(fileName) {
|
|
64
|
+
const res = await fetch(`${BASE}/reports/${encodeURIComponent(fileName)}`, {
|
|
65
|
+
method: 'DELETE'
|
|
66
|
+
});
|
|
67
|
+
if (!res.ok) throw new Error('Failed to delete report');
|
|
68
|
+
return res.json();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function deleteReports(fileNames) {
|
|
72
|
+
const res = await fetch(`${BASE}/reports/bulk`, {
|
|
73
|
+
method: 'DELETE',
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
body: JSON.stringify({ fileNames })
|
|
76
|
+
});
|
|
77
|
+
if (!res.ok) throw new Error('Failed to delete reports');
|
|
78
|
+
return res.json();
|
|
68
79
|
}
|
|
@@ -15,45 +15,29 @@
|
|
|
15
15
|
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
/*
|
|
19
|
-
This file is part of Plum.
|
|
20
|
-
|
|
21
|
-
Plum is free software: you can redistribute it and/or modify
|
|
22
|
-
it under the terms of the GNU General Public License as published by
|
|
23
|
-
the Free Software Foundation, either version 3 of the License, or
|
|
24
|
-
(at your option) any later version.
|
|
25
|
-
|
|
26
|
-
Plum is distributed in the hope that it will be useful,
|
|
27
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
28
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
29
|
-
GNU General Public License for more details.
|
|
30
|
-
|
|
31
|
-
You should have received a copy of the GNU General Public License
|
|
32
|
-
along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
18
|
const BASE = 'http://localhost:3001';
|
|
36
19
|
|
|
37
|
-
export async function fetchSchedules() {
|
|
38
|
-
const res = await fetch(`${BASE}/schedules`);
|
|
39
|
-
const { schedules } = await res.json();
|
|
40
|
-
return schedules ?? [];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
20
|
export async function fetchCronJobs() {
|
|
44
21
|
const res = await fetch(`${BASE}/cron-jobs`);
|
|
45
22
|
const { cronJobs } = await res.json();
|
|
46
23
|
return cronJobs ?? [];
|
|
47
24
|
}
|
|
48
25
|
|
|
49
|
-
export async function saveCronJob({
|
|
26
|
+
export async function saveCronJob({
|
|
27
|
+
taskName,
|
|
28
|
+
cronExpression,
|
|
29
|
+
tags,
|
|
30
|
+
workers,
|
|
31
|
+
isEditing,
|
|
32
|
+
editTaskName
|
|
33
|
+
}) {
|
|
50
34
|
const formattedTags = tags.replace(/\sOR\s/gi, (m) => m.toLowerCase());
|
|
51
35
|
const url = isEditing ? `${BASE}/cron-jobs/${editTaskName}` : `${BASE}/cron-jobs`;
|
|
52
36
|
const method = isEditing ? 'PUT' : 'POST';
|
|
53
37
|
const res = await fetch(url, {
|
|
54
38
|
method,
|
|
55
39
|
headers: { 'Content-Type': 'application/json' },
|
|
56
|
-
body: JSON.stringify({ cronExpression, taskName, tags: formattedTags })
|
|
40
|
+
body: JSON.stringify({ cronExpression, taskName, tags: formattedTags, workers })
|
|
57
41
|
});
|
|
58
42
|
return res.json();
|
|
59
43
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file is part of Plum.
|
|
3
|
+
*
|
|
4
|
+
* Plum is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
|
6
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* Plum is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU General Public License
|
|
15
|
+
* along with Plum. If not, see https://www.gnu.org/licenses/.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const BASE = 'http://localhost:3001';
|
|
19
|
+
|
|
20
|
+
export async function fetchProject() {
|
|
21
|
+
const res = await fetch(`${BASE}/settings/project`);
|
|
22
|
+
if (!res.ok) return { name: '', logoUrl: '' };
|
|
23
|
+
return res.json();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function saveProject({ name, logoUrl }) {
|
|
27
|
+
const res = await fetch(`${BASE}/settings/project`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'Content-Type': 'application/json' },
|
|
30
|
+
body: JSON.stringify({ name, logoUrl })
|
|
31
|
+
});
|
|
32
|
+
return res.json();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function exportBackup() {
|
|
36
|
+
const res = await fetch(`${BASE}/backup/export`);
|
|
37
|
+
if (!res.ok) throw new Error('Export failed');
|
|
38
|
+
return res.json();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function importBackup(data) {
|
|
42
|
+
const res = await fetch(`${BASE}/backup/import`, {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: { 'Content-Type': 'application/json' },
|
|
45
|
+
body: JSON.stringify(data)
|
|
46
|
+
});
|
|
47
|
+
return res.json();
|
|
48
|
+
}
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
const links = [
|
|
26
26
|
{ href: '/', label: 'Run Tests' },
|
|
27
27
|
{ href: '/reports', label: 'Reports' },
|
|
28
|
-
{ href: '/scheduled-tests', label: 'Scheduled' }
|
|
28
|
+
{ href: '/scheduled-tests', label: 'Scheduled' },
|
|
29
|
+
{ href: '/settings', label: 'Settings' }
|
|
29
30
|
];
|
|
30
31
|
|
|
31
32
|
function toggleTheme() {
|
|
@@ -19,7 +19,16 @@
|
|
|
19
19
|
import { onMount } from 'svelte';
|
|
20
20
|
import { slide, fly } from 'svelte/transition';
|
|
21
21
|
import { io } from 'socket.io-client';
|
|
22
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
socket,
|
|
24
|
+
runnerState,
|
|
25
|
+
runnerConfig,
|
|
26
|
+
panelExpanded,
|
|
27
|
+
triggerRun,
|
|
28
|
+
testsVersion,
|
|
29
|
+
reportsVersion,
|
|
30
|
+
activeCronJobs
|
|
31
|
+
} from '$lib/stores/runner';
|
|
23
32
|
import { fetchLatestReport, reportUrl } from '$lib/api/reports';
|
|
24
33
|
import Terminal from '$lib/components/ui/Terminal.svelte';
|
|
25
34
|
import Button from '$lib/components/ui/Button.svelte';
|
|
@@ -47,30 +56,56 @@
|
|
|
47
56
|
}));
|
|
48
57
|
});
|
|
49
58
|
|
|
59
|
+
s.on('tests-changed', () => {
|
|
60
|
+
testsVersion.update((v) => v + 1);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
s.on('report-ready', () => {
|
|
64
|
+
reportsVersion.update((v) => v + 1);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
s.on('cron-start', ({ taskName }) => {
|
|
68
|
+
activeCronJobs.update((j) => ({ ...j, [taskName]: true }));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
s.on('cron-done', ({ taskName }) => {
|
|
72
|
+
activeCronJobs.update((j) => {
|
|
73
|
+
const next = { ...j };
|
|
74
|
+
delete next[taskName];
|
|
75
|
+
return next;
|
|
76
|
+
});
|
|
77
|
+
reportsVersion.update((v) => v + 1);
|
|
78
|
+
});
|
|
79
|
+
|
|
50
80
|
return () => s.disconnect();
|
|
51
81
|
});
|
|
52
82
|
|
|
53
83
|
$: state = $runnerState;
|
|
54
84
|
$: cfg = $runnerConfig;
|
|
55
|
-
$:
|
|
56
|
-
$:
|
|
85
|
+
$: dots = Array.from({ length: cfg.workers });
|
|
86
|
+
$: cronJobs = Object.keys($activeCronJobs);
|
|
87
|
+
$: anyCronRunning = cronJobs.length > 0;
|
|
88
|
+
$: anyRunning = state.running || anyCronRunning;
|
|
57
89
|
|
|
58
90
|
$: statusColor =
|
|
59
91
|
state.status === 'pass'
|
|
60
92
|
? 'var(--pass)'
|
|
61
93
|
: state.status === 'fail'
|
|
62
94
|
? 'var(--fail)'
|
|
63
|
-
: state.
|
|
95
|
+
: state.running
|
|
64
96
|
? 'var(--accent)'
|
|
65
|
-
:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
97
|
+
: anyCronRunning
|
|
98
|
+
? 'var(--pass)'
|
|
99
|
+
: 'var(--border)';
|
|
100
|
+
|
|
101
|
+
$: statusLabel = state.running
|
|
102
|
+
? 'running'
|
|
103
|
+
: state.status === 'pass'
|
|
104
|
+
? 'passed'
|
|
105
|
+
: state.status === 'fail'
|
|
106
|
+
? 'failed'
|
|
107
|
+
: anyCronRunning
|
|
108
|
+
? 'scheduled'
|
|
74
109
|
: 'ready';
|
|
75
110
|
|
|
76
111
|
function handleKeydown(e) {
|
|
@@ -142,7 +177,7 @@
|
|
|
142
177
|
class:active={cfg.workers === n}
|
|
143
178
|
on:click={() => runnerConfig.update((c) => ({ ...c, workers: n }))}
|
|
144
179
|
>
|
|
145
|
-
{n
|
|
180
|
+
{n}
|
|
146
181
|
</button>
|
|
147
182
|
{/each}
|
|
148
183
|
</div>
|
|
@@ -152,15 +187,38 @@
|
|
|
152
187
|
</Button>
|
|
153
188
|
</div>
|
|
154
189
|
|
|
155
|
-
<
|
|
190
|
+
<div class="main-row">
|
|
191
|
+
<!-- Terminal column -->
|
|
192
|
+
<div class="terminal-col">
|
|
193
|
+
<Terminal output={state.output} />
|
|
194
|
+
{#if state.testCompleted && state.latestReport}
|
|
195
|
+
<div class="report-row" transition:fly={{ y: 6, duration: 200 }}>
|
|
196
|
+
<a href={reportUrl(state.latestReport)} target="_blank" rel="noopener noreferrer">
|
|
197
|
+
<Button variant="outline" size="sm">View Report →</Button>
|
|
198
|
+
</a>
|
|
199
|
+
</div>
|
|
200
|
+
{/if}
|
|
201
|
+
</div>
|
|
156
202
|
|
|
157
|
-
|
|
158
|
-
<div class="
|
|
159
|
-
<
|
|
160
|
-
<
|
|
161
|
-
|
|
203
|
+
<!-- Sidebar: scheduled jobs -->
|
|
204
|
+
<div class="sidebar">
|
|
205
|
+
<div class="sidebar-section">
|
|
206
|
+
<span class="sidebar-label">Scheduled</span>
|
|
207
|
+
{#if cronJobs.length === 0}
|
|
208
|
+
<span class="sidebar-empty">none running</span>
|
|
209
|
+
{:else}
|
|
210
|
+
<ul class="cron-list">
|
|
211
|
+
{#each cronJobs as name}
|
|
212
|
+
<li class="cron-item" transition:fly={{ x: -6, duration: 180 }}>
|
|
213
|
+
<span class="cron-dot"></span>
|
|
214
|
+
<span class="cron-name">{name}</span>
|
|
215
|
+
</li>
|
|
216
|
+
{/each}
|
|
217
|
+
</ul>
|
|
218
|
+
{/if}
|
|
219
|
+
</div>
|
|
162
220
|
</div>
|
|
163
|
-
|
|
221
|
+
</div>
|
|
164
222
|
</div>
|
|
165
223
|
{/if}
|
|
166
224
|
</div>
|
|
@@ -372,7 +430,88 @@
|
|
|
372
430
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
373
431
|
}
|
|
374
432
|
|
|
433
|
+
/* ── Main row: terminal + sidebar ── */
|
|
434
|
+
.main-row {
|
|
435
|
+
display: flex;
|
|
436
|
+
gap: 1rem;
|
|
437
|
+
align-items: flex-start;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.terminal-col {
|
|
441
|
+
flex: 1;
|
|
442
|
+
min-width: 0;
|
|
443
|
+
display: flex;
|
|
444
|
+
flex-direction: column;
|
|
445
|
+
gap: 0.5rem;
|
|
446
|
+
/* Constrain terminal height via the Terminal component's wrapper */
|
|
447
|
+
--terminal-max-height: 140px;
|
|
448
|
+
}
|
|
449
|
+
|
|
375
450
|
.report-row {
|
|
376
451
|
display: flex;
|
|
377
452
|
}
|
|
453
|
+
|
|
454
|
+
/* ── Sidebar ── */
|
|
455
|
+
.sidebar {
|
|
456
|
+
width: 260px;
|
|
457
|
+
flex-shrink: 0;
|
|
458
|
+
display: flex;
|
|
459
|
+
flex-direction: column;
|
|
460
|
+
gap: 1rem;
|
|
461
|
+
padding-left: 1.25rem;
|
|
462
|
+
border-left: 1px solid var(--border);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.sidebar-section {
|
|
466
|
+
display: flex;
|
|
467
|
+
flex-direction: column;
|
|
468
|
+
gap: 0.5rem;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.sidebar-label {
|
|
472
|
+
font-size: 0.65rem;
|
|
473
|
+
font-weight: 600;
|
|
474
|
+
letter-spacing: 0.09em;
|
|
475
|
+
text-transform: uppercase;
|
|
476
|
+
color: var(--text-muted);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.sidebar-empty {
|
|
480
|
+
font-size: 0.75rem;
|
|
481
|
+
color: var(--text-muted);
|
|
482
|
+
font-style: italic;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.cron-list {
|
|
486
|
+
list-style: none;
|
|
487
|
+
padding: 0;
|
|
488
|
+
margin: 0;
|
|
489
|
+
display: flex;
|
|
490
|
+
flex-direction: column;
|
|
491
|
+
gap: 0.375rem;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.cron-item {
|
|
495
|
+
display: flex;
|
|
496
|
+
align-items: center;
|
|
497
|
+
gap: 0.375rem;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.cron-dot {
|
|
501
|
+
width: 7px;
|
|
502
|
+
height: 7px;
|
|
503
|
+
border-radius: 50%;
|
|
504
|
+
background: var(--pass);
|
|
505
|
+
flex-shrink: 0;
|
|
506
|
+
animation: statusPulse 1.6s ease-in-out infinite;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.cron-name {
|
|
510
|
+
font-size: 0.75rem;
|
|
511
|
+
font-family: 'JetBrains Mono', monospace;
|
|
512
|
+
color: var(--text);
|
|
513
|
+
white-space: nowrap;
|
|
514
|
+
overflow: hidden;
|
|
515
|
+
text-overflow: ellipsis;
|
|
516
|
+
}
|
|
378
517
|
</style>
|
|
@@ -35,6 +35,15 @@ export const runnerConfig = writable({
|
|
|
35
35
|
|
|
36
36
|
export const panelExpanded = writable(true);
|
|
37
37
|
|
|
38
|
+
// Increments whenever the backend detects a change in tests/features/
|
|
39
|
+
export const testsVersion = writable(0);
|
|
40
|
+
|
|
41
|
+
// Increments whenever a new report file is detected
|
|
42
|
+
export const reportsVersion = writable(0);
|
|
43
|
+
|
|
44
|
+
// Map of taskName → true for every cron job currently executing
|
|
45
|
+
export const activeCronJobs = writable({});
|
|
46
|
+
|
|
38
47
|
export function triggerRun(id) {
|
|
39
48
|
const s = get(socket);
|
|
40
49
|
if (!s) return;
|