@checkmate-monitor/queue-frontend 0.0.2
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/CHANGELOG.md +13 -0
- package/package.json +34 -0
- package/src/api.ts +15 -0
- package/src/components/UserMenuItems.tsx +27 -0
- package/src/index.tsx +44 -0
- package/src/pages/QueueConfigPage.tsx +126 -0
- package/tsconfig.json +6 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @checkmate-monitor/queue-frontend
|
|
2
|
+
|
|
3
|
+
## 0.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [eff5b4e]
|
|
8
|
+
- Updated dependencies [ffc28f6]
|
|
9
|
+
- Updated dependencies [b354ab3]
|
|
10
|
+
- @checkmate-monitor/ui@0.1.0
|
|
11
|
+
- @checkmate-monitor/common@0.1.0
|
|
12
|
+
- @checkmate-monitor/frontend-api@0.0.2
|
|
13
|
+
- @checkmate-monitor/queue-common@0.0.2
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@checkmate-monitor/queue-frontend",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"typecheck": "tsc --noEmit",
|
|
11
|
+
"lint": "bun run lint:code",
|
|
12
|
+
"lint:code": "eslint . --max-warnings 0"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@checkmate-monitor/common": "workspace:*",
|
|
16
|
+
"@checkmate-monitor/frontend-api": "workspace:*",
|
|
17
|
+
"@checkmate-monitor/queue-common": "workspace:*",
|
|
18
|
+
"@checkmate-monitor/ui": "workspace:*",
|
|
19
|
+
"ajv": "^8.17.1",
|
|
20
|
+
"ajv-formats": "^3.0.1",
|
|
21
|
+
"lucide-react": "^0.468.0",
|
|
22
|
+
"prismjs": "^1.29.0",
|
|
23
|
+
"react": "^18.3.1",
|
|
24
|
+
"react-router-dom": "^7.1.1",
|
|
25
|
+
"react-simple-code-editor": "^0.14.1",
|
|
26
|
+
"zod": "^4.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/react": "^18.3.18",
|
|
30
|
+
"typescript": "^5.7.2",
|
|
31
|
+
"@checkmate-monitor/tsconfig": "workspace:*",
|
|
32
|
+
"@checkmate-monitor/scripts": "workspace:*"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { createApiRef } from "@checkmate-monitor/frontend-api";
|
|
2
|
+
import { QueueApi } from "@checkmate-monitor/queue-common";
|
|
3
|
+
import type { InferClient } from "@checkmate-monitor/common";
|
|
4
|
+
|
|
5
|
+
// Re-export types for convenience
|
|
6
|
+
export type {
|
|
7
|
+
QueuePluginDto,
|
|
8
|
+
QueueConfigurationDto,
|
|
9
|
+
UpdateQueueConfiguration,
|
|
10
|
+
} from "@checkmate-monitor/queue-common";
|
|
11
|
+
|
|
12
|
+
// QueueApiClient type inferred from the client definition
|
|
13
|
+
export type QueueApiClient = InferClient<typeof QueueApi>;
|
|
14
|
+
|
|
15
|
+
export const queueApiRef = createApiRef<QueueApiClient>("queue-api");
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link } from "react-router-dom";
|
|
3
|
+
import { ListOrdered } from "lucide-react";
|
|
4
|
+
import { useApi, permissionApiRef } from "@checkmate-monitor/frontend-api";
|
|
5
|
+
import { DropdownMenuItem } from "@checkmate-monitor/ui";
|
|
6
|
+
import { resolveRoute } from "@checkmate-monitor/common";
|
|
7
|
+
import { queueRoutes } from "@checkmate-monitor/queue-common";
|
|
8
|
+
|
|
9
|
+
export const QueueUserMenuItems = () => {
|
|
10
|
+
const permissionApi = useApi(permissionApiRef);
|
|
11
|
+
const { allowed: canRead, loading } = permissionApi.useResourcePermission(
|
|
12
|
+
"queue",
|
|
13
|
+
"read"
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (loading || !canRead) {
|
|
17
|
+
return <React.Fragment />;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Link to={resolveRoute(queueRoutes.routes.config)}>
|
|
22
|
+
<DropdownMenuItem icon={<ListOrdered className="h-4 w-4" />}>
|
|
23
|
+
Queue Settings
|
|
24
|
+
</DropdownMenuItem>
|
|
25
|
+
</Link>
|
|
26
|
+
);
|
|
27
|
+
};
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
rpcApiRef,
|
|
3
|
+
ApiRef,
|
|
4
|
+
UserMenuItemsSlot,
|
|
5
|
+
} from "@checkmate-monitor/frontend-api";
|
|
6
|
+
import { queueApiRef, type QueueApiClient } from "./api";
|
|
7
|
+
import { createFrontendPlugin } from "@checkmate-monitor/frontend-api";
|
|
8
|
+
import { QueueConfigPage } from "./pages/QueueConfigPage";
|
|
9
|
+
import { QueueUserMenuItems } from "./components/UserMenuItems";
|
|
10
|
+
import {
|
|
11
|
+
queueRoutes,
|
|
12
|
+
QueueApi,
|
|
13
|
+
pluginMetadata,
|
|
14
|
+
permissions,
|
|
15
|
+
} from "@checkmate-monitor/queue-common";
|
|
16
|
+
|
|
17
|
+
export const queuePlugin = createFrontendPlugin({
|
|
18
|
+
metadata: pluginMetadata,
|
|
19
|
+
apis: [
|
|
20
|
+
{
|
|
21
|
+
ref: queueApiRef,
|
|
22
|
+
factory: (deps: { get: <T>(ref: ApiRef<T>) => T }): QueueApiClient => {
|
|
23
|
+
const rpcApi = deps.get(rpcApiRef);
|
|
24
|
+
return rpcApi.forPlugin(QueueApi);
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
routes: [
|
|
29
|
+
{
|
|
30
|
+
route: queueRoutes.routes.config,
|
|
31
|
+
element: <QueueConfigPage />,
|
|
32
|
+
permission: permissions.queueRead,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
extensions: [
|
|
36
|
+
{
|
|
37
|
+
id: "queue.user-menu.items",
|
|
38
|
+
slot: UserMenuItemsSlot,
|
|
39
|
+
component: QueueUserMenuItems,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export * from "./api";
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
useApi,
|
|
4
|
+
wrapInSuspense,
|
|
5
|
+
permissionApiRef,
|
|
6
|
+
} from "@checkmate-monitor/frontend-api";
|
|
7
|
+
import { queueApiRef } from "../api";
|
|
8
|
+
import { QueuePluginDto } from "@checkmate-monitor/queue-common";
|
|
9
|
+
import {
|
|
10
|
+
Button,
|
|
11
|
+
Alert,
|
|
12
|
+
AlertTitle,
|
|
13
|
+
AlertDescription,
|
|
14
|
+
PageLayout,
|
|
15
|
+
PluginConfigForm,
|
|
16
|
+
Card,
|
|
17
|
+
CardContent,
|
|
18
|
+
CardFooter,
|
|
19
|
+
CardHeader,
|
|
20
|
+
CardTitle,
|
|
21
|
+
useToast,
|
|
22
|
+
} from "@checkmate-monitor/ui";
|
|
23
|
+
import { AlertTriangle, Save } from "lucide-react";
|
|
24
|
+
|
|
25
|
+
const QueueConfigPageContent = () => {
|
|
26
|
+
const api = useApi(queueApiRef);
|
|
27
|
+
const permissionApi = useApi(permissionApiRef);
|
|
28
|
+
const toast = useToast();
|
|
29
|
+
const { allowed: canRead, loading: permissionLoading } =
|
|
30
|
+
permissionApi.useResourcePermission("queue", "read");
|
|
31
|
+
const { allowed: canUpdate } = permissionApi.useManagePermission("queue");
|
|
32
|
+
|
|
33
|
+
const [plugins, setPlugins] = useState<QueuePluginDto[]>([]);
|
|
34
|
+
const [selectedPluginId, setSelectedPluginId] = useState<string>("");
|
|
35
|
+
const [config, setConfig] = useState<Record<string, unknown>>({});
|
|
36
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const fetchData = async () => {
|
|
40
|
+
const [pluginsList, configuration] = await Promise.all([
|
|
41
|
+
api.getPlugins(),
|
|
42
|
+
api.getConfiguration(),
|
|
43
|
+
]);
|
|
44
|
+
setPlugins(pluginsList);
|
|
45
|
+
setSelectedPluginId(configuration.pluginId);
|
|
46
|
+
setConfig(configuration.config);
|
|
47
|
+
};
|
|
48
|
+
fetchData();
|
|
49
|
+
}, [api]);
|
|
50
|
+
|
|
51
|
+
const handleSave = async () => {
|
|
52
|
+
if (!selectedPluginId) return;
|
|
53
|
+
setIsSaving(true);
|
|
54
|
+
try {
|
|
55
|
+
await api.updateConfiguration({
|
|
56
|
+
pluginId: selectedPluginId,
|
|
57
|
+
config,
|
|
58
|
+
});
|
|
59
|
+
toast.success("Configuration saved successfully!");
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
62
|
+
toast.error(`Failed to save configuration: ${message}`);
|
|
63
|
+
} finally {
|
|
64
|
+
setIsSaving(false);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const isMemoryQueue = selectedPluginId === "memory";
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<PageLayout
|
|
72
|
+
title="Queue Settings"
|
|
73
|
+
subtitle="Configure the queue system for background jobs"
|
|
74
|
+
loading={permissionLoading}
|
|
75
|
+
allowed={canRead}
|
|
76
|
+
maxWidth="3xl"
|
|
77
|
+
>
|
|
78
|
+
<Card>
|
|
79
|
+
<CardHeader>
|
|
80
|
+
<CardTitle>Queue Configuration</CardTitle>
|
|
81
|
+
<p className="text-sm text-muted-foreground">
|
|
82
|
+
Select and configure the queue plugin
|
|
83
|
+
</p>
|
|
84
|
+
</CardHeader>
|
|
85
|
+
<CardContent className="space-y-6">
|
|
86
|
+
{isMemoryQueue && (
|
|
87
|
+
<Alert variant="warning">
|
|
88
|
+
<AlertTriangle className="h-5 w-5" />
|
|
89
|
+
<div>
|
|
90
|
+
<AlertTitle>In-Memory Queue Warning</AlertTitle>
|
|
91
|
+
<AlertDescription>
|
|
92
|
+
The in-memory queue is suitable for development and
|
|
93
|
+
single-instance deployments only. It will not scale across
|
|
94
|
+
multiple instances and jobs will be lost on restart. For
|
|
95
|
+
production environments with multiple instances, consider
|
|
96
|
+
using a persistent queue implementation.
|
|
97
|
+
</AlertDescription>
|
|
98
|
+
</div>
|
|
99
|
+
</Alert>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
<PluginConfigForm
|
|
103
|
+
label="Queue Plugin"
|
|
104
|
+
plugins={plugins}
|
|
105
|
+
selectedPluginId={selectedPluginId}
|
|
106
|
+
onPluginChange={(value) => {
|
|
107
|
+
setSelectedPluginId(value);
|
|
108
|
+
setConfig({});
|
|
109
|
+
}}
|
|
110
|
+
config={config}
|
|
111
|
+
onConfigChange={setConfig}
|
|
112
|
+
disabled={!canUpdate}
|
|
113
|
+
/>
|
|
114
|
+
</CardContent>
|
|
115
|
+
<CardFooter className="flex justify-end gap-2">
|
|
116
|
+
<Button onClick={handleSave} disabled={!canUpdate || isSaving}>
|
|
117
|
+
<Save className="mr-2 h-4 w-4" />
|
|
118
|
+
{isSaving ? "Saving..." : "Save Configuration"}
|
|
119
|
+
</Button>
|
|
120
|
+
</CardFooter>
|
|
121
|
+
</Card>
|
|
122
|
+
</PageLayout>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const QueueConfigPage = wrapInSuspense(QueueConfigPageContent);
|