Skip to content

Commit 5455dd7

Browse files
committed
chore: a mess of merging everything together
1 parent 8aebfec commit 5455dd7

File tree

71 files changed

+937
-416
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+937
-416
lines changed

docker/dev-full/vector-server/vector.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ transforms:
6060
type: vrl
6161
source: .source == "pegboard_container_runner"
6262

63+
actors_transform:
64+
type: remap
65+
inputs:
66+
- actors
67+
source: |
68+
# Add namespace label to actor logs
69+
.namespace = "rivet"
70+
6371
clickhouse_dynamic_events_filter:
6472
type: filter
6573
inputs:
@@ -107,7 +115,7 @@ sinks:
107115
clickhouse_actor_logs:
108116
type: clickhouse
109117
inputs:
110-
- actors
118+
- actors_transform
111119
compression: gzip
112120
database: db_pegboard_actor_log
113121
endpoint: http://clickhouse:8123

docker/monolith/vector-server/vector.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ transforms:
5959
condition:
6060
type: vrl
6161
source: .source == "pegboard_container_runner"
62+
63+
actors_transform:
64+
type: remap
65+
inputs:
66+
- actors
67+
source: |
68+
# Add namespace label to actor logs
69+
.namespace = "rivet"
6270
6371
sinks:
6472
prom_exporter:
@@ -78,7 +86,7 @@ sinks:
7886
clickhouse_actor_logs:
7987
type: clickhouse
8088
inputs:
81-
- actors
89+
- actors_transform
8290
compression: gzip
8391
endpoint: http://clickhouse:9300
8492
database: db_pegboard_actor_log

frontend/apps/hub/ARCHITECTURE.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Hub Architecture
2+
3+
## Overview
4+
5+
The Hub is a React/TypeScript dashboard application built with:
6+
- **TanStack Router** - File-based routing
7+
- **TanStack Query** - Server state management
8+
- **Jotai** - Complex client state
9+
- **React Context** - Global app state
10+
- **Tailwind CSS** - Styling
11+
12+
## Directory Structure
13+
14+
```
15+
src/
16+
├── domains/ # Feature domains
17+
│ └── {domain}/
18+
│ ├── components/ # Domain-specific components
19+
│ ├── queries/ # Query options & mutations
20+
│ ├── data/ # Context providers
21+
│ └── forms/ # Form schemas
22+
├── routes/ # Page components (file-based)
23+
├── components/ # Shared UI components
24+
├── queries/ # Global query setup
25+
├── hooks/ # Custom React hooks
26+
├── lib/ # Utilities
27+
└── app.tsx # Root setup
28+
```
29+
30+
## State Management
31+
32+
### Server State (TanStack Query)
33+
```typescript
34+
// Query pattern: src/domains/{domain}/queries/query-options.ts
35+
export const actorLogsQueryOptions = ({ projectNameId, environmentNameId, actorId }) =>
36+
queryOptions({
37+
queryKey: ["project", projectNameId, "environment", environmentNameId, "actor", actorId, "logs"],
38+
queryFn: async ({ signal }) => rivetClient.actors.logs.get(...),
39+
meta: { watch: true }, // Enable real-time updates
40+
});
41+
```
42+
43+
### Client State (Jotai)
44+
Used for complex, modular state (e.g., actor management):
45+
```typescript
46+
// Atoms for fine-grained reactivity
47+
export const currentActorIdAtom = atom<string | undefined>(undefined);
48+
export const actorsAtom = atom<Actor[]>([]);
49+
```
50+
51+
### Global State (React Context)
52+
```typescript
53+
// Context for app-wide concerns
54+
AuthContext // User authentication
55+
ProjectContext // Current project
56+
EnvironmentContext // Current environment
57+
```
58+
59+
## Query Patterns
60+
61+
### Standard Query
62+
```typescript
63+
const { data } = useQuery(projectQueryOptions(projectId));
64+
```
65+
66+
### Infinite Query
67+
```typescript
68+
const { data, fetchNextPage } = useInfiniteQuery(
69+
projectActorsQueryOptions({ projectNameId, environmentNameId })
70+
);
71+
```
72+
73+
### Mutations
74+
```typescript
75+
const mutation = useMutation({
76+
mutationFn: (data) => rivetClient.actors.destroy(data),
77+
onSuccess: () => queryClient.invalidateQueries(...)
78+
});
79+
```
80+
81+
### Real-time Updates
82+
Queries with `watchIndex` parameter automatically refetch when server data changes:
83+
```typescript
84+
queryFn: ({ meta }) => api.call({
85+
watchIndex: getMetaWatchIndex(meta)
86+
})
87+
```
88+
89+
## Key Conventions
90+
91+
### Query Keys
92+
Hierarchical structure matching API resources:
93+
```typescript
94+
["project", projectId, "environment", envId, "actor", actorId, "logs"]
95+
```
96+
97+
### File Naming
98+
- Query options: `query-options.ts`
99+
- Mutations: `mutations.ts`
100+
- Context: `{resource}-context.tsx`
101+
- Components: `{feature}-{component}.tsx`
102+
103+
### Import Aliases
104+
```typescript
105+
@/domains // Domain logic
106+
@/components // Shared components
107+
@/queries // Query utilities
108+
@/hooks // Custom hooks
109+
@/lib // Utilities
110+
```
111+
112+
## API Integration
113+
114+
- **rivetClient**: Main API client (`@rivet-gg/api-full`)
115+
- **rivetEeClient**: Enterprise API (`@rivet-gg/api-ee`)
116+
- Auto token refresh on expiration
117+
- Request deduplication & caching
118+
119+
## Example: Adding a New Feature
120+
121+
1. **Create query options**:
122+
```typescript
123+
// src/domains/project/queries/feature/query-options.ts
124+
export const featureQueryOptions = (id: string) => queryOptions({
125+
queryKey: ["feature", id],
126+
queryFn: () => rivetClient.feature.get(id),
127+
});
128+
```
129+
130+
2. **Create mutations**:
131+
```typescript
132+
// src/domains/project/queries/feature/mutations.ts
133+
export const useCreateFeatureMutation = () => useMutation({
134+
mutationFn: (data) => rivetClient.feature.create(data),
135+
});
136+
```
137+
138+
3. **Create route**:
139+
```typescript
140+
// src/routes/.../feature.tsx
141+
export const Route = createFileRoute('...')({
142+
component: FeaturePage,
143+
});
144+
```
145+
146+
4. **Use in component**:
147+
```typescript
148+
function FeaturePage() {
149+
const { data } = useQuery(featureQueryOptions(id));
150+
const mutation = useCreateFeatureMutation();
151+
// ...
152+
}
153+
```
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { ActorsActorDetails } from "@rivet-gg/components/actors";
2+
import { useExportActorLogsMutation } from "../../queries/actors/mutations";
3+
import { useProject } from "../../data/project-context";
4+
import { useEnvironment } from "../../data/environment-context";
5+
import type { ActorAtom } from "@rivet-gg/components/actors";
6+
7+
interface ActorsActorDetailsWrapperProps {
8+
tab?: string;
9+
actor: ActorAtom;
10+
onTabChange?: (tab: string) => void;
11+
}
12+
13+
export function ActorsActorDetailsWrapper({
14+
tab,
15+
actor,
16+
onTabChange
17+
}: ActorsActorDetailsWrapperProps) {
18+
const { nameId: projectNameId } = useProject();
19+
const { nameId: environmentNameId } = useEnvironment();
20+
const exportMutation = useExportActorLogsMutation();
21+
22+
const handleExportLogs = async (actorId: string, typeFilter?: string, filter?: string) => {
23+
// Build query JSON for the API
24+
const query: any = {
25+
actorIds: [actorId],
26+
};
27+
28+
// Add stream filter based on typeFilter
29+
if (typeFilter === "output") {
30+
query.stream = 0; // stdout
31+
} else if (typeFilter === "errors") {
32+
query.stream = 1; // stderr
33+
}
34+
35+
// Add text search if filter is provided
36+
if (filter) {
37+
query.searchText = filter;
38+
}
39+
40+
const result = await exportMutation.mutateAsync({
41+
projectNameId,
42+
environmentNameId,
43+
queryJson: JSON.stringify(query),
44+
});
45+
46+
// Open the presigned URL in a new tab to download
47+
window.open(result.url, "_blank");
48+
};
49+
50+
return (
51+
<ActorsActorDetails
52+
tab={tab}
53+
actor={actor}
54+
onTabChange={onTabChange}
55+
onExportLogs={handleExportLogs}
56+
isExportingLogs={exportMutation.isPending}
57+
/>
58+
);
59+
}

frontend/apps/hub/src/domains/project/components/actors/actors-provider.tsx

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { router } from "@/app";
2-
import { queryClient, rivetClient } from "@/queries/global";
2+
import { queryClient } from "@/queries/global";
33
import { type FilterValue, toRecord } from "@rivet-gg/components";
44
import {
55
currentActorIdAtom,
@@ -17,7 +17,6 @@ import {
1717
actorsInternalFilterAtom,
1818
type Actor,
1919
actorEnvironmentAtom,
20-
exportLogsHandlerAtom,
2120
} from "@rivet-gg/components/actors";
2221
import {
2322
InfiniteQueryObserver,
@@ -85,16 +84,6 @@ export function ActorsProvider({
8584
store.set(actorEnvironmentAtom, { projectNameId, environmentNameId });
8685
}, [projectNameId, environmentNameId]);
8786

88-
// biome-ignore lint/correctness/useExhaustiveDependencies: store is not a dependency
89-
useEffect(() => {
90-
store.set(exportLogsHandlerAtom, async ({ projectNameId, environmentNameId, queryJson }) => {
91-
return rivetClient.actors.logs.export({
92-
project: projectNameId,
93-
environment: environmentNameId,
94-
queryJson,
95-
});
96-
});
97-
}, []);
9887

9988
// biome-ignore lint/correctness/useExhaustiveDependencies: store is not a dependency
10089
useEffect(() => {

0 commit comments

Comments
 (0)