@weirdfingers/boards 0.5.2 → 0.6.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/dist/index.d.mts +148 -7
- package/dist/index.d.ts +148 -7
- package/dist/index.js +307 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +292 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/graphql/operations.ts +103 -6
- package/src/hooks/useLineage.ts +210 -0
- package/src/hooks/useUpload.ts +175 -0
- package/src/index.ts +27 -2
|
@@ -51,6 +51,51 @@ export const GENERATION_FRAGMENT = gql`
|
|
|
51
51
|
}
|
|
52
52
|
`;
|
|
53
53
|
|
|
54
|
+
// Lineage fragments
|
|
55
|
+
export const ARTIFACT_LINEAGE_FRAGMENT = gql`
|
|
56
|
+
fragment ArtifactLineageFragment on ArtifactLineage {
|
|
57
|
+
generationId
|
|
58
|
+
role
|
|
59
|
+
artifactType
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
export const ANCESTRY_NODE_FRAGMENT = gql`
|
|
64
|
+
${GENERATION_FRAGMENT}
|
|
65
|
+
fragment AncestryNodeFragment on AncestryNode {
|
|
66
|
+
depth
|
|
67
|
+
role
|
|
68
|
+
generation {
|
|
69
|
+
...GenerationFragment
|
|
70
|
+
}
|
|
71
|
+
parents {
|
|
72
|
+
depth
|
|
73
|
+
role
|
|
74
|
+
generation {
|
|
75
|
+
...GenerationFragment
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
export const DESCENDANT_NODE_FRAGMENT = gql`
|
|
82
|
+
${GENERATION_FRAGMENT}
|
|
83
|
+
fragment DescendantNodeFragment on DescendantNode {
|
|
84
|
+
depth
|
|
85
|
+
role
|
|
86
|
+
generation {
|
|
87
|
+
...GenerationFragment
|
|
88
|
+
}
|
|
89
|
+
children {
|
|
90
|
+
depth
|
|
91
|
+
role
|
|
92
|
+
generation {
|
|
93
|
+
...GenerationFragment
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
54
99
|
// Auth queries
|
|
55
100
|
export const GET_CURRENT_USER = gql`
|
|
56
101
|
${USER_FRAGMENT}
|
|
@@ -150,6 +195,40 @@ export const GET_GENERATION = gql`
|
|
|
150
195
|
}
|
|
151
196
|
`;
|
|
152
197
|
|
|
198
|
+
// Lineage queries
|
|
199
|
+
export const GET_ANCESTRY = gql`
|
|
200
|
+
${ANCESTRY_NODE_FRAGMENT}
|
|
201
|
+
query GetAncestry($id: UUID!, $maxDepth: Int = 25) {
|
|
202
|
+
generation(id: $id) {
|
|
203
|
+
ancestry(maxDepth: $maxDepth) {
|
|
204
|
+
...AncestryNodeFragment
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
export const GET_DESCENDANTS = gql`
|
|
211
|
+
${DESCENDANT_NODE_FRAGMENT}
|
|
212
|
+
query GetDescendants($id: UUID!, $maxDepth: Int = 25) {
|
|
213
|
+
generation(id: $id) {
|
|
214
|
+
descendants(maxDepth: $maxDepth) {
|
|
215
|
+
...DescendantNodeFragment
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
`;
|
|
220
|
+
|
|
221
|
+
export const GET_INPUT_ARTIFACTS = gql`
|
|
222
|
+
${ARTIFACT_LINEAGE_FRAGMENT}
|
|
223
|
+
query GetInputArtifacts($id: UUID!) {
|
|
224
|
+
generation(id: $id) {
|
|
225
|
+
inputArtifacts {
|
|
226
|
+
...ArtifactLineageFragment
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
`;
|
|
231
|
+
|
|
153
232
|
// Board mutations
|
|
154
233
|
export const CREATE_BOARD = gql`
|
|
155
234
|
${BOARD_FRAGMENT}
|
|
@@ -243,6 +322,15 @@ export const RETRY_GENERATION = gql`
|
|
|
243
322
|
}
|
|
244
323
|
`;
|
|
245
324
|
|
|
325
|
+
export const UPLOAD_ARTIFACT_FROM_URL = gql`
|
|
326
|
+
${GENERATION_FRAGMENT}
|
|
327
|
+
mutation UploadArtifactFromUrl($input: UploadArtifactInput!) {
|
|
328
|
+
uploadArtifact(input: $input) {
|
|
329
|
+
...GenerationFragment
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
`;
|
|
333
|
+
|
|
246
334
|
// Input types (these should match your backend GraphQL schema)
|
|
247
335
|
export interface CreateBoardInput {
|
|
248
336
|
title: string;
|
|
@@ -268,6 +356,15 @@ export interface CreateGenerationInput {
|
|
|
268
356
|
metadata?: Record<string, unknown>;
|
|
269
357
|
}
|
|
270
358
|
|
|
359
|
+
export interface UploadArtifactInput {
|
|
360
|
+
boardId: string;
|
|
361
|
+
artifactType: ArtifactType;
|
|
362
|
+
fileUrl?: string;
|
|
363
|
+
originalFilename?: string;
|
|
364
|
+
userDescription?: string;
|
|
365
|
+
parentGenerationId?: string;
|
|
366
|
+
}
|
|
367
|
+
|
|
271
368
|
// Enums (should match backend)
|
|
272
369
|
export enum BoardRole {
|
|
273
370
|
VIEWER = "VIEWER",
|
|
@@ -284,10 +381,10 @@ export enum GenerationStatus {
|
|
|
284
381
|
}
|
|
285
382
|
|
|
286
383
|
export enum ArtifactType {
|
|
287
|
-
IMAGE = "
|
|
288
|
-
VIDEO = "
|
|
289
|
-
AUDIO = "
|
|
290
|
-
TEXT = "
|
|
291
|
-
LORA = "
|
|
292
|
-
MODEL = "
|
|
384
|
+
IMAGE = "IMAGE",
|
|
385
|
+
VIDEO = "VIDEO",
|
|
386
|
+
AUDIO = "AUDIO",
|
|
387
|
+
TEXT = "TEXT",
|
|
388
|
+
LORA = "LORA",
|
|
389
|
+
MODEL = "MODEL",
|
|
293
390
|
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for accessing generation lineage (ancestry and descendants).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useMemo } from "react";
|
|
6
|
+
import { useQuery } from "urql";
|
|
7
|
+
import {
|
|
8
|
+
GET_ANCESTRY,
|
|
9
|
+
GET_DESCENDANTS,
|
|
10
|
+
GET_INPUT_ARTIFACTS,
|
|
11
|
+
} from "../graphql/operations";
|
|
12
|
+
|
|
13
|
+
export interface ArtifactLineage {
|
|
14
|
+
generationId: string;
|
|
15
|
+
role: string;
|
|
16
|
+
artifactType: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface AncestryNode {
|
|
20
|
+
generation: {
|
|
21
|
+
id: string;
|
|
22
|
+
generatorName: string;
|
|
23
|
+
artifactType: string;
|
|
24
|
+
status: string;
|
|
25
|
+
storageUrl?: string;
|
|
26
|
+
thumbnailUrl?: string;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
};
|
|
30
|
+
depth: number;
|
|
31
|
+
role: string | null;
|
|
32
|
+
parents: AncestryNode[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface DescendantNode {
|
|
36
|
+
generation: {
|
|
37
|
+
id: string;
|
|
38
|
+
generatorName: string;
|
|
39
|
+
artifactType: string;
|
|
40
|
+
status: string;
|
|
41
|
+
storageUrl?: string;
|
|
42
|
+
thumbnailUrl?: string;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
};
|
|
46
|
+
depth: number;
|
|
47
|
+
role: string | null;
|
|
48
|
+
children: DescendantNode[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
interface UseAncestryOptions {
|
|
52
|
+
maxDepth?: number;
|
|
53
|
+
pause?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface UseAncestryHook {
|
|
57
|
+
ancestry: AncestryNode | null;
|
|
58
|
+
loading: boolean;
|
|
59
|
+
error: Error | null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Hook for fetching the ancestry tree of a generation.
|
|
64
|
+
* @param generationId - The ID of the generation to fetch ancestry for
|
|
65
|
+
* @param options - Optional configuration (maxDepth, pause)
|
|
66
|
+
*/
|
|
67
|
+
export function useAncestry(
|
|
68
|
+
generationId: string,
|
|
69
|
+
options: UseAncestryOptions = {}
|
|
70
|
+
): UseAncestryHook {
|
|
71
|
+
const { maxDepth = 25, pause = false } = options;
|
|
72
|
+
|
|
73
|
+
const [{ data, fetching, error }] = useQuery({
|
|
74
|
+
query: GET_ANCESTRY,
|
|
75
|
+
variables: { id: generationId, maxDepth },
|
|
76
|
+
pause,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const ancestry = useMemo(
|
|
80
|
+
() => data?.generation?.ancestry || null,
|
|
81
|
+
[data?.generation?.ancestry]
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
ancestry,
|
|
86
|
+
loading: fetching,
|
|
87
|
+
error: error ? new Error(error.message) : null,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface UseDescendantsOptions {
|
|
92
|
+
maxDepth?: number;
|
|
93
|
+
pause?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface UseDescendantsHook {
|
|
97
|
+
descendants: DescendantNode | null;
|
|
98
|
+
loading: boolean;
|
|
99
|
+
error: Error | null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Hook for fetching the descendants tree of a generation.
|
|
104
|
+
* @param generationId - The ID of the generation to fetch descendants for
|
|
105
|
+
* @param options - Optional configuration (maxDepth, pause)
|
|
106
|
+
*/
|
|
107
|
+
export function useDescendants(
|
|
108
|
+
generationId: string,
|
|
109
|
+
options: UseDescendantsOptions = {}
|
|
110
|
+
): UseDescendantsHook {
|
|
111
|
+
const { maxDepth = 25, pause = false } = options;
|
|
112
|
+
|
|
113
|
+
const [{ data, fetching, error }] = useQuery({
|
|
114
|
+
query: GET_DESCENDANTS,
|
|
115
|
+
variables: { id: generationId, maxDepth },
|
|
116
|
+
pause,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const descendants = useMemo(
|
|
120
|
+
() => data?.generation?.descendants || null,
|
|
121
|
+
[data?.generation?.descendants]
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
descendants,
|
|
126
|
+
loading: fetching,
|
|
127
|
+
error: error ? new Error(error.message) : null,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface UseInputArtifactsOptions {
|
|
132
|
+
pause?: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface UseInputArtifactsHook {
|
|
136
|
+
inputArtifacts: ArtifactLineage[];
|
|
137
|
+
loading: boolean;
|
|
138
|
+
error: Error | null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Hook for fetching the input artifacts of a generation.
|
|
143
|
+
* @param generationId - The ID of the generation to fetch input artifacts for
|
|
144
|
+
* @param options - Optional configuration (pause)
|
|
145
|
+
*/
|
|
146
|
+
export function useInputArtifacts(
|
|
147
|
+
generationId: string,
|
|
148
|
+
options: UseInputArtifactsOptions = {}
|
|
149
|
+
): UseInputArtifactsHook {
|
|
150
|
+
const { pause = false } = options;
|
|
151
|
+
|
|
152
|
+
const [{ data, fetching, error }] = useQuery({
|
|
153
|
+
query: GET_INPUT_ARTIFACTS,
|
|
154
|
+
variables: { id: generationId },
|
|
155
|
+
pause,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const inputArtifacts = useMemo(
|
|
159
|
+
() => data?.generation?.inputArtifacts || [],
|
|
160
|
+
[data?.generation?.inputArtifacts]
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
inputArtifacts,
|
|
165
|
+
loading: fetching,
|
|
166
|
+
error: error ? new Error(error.message) : null,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Combined hook for fetching both ancestry and descendants.
|
|
172
|
+
* Useful for lineage explorer pages that show both trees.
|
|
173
|
+
*/
|
|
174
|
+
interface UseLineageOptions {
|
|
175
|
+
maxDepth?: number;
|
|
176
|
+
pause?: boolean;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
interface UseLineageHook {
|
|
180
|
+
ancestry: AncestryNode | null;
|
|
181
|
+
descendants: DescendantNode | null;
|
|
182
|
+
inputArtifacts: ArtifactLineage[];
|
|
183
|
+
loading: boolean;
|
|
184
|
+
error: Error | null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function useLineage(
|
|
188
|
+
generationId: string,
|
|
189
|
+
options: UseLineageOptions = {}
|
|
190
|
+
): UseLineageHook {
|
|
191
|
+
const ancestryResult = useAncestry(generationId, options);
|
|
192
|
+
const descendantsResult = useDescendants(generationId, options);
|
|
193
|
+
const inputArtifactsResult = useInputArtifacts(generationId, options);
|
|
194
|
+
|
|
195
|
+
const loading =
|
|
196
|
+
ancestryResult.loading ||
|
|
197
|
+
descendantsResult.loading ||
|
|
198
|
+
inputArtifactsResult.loading;
|
|
199
|
+
|
|
200
|
+
const error =
|
|
201
|
+
ancestryResult.error || descendantsResult.error || inputArtifactsResult.error;
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
ancestry: ancestryResult.ancestry,
|
|
205
|
+
descendants: descendantsResult.descendants,
|
|
206
|
+
inputArtifacts: inputArtifactsResult.inputArtifacts,
|
|
207
|
+
loading,
|
|
208
|
+
error,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook for uploading artifacts (images, videos, audio, text).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useCallback, useState } from "react";
|
|
6
|
+
import { useMutation } from "urql";
|
|
7
|
+
import { UPLOAD_ARTIFACT_FROM_URL, ArtifactType } from "../graphql/operations";
|
|
8
|
+
import { useAuth } from "../auth/context";
|
|
9
|
+
import { useApiConfig } from "../config/ApiConfigContext";
|
|
10
|
+
|
|
11
|
+
export interface UploadRequest {
|
|
12
|
+
boardId: string;
|
|
13
|
+
artifactType: ArtifactType;
|
|
14
|
+
source: File | string; // File object or URL string
|
|
15
|
+
userDescription?: string;
|
|
16
|
+
parentGenerationId?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UploadResult {
|
|
20
|
+
id: string;
|
|
21
|
+
storageUrl: string;
|
|
22
|
+
thumbnailUrl?: string;
|
|
23
|
+
status: "completed" | "failed";
|
|
24
|
+
artifactType: ArtifactType;
|
|
25
|
+
generatorName: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface UploadHook {
|
|
29
|
+
upload: (request: UploadRequest) => Promise<UploadResult>;
|
|
30
|
+
isUploading: boolean;
|
|
31
|
+
progress: number; // 0-100
|
|
32
|
+
error: Error | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function useUpload(): UploadHook {
|
|
36
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
37
|
+
const [progress, setProgress] = useState(0);
|
|
38
|
+
const [error, setError] = useState<Error | null>(null);
|
|
39
|
+
|
|
40
|
+
const { apiUrl } = useApiConfig();
|
|
41
|
+
const auth = useAuth();
|
|
42
|
+
|
|
43
|
+
const [, uploadFromUrlMutation] = useMutation(UPLOAD_ARTIFACT_FROM_URL);
|
|
44
|
+
|
|
45
|
+
const upload = useCallback(
|
|
46
|
+
async (request: UploadRequest): Promise<UploadResult> => {
|
|
47
|
+
setError(null);
|
|
48
|
+
setProgress(0);
|
|
49
|
+
setIsUploading(true);
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// Handle URL upload via GraphQL
|
|
53
|
+
if (typeof request.source === "string") {
|
|
54
|
+
const result = await uploadFromUrlMutation({
|
|
55
|
+
input: {
|
|
56
|
+
boardId: request.boardId,
|
|
57
|
+
artifactType: request.artifactType,
|
|
58
|
+
fileUrl: request.source,
|
|
59
|
+
userDescription: request.userDescription,
|
|
60
|
+
parentGenerationId: request.parentGenerationId,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (result.error) {
|
|
65
|
+
throw new Error(result.error.message);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!result.data?.uploadArtifact) {
|
|
69
|
+
throw new Error("Upload failed");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setProgress(100);
|
|
73
|
+
setIsUploading(false);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
id: result.data.uploadArtifact.id,
|
|
77
|
+
storageUrl: result.data.uploadArtifact.storageUrl,
|
|
78
|
+
thumbnailUrl: result.data.uploadArtifact.thumbnailUrl,
|
|
79
|
+
status: "completed",
|
|
80
|
+
artifactType: result.data.uploadArtifact.artifactType,
|
|
81
|
+
generatorName: result.data.uploadArtifact.generatorName,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Handle file upload via REST API
|
|
86
|
+
const formData = new FormData();
|
|
87
|
+
formData.append("board_id", request.boardId);
|
|
88
|
+
formData.append("artifact_type", request.artifactType.toLowerCase());
|
|
89
|
+
formData.append("file", request.source);
|
|
90
|
+
if (request.userDescription) {
|
|
91
|
+
formData.append("user_description", request.userDescription);
|
|
92
|
+
}
|
|
93
|
+
if (request.parentGenerationId) {
|
|
94
|
+
formData.append("parent_generation_id", request.parentGenerationId);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const token = await auth.getToken();
|
|
98
|
+
const headers: Record<string, string> = {};
|
|
99
|
+
if (token) {
|
|
100
|
+
headers.Authorization = `Bearer ${token}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Use XMLHttpRequest for progress tracking
|
|
104
|
+
const result = await new Promise<UploadResult>((resolve, reject) => {
|
|
105
|
+
const xhr = new XMLHttpRequest();
|
|
106
|
+
|
|
107
|
+
xhr.upload.addEventListener("progress", (e) => {
|
|
108
|
+
if (e.lengthComputable) {
|
|
109
|
+
const percentComplete = (e.loaded / e.total) * 100;
|
|
110
|
+
setProgress(percentComplete);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
xhr.addEventListener("load", () => {
|
|
115
|
+
if (xhr.status === 200) {
|
|
116
|
+
try {
|
|
117
|
+
const data = JSON.parse(xhr.responseText);
|
|
118
|
+
resolve({
|
|
119
|
+
id: data.id,
|
|
120
|
+
storageUrl: data.storageUrl,
|
|
121
|
+
thumbnailUrl: data.thumbnailUrl,
|
|
122
|
+
status: "completed",
|
|
123
|
+
artifactType: data.artifactType as ArtifactType,
|
|
124
|
+
generatorName: data.generatorName,
|
|
125
|
+
});
|
|
126
|
+
} catch (err) {
|
|
127
|
+
reject(new Error("Failed to parse response"));
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
try {
|
|
131
|
+
const errorData = JSON.parse(xhr.responseText);
|
|
132
|
+
reject(new Error(errorData.detail || `Upload failed: ${xhr.statusText}`));
|
|
133
|
+
} catch {
|
|
134
|
+
reject(new Error(`Upload failed: ${xhr.statusText}`));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
xhr.addEventListener("error", () => {
|
|
140
|
+
reject(new Error("Upload failed: Network error"));
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
xhr.addEventListener("abort", () => {
|
|
144
|
+
reject(new Error("Upload cancelled"));
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
xhr.open("POST", `${apiUrl}/api/uploads/artifact`);
|
|
148
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
149
|
+
xhr.setRequestHeader(key, value);
|
|
150
|
+
});
|
|
151
|
+
xhr.send(formData);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
setProgress(100);
|
|
155
|
+
setIsUploading(false);
|
|
156
|
+
return result;
|
|
157
|
+
} catch (err) {
|
|
158
|
+
const uploadError =
|
|
159
|
+
err instanceof Error ? err : new Error("Upload failed");
|
|
160
|
+
setError(uploadError);
|
|
161
|
+
setIsUploading(false);
|
|
162
|
+
setProgress(0);
|
|
163
|
+
throw uploadError;
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
[uploadFromUrlMutation, apiUrl, auth]
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
upload,
|
|
171
|
+
isUploading,
|
|
172
|
+
progress,
|
|
173
|
+
error,
|
|
174
|
+
};
|
|
175
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,8 +12,16 @@ export { useApiConfig } from "./config/ApiConfigContext";
|
|
|
12
12
|
export type { ApiConfig } from "./config/ApiConfigContext";
|
|
13
13
|
|
|
14
14
|
// Generator selection context
|
|
15
|
-
export {
|
|
16
|
-
|
|
15
|
+
export {
|
|
16
|
+
GeneratorSelectionProvider,
|
|
17
|
+
useGeneratorSelection,
|
|
18
|
+
} from "./config/GeneratorSelectionContext";
|
|
19
|
+
export type {
|
|
20
|
+
GeneratorInfo,
|
|
21
|
+
GeneratorSelectionContextValue,
|
|
22
|
+
ArtifactSlotInfo,
|
|
23
|
+
Artifact,
|
|
24
|
+
} from "./config/GeneratorSelectionContext";
|
|
17
25
|
|
|
18
26
|
// GraphQL exports
|
|
19
27
|
export { createGraphQLClient } from "./graphql/client";
|
|
@@ -24,7 +32,24 @@ export { useBoards } from "./hooks/useBoards";
|
|
|
24
32
|
export { useBoard } from "./hooks/useBoard";
|
|
25
33
|
export { useGeneration } from "./hooks/useGeneration";
|
|
26
34
|
export { useGenerators } from "./hooks/useGenerators";
|
|
35
|
+
export { useUpload } from "./hooks/useUpload";
|
|
27
36
|
export type { Generator, JSONSchema7 } from "./hooks/useGenerators";
|
|
37
|
+
export {
|
|
38
|
+
useAncestry,
|
|
39
|
+
useDescendants,
|
|
40
|
+
useInputArtifacts,
|
|
41
|
+
useLineage,
|
|
42
|
+
} from "./hooks/useLineage";
|
|
43
|
+
export type {
|
|
44
|
+
ArtifactLineage,
|
|
45
|
+
AncestryNode,
|
|
46
|
+
DescendantNode,
|
|
47
|
+
} from "./hooks/useLineage";
|
|
48
|
+
export type {
|
|
49
|
+
UploadRequest,
|
|
50
|
+
UploadResult,
|
|
51
|
+
UploadHook,
|
|
52
|
+
} from "./hooks/useUpload";
|
|
28
53
|
|
|
29
54
|
// Generator schema utilities
|
|
30
55
|
export * from "./types/generatorSchema";
|