@@ -606,6 +718,17 @@ export default function DataUploadPage() {
{file.kind}
)}
+ {(file.attachmentCount ?? 0) > 0 && (
+
+
+ {file.attachmentCount} attached
+
+ )}
+ {file.experimentTypeId && (
+
+ exp: {file.experimentTypeId}
+
+ )}
{file.status === "uploading" && (
@@ -648,10 +771,40 @@ export default function DataUploadPage() {
)}
- {file.id && file.status === "success" && (
+ {file.id &&
+ file.equipmentId !== "etcher" &&
+ file.kind !== "input" &&
+ file.name.toLowerCase().endsWith(".csv") &&
+ (file.status === "success" || file.status === "failed" || file.status === "processed") && (
+
3. Processing
- Processing runs in the background and the status updates here automatically — no need to reload. Input and output CSV files are merged by lot name and run date. Excel files are stored for provenance but are not ingested automatically.
+ Processing runs in the background and the status updates here automatically — no need to reload. Input and output CSV files are merged by lot name and run date. Excel files are stored for provenance but are not ingested automatically. For outputs registered with type "file" (for example an XRD pattern), put each file's path in the CSV cell, attach the files (or one .zip, up to 64 MB) before processing, and they are stored with their runs.
{uploadCapabilities.db3_upload.enabled && " The temporary DB3 pilot creates one catalog row per physical GLANCE run and stores every timestamped sample as its linked trace."}
diff --git a/web/app/equipment/register/page.tsx b/web/app/equipment/register/page.tsx
index 01477b9..84f93e6 100644
--- a/web/app/equipment/register/page.tsx
+++ b/web/app/equipment/register/page.tsx
@@ -186,6 +186,9 @@ const PARAMETER_TYPE_OPTIONS = [
"boolean",
"array",
"map",
+ // A platform-issued sample ID (IGSN syntax). As an output the platform issues
+ // it; as an input it must name a sample an earlier process produced.
+ "sample_id",
];
const OUTPUT_TYPE_OPTIONS = [...PARAMETER_TYPE_OPTIONS, "file"];
diff --git a/web/lib/api-client.ts b/web/lib/api-client.ts
index b7e309b..4f7d9f1 100644
--- a/web/lib/api-client.ts
+++ b/web/lib/api-client.ts
@@ -133,6 +133,22 @@ export interface V2Project {
optimization_iterations: number;
}
+/** A file output (e.g. an XRD pattern) stored with a generic equipment run. */
+export interface V2RunStoredFile {
+ id: number;
+ output_name: string;
+ filename: string;
+ content_type: string;
+ size_bytes: number;
+ sha256: string;
+ source_path: string;
+ created_at: string | null;
+}
+
+export function runFileDownloadUrl(runId: number, fileId: number) {
+ return `${API_URL}/dataset/v2/runs/${encodeURIComponent(String(runId))}/files/${encodeURIComponent(String(fileId))}`;
+}
+
export interface V2RunFileRef {
id: string;
run_id: number;
@@ -172,6 +188,15 @@ export interface V2Run {
pi_name: string | null;
project_access: V2Project["access"] | null;
file_refs: V2RunFileRef[];
+ /** Experiment (experiment_types.id) the run was uploaded into; "" if none. */
+ experiment_type_id?: string;
+ file_count?: number;
+ /** Stored file outputs; returned by the run detail endpoint only. */
+ files?: V2RunStoredFile[];
+ /** Experiment template version the run was captured under. */
+ experiment_type_version?: number | null;
+ /** Samples the run produced (output) or used (input); run detail only. */
+ samples?: { sample_id: string; role: "input" | "output"; field_name: string }[];
source?: string;
upload_filename?: string;
raw_payload?: {
@@ -497,6 +522,7 @@ export interface GetV2RunsOptions {
limit?: number;
offset?: number;
project_id?: string;
+ experiment_type_id?: string;
}
export function getV2Runs(options: GetV2RunsOptions = {}) {
@@ -513,6 +539,9 @@ export function getV2Runs(options: GetV2RunsOptions = {}) {
if (options.project_id) {
params.set("project_id", options.project_id);
}
+ if (options.experiment_type_id) {
+ params.set("experiment_type_id", options.experiment_type_id);
+ }
const query = params.toString();
const path = query ? `/dataset/v2/runs?${query}` : "/dataset/v2/runs";
return apiFetch