@creezio/observability 0.22.0
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 +328 -0
- package/dist/.creezio-src-hash.json +4 -0
- package/dist/api-endpoints/http-routes.d.ts +11 -0
- package/dist/api-endpoints/http-routes.d.ts.map +1 -0
- package/dist/api-endpoints/http-routes.js +11 -0
- package/dist/api-endpoints/http-routes.js.map +1 -0
- package/dist/api-endpoints/index.d.ts +4 -0
- package/dist/api-endpoints/index.d.ts.map +1 -0
- package/dist/api-endpoints/index.js +3 -0
- package/dist/api-endpoints/index.js.map +1 -0
- package/dist/api-endpoints/registry.d.ts +66 -0
- package/dist/api-endpoints/registry.d.ts.map +1 -0
- package/dist/api-endpoints/registry.js +102 -0
- package/dist/api-endpoints/registry.js.map +1 -0
- package/dist/api-mount.d.ts +7 -0
- package/dist/api-mount.d.ts.map +1 -0
- package/dist/api-mount.js +114 -0
- package/dist/api-mount.js.map +1 -0
- package/dist/helpers.d.ts +23 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +36 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-store.d.ts +3 -0
- package/dist/memory-store.d.ts.map +1 -0
- package/dist/memory-store.js +113 -0
- package/dist/memory-store.js.map +1 -0
- package/dist/ops/emit.d.ts +8 -0
- package/dist/ops/emit.d.ts.map +1 -0
- package/dist/ops/emit.js +15 -0
- package/dist/ops/emit.js.map +1 -0
- package/dist/ops/fleet-activity.d.ts +50 -0
- package/dist/ops/fleet-activity.d.ts.map +1 -0
- package/dist/ops/fleet-activity.js +123 -0
- package/dist/ops/fleet-activity.js.map +1 -0
- package/dist/ops/fleet-agent.d.ts +102 -0
- package/dist/ops/fleet-agent.d.ts.map +1 -0
- package/dist/ops/fleet-agent.js +352 -0
- package/dist/ops/fleet-agent.js.map +1 -0
- package/dist/ops/fleet-samples.d.ts +33 -0
- package/dist/ops/fleet-samples.d.ts.map +1 -0
- package/dist/ops/fleet-samples.js +223 -0
- package/dist/ops/fleet-samples.js.map +1 -0
- package/dist/ops/journal.d.ts +56 -0
- package/dist/ops/journal.d.ts.map +1 -0
- package/dist/ops/journal.js +307 -0
- package/dist/ops/journal.js.map +1 -0
- package/dist/ops/rules.d.ts +16 -0
- package/dist/ops/rules.d.ts.map +1 -0
- package/dist/ops/rules.js +98 -0
- package/dist/ops/rules.js.map +1 -0
- package/dist/ops/types.d.ts +69 -0
- package/dist/ops/types.d.ts.map +1 -0
- package/dist/ops/types.js +119 -0
- package/dist/ops/types.js.map +1 -0
- package/dist/request-logs/config.d.ts +19 -0
- package/dist/request-logs/config.d.ts.map +1 -0
- package/dist/request-logs/config.js +36 -0
- package/dist/request-logs/config.js.map +1 -0
- package/dist/request-logs/http-routes.d.ts +8 -0
- package/dist/request-logs/http-routes.d.ts.map +1 -0
- package/dist/request-logs/http-routes.js +29 -0
- package/dist/request-logs/http-routes.js.map +1 -0
- package/dist/request-logs/index.d.ts +6 -0
- package/dist/request-logs/index.d.ts.map +1 -0
- package/dist/request-logs/index.js +5 -0
- package/dist/request-logs/index.js.map +1 -0
- package/dist/request-logs/middleware.d.ts +11 -0
- package/dist/request-logs/middleware.d.ts.map +1 -0
- package/dist/request-logs/middleware.js +198 -0
- package/dist/request-logs/middleware.js.map +1 -0
- package/dist/request-logs/request-logs.d.ts +60 -0
- package/dist/request-logs/request-logs.d.ts.map +1 -0
- package/dist/request-logs/request-logs.js +260 -0
- package/dist/request-logs/request-logs.js.map +1 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +21 -0
- package/dist/schema.js.map +1 -0
- package/dist/sqlite-driver.d.ts +16 -0
- package/dist/sqlite-driver.d.ts.map +1 -0
- package/dist/sqlite-driver.js +15 -0
- package/dist/sqlite-driver.js.map +1 -0
- package/dist/sqlite-store.d.ts +12 -0
- package/dist/sqlite-store.d.ts.map +1 -0
- package/dist/sqlite-store.js +176 -0
- package/dist/sqlite-store.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/usage/adapters.d.ts +31 -0
- package/dist/usage/adapters.d.ts.map +1 -0
- package/dist/usage/adapters.js +37 -0
- package/dist/usage/adapters.js.map +1 -0
- package/dist/usage/http-routes.d.ts +23 -0
- package/dist/usage/http-routes.d.ts.map +1 -0
- package/dist/usage/http-routes.js +150 -0
- package/dist/usage/http-routes.js.map +1 -0
- package/dist/usage/index.d.ts +11 -0
- package/dist/usage/index.d.ts.map +1 -0
- package/dist/usage/index.js +7 -0
- package/dist/usage/index.js.map +1 -0
- package/dist/usage/ui-brand.d.ts +23 -0
- package/dist/usage/ui-brand.d.ts.map +1 -0
- package/dist/usage/ui-brand.js +18 -0
- package/dist/usage/ui-brand.js.map +1 -0
- package/dist/usage/usage-analytics-productivity.d.ts +73 -0
- package/dist/usage/usage-analytics-productivity.d.ts.map +1 -0
- package/dist/usage/usage-analytics-productivity.js +317 -0
- package/dist/usage/usage-analytics-productivity.js.map +1 -0
- package/dist/usage/usage-analytics-shared.d.ts +5 -0
- package/dist/usage/usage-analytics-shared.d.ts.map +1 -0
- package/dist/usage/usage-analytics-shared.js +20 -0
- package/dist/usage/usage-analytics-shared.js.map +1 -0
- package/dist/usage/usage-analytics.d.ts +127 -0
- package/dist/usage/usage-analytics.d.ts.map +1 -0
- package/dist/usage/usage-analytics.js +338 -0
- package/dist/usage/usage-analytics.js.map +1 -0
- package/dist-cjs/api-endpoints/http-routes.js +14 -0
- package/dist-cjs/api-endpoints/http-routes.js.map +1 -0
- package/dist-cjs/api-endpoints/index.js +10 -0
- package/dist-cjs/api-endpoints/index.js.map +1 -0
- package/dist-cjs/api-endpoints/registry.js +107 -0
- package/dist-cjs/api-endpoints/registry.js.map +1 -0
- package/dist-cjs/api-mount.js +117 -0
- package/dist-cjs/api-mount.js.map +1 -0
- package/dist-cjs/helpers.js +41 -0
- package/dist-cjs/helpers.js.map +1 -0
- package/dist-cjs/index.js +118 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/memory-store.js +119 -0
- package/dist-cjs/memory-store.js.map +1 -0
- package/dist-cjs/ops/emit.js +18 -0
- package/dist-cjs/ops/emit.js.map +1 -0
- package/dist-cjs/ops/fleet-activity.js +131 -0
- package/dist-cjs/ops/fleet-activity.js.map +1 -0
- package/dist-cjs/ops/fleet-agent.js +358 -0
- package/dist-cjs/ops/fleet-agent.js.map +1 -0
- package/dist-cjs/ops/fleet-samples.js +229 -0
- package/dist-cjs/ops/fleet-samples.js.map +1 -0
- package/dist-cjs/ops/journal.js +326 -0
- package/dist-cjs/ops/journal.js.map +1 -0
- package/dist-cjs/ops/rules.js +102 -0
- package/dist-cjs/ops/rules.js.map +1 -0
- package/dist-cjs/ops/types.js +126 -0
- package/dist-cjs/ops/types.js.map +1 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/request-logs/config.js +42 -0
- package/dist-cjs/request-logs/config.js.map +1 -0
- package/dist-cjs/request-logs/http-routes.js +32 -0
- package/dist-cjs/request-logs/http-routes.js.map +1 -0
- package/dist-cjs/request-logs/index.js +27 -0
- package/dist-cjs/request-logs/index.js.map +1 -0
- package/dist-cjs/request-logs/middleware.js +203 -0
- package/dist-cjs/request-logs/middleware.js.map +1 -0
- package/dist-cjs/request-logs/request-logs.js +277 -0
- package/dist-cjs/request-logs/request-logs.js.map +1 -0
- package/dist-cjs/schema.js +24 -0
- package/dist-cjs/schema.js.map +1 -0
- package/dist-cjs/sqlite-driver.js +18 -0
- package/dist-cjs/sqlite-driver.js.map +1 -0
- package/dist-cjs/sqlite-store.js +182 -0
- package/dist-cjs/sqlite-store.js.map +1 -0
- package/dist-cjs/types.js +12 -0
- package/dist-cjs/types.js.map +1 -0
- package/dist-cjs/usage/adapters.js +47 -0
- package/dist-cjs/usage/adapters.js.map +1 -0
- package/dist-cjs/usage/http-routes.js +154 -0
- package/dist-cjs/usage/http-routes.js.map +1 -0
- package/dist-cjs/usage/index.js +34 -0
- package/dist-cjs/usage/index.js.map +1 -0
- package/dist-cjs/usage/ui-brand.js +23 -0
- package/dist-cjs/usage/ui-brand.js.map +1 -0
- package/dist-cjs/usage/usage-analytics-productivity.js +321 -0
- package/dist-cjs/usage/usage-analytics-productivity.js.map +1 -0
- package/dist-cjs/usage/usage-analytics-shared.js +23 -0
- package/dist-cjs/usage/usage-analytics-shared.js.map +1 -0
- package/dist-cjs/usage/usage-analytics.js +353 -0
- package/dist-cjs/usage/usage-analytics.js.map +1 -0
- package/fleet-collector/AGENTS.md +7 -0
- package/fleet-collector/README.md +83 -0
- package/fleet-collector/configure-fleet-npm.sh +108 -0
- package/fleet-collector/env.mjs +174 -0
- package/fleet-collector/ops-api.mjs +455 -0
- package/fleet-collector/public/admin.html +696 -0
- package/fleet-collector/public/index.html +941 -0
- package/fleet-collector/server.mjs +564 -0
- package/fleet-collector/test-fleet-collector.mjs +413 -0
- package/fleet-collector/test-server-admin.mjs +475 -0
- package/package.json +109 -0
- package/scripts/test-api-endpoints-registry.mjs +60 -0
- package/ui/analytics-client.tsx +834 -0
- package/ui/analytics-productivity-panel.tsx +513 -0
- package/ui/api-endpoints-client.tsx +228 -0
- package/ui/index.ts +39 -0
- package/ui/primitives/badge.tsx +37 -0
- package/ui/primitives/button.tsx +44 -0
- package/ui/primitives/card.tsx +44 -0
- package/ui/primitives/cn.ts +6 -0
- package/ui/primitives/input.tsx +19 -0
- package/ui/primitives/tabs.tsx +51 -0
- package/ui/request-logs-client.tsx +327 -0
- package/ui/session-usage-analytics-provider.tsx +28 -0
- package/ui/usage-analytics-client.ts +479 -0
- package/ui/usage-analytics-provider.tsx +84 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { Braces, RefreshCw, Search } from "lucide-react";
|
|
5
|
+
import { Badge } from "./primitives/badge";
|
|
6
|
+
import { Button } from "./primitives/button";
|
|
7
|
+
import { Card, CardContent, CardHeader, CardTitle } from "./primitives/card";
|
|
8
|
+
import { Input } from "./primitives/input";
|
|
9
|
+
|
|
10
|
+
type Endpoint = {
|
|
11
|
+
method: string;
|
|
12
|
+
path: string;
|
|
13
|
+
documented: boolean;
|
|
14
|
+
summary: string | null;
|
|
15
|
+
description: string | null;
|
|
16
|
+
tags: string[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type RegistryResponse = {
|
|
20
|
+
generatedAt: string;
|
|
21
|
+
source: string;
|
|
22
|
+
openapiUrl: string;
|
|
23
|
+
endpoints: Endpoint[];
|
|
24
|
+
error?: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const METHOD_STYLE: Record<string, string> = {
|
|
28
|
+
GET: "bg-emerald-100 text-emerald-800",
|
|
29
|
+
POST: "bg-sky-100 text-sky-800",
|
|
30
|
+
PUT: "bg-amber-100 text-amber-800",
|
|
31
|
+
PATCH: "bg-violet-100 text-violet-800",
|
|
32
|
+
DELETE: "bg-red-100 text-red-800",
|
|
33
|
+
OPTIONS: "bg-slate-100 text-slate-700",
|
|
34
|
+
HEAD: "bg-slate-100 text-slate-700",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function ApiEndpointsClient() {
|
|
38
|
+
const [registry, setRegistry] = useState<RegistryResponse | null>(null);
|
|
39
|
+
const [query, setQuery] = useState("");
|
|
40
|
+
const [method, setMethod] = useState("ALL");
|
|
41
|
+
const [loading, setLoading] = useState(true);
|
|
42
|
+
const [error, setError] = useState("");
|
|
43
|
+
|
|
44
|
+
const refresh = useCallback(async () => {
|
|
45
|
+
setLoading(true);
|
|
46
|
+
setError("");
|
|
47
|
+
try {
|
|
48
|
+
const response = await fetch("/api/v1/admin/endpoints");
|
|
49
|
+
const body = (await response.json()) as RegistryResponse;
|
|
50
|
+
if (!response.ok) throw new Error(body.error || "Chargement impossible");
|
|
51
|
+
setRegistry(body);
|
|
52
|
+
} catch (cause) {
|
|
53
|
+
setError(cause instanceof Error ? cause.message : "Chargement impossible");
|
|
54
|
+
} finally {
|
|
55
|
+
setLoading(false);
|
|
56
|
+
}
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
void refresh();
|
|
61
|
+
}, [refresh]);
|
|
62
|
+
|
|
63
|
+
const methods = useMemo(
|
|
64
|
+
() =>
|
|
65
|
+
Array.from(
|
|
66
|
+
new Set(registry?.endpoints.map((endpoint) => endpoint.method) || []),
|
|
67
|
+
).sort(),
|
|
68
|
+
[registry],
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const endpoints = useMemo(() => {
|
|
72
|
+
const needle = query.trim().toLowerCase();
|
|
73
|
+
return (registry?.endpoints || []).filter((endpoint) => {
|
|
74
|
+
if (method !== "ALL" && endpoint.method !== method) return false;
|
|
75
|
+
if (!needle) return true;
|
|
76
|
+
return (
|
|
77
|
+
endpoint.path.toLowerCase().includes(needle) ||
|
|
78
|
+
endpoint.method.toLowerCase().includes(needle) ||
|
|
79
|
+
endpoint.summary?.toLowerCase().includes(needle) ||
|
|
80
|
+
endpoint.tags.some((tag) => tag.toLowerCase().includes(needle))
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
}, [method, query, registry]);
|
|
84
|
+
|
|
85
|
+
const documentedCount =
|
|
86
|
+
registry?.endpoints.filter((endpoint) => endpoint.documented).length || 0;
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div className="space-y-4">
|
|
90
|
+
<div className="grid gap-3 sm:grid-cols-3">
|
|
91
|
+
<Stat label="Routes runtime" value={registry?.endpoints.length || 0} />
|
|
92
|
+
<Stat label="Documentées OpenAPI" value={documentedCount} />
|
|
93
|
+
<Stat
|
|
94
|
+
label="Routes Hono seules"
|
|
95
|
+
value={(registry?.endpoints.length || 0) - documentedCount}
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<Card>
|
|
100
|
+
<CardHeader className="gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
101
|
+
<div>
|
|
102
|
+
<CardTitle className="flex items-center gap-2 text-base">
|
|
103
|
+
<Braces className="h-4 w-4" />
|
|
104
|
+
Endpoints montés
|
|
105
|
+
</CardTitle>
|
|
106
|
+
<p className="mt-1 text-xs text-slate-500">
|
|
107
|
+
Registre Hono enrichi par{" "}
|
|
108
|
+
<a
|
|
109
|
+
href={registry?.openapiUrl || "/api/v1/openapi.json"}
|
|
110
|
+
target="_blank"
|
|
111
|
+
rel="noreferrer"
|
|
112
|
+
className="font-mono text-sky-700 hover:underline"
|
|
113
|
+
>
|
|
114
|
+
/api/v1/openapi.json
|
|
115
|
+
</a>
|
|
116
|
+
</p>
|
|
117
|
+
</div>
|
|
118
|
+
<Button size="sm" variant="outline" onClick={() => void refresh()} disabled={loading}>
|
|
119
|
+
<RefreshCw className={`mr-1 h-3.5 w-3.5 ${loading ? "animate-spin" : ""}`} />
|
|
120
|
+
Actualiser
|
|
121
|
+
</Button>
|
|
122
|
+
</CardHeader>
|
|
123
|
+
<CardContent className="space-y-4">
|
|
124
|
+
<div className="flex flex-col gap-2 sm:flex-row">
|
|
125
|
+
<div className="relative flex-1">
|
|
126
|
+
<Search className="absolute left-3 top-2.5 h-4 w-4 text-slate-400" />
|
|
127
|
+
<Input
|
|
128
|
+
value={query}
|
|
129
|
+
onChange={(event) => setQuery(event.target.value)}
|
|
130
|
+
placeholder="Chemin, résumé ou tag…"
|
|
131
|
+
className="pl-9"
|
|
132
|
+
/>
|
|
133
|
+
</div>
|
|
134
|
+
<select
|
|
135
|
+
value={method}
|
|
136
|
+
onChange={(event) => setMethod(event.target.value)}
|
|
137
|
+
className="h-10 rounded-md border border-slate-200 bg-white px-3 text-sm"
|
|
138
|
+
>
|
|
139
|
+
<option value="ALL">Toutes les méthodes</option>
|
|
140
|
+
{methods.map((item) => (
|
|
141
|
+
<option key={item} value={item}>
|
|
142
|
+
{item}
|
|
143
|
+
</option>
|
|
144
|
+
))}
|
|
145
|
+
</select>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
{error ? (
|
|
149
|
+
<div className="rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700">
|
|
150
|
+
{error}
|
|
151
|
+
</div>
|
|
152
|
+
) : null}
|
|
153
|
+
|
|
154
|
+
<div className="overflow-x-auto rounded-lg border">
|
|
155
|
+
<table className="min-w-full text-left text-sm">
|
|
156
|
+
<thead className="border-b bg-slate-50 text-xs uppercase text-slate-500">
|
|
157
|
+
<tr>
|
|
158
|
+
<th className="px-3 py-2">Méthode</th>
|
|
159
|
+
<th className="px-3 py-2">Chemin</th>
|
|
160
|
+
<th className="px-3 py-2">Description</th>
|
|
161
|
+
<th className="px-3 py-2">Source</th>
|
|
162
|
+
</tr>
|
|
163
|
+
</thead>
|
|
164
|
+
<tbody>
|
|
165
|
+
{endpoints.map((endpoint) => (
|
|
166
|
+
<tr
|
|
167
|
+
key={`${endpoint.method}:${endpoint.path}`}
|
|
168
|
+
className="border-b last:border-0 hover:bg-slate-50"
|
|
169
|
+
>
|
|
170
|
+
<td className="px-3 py-2">
|
|
171
|
+
<span
|
|
172
|
+
className={`inline-flex rounded px-2 py-0.5 font-mono text-[11px] font-bold ${
|
|
173
|
+
METHOD_STYLE[endpoint.method] || METHOD_STYLE.OPTIONS
|
|
174
|
+
}`}
|
|
175
|
+
>
|
|
176
|
+
{endpoint.method}
|
|
177
|
+
</span>
|
|
178
|
+
</td>
|
|
179
|
+
<td className="whitespace-nowrap px-3 py-2 font-mono text-xs text-slate-800">
|
|
180
|
+
{endpoint.path}
|
|
181
|
+
</td>
|
|
182
|
+
<td className="min-w-[16rem] px-3 py-2 text-xs text-slate-600">
|
|
183
|
+
{endpoint.summary || endpoint.description || "—"}
|
|
184
|
+
{endpoint.tags.length ? (
|
|
185
|
+
<div className="mt-1 flex flex-wrap gap-1">
|
|
186
|
+
{endpoint.tags.map((tag) => (
|
|
187
|
+
<Badge key={tag} variant="secondary" className="text-[10px]">
|
|
188
|
+
{tag}
|
|
189
|
+
</Badge>
|
|
190
|
+
))}
|
|
191
|
+
</div>
|
|
192
|
+
) : null}
|
|
193
|
+
</td>
|
|
194
|
+
<td className="px-3 py-2 text-xs">
|
|
195
|
+
{endpoint.documented ? (
|
|
196
|
+
<span className="text-emerald-700">OpenAPI</span>
|
|
197
|
+
) : (
|
|
198
|
+
<span className="text-slate-500">Runtime Hono</span>
|
|
199
|
+
)}
|
|
200
|
+
</td>
|
|
201
|
+
</tr>
|
|
202
|
+
))}
|
|
203
|
+
{!endpoints.length && !loading ? (
|
|
204
|
+
<tr>
|
|
205
|
+
<td colSpan={4} className="px-4 py-8 text-center text-slate-500">
|
|
206
|
+
Aucun endpoint pour ce filtre.
|
|
207
|
+
</td>
|
|
208
|
+
</tr>
|
|
209
|
+
) : null}
|
|
210
|
+
</tbody>
|
|
211
|
+
</table>
|
|
212
|
+
</div>
|
|
213
|
+
</CardContent>
|
|
214
|
+
</Card>
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function Stat({ label, value }: { label: string; value: number }) {
|
|
220
|
+
return (
|
|
221
|
+
<Card>
|
|
222
|
+
<CardContent className="p-4">
|
|
223
|
+
<div className="text-2xl font-semibold tabular-nums text-slate-900">{value}</div>
|
|
224
|
+
<div className="text-xs text-slate-500">{label}</div>
|
|
225
|
+
</CardContent>
|
|
226
|
+
</Card>
|
|
227
|
+
);
|
|
228
|
+
}
|
package/ui/index.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observability Admin UI (usage analytics N6 + request-logs / api-endpoints O5).
|
|
3
|
+
* Consommer via `@creezio/observability/ui`.
|
|
4
|
+
*/
|
|
5
|
+
export { AnalyticsClient } from "./analytics-client";
|
|
6
|
+
export {
|
|
7
|
+
AnalyticsProductivityPanel,
|
|
8
|
+
type ProductivityPayload,
|
|
9
|
+
} from "./analytics-productivity-panel";
|
|
10
|
+
export {
|
|
11
|
+
UsageAnalyticsProvider,
|
|
12
|
+
type UsageAnalyticsProviderSession,
|
|
13
|
+
} from "./usage-analytics-provider";
|
|
14
|
+
export { SessionUsageAnalyticsProvider } from "./session-usage-analytics-provider";
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
flushUsageAnalytics,
|
|
18
|
+
setUsageAnalyticsSession,
|
|
19
|
+
trackUsagePageView,
|
|
20
|
+
trackUsageEvent,
|
|
21
|
+
ensureUsageAnalyticsDom,
|
|
22
|
+
} from "./usage-analytics-client";
|
|
23
|
+
|
|
24
|
+
/** Tokens UI marque (aidAttr / fleet) — safe client via dist. */
|
|
25
|
+
export {
|
|
26
|
+
configureUsageAnalyticsUiBrand,
|
|
27
|
+
getUsageAnalyticsUiBrand,
|
|
28
|
+
type UsageAnalyticsUiBrand,
|
|
29
|
+
type FleetActionPayload,
|
|
30
|
+
} from "../dist/usage/ui-brand.js";
|
|
31
|
+
|
|
32
|
+
/* ── O5 : request-logs / api-endpoints ── */
|
|
33
|
+
export { RequestLogsClient } from "./request-logs-client";
|
|
34
|
+
export { ApiEndpointsClient } from "./api-endpoints-client";
|
|
35
|
+
export type {
|
|
36
|
+
RequestLogEntry,
|
|
37
|
+
RequestLogSource,
|
|
38
|
+
RequestLogDetail,
|
|
39
|
+
} from "../dist/request-logs/request-logs.js";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { cn } from "./cn";
|
|
4
|
+
|
|
5
|
+
const badgeVariants = cva(
|
|
6
|
+
"inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-medium transition-colors",
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: "border-transparent bg-slate-900 text-white",
|
|
11
|
+
secondary: "border-transparent bg-slate-100 text-slate-700",
|
|
12
|
+
outline: "border-slate-200 text-slate-700",
|
|
13
|
+
success: "border-transparent bg-emerald-100 text-emerald-800",
|
|
14
|
+
warning: "border-transparent bg-amber-100 text-amber-800",
|
|
15
|
+
danger: "border-transparent bg-red-100 text-red-800",
|
|
16
|
+
info: "border-transparent bg-sky-100 text-sky-800",
|
|
17
|
+
muted: "border-transparent bg-slate-50 text-slate-500",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: { variant: "default" },
|
|
21
|
+
},
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export interface BadgeProps
|
|
25
|
+
extends React.HTMLAttributes<HTMLSpanElement>,
|
|
26
|
+
VariantProps<typeof badgeVariants> {}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* <span> et non <div> : un badge est utilisé DANS des <p>, <a> et <span>
|
|
30
|
+
* (fiche produit, dashboard, préférences…). Un <div> y est du HTML invalide :
|
|
31
|
+
* le parseur navigateur restructure le DOM (ferme le <p> avant le div) et
|
|
32
|
+
* l'hydratation React échoue (« Hydration failed » #418/#422, cascade
|
|
33
|
+
* possible en #310) — écran « Application error » dans l'app desktop.
|
|
34
|
+
*/
|
|
35
|
+
export function Badge({ className, variant, ...props }: BadgeProps) {
|
|
36
|
+
return <span className={cn(badgeVariants({ variant }), className)} {...props} />;
|
|
37
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
+
import { cn } from "./cn";
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva(
|
|
7
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400 disabled:pointer-events-none disabled:opacity-50",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-slate-900 text-white hover:bg-slate-800",
|
|
12
|
+
secondary: "bg-slate-100 text-slate-900 hover:bg-slate-200",
|
|
13
|
+
outline: "border border-slate-200 bg-white hover:bg-slate-50",
|
|
14
|
+
ghost: "hover:bg-slate-100",
|
|
15
|
+
destructive: "bg-red-600 text-white hover:bg-red-700",
|
|
16
|
+
},
|
|
17
|
+
size: {
|
|
18
|
+
default: "h-9 px-4 py-2",
|
|
19
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
20
|
+
lg: "h-10 rounded-md px-8",
|
|
21
|
+
icon: "h-9 w-9",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: { variant: "default", size: "default" },
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export interface ButtonProps
|
|
29
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
30
|
+
VariantProps<typeof buttonVariants> {
|
|
31
|
+
asChild?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
35
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
36
|
+
const Comp = asChild ? Slot : "button";
|
|
37
|
+
return (
|
|
38
|
+
<Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
Button.displayName = "Button";
|
|
43
|
+
|
|
44
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "./cn";
|
|
3
|
+
|
|
4
|
+
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
5
|
+
({ className, ...props }, ref) => (
|
|
6
|
+
<div
|
|
7
|
+
ref={ref}
|
|
8
|
+
className={cn("rounded-xl border border-slate-200 bg-white shadow-sm", className)}
|
|
9
|
+
{...props}
|
|
10
|
+
/>
|
|
11
|
+
),
|
|
12
|
+
);
|
|
13
|
+
Card.displayName = "Card";
|
|
14
|
+
|
|
15
|
+
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
16
|
+
({ className, ...props }, ref) => (
|
|
17
|
+
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
|
|
18
|
+
),
|
|
19
|
+
);
|
|
20
|
+
CardHeader.displayName = "CardHeader";
|
|
21
|
+
|
|
22
|
+
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
|
23
|
+
({ className, ...props }, ref) => (
|
|
24
|
+
<h3 ref={ref} className={cn("font-semibold leading-none tracking-tight", className)} {...props} />
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
CardTitle.displayName = "CardTitle";
|
|
28
|
+
|
|
29
|
+
const CardDescription = React.forwardRef<
|
|
30
|
+
HTMLParagraphElement,
|
|
31
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
32
|
+
>(({ className, ...props }, ref) => (
|
|
33
|
+
<p ref={ref} className={cn("text-sm text-slate-500", className)} {...props} />
|
|
34
|
+
));
|
|
35
|
+
CardDescription.displayName = "CardDescription";
|
|
36
|
+
|
|
37
|
+
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
|
38
|
+
({ className, ...props }, ref) => (
|
|
39
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
CardContent.displayName = "CardContent";
|
|
43
|
+
|
|
44
|
+
export { Card, CardHeader, CardTitle, CardDescription, CardContent };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "./cn";
|
|
3
|
+
|
|
4
|
+
const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
|
5
|
+
({ className, type, ...props }, ref) => (
|
|
6
|
+
<input
|
|
7
|
+
type={type}
|
|
8
|
+
className={cn(
|
|
9
|
+
"flex h-9 w-full rounded-md border border-slate-200 bg-white px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-slate-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400 disabled:cursor-not-allowed disabled:opacity-50",
|
|
10
|
+
className,
|
|
11
|
+
)}
|
|
12
|
+
ref={ref}
|
|
13
|
+
{...props}
|
|
14
|
+
/>
|
|
15
|
+
),
|
|
16
|
+
);
|
|
17
|
+
Input.displayName = "Input";
|
|
18
|
+
|
|
19
|
+
export { Input };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
5
|
+
import { cn } from "./cn";
|
|
6
|
+
|
|
7
|
+
const Tabs = TabsPrimitive.Root;
|
|
8
|
+
|
|
9
|
+
const TabsList = React.forwardRef<
|
|
10
|
+
React.ElementRef<typeof TabsPrimitive.List>,
|
|
11
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
|
12
|
+
>(({ className, ...props }, ref) => (
|
|
13
|
+
<TabsPrimitive.List
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={cn(
|
|
16
|
+
"inline-flex h-10 items-center justify-start gap-1 rounded-lg bg-slate-100 p-1 text-slate-600",
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
));
|
|
22
|
+
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
23
|
+
|
|
24
|
+
const TabsTrigger = React.forwardRef<
|
|
25
|
+
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
|
26
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
|
27
|
+
>(({ className, ...props }, ref) => (
|
|
28
|
+
<TabsPrimitive.Trigger
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={cn(
|
|
31
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-400 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm",
|
|
32
|
+
className,
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
));
|
|
37
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
38
|
+
|
|
39
|
+
const TabsContent = React.forwardRef<
|
|
40
|
+
React.ElementRef<typeof TabsPrimitive.Content>,
|
|
41
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
|
42
|
+
>(({ className, ...props }, ref) => (
|
|
43
|
+
<TabsPrimitive.Content
|
|
44
|
+
ref={ref}
|
|
45
|
+
className={cn("mt-4 focus-visible:outline-none", className)}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
));
|
|
49
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
50
|
+
|
|
51
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|