mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-01 17:39:39 +02:00
refactor(ts): make port effect native
This commit is contained in:
parent
2868ced2d3
commit
b6759e75df
113 changed files with 4140 additions and 4554 deletions
|
|
@ -10,18 +10,18 @@
|
|||
"qa:browser": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@effect/ai-anthropic": "4.0.0-beta.75",
|
||||
"@effect/ai-openai": "4.0.0-beta.75",
|
||||
"@effect/ai-openrouter": "4.0.0-beta.75",
|
||||
"@effect/atom-react": "4.0.0-beta.75",
|
||||
"@effect/openapi-generator": "4.0.0-beta.75",
|
||||
"@effect/opentelemetry": "4.0.0-beta.75",
|
||||
"@effect/platform-browser": "4.0.0-beta.75",
|
||||
"@effect/platform-bun": "4.0.0-beta.75",
|
||||
"@effect/platform-node": "4.0.0-beta.75",
|
||||
"@effect/platform-node-shared": "4.0.0-beta.75",
|
||||
"@effect/tsgo": "0.13.0",
|
||||
"@effect/vitest": "4.0.0-beta.75",
|
||||
"@effect/ai-anthropic": "4.0.0-beta.78",
|
||||
"@effect/ai-openai": "4.0.0-beta.78",
|
||||
"@effect/ai-openrouter": "4.0.0-beta.78",
|
||||
"@effect/atom-react": "4.0.0-beta.78",
|
||||
"@effect/openapi-generator": "4.0.0-beta.78",
|
||||
"@effect/opentelemetry": "4.0.0-beta.78",
|
||||
"@effect/platform-browser": "4.0.0-beta.78",
|
||||
"@effect/platform-bun": "4.0.0-beta.78",
|
||||
"@effect/platform-node": "4.0.0-beta.78",
|
||||
"@effect/platform-node-shared": "4.0.0-beta.78",
|
||||
"@effect/tsgo": "0.14.0",
|
||||
"@effect/vitest": "4.0.0-beta.78",
|
||||
"@tanstack/react-query": "^5.75.0",
|
||||
"@trustgraph/client": "workspace:*",
|
||||
"clsx": "^2.1.0",
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
"zustand": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@effect/vitest": "4.0.0-beta.75",
|
||||
"@effect/vitest": "4.0.0-beta.78",
|
||||
"@playwright/test": "^1.57.0",
|
||||
"@tailwindcss/vite": "^4.1.0",
|
||||
"@types/react": "^19.1.0",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default defineConfig({
|
|||
video: "retain-on-failure",
|
||||
},
|
||||
webServer: {
|
||||
command: `bun run dev -- --host 127.0.0.1 --port ${port} --strictPort`,
|
||||
command: `WORKBENCH_QA=1 bun run dev -- --host 127.0.0.1 --port ${port} --strictPort`,
|
||||
cwd: ".",
|
||||
url: baseURL,
|
||||
reuseExistingServer: false,
|
||||
|
|
|
|||
|
|
@ -353,12 +353,12 @@ const ChatMessageSchema = S.Struct({
|
|||
id: S.String,
|
||||
role: S.Union([S.Literal("user"), S.Literal("assistant"), S.Literal("system")]),
|
||||
content: S.String,
|
||||
timestamp: S.Number,
|
||||
timestamp: S.Finite,
|
||||
isStreaming: S.optionalKey(S.Boolean),
|
||||
metadata: S.optionalKey(S.Struct({
|
||||
model: S.optionalKey(S.String),
|
||||
inTokens: S.optionalKey(S.Number),
|
||||
outTokens: S.optionalKey(S.Number),
|
||||
inTokens: S.optionalKey(S.Finite),
|
||||
outTokens: S.optionalKey(S.Finite),
|
||||
})),
|
||||
agentPhases: S.optionalKey(S.Struct({
|
||||
think: S.String,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import {
|
|||
localName,
|
||||
type GraphNode,
|
||||
type GraphLink,
|
||||
directedGraphLinkProps,
|
||||
DEFAULT_GRAPH_NODE_COLOR,
|
||||
} from "@/lib/graph-utils";
|
||||
import type { ExplainEvent } from "@trustgraph/client";
|
||||
import type { ForceGraphProps } from "react-force-graph-2d";
|
||||
|
|
@ -34,7 +36,7 @@ function paintNode(node: GraphNode, ctx: CanvasRenderingContext2D, globalScale:
|
|||
const y = node.y ?? 0;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = node.color ?? "#5b80ff";
|
||||
ctx.fillStyle = node.color ?? DEFAULT_GRAPH_NODE_COLOR;
|
||||
ctx.fill();
|
||||
const fontSize = Math.max(9 / globalScale, 1.5);
|
||||
ctx.font = `${fontSize}px Inter, sans-serif`;
|
||||
|
|
@ -115,7 +117,7 @@ export function ExplainGraph({ explainEvents, collection }: ExplainGraphProps) {
|
|||
nodeCanvasObject={paintNode}
|
||||
linkCanvasObjectMode={() => "after"}
|
||||
linkCanvasObject={paintLink}
|
||||
linkColor={() => "rgba(120,120,140,0.32)"}
|
||||
{...directedGraphLinkProps}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,34 @@
|
|||
/**
|
||||
* Ambient glow background — forest green radial blobs that drift and pulse.
|
||||
* Ambient glow background -- forest green radial fields that drift and pulse.
|
||||
*
|
||||
* Ported from beep-effect4's GlowEffectPaper, adapted for plain CSS
|
||||
* with multiple independent blobs for organic movement.
|
||||
* with multiple independent fields for organic movement.
|
||||
*/
|
||||
|
||||
const primaryGlow = "radial-gradient(ellipse at center, var(--tg-glow-primary-start) 0%, var(--tg-glow-primary-mid) 40%, transparent 70%)";
|
||||
const secondaryGlow = "radial-gradient(ellipse at center, var(--tg-glow-secondary-start) 0%, var(--tg-glow-secondary-mid) 45%, transparent 70%)";
|
||||
const tertiaryGlow = "radial-gradient(ellipse at center, var(--tg-glow-tertiary-start) 0%, var(--tg-glow-tertiary-mid) 50%, transparent 70%)";
|
||||
|
||||
export function GlowBackground() {
|
||||
return (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute inset-0 z-0 overflow-hidden animate-[glow-fade-in_1.2s_ease-out_forwards] opacity-0"
|
||||
>
|
||||
{/* Primary blob — large, centered, slow drift */}
|
||||
<div className="absolute left-1/2 top-1/3 h-[70vh] w-[70vw] -translate-x-1/2 -translate-y-1/2 animate-[glow-drift-1_20s_ease-in-out_infinite] rounded-full bg-[radial-gradient(ellipse_at_center,rgba(61,125,61,0.35)_0%,rgba(45,99,45,0.15)_40%,transparent_70%)] blur-[80px]" />
|
||||
<div
|
||||
className="absolute left-1/2 top-1/3 h-[70vh] w-[70vw] -translate-x-1/2 -translate-y-1/2 animate-[glow-drift-1_20s_ease-in-out_infinite] rounded-full blur-[80px]"
|
||||
style={{ background: primaryGlow }}
|
||||
/>
|
||||
|
||||
{/* Secondary blob — smaller, offset right, faster */}
|
||||
<div className="absolute right-[10%] top-[20%] h-[50vh] w-[40vw] animate-[glow-drift-2_15s_ease-in-out_infinite] rounded-full bg-[radial-gradient(ellipse_at_center,rgba(92,154,92,0.28)_0%,rgba(61,125,61,0.12)_45%,transparent_70%)] blur-[60px]" />
|
||||
<div
|
||||
className="absolute right-[10%] top-[20%] h-[50vh] w-[40vw] animate-[glow-drift-2_15s_ease-in-out_infinite] rounded-full blur-[60px]"
|
||||
style={{ background: secondaryGlow }}
|
||||
/>
|
||||
|
||||
{/* Tertiary blob — bottom left, subtle */}
|
||||
<div className="absolute bottom-[5%] left-[15%] h-[45vh] w-[45vw] animate-[glow-drift-3_25s_ease-in-out_infinite] rounded-full bg-[radial-gradient(ellipse_at_center,rgba(33,78,33,0.30)_0%,rgba(26,58,26,0.12)_50%,transparent_70%)] blur-[70px]" />
|
||||
<div
|
||||
className="absolute bottom-[5%] left-[15%] h-[45vh] w-[45vw] animate-[glow-drift-3_25s_ease-in-out_infinite] rounded-full blur-[70px]"
|
||||
style={{ background: tertiaryGlow }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,15 @@
|
|||
--font-mono: "JetBrains Mono", ui-monospace, monospace;
|
||||
}
|
||||
|
||||
:root {
|
||||
--tg-glow-primary-start: rgba(61, 125, 61, 0.35);
|
||||
--tg-glow-primary-mid: rgba(45, 99, 45, 0.15);
|
||||
--tg-glow-secondary-start: rgba(92, 154, 92, 0.28);
|
||||
--tg-glow-secondary-mid: rgba(61, 125, 61, 0.12);
|
||||
--tg-glow-tertiary-start: rgba(33, 78, 33, 0.30);
|
||||
--tg-glow-tertiary-mid: rgba(26, 58, 26, 0.12);
|
||||
}
|
||||
|
||||
/* Base layer: dark background, light text by default */
|
||||
@layer base {
|
||||
*,
|
||||
|
|
@ -182,4 +191,11 @@ html.light {
|
|||
--color-success: #16a34a;
|
||||
--color-warning: #854d0e;
|
||||
--color-error: #b91c1c;
|
||||
|
||||
--tg-glow-primary-start: rgba(61, 125, 61, 0.28);
|
||||
--tg-glow-primary-mid: rgba(92, 154, 92, 0.16);
|
||||
--tg-glow-secondary-start: rgba(45, 99, 45, 0.22);
|
||||
--tg-glow-secondary-mid: rgba(61, 125, 61, 0.12);
|
||||
--tg-glow-tertiary-start: rgba(33, 78, 33, 0.18);
|
||||
--tg-glow-tertiary-mid: rgba(92, 154, 92, 0.10);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Triple, Term } from "@trustgraph/client";
|
||||
import { Match } from "effect";
|
||||
import type { NodeObject, LinkObject } from "react-force-graph-2d";
|
||||
import type { ForceGraphProps, NodeObject, LinkObject } from "react-force-graph-2d";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
|
|
@ -32,6 +32,32 @@ export interface GraphData {
|
|||
links: GraphLink[];
|
||||
}
|
||||
|
||||
export const DEFAULT_GRAPH_NODE_COLOR = "#82b582";
|
||||
|
||||
const GRAPH_NODE_PALETTE = [
|
||||
DEFAULT_GRAPH_NODE_COLOR,
|
||||
"#5c9a5c",
|
||||
"#3d7d3d",
|
||||
"#aed1ae",
|
||||
"#22c55e",
|
||||
"#eab308",
|
||||
"#a1a1aa",
|
||||
"#71717a",
|
||||
];
|
||||
|
||||
export const directedGraphLinkProps = {
|
||||
autoPauseRedraw: false,
|
||||
linkColor: "rgba(161,161,170,0.55)",
|
||||
linkWidth: 1.4,
|
||||
linkDirectionalArrowLength: 9,
|
||||
linkDirectionalArrowRelPos: 0.58,
|
||||
linkDirectionalArrowColor: "rgba(174,209,174,0.98)",
|
||||
linkDirectionalParticles: 1,
|
||||
linkDirectionalParticleSpeed: 0.005,
|
||||
linkDirectionalParticleWidth: 2.2,
|
||||
linkDirectionalParticleColor: "rgba(92,154,92,0.95)",
|
||||
} satisfies Partial<ForceGraphProps<GraphNode, GraphLink>>;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Term helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -66,8 +92,8 @@ export function hashColor(s: string): string {
|
|||
for (let i = 0; i < s.length; i++) {
|
||||
hash = s.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
const hue = ((hash % 360) + 360) % 360;
|
||||
return `hsl(${hue}, 60%, 55%)`;
|
||||
const index = Math.abs(hash) % GRAPH_NODE_PALETTE.length;
|
||||
return GRAPH_NODE_PALETTE[index];
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -103,7 +129,7 @@ export function triplesToGraph(triples: Triple[]): {
|
|||
nodeMap.set(uri, {
|
||||
id: uri,
|
||||
label: labelMap.get(uri) ?? localName(uri),
|
||||
color: type !== undefined ? hashColor(localName(type)) : "#5b80ff",
|
||||
color: hashColor(type !== undefined ? localName(type) : uri),
|
||||
degree: 0,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import {
|
|||
termValue,
|
||||
type GraphNode,
|
||||
type GraphLink,
|
||||
directedGraphLinkProps,
|
||||
DEFAULT_GRAPH_NODE_COLOR,
|
||||
} from "@/lib/graph-utils";
|
||||
import type { ForceGraphProps } from "react-force-graph-2d";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
|
|
@ -120,7 +122,7 @@ function paintNode(showLabels: boolean) {
|
|||
const y = node.y ?? 0;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius, 0, 2 * Math.PI);
|
||||
ctx.fillStyle = node.color ?? "#5b80ff";
|
||||
ctx.fillStyle = node.color ?? DEFAULT_GRAPH_NODE_COLOR;
|
||||
ctx.fill();
|
||||
if (!showLabels || globalScale < 0.7) return;
|
||||
const fontSize = Math.max(10 / globalScale, 2);
|
||||
|
|
@ -257,7 +259,7 @@ export default function GraphPage() {
|
|||
nodeCanvasObject={paintNode(view.showLabels)}
|
||||
linkCanvasObjectMode={() => "after"}
|
||||
linkCanvasObject={paintLink}
|
||||
linkColor={() => "rgba(120,120,140,0.32)"}
|
||||
{...directedGraphLinkProps}
|
||||
nodePointerAreaPaint={(node, color, ctx) => {
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
|
|
|
|||
|
|
@ -3,8 +3,23 @@ import react from "@vitejs/plugin-react";
|
|||
import tailwindcss from "@tailwindcss/vite";
|
||||
import path from "path";
|
||||
|
||||
const isWorkbenchQa = process.env.WORKBENCH_QA === "1";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss()],
|
||||
plugins: [
|
||||
react(),
|
||||
tailwindcss(),
|
||||
{
|
||||
name: "trustgraph-workbench-qa-otel",
|
||||
configureServer(server) {
|
||||
if (!isWorkbenchQa) return;
|
||||
server.middlewares.use("/otel", (_request, response) => {
|
||||
response.statusCode = 204;
|
||||
response.end();
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue