chore: trim distribution clutter and add lint/test tooling

Keep only example workflows in default/, move site-specific YAMLs to gitignored local/, remove the duplicate get-current-time plugin install, document personal plugins, clarify PM2 ecosystem usage, add shared Vitest and web ESLint, and extract OpsStatusCard for ops cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-22 06:30:37 +07:00
co-authored by Cursor
parent db884808f2
commit f9f21052d9
34 changed files with 2057 additions and 551 deletions
+41
View File
@@ -0,0 +1,41 @@
import js from "@eslint/js";
import reactHooks from "eslint-plugin-react-hooks";
import jsxA11y from "eslint-plugin-jsx-a11y";
import globals from "globals";
export default [
{ ignores: ["dist/**"] },
{
files: ["src/**/*.{js,jsx}"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: {
...globals.browser,
},
parserOptions: {
ecmaFeatures: { jsx: true },
},
},
plugins: {
"react-hooks": reactHooks,
"jsx-a11y": jsxA11y,
},
rules: {
...js.configs.recommended.rules,
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"jsx-a11y/alt-text": "warn",
"jsx-a11y/anchor-has-content": "warn",
"jsx-a11y/aria-role": "warn",
"no-unused-vars": [
"warn",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^([A-Z_]|Lu)",
caughtErrorsIgnorePattern: "^_",
},
],
},
},
];
+7 -1
View File
@@ -6,7 +6,8 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
"preview": "vite preview",
"lint": "eslint src"
},
"dependencies": {
"@jerapah-flow/shared": "workspace:*",
@@ -26,9 +27,14 @@
"yaml": "^2.8.1"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
"@tailwindcss/vite": "^4.1.11",
"@vitejs/plugin-react": "^5.0.0",
"daisyui": "^5.0.50",
"eslint": "^9.33.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react-hooks": "^5.2.0",
"globals": "^16.3.0",
"tailwindcss": "^4.1.11",
"vite": "^7.1.2"
}
+33 -33
View File
@@ -1,4 +1,5 @@
import { LuCircleCheck, LuCircleX } from "react-icons/lu";
import { OpsStatusCard } from "./OpsStatusCard.jsx";
export function HttpProcessCard({
httpOnline,
@@ -8,39 +9,38 @@ export function HttpProcessCard({
stopPending = false,
}) {
return (
<div className="card bg-base-100 border border-base-300 shadow-sm">
<div className="card-body gap-4">
<h2 className="card-title text-lg">HTTP process</h2>
<div className="flex items-center gap-2">
{httpOnline ? (
<LuCircleCheck className="size-6 text-success" aria-hidden />
) : (
<LuCircleX className="size-6 text-error" aria-hidden />
)}
<span>{httpOnline ? "Running" : "Stopped"}</span>
</div>
<div className="card-actions justify-start px-0">
{httpOnline ? (
<button
type="button"
className="btn btn-sm btn-warning"
disabled={stopPending}
onClick={onStop}
>
Stop HTTP
</button>
) : (
<button
type="button"
className="btn btn-sm btn-primary"
disabled={startPending}
onClick={onStart}
>
Start HTTP
</button>
)}
</div>
<OpsStatusCard
title="HTTP process"
actions={
httpOnline ? (
<button
type="button"
className="btn btn-sm btn-warning"
disabled={stopPending}
onClick={onStop}
>
Stop HTTP
</button>
) : (
<button
type="button"
className="btn btn-sm btn-primary"
disabled={startPending}
onClick={onStart}
>
Start HTTP
</button>
)
}
>
<div className="flex items-center gap-2">
{httpOnline ? (
<LuCircleCheck className="size-6 text-success" aria-hidden />
) : (
<LuCircleX className="size-6 text-error" aria-hidden />
)}
<span>{httpOnline ? "Running" : "Stopped"}</span>
</div>
</div>
</OpsStatusCard>
);
}
@@ -0,0 +1,11 @@
export function OpsStatusCard({ title, children, actions }) {
return (
<div className="card bg-base-100 border border-base-300 shadow-sm">
<div className="card-body gap-4">
<h2 className="card-title text-lg">{title}</h2>
{children}
{actions ? <div className="card-actions justify-start px-0">{actions}</div> : null}
</div>
</div>
);
}
+45 -45
View File
@@ -1,4 +1,5 @@
import { LuCircleCheck, LuCirclePause } from "react-icons/lu";
import { OpsStatusCard } from "./OpsStatusCard.jsx";
export function QueueCard({
paused = false,
@@ -11,51 +12,50 @@ export function QueueCard({
resumePending = false,
}) {
return (
<div className="card bg-base-100 border border-base-300 shadow-sm">
<div className="card-body gap-4">
<h2 className="card-title text-lg">Queue</h2>
<div className="flex items-center gap-2">
{paused ? (
<LuCirclePause className="size-6 text-warning" aria-hidden />
) : (
<LuCircleCheck className="size-6 text-success" aria-hidden />
)}
<span>
{paused
? "Paused"
: `Running (${workersOnline} worker${workersOnline === 1 ? "" : "s"})`}
</span>
</div>
<div className="space-y-1 text-sm tabular-nums">
<p>
{activeJobs} running job{activeJobs === 1 ? "" : "s"}
</p>
<p>
{queuedJobs} queued job{queuedJobs === 1 ? "" : "s"}
</p>
</div>
<div className="card-actions justify-start px-0">
{paused ? (
<button
type="button"
className="btn btn-sm btn-primary"
disabled={resumePending}
onClick={onResume}
>
Resume workers
</button>
) : (
<button
type="button"
className="btn btn-sm btn-warning"
disabled={pausePending}
onClick={onPause}
>
Pause workers
</button>
)}
</div>
<OpsStatusCard
title="Queue"
actions={
paused ? (
<button
type="button"
className="btn btn-sm btn-primary"
disabled={resumePending}
onClick={onResume}
>
Resume workers
</button>
) : (
<button
type="button"
className="btn btn-sm btn-warning"
disabled={pausePending}
onClick={onPause}
>
Pause workers
</button>
)
}
>
<div className="flex items-center gap-2">
{paused ? (
<LuCirclePause className="size-6 text-warning" aria-hidden />
) : (
<LuCircleCheck className="size-6 text-success" aria-hidden />
)}
<span>
{paused
? "Paused"
: `Running (${workersOnline} worker${workersOnline === 1 ? "" : "s"})`}
</span>
</div>
</div>
<div className="space-y-1 text-sm tabular-nums">
<p>
{activeJobs} running job{activeJobs === 1 ? "" : "s"}
</p>
<p>
{queuedJobs} queued job{queuedJobs === 1 ? "" : "s"}
</p>
</div>
</OpsStatusCard>
);
}
+1 -1
View File
@@ -39,7 +39,7 @@ function parentIdsFromNeeds(needs) {
function mermaidLabel(text) {
return String(text ?? "")
.replace(/"/g, "#quot;")
.replace(/[\[\]]/g, " ")
.replace(/[[\]]/g, " ")
.trim() || "node";
}