diff --git a/apps/i15-1/README.md b/apps/i15-1/README.md index 47fbf49c..5bcbeccc 100644 --- a/apps/i15-1/README.md +++ b/apps/i15-1/README.md @@ -13,6 +13,16 @@ To run this locally: - If you want to test against mocked behaviour run `turbo dev --filter @atlas/i15-1` 1. Navigate to http://localhost:5173/ +## Updating Queue Types + +You can generate types from the queue API automatically using the following command: + +`pnpm --filter i15-1 generate:queue` + +This will generate from main on GitHub, to target a branch, use: + +`npx @hey-api/openapi-ts -i https://raw.githubusercontent.com/DiamondLightSource/daq-queuing-service/{BRANCH_NAME}/docs/reference/rest_api.json -o /workspaces/atlas/apps/i15-1/generated/queue` + ## Updating Supergraph Schema Types 1. Navigate to app containing folder (i.e. `.../atlas/apps/i15-1`) diff --git a/apps/i15-1/generated/queue/core/params.gen.ts b/apps/i15-1/generated/queue/core/params.gen.ts index 0f50047b..5e8908f2 100644 --- a/apps/i15-1/generated/queue/core/params.gen.ts +++ b/apps/i15-1/generated/queue/core/params.gen.ts @@ -88,16 +88,15 @@ function buildKeyMap(fields: FieldsConfig, map?: KeyMap): KeyMap { } interface Params { - body: unknown; + body?: unknown; headers: Record; path: Record; query: Record; } -type ParamsSlotMap = Record; - -function stripEmptySlots(params: ParamsSlotMap): void { +function stripEmptySlots(params: Params): void { for (const [slot, value] of Object.entries(params)) { + if (slot === 'body') continue; if (value && typeof value === 'object' && !Array.isArray(value) && !Object.keys(value).length) { delete params[slot as Slot]; } @@ -105,8 +104,7 @@ function stripEmptySlots(params: ParamsSlotMap): void { } export function buildClientParams(args: ReadonlyArray, fields: FieldsConfig): Params { - const params: ParamsSlotMap = { - body: Object.create(null), + const params: Params = { headers: Object.create(null), path: Object.create(null), query: Object.create(null), @@ -114,6 +112,15 @@ export function buildClientParams(args: ReadonlyArray, fields: FieldsCo const map = buildKeyMap(fields); + function writeSlot(slot: Slot, key: string, value: unknown): void { + let record = params[slot] as Record | undefined; + if (record === undefined) { + record = Object.create(null) as Record; + params[slot] = record; + } + record[key] = value; + } + let config: FieldsConfig[number] | undefined; for (const [index, arg] of args.entries()) { @@ -130,7 +137,7 @@ export function buildClientParams(args: ReadonlyArray, fields: FieldsCo const field = map.get(config.key)!; const name = field.map || config.key; if (field.in) { - (params[field.in] as Record)[name] = arg; + writeSlot(field.in, name, arg); } } else { params.body = arg; @@ -142,7 +149,7 @@ export function buildClientParams(args: ReadonlyArray, fields: FieldsCo if (field) { if (field.in) { const name = field.map || key; - (params[field.in] as Record)[name] = value; + writeSlot(field.in, name, value); } else { params[field.map] = value; } @@ -151,11 +158,11 @@ export function buildClientParams(args: ReadonlyArray, fields: FieldsCo if (extra) { const [prefix, slot] = extra; - (params[slot] as Record)[key.slice(prefix.length)] = value; + writeSlot(slot, key.slice(prefix.length), value); } else if ('allowExtra' in config && config.allowExtra) { for (const [slot, allowed] of Object.entries(config.allowExtra)) { if (allowed) { - (params[slot as Slot] as Record)[key] = value; + writeSlot(slot as Slot, key, value); break; } } @@ -167,5 +174,5 @@ export function buildClientParams(args: ReadonlyArray, fields: FieldsCo stripEmptySlots(params); - return params as Params; + return params; } diff --git a/apps/i15-1/generated/queue/index.ts b/apps/i15-1/generated/queue/index.ts index e8cfe614..7e8658bc 100644 --- a/apps/i15-1/generated/queue/index.ts +++ b/apps/i15-1/generated/queue/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts export { addTasksToQueueQueuePost, cancelTasksQueueTasksDelete, clearHistoryHistoryDelete, getAllTasksTasksGet, getCallHistoryCallHistoryGet, getCallQueueCallQueueGet, getCompletedTasksHistoryGet, getConfigConfigGet, getQueuedTasksQueueGet, getQueueStateQueueStateGet, getTaskByIdTasksTaskIdGet, getTaskByPositionQueuePositionGet, healthzHealthzGet, moveTaskQueueMovePost, type Options, readRootGet, streamEventsEventsGet, updateQueueStateQueueStatePatch } from './sdk.gen'; -export type { AddTasksToQueueQueuePostData, AddTasksToQueueQueuePostError, AddTasksToQueueQueuePostErrors, AddTasksToQueueQueuePostResponse, AddTasksToQueueQueuePostResponses, AppConfig, AppConfigWritable, ApplicationConfig, ApplicationConfigWritable, BasicAuthentication, BlueapiCallResponse, CallStatus, CancelTasksQueueTasksDeleteData, CancelTasksQueueTasksDeleteError, CancelTasksQueueTasksDeleteErrors, CancelTasksQueueTasksDeleteResponse, CancelTasksQueueTasksDeleteResponses, ClearHistoryHistoryDeleteData, ClearHistoryHistoryDeleteResponses, ClientOptions, CorsConfig, DeviceManagerSource, DeviceSource, DodalSource, EnvironmentConfig, ExperimentDefinition, GetAllTasksTasksGetData, GetAllTasksTasksGetError, GetAllTasksTasksGetErrors, GetAllTasksTasksGetResponse, GetAllTasksTasksGetResponses, GetCallHistoryCallHistoryGetData, GetCallHistoryCallHistoryGetResponse, GetCallHistoryCallHistoryGetResponses, GetCallQueueCallQueueGetData, GetCallQueueCallQueueGetResponse, GetCallQueueCallQueueGetResponses, GetCompletedTasksHistoryGetData, GetCompletedTasksHistoryGetError, GetCompletedTasksHistoryGetErrors, GetCompletedTasksHistoryGetResponse, GetCompletedTasksHistoryGetResponses, GetConfigConfigGetData, GetConfigConfigGetResponse, GetConfigConfigGetResponses, GetQueuedTasksQueueGetData, GetQueuedTasksQueueGetError, GetQueuedTasksQueueGetErrors, GetQueuedTasksQueueGetResponse, GetQueuedTasksQueueGetResponses, GetQueueStateQueueStateGetData, GetQueueStateQueueStateGetResponse, GetQueueStateQueueStateGetResponses, GetTaskByIdTasksTaskIdGetData, GetTaskByIdTasksTaskIdGetError, GetTaskByIdTasksTaskIdGetErrors, GetTaskByIdTasksTaskIdGetResponse, GetTaskByIdTasksTaskIdGetResponses, GetTaskByPositionQueuePositionGetData, GetTaskByPositionQueuePositionGetError, GetTaskByPositionQueuePositionGetErrors, GetTaskByPositionQueuePositionGetResponse, GetTaskByPositionQueuePositionGetResponses, GraylogConfig, HealthzHealthzGetData, HealthzHealthzGetResponses, HttpValidationError, LoggingConfig, MetadataConfig, MoveTaskQueueMovePostData, MoveTaskQueueMovePostError, MoveTaskQueueMovePostErrors, MoveTaskQueueMovePostResponse, MoveTaskQueueMovePostResponses, NumtrackerConfig, OidcConfig, PlanSource, QueueState, QueueStateUpdate, ReadRootGetData, ReadRootGetResponses, RestConfig, ScratchConfig, ScratchRepository, ServiceAccount, ServiceAccountWritable, Status, StompConfig, StreamEventsEventsGetData, StreamEventsEventsGetResponses, TaskCancelRequest, TaskError, TaskRequest, TaskResult, TaskWithPosition, TiledConfig, TiledConfigWritable, UpdateQueueStateQueueStatePatchData, UpdateQueueStateQueueStatePatchError, UpdateQueueStateQueueStatePatchErrors, UpdateQueueStateQueueStatePatchResponse, UpdateQueueStateQueueStatePatchResponses, ValidationError, WorkerEventConfig } from './types.gen'; +export type { AddTasksToQueueQueuePostData, AddTasksToQueueQueuePostError, AddTasksToQueueQueuePostErrors, AddTasksToQueueQueuePostResponse, AddTasksToQueueQueuePostResponses, AppConfig, AppConfigWritable, ApplicationConfig, ApplicationConfigWritable, BasicAuthentication, BlueapiCallResponse, CallStatus, CancelTasksQueueTasksDeleteData, CancelTasksQueueTasksDeleteError, CancelTasksQueueTasksDeleteErrors, CancelTasksQueueTasksDeleteResponse, CancelTasksQueueTasksDeleteResponses, ClearHistoryHistoryDeleteData, ClearHistoryHistoryDeleteResponses, ClientOptions, ConverterConfig, CorsConfig, DeviceManagerSource, DeviceSource, DodalSource, EnvironmentConfig, Experiment, ExperimentDefinition, GetAllTasksTasksGetData, GetAllTasksTasksGetError, GetAllTasksTasksGetErrors, GetAllTasksTasksGetResponse, GetAllTasksTasksGetResponses, GetCallHistoryCallHistoryGetData, GetCallHistoryCallHistoryGetResponse, GetCallHistoryCallHistoryGetResponses, GetCallQueueCallQueueGetData, GetCallQueueCallQueueGetResponse, GetCallQueueCallQueueGetResponses, GetCompletedTasksHistoryGetData, GetCompletedTasksHistoryGetError, GetCompletedTasksHistoryGetErrors, GetCompletedTasksHistoryGetResponse, GetCompletedTasksHistoryGetResponses, GetConfigConfigGetData, GetConfigConfigGetResponse, GetConfigConfigGetResponses, GetQueuedTasksQueueGetData, GetQueuedTasksQueueGetError, GetQueuedTasksQueueGetErrors, GetQueuedTasksQueueGetResponse, GetQueuedTasksQueueGetResponses, GetQueueStateQueueStateGetData, GetQueueStateQueueStateGetResponse, GetQueueStateQueueStateGetResponses, GetTaskByIdTasksTaskIdGetData, GetTaskByIdTasksTaskIdGetError, GetTaskByIdTasksTaskIdGetErrors, GetTaskByIdTasksTaskIdGetResponse, GetTaskByIdTasksTaskIdGetResponses, GetTaskByPositionQueuePositionGetData, GetTaskByPositionQueuePositionGetError, GetTaskByPositionQueuePositionGetErrors, GetTaskByPositionQueuePositionGetResponse, GetTaskByPositionQueuePositionGetResponses, GraylogConfig, HealthzHealthzGetData, HealthzHealthzGetResponses, HttpValidationError, LoggingConfig, MetadataConfig, MoveTaskQueueMovePostData, MoveTaskQueueMovePostError, MoveTaskQueueMovePostErrors, MoveTaskQueueMovePostResponse, MoveTaskQueueMovePostResponses, NumtrackerConfig, OidcConfig, PlanSource, QueueState, QueueStateUpdate, ReadRootGetData, ReadRootGetResponses, RestConfig, Sample, ScratchConfig, ScratchRepository, ServiceAccount, ServiceAccountWritable, Status, StompConfig, StreamEventsEventsGetData, StreamEventsEventsGetResponses, TaskCancelRequest, TaskError, TaskKind, TaskRequest, TaskResult, TaskWithPosition, TiledConfig, TiledConfigWritable, UpdateQueueStateQueueStatePatchData, UpdateQueueStateQueueStatePatchError, UpdateQueueStateQueueStatePatchErrors, UpdateQueueStateQueueStatePatchResponse, UpdateQueueStateQueueStatePatchResponses, ValidationError, WorkerEventConfig } from './types.gen'; diff --git a/apps/i15-1/generated/queue/types.gen.ts b/apps/i15-1/generated/queue/types.gen.ts index 8b786729..aba29e61 100644 --- a/apps/i15-1/generated/queue/types.gen.ts +++ b/apps/i15-1/generated/queue/types.gen.ts @@ -1,18 +1,15 @@ // This file is auto-generated by @hey-api/openapi-ts export type ClientOptions = { - baseUrl: 'https://raw.githubusercontent.com' | (string & {}); + baseUrl: "https://raw.githubusercontent.com" | (string & {}); }; /** * AppConfig */ export type AppConfig = { - blueapi: ApplicationConfig; - /** - * Blueapi Call Constructor - */ - blueapi_call_constructor: string; + blueapi: ApplicationConfig; + converter: ConverterConfig; }; /** @@ -22,18 +19,18 @@ export type AppConfig = { * config tree. */ export type ApplicationConfig = { - stomp?: StompConfig; - tiled?: TiledConfig; - env?: EnvironmentConfig; - logging?: LoggingConfig; - api?: RestConfig; - scratch?: ScratchConfig | null; - oidc?: OidcConfig | null; - /** - * Auth Token Path - */ - auth_token_path?: string | null; - numtracker?: NumtrackerConfig | null; + stomp?: StompConfig; + tiled?: TiledConfig; + env?: EnvironmentConfig; + logging?: LoggingConfig; + api?: RestConfig; + scratch?: ScratchConfig | null; + oidc?: OidcConfig | null; + /** + * Auth Token Path + */ + auth_token_path?: string | null; + numtracker?: NumtrackerConfig | null; }; /** @@ -42,140 +39,160 @@ export type ApplicationConfig = { * User credentials for basic authentication */ export type BasicAuthentication = { - /** - * Username - * - * Unique identifier for user - */ - username: string; - /** - * Password - * - * Password to verify user's identity - */ - password: string; + /** + * Username + * + * Unique identifier for user + */ + username: string; + /** + * Password + * + * Password to verify user's identity + */ + password: string; }; /** * BlueapiCallResponse */ export type BlueapiCallResponse = { - task_request: TaskRequest; - /** - * Parent Task Id - */ - parent_task_id: string | null; - status: CallStatus; - /** - * Time Started - */ - time_started: string | null; - /** - * Time Completed - */ - time_completed: string | null; - result: TaskResult | null; - /** - * Errors - */ - errors: Array; - /** - * Blueapi Id - */ - blueapi_id: string | null; + task_request: TaskRequest; + /** + * Parent Task Id + */ + parent_task_id: string | null; + status: CallStatus; + /** + * Time Started + */ + time_started: string | null; + /** + * Time Completed + */ + time_completed: string | null; + result: TaskResult | null; + /** + * Errors + */ + errors: Array; + /** + * Blueapi Id + */ + blueapi_id: string | null; }; /** * CORSConfig */ export type CorsConfig = { - /** - * Origins - */ - origins: Array; - /** - * Allow Credentials - */ - allow_credentials?: boolean; - /** - * Allow Methods - */ - allow_methods?: Array; - /** - * Allow Headers - */ - allow_headers?: Array; + /** + * Origins + */ + origins: Array; + /** + * Allow Credentials + */ + allow_credentials?: boolean; + /** + * Allow Methods + */ + allow_methods?: Array; + /** + * Allow Headers + */ + allow_headers?: Array; }; /** * CallStatus */ -export type CallStatus = 'Waiting' | 'Claimed' | 'In progress' | 'Success' | 'Error'; +export type CallStatus = + | "Waiting" + | "Claimed" + | "In progress" + | "Success" + | "Error" + | "Skipped"; + +/** + * ConverterConfig + */ +export type ConverterConfig = { + /** + * Path + */ + path: string; + /** + * Name + */ + name: string; +}; /** * DeviceManagerSource */ export type DeviceManagerSource = { - /** - * Module - * - * Module to be imported - */ - module: string; - /** - * Kind - */ - kind?: 'deviceManager'; - /** - * Mock - * - * If true, ophyd_async device connections are mocked - */ - mock?: boolean; - /** - * Name - * - * Name of the device manager in the module - */ - name?: string; + /** + * Module + * + * Module to be imported + */ + module: string; + /** + * Kind + */ + kind?: "deviceManager"; + /** + * Mock + * + * If true, ophyd_async device connections are mocked + */ + mock?: boolean; + /** + * Name + * + * Name of the device manager in the module + */ + name?: string; }; /** * DeviceSource */ export type DeviceSource = { - /** - * Module - * - * Module to be imported - */ - module: string; - /** - * Kind - */ - kind?: 'deviceFunctions'; + /** + * Module + * + * Module to be imported + */ + module: string; + /** + * Kind + */ + kind?: "deviceFunctions"; }; /** * DodalSource */ export type DodalSource = { - /** - * Module - * - * Module to be imported - */ - module: string; - /** - * Kind - */ - kind?: 'dodal'; - /** - * Mock - * - * If true, ophyd_async device connections are mocked - */ - mock?: boolean; + /** + * Module + * + * Module to be imported + */ + module: string; + /** + * Kind + */ + kind?: "dodal"; + /** + * Mock + * + * If true, ophyd_async device connections are mocked + */ + mock?: boolean; }; /** @@ -184,252 +201,281 @@ export type DodalSource = { * Config for the RunEngine environment */ export type EnvironmentConfig = { - /** - * Sources - */ - sources?: Array<({ - kind: 'planFunctions'; - } & PlanSource) | ({ - kind: 'deviceFunctions'; - } & DeviceSource) | ({ - kind: 'dodal'; - } & DodalSource) | ({ - kind: 'deviceManager'; - } & DeviceManagerSource)>; - events?: WorkerEventConfig; - metadata?: MetadataConfig | null; + /** + * Sources + */ + sources?: Array< + PlanSource | DeviceSource | DodalSource | DeviceManagerSource + >; + events?: WorkerEventConfig; + metadata?: MetadataConfig | null; +}; + +/** + * Experiment + */ +export type Experiment = { + /** + * Name + */ + name: string; + /** + * Instrument Session + */ + instrument_session: string; + sample: Sample; + experiment_definition: ExperimentDefinition; }; /** * ExperimentDefinition */ export type ExperimentDefinition = { - /** - * Plan Name - */ - plan_name: string; - /** - * Sample Id - */ - sample_id: string; - /** - * Params - * - * Values for parameters to plan, if any - */ - params?: { - [key: string]: unknown; - }; - /** - * Instrument Session - */ - instrument_session: string; + /** + * Name + */ + name: string; + /** + * Id + */ + id: string; + /** + * Data + */ + data: { + [key: string]: unknown; + }; }; /** * GraylogConfig */ export type GraylogConfig = { - /** - * Enabled - */ - enabled?: boolean; - /** - * Url - */ - url?: string; + /** + * Enabled + */ + enabled?: boolean; + /** + * Url + */ + url?: string; }; /** * HTTPValidationError */ export type HttpValidationError = { - /** - * Detail - */ - detail?: Array; + /** + * Detail + */ + detail?: Array; }; /** * LoggingConfig */ export type LoggingConfig = { - /** - * Level - */ - level?: 'NOTSET' | 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL'; - graylog?: GraylogConfig; + /** + * Level + */ + level?: "NOTSET" | "DEBUG" | "INFO" | "WARNING" | "ERROR" | "CRITICAL"; + graylog?: GraylogConfig; }; /** * MetadataConfig */ export type MetadataConfig = { - /** - * Instrument - */ - instrument: string; + /** + * Instrument + */ + instrument: string; }; /** * NumtrackerConfig */ export type NumtrackerConfig = { - /** - * Url - */ - url?: string; - /** - * Detector File Template - */ - detector_file_template?: string; + /** + * Url + */ + url?: string; + /** + * Detector File Template + */ + detector_file_template?: string; }; /** * OIDCConfig */ export type OidcConfig = { - /** - * Well Known Url - * - * URL to fetch OIDC config from the provider - */ - well_known_url: string; - /** - * Client Id - * - * Client ID - */ - client_id: string; - /** - * Client Audience - * - * Client Audience(s) - */ - client_audience?: string; - /** - * Logout Redirect Endpoint - * - * The oidc endpoint required to logout - */ - logout_redirect_endpoint?: string; + /** + * Well Known Url + * + * URL to fetch OIDC config from the provider + */ + well_known_url: string; + /** + * Client Id + * + * Client ID + */ + client_id: string; + /** + * Client Audience + * + * Client Audience(s) + */ + client_audience?: string; + /** + * Logout Redirect Endpoint + * + * The oidc endpoint required to logout + */ + logout_redirect_endpoint?: string; }; /** * PlanSource */ export type PlanSource = { - /** - * Module - * - * Module to be imported - */ - module: string; - /** - * Kind - */ - kind?: 'planFunctions'; + /** + * Module + * + * Module to be imported + */ + module: string; + /** + * Kind + */ + kind?: "planFunctions"; }; /** * QueueState */ export type QueueState = { - /** - * Paused - */ - paused: boolean; + /** + * Paused + */ + paused: boolean; }; /** * QueueStateUpdate */ export type QueueStateUpdate = { - /** - * Paused - */ - paused?: boolean | null; + /** + * Paused + */ + paused?: boolean | null; }; /** * RestConfig */ export type RestConfig = { - /** - * Url - */ - url?: string; - cors?: CorsConfig | null; + /** + * Url + */ + url?: string; + cors?: CorsConfig | null; +}; + +/** + * Sample + */ +export type Sample = { + /** + * Name + */ + name: string; + /** + * Id + */ + id: string; + /** + * Data + */ + data: { + [key: string]: unknown; + }; }; /** * ScratchConfig */ export type ScratchConfig = { - /** - * Root - * - * The root directory of the scratch area, all repositories will be cloned under this directory. - */ - root?: string; - /** - * Required Gid - * - * - * Required owner GID for the scratch directory. If supplied, the setup-scratch - * command will check the scratch area ownership and raise an error if it is - * not owned by , or if it does not have SGID permission bit set. - * - */ - required_gid?: number | null; - /** - * Repositories - * - * Details of repositories to be cloned and imported into blueapi - */ - repositories?: Array; + /** + * Root + * + * The root directory of the scratch area, all repositories will be cloned under this directory. + */ + root?: string; + /** + * Required Gid + * + * + * Required owner GID for the scratch directory. If supplied, the setup-scratch + * command will check the scratch area ownership and raise an error if it is + * not owned by , or if it does not have SGID permission bit set. + * + */ + required_gid?: number | null; + /** + * Repositories + * + * Details of repositories to be cloned and imported into blueapi + */ + repositories?: Array; }; /** * ScratchRepository */ export type ScratchRepository = { - /** - * Name - * - * Unique name for this repository in the scratch directory - */ - name?: string; - /** - * Remote Url - * - * URL to clone from - */ - remote_url?: string; - /** - * Target Revision - * - * Revision (branch or tag) to check out when cloning - defaults to remote's HEAD. If a tag is used, the repo will be left in a 'detached head' state. - */ - target_revision?: string; + /** + * Name + * + * Unique name for this repository in the scratch directory + */ + name?: string; + /** + * Remote Url + * + * URL to clone from + */ + remote_url?: string; + /** + * Target Revision + * + * Revision (branch or tag) to check out when cloning - defaults to remote's HEAD. If a tag is used, the repo will be left in a 'detached head' state. + */ + target_revision?: string; }; /** * ServiceAccount */ export type ServiceAccount = { - /** - * Client Id - * - * Service account client ID - */ - client_id?: string; + /** + * Client Id + * + * Service account client ID + */ + client_id?: string; }; /** * Status */ -export type Status = 'Queued' | 'In progress' | 'Complete' | 'Cancelled'; +export type Status = + | "Queued" + | "In progress" + | "Complete" + | "Error" + | "Cancelled"; /** * StompConfig @@ -437,30 +483,30 @@ export type Status = 'Queued' | 'In progress' | 'Complete' | 'Cancelled'; * Config for connecting to stomp broker */ export type StompConfig = { - /** - * Enabled - * - * True if blueapi should connect to stomp for asynchronous event publishing - */ - enabled?: boolean; - /** - * Url - */ - url?: string; - /** - * Auth information for communicating with STOMP broker, if required - */ - auth?: BasicAuthentication | null; + /** + * Enabled + * + * True if blueapi should connect to stomp for asynchronous event publishing + */ + enabled?: boolean; + /** + * Url + */ + url?: string; + /** + * Auth information for communicating with STOMP broker, if required + */ + auth?: BasicAuthentication | null; }; /** * TaskCancelRequest */ export type TaskCancelRequest = { - /** - * Task Ids - */ - task_ids: Array; + /** + * Task Ids + */ + task_ids: Array; }; /** @@ -469,46 +515,51 @@ export type TaskCancelRequest = { * Wrapper around an exception raised by a plan */ export type TaskError = { - /** - * Outcome - */ - outcome?: 'error'; - /** - * Type - */ - type: string; - /** - * Message - */ - message: string; + /** + * Outcome + */ + outcome?: "error"; + /** + * Type + */ + type: string; + /** + * Message + */ + message: string; }; +/** + * TaskKind + */ +export type TaskKind = "Experiment" | "Plan"; + /** * TaskRequest * * Request to run a task with related info */ export type TaskRequest = { - /** - * Name - * - * Name of plan to run - */ - name: string; - /** - * Params - * - * Values for parameters to plan, if any - */ - params?: { - [key: string]: unknown; - }; - /** - * Instrument Session - * - * Instrument session associated with this task - */ - instrument_session: string; + /** + * Name + * + * Name of plan to run + */ + name: string; + /** + * Params + * + * Values for parameters to plan, if any + */ + params?: { + [key: string]: unknown; + }; + /** + * Instrument Session + * + * Instrument session associated with this task + */ + instrument_session: string; }; /** @@ -521,88 +572,92 @@ export type TaskRequest = { * be 'NoneType'. */ export type TaskResult = { - /** - * Outcome - */ - outcome?: 'success'; - /** - * Result - */ - result?: unknown; - /** - * Type - */ - type: string; + /** + * Outcome + */ + outcome?: "success"; + /** + * Result + */ + result?: unknown; + /** + * Type + */ + type: string; }; /** * TaskWithPosition */ export type TaskWithPosition = { - experiment_definition: ExperimentDefinition; - /** - * Id - */ - id: string; - status: Status; - /** - * Blueapi Calls - */ - blueapi_calls: Array; - /** - * Position - */ - position: number | null; + /** + * Experiment + */ + experiment: Experiment | TaskRequest; + /** + * Id + */ + id: string; + status: Status; + /** + * Blueapi Calls + */ + blueapi_calls: Array; + /** + * Position + */ + position: number | null; + kind: TaskKind; }; /** * TiledConfig */ export type TiledConfig = { - /** - * Enabled - * - * True if blueapi should forward data to a Tiled instance - */ - enabled?: boolean; - /** - * Url - */ - url?: string; - /** - * Authentication - * - * Tiled Authentication can be API_KEY or OIDC Service account - */ - authentication?: string | ServiceAccount | null; + /** + * Enabled + * + * True if blueapi should forward data to a Tiled instance + */ + enabled?: boolean; + /** + * Url + */ + url?: string; + /** + * Authentication + * + * Tiled Authentication can be API_KEY or OIDC Service account + */ + authentication?: string | ServiceAccount | null; }; /** * ValidationError */ export type ValidationError = { - /** - * Location - */ - loc: Array; - /** - * Message - */ - msg: string; - /** - * Error Type - */ - type: string; - /** - * Input - */ - input?: unknown; - /** - * Context - */ - ctx?: { - [key: string]: unknown; - }; + /** + * Location + */ + loc: Array; + /** + * Message + */ + msg: string; + /** + * Error Type + */ + type: string; + /** + * Input + */ + input?: unknown; + /** + * Context + */ + ctx?: { + [key: string]: unknown; + }; }; /** @@ -611,21 +666,18 @@ export type ValidationError = { * Config for event broadcasting via the message bus */ export type WorkerEventConfig = { - /** - * Broadcast Status Events - */ - broadcast_status_events?: boolean; + /** + * Broadcast Status Events + */ + broadcast_status_events?: boolean; }; /** * AppConfig */ export type AppConfigWritable = { - blueapi: ApplicationConfigWritable; - /** - * Blueapi Call Constructor - */ - blueapi_call_constructor: string; + blueapi: ApplicationConfigWritable; + converter: ConverterConfig; }; /** @@ -635,461 +687,483 @@ export type AppConfigWritable = { * config tree. */ export type ApplicationConfigWritable = { - stomp?: StompConfig; - tiled?: TiledConfigWritable; - env?: EnvironmentConfig; - logging?: LoggingConfig; - api?: RestConfig; - scratch?: ScratchConfig | null; - oidc?: OidcConfig | null; - /** - * Auth Token Path - */ - auth_token_path?: string | null; - numtracker?: NumtrackerConfig | null; + stomp?: StompConfig; + tiled?: TiledConfigWritable; + env?: EnvironmentConfig; + logging?: LoggingConfig; + api?: RestConfig; + scratch?: ScratchConfig | null; + oidc?: OidcConfig | null; + /** + * Auth Token Path + */ + auth_token_path?: string | null; + numtracker?: NumtrackerConfig | null; }; /** * ServiceAccount */ export type ServiceAccountWritable = { - /** - * Client Id - * - * Service account client ID - */ - client_id?: string; - /** - * Client Secret - * - * Service account client secret - */ - client_secret?: string; + /** + * Client Id + * + * Service account client ID + */ + client_id?: string; + /** + * Client Secret + * + * Service account client secret + */ + client_secret?: string; }; /** * TiledConfig */ export type TiledConfigWritable = { - /** - * Enabled - * - * True if blueapi should forward data to a Tiled instance - */ - enabled?: boolean; - /** - * Url - */ - url?: string; - /** - * Authentication - * - * Tiled Authentication can be API_KEY or OIDC Service account - */ - authentication?: string | ServiceAccountWritable | null; + /** + * Enabled + * + * True if blueapi should forward data to a Tiled instance + */ + enabled?: boolean; + /** + * Url + */ + url?: string; + /** + * Authentication + * + * Tiled Authentication can be API_KEY or OIDC Service account + */ + authentication?: string | ServiceAccountWritable | null; }; export type HealthzHealthzGetData = { - body?: never; - path?: never; - query?: never; - url: '/healthz'; + body?: never; + path?: never; + query?: never; + url: "/healthz"; }; export type HealthzHealthzGetResponses = { - /** - * Successful Response - */ - 200: unknown; + /** + * Successful Response + */ + 200: unknown; }; export type ReadRootGetData = { - body?: never; - path?: never; - query?: never; - url: '/'; + body?: never; + path?: never; + query?: never; + url: "/"; }; export type ReadRootGetResponses = { - /** - * Successful Response - */ - 200: unknown; + /** + * Successful Response + */ + 200: unknown; }; export type GetConfigConfigGetData = { - body?: never; - path?: never; - query?: never; - url: '/config'; + body?: never; + path?: never; + query?: never; + url: "/config"; }; export type GetConfigConfigGetResponses = { - /** - * Successful Response - */ - 200: AppConfig; + /** + * Successful Response + */ + 200: AppConfig; }; -export type GetConfigConfigGetResponse = GetConfigConfigGetResponses[keyof GetConfigConfigGetResponses]; +export type GetConfigConfigGetResponse = + GetConfigConfigGetResponses[keyof GetConfigConfigGetResponses]; export type GetQueueStateQueueStateGetData = { - body?: never; - path?: never; - query?: never; - url: '/queue/state'; + body?: never; + path?: never; + query?: never; + url: "/queue/state"; }; export type GetQueueStateQueueStateGetResponses = { - /** - * Successful Response - */ - 200: QueueState; + /** + * Successful Response + */ + 200: QueueState; }; -export type GetQueueStateQueueStateGetResponse = GetQueueStateQueueStateGetResponses[keyof GetQueueStateQueueStateGetResponses]; +export type GetQueueStateQueueStateGetResponse = + GetQueueStateQueueStateGetResponses[keyof GetQueueStateQueueStateGetResponses]; export type UpdateQueueStateQueueStatePatchData = { - body: QueueStateUpdate; - path?: never; - query?: never; - url: '/queue/state'; + body: QueueStateUpdate; + path?: never; + query?: never; + url: "/queue/state"; }; export type UpdateQueueStateQueueStatePatchErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type UpdateQueueStateQueueStatePatchError = UpdateQueueStateQueueStatePatchErrors[keyof UpdateQueueStateQueueStatePatchErrors]; +export type UpdateQueueStateQueueStatePatchError = + UpdateQueueStateQueueStatePatchErrors[keyof UpdateQueueStateQueueStatePatchErrors]; export type UpdateQueueStateQueueStatePatchResponses = { - /** - * Successful Response - */ - 200: QueueState; + /** + * Successful Response + */ + 200: QueueState; }; -export type UpdateQueueStateQueueStatePatchResponse = UpdateQueueStateQueueStatePatchResponses[keyof UpdateQueueStateQueueStatePatchResponses]; +export type UpdateQueueStateQueueStatePatchResponse = + UpdateQueueStateQueueStatePatchResponses[keyof UpdateQueueStateQueueStatePatchResponses]; export type GetQueuedTasksQueueGetData = { - body?: never; - path?: never; - query?: { - /** - * Status - */ - status?: Status | null; - }; - url: '/queue'; + body?: never; + path?: never; + query?: { + /** + * Status + */ + status?: Status | null; + }; + url: "/queue"; }; export type GetQueuedTasksQueueGetErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type GetQueuedTasksQueueGetError = GetQueuedTasksQueueGetErrors[keyof GetQueuedTasksQueueGetErrors]; +export type GetQueuedTasksQueueGetError = + GetQueuedTasksQueueGetErrors[keyof GetQueuedTasksQueueGetErrors]; export type GetQueuedTasksQueueGetResponses = { - /** - * Response Get Queued Tasks Queue Get - * - * Successful Response - */ - 200: Array; + /** + * Response Get Queued Tasks Queue Get + * + * Successful Response + */ + 200: Array; }; -export type GetQueuedTasksQueueGetResponse = GetQueuedTasksQueueGetResponses[keyof GetQueuedTasksQueueGetResponses]; +export type GetQueuedTasksQueueGetResponse = + GetQueuedTasksQueueGetResponses[keyof GetQueuedTasksQueueGetResponses]; export type AddTasksToQueueQueuePostData = { + /** + * Experiments + */ + body: Array; + path?: never; + query?: { /** - * Experiment Definitions + * Position */ - body: Array; - path?: never; - query?: { - /** - * Position - */ - position?: number | null; - }; - url: '/queue'; + position?: number | null; + }; + url: "/queue"; }; export type AddTasksToQueueQueuePostErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type AddTasksToQueueQueuePostError = AddTasksToQueueQueuePostErrors[keyof AddTasksToQueueQueuePostErrors]; +export type AddTasksToQueueQueuePostError = + AddTasksToQueueQueuePostErrors[keyof AddTasksToQueueQueuePostErrors]; export type AddTasksToQueueQueuePostResponses = { - /** - * Response Add Tasks To Queue Queue Post - * - * Successful Response - */ - 200: Array; + /** + * Response Add Tasks To Queue Queue Post + * + * Successful Response + */ + 200: Array; }; -export type AddTasksToQueueQueuePostResponse = AddTasksToQueueQueuePostResponses[keyof AddTasksToQueueQueuePostResponses]; +export type AddTasksToQueueQueuePostResponse = + AddTasksToQueueQueuePostResponses[keyof AddTasksToQueueQueuePostResponses]; export type MoveTaskQueueMovePostData = { - body?: never; - path?: never; - query: { - /** - * Task Id - */ - task_id: string; - /** - * New Position - */ - new_position: number; - }; - url: '/queue/move'; + body?: never; + path?: never; + query: { + /** + * Task Id + */ + task_id: string; + /** + * New Position + */ + new_position: number; + }; + url: "/queue/move"; }; export type MoveTaskQueueMovePostErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type MoveTaskQueueMovePostError = MoveTaskQueueMovePostErrors[keyof MoveTaskQueueMovePostErrors]; +export type MoveTaskQueueMovePostError = + MoveTaskQueueMovePostErrors[keyof MoveTaskQueueMovePostErrors]; export type MoveTaskQueueMovePostResponses = { - /** - * Response Move Task Queue Move Post - * - * Successful Response - */ - 200: number; + /** + * Response Move Task Queue Move Post + * + * Successful Response + */ + 200: number; }; -export type MoveTaskQueueMovePostResponse = MoveTaskQueueMovePostResponses[keyof MoveTaskQueueMovePostResponses]; +export type MoveTaskQueueMovePostResponse = + MoveTaskQueueMovePostResponses[keyof MoveTaskQueueMovePostResponses]; export type CancelTasksQueueTasksDeleteData = { - body: TaskCancelRequest; - path?: never; - query?: never; - url: '/queue/tasks'; + body: TaskCancelRequest; + path?: never; + query?: never; + url: "/queue/tasks"; }; export type CancelTasksQueueTasksDeleteErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type CancelTasksQueueTasksDeleteError = CancelTasksQueueTasksDeleteErrors[keyof CancelTasksQueueTasksDeleteErrors]; +export type CancelTasksQueueTasksDeleteError = + CancelTasksQueueTasksDeleteErrors[keyof CancelTasksQueueTasksDeleteErrors]; export type CancelTasksQueueTasksDeleteResponses = { - /** - * Response Cancel Tasks Queue Tasks Delete - * - * Successful Response - */ - 200: Array; + /** + * Response Cancel Tasks Queue Tasks Delete + * + * Successful Response + */ + 200: Array; }; -export type CancelTasksQueueTasksDeleteResponse = CancelTasksQueueTasksDeleteResponses[keyof CancelTasksQueueTasksDeleteResponses]; +export type CancelTasksQueueTasksDeleteResponse = + CancelTasksQueueTasksDeleteResponses[keyof CancelTasksQueueTasksDeleteResponses]; export type GetTaskByPositionQueuePositionGetData = { - body?: never; - path: { - /** - * Position - */ - position: number; - }; - query?: never; - url: '/queue/{position}'; + body?: never; + path: { + /** + * Position + */ + position: number; + }; + query?: never; + url: "/queue/{position}"; }; export type GetTaskByPositionQueuePositionGetErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type GetTaskByPositionQueuePositionGetError = GetTaskByPositionQueuePositionGetErrors[keyof GetTaskByPositionQueuePositionGetErrors]; +export type GetTaskByPositionQueuePositionGetError = + GetTaskByPositionQueuePositionGetErrors[keyof GetTaskByPositionQueuePositionGetErrors]; export type GetTaskByPositionQueuePositionGetResponses = { - /** - * Response Get Task By Position Queue Position Get - * - * Successful Response - */ - 200: TaskWithPosition | null; + /** + * Response Get Task By Position Queue Position Get + * + * Successful Response + */ + 200: TaskWithPosition | null; }; -export type GetTaskByPositionQueuePositionGetResponse = GetTaskByPositionQueuePositionGetResponses[keyof GetTaskByPositionQueuePositionGetResponses]; +export type GetTaskByPositionQueuePositionGetResponse = + GetTaskByPositionQueuePositionGetResponses[keyof GetTaskByPositionQueuePositionGetResponses]; export type GetAllTasksTasksGetData = { - body?: never; - path?: never; - query?: { - /** - * Status - */ - status?: Status | null; - }; - url: '/tasks'; + body?: never; + path?: never; + query?: { + /** + * Status + */ + status?: Status | null; + }; + url: "/tasks"; }; export type GetAllTasksTasksGetErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type GetAllTasksTasksGetError = GetAllTasksTasksGetErrors[keyof GetAllTasksTasksGetErrors]; +export type GetAllTasksTasksGetError = + GetAllTasksTasksGetErrors[keyof GetAllTasksTasksGetErrors]; export type GetAllTasksTasksGetResponses = { - /** - * Response Get All Tasks Tasks Get - * - * Successful Response - */ - 200: Array; + /** + * Response Get All Tasks Tasks Get + * + * Successful Response + */ + 200: Array; }; -export type GetAllTasksTasksGetResponse = GetAllTasksTasksGetResponses[keyof GetAllTasksTasksGetResponses]; +export type GetAllTasksTasksGetResponse = + GetAllTasksTasksGetResponses[keyof GetAllTasksTasksGetResponses]; export type GetTaskByIdTasksTaskIdGetData = { - body?: never; - path: { - /** - * Task Id - */ - task_id: string; - }; - query?: never; - url: '/tasks/{task_id}'; + body?: never; + path: { + /** + * Task Id + */ + task_id: string; + }; + query?: never; + url: "/tasks/{task_id}"; }; export type GetTaskByIdTasksTaskIdGetErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type GetTaskByIdTasksTaskIdGetError = GetTaskByIdTasksTaskIdGetErrors[keyof GetTaskByIdTasksTaskIdGetErrors]; +export type GetTaskByIdTasksTaskIdGetError = + GetTaskByIdTasksTaskIdGetErrors[keyof GetTaskByIdTasksTaskIdGetErrors]; export type GetTaskByIdTasksTaskIdGetResponses = { - /** - * Successful Response - */ - 200: TaskWithPosition; + /** + * Successful Response + */ + 200: TaskWithPosition; }; -export type GetTaskByIdTasksTaskIdGetResponse = GetTaskByIdTasksTaskIdGetResponses[keyof GetTaskByIdTasksTaskIdGetResponses]; +export type GetTaskByIdTasksTaskIdGetResponse = + GetTaskByIdTasksTaskIdGetResponses[keyof GetTaskByIdTasksTaskIdGetResponses]; export type ClearHistoryHistoryDeleteData = { - body?: never; - path?: never; - query?: never; - url: '/history'; + body?: never; + path?: never; + query?: never; + url: "/history"; }; export type ClearHistoryHistoryDeleteResponses = { - /** - * Successful Response - */ - 200: unknown; + /** + * Successful Response + */ + 200: unknown; }; export type GetCompletedTasksHistoryGetData = { - body?: never; - path?: never; - query?: { - /** - * Status - */ - status?: Status | null; - }; - url: '/history'; + body?: never; + path?: never; + query?: { + /** + * Status + */ + status?: Status | null; + }; + url: "/history"; }; export type GetCompletedTasksHistoryGetErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; + /** + * Validation Error + */ + 422: HttpValidationError; }; -export type GetCompletedTasksHistoryGetError = GetCompletedTasksHistoryGetErrors[keyof GetCompletedTasksHistoryGetErrors]; +export type GetCompletedTasksHistoryGetError = + GetCompletedTasksHistoryGetErrors[keyof GetCompletedTasksHistoryGetErrors]; export type GetCompletedTasksHistoryGetResponses = { - /** - * Response Get Completed Tasks History Get - * - * Successful Response - */ - 200: Array; + /** + * Response Get Completed Tasks History Get + * + * Successful Response + */ + 200: Array; }; -export type GetCompletedTasksHistoryGetResponse = GetCompletedTasksHistoryGetResponses[keyof GetCompletedTasksHistoryGetResponses]; +export type GetCompletedTasksHistoryGetResponse = + GetCompletedTasksHistoryGetResponses[keyof GetCompletedTasksHistoryGetResponses]; export type GetCallQueueCallQueueGetData = { - body?: never; - path?: never; - query?: never; - url: '/call_queue'; + body?: never; + path?: never; + query?: never; + url: "/call_queue"; }; export type GetCallQueueCallQueueGetResponses = { - /** - * Response Get Call Queue Call Queue Get - * - * Successful Response - */ - 200: Array; + /** + * Response Get Call Queue Call Queue Get + * + * Successful Response + */ + 200: Array; }; -export type GetCallQueueCallQueueGetResponse = GetCallQueueCallQueueGetResponses[keyof GetCallQueueCallQueueGetResponses]; +export type GetCallQueueCallQueueGetResponse = + GetCallQueueCallQueueGetResponses[keyof GetCallQueueCallQueueGetResponses]; export type GetCallHistoryCallHistoryGetData = { - body?: never; - path?: never; - query?: never; - url: '/call_history'; + body?: never; + path?: never; + query?: never; + url: "/call_history"; }; export type GetCallHistoryCallHistoryGetResponses = { - /** - * Response Get Call History Call History Get - * - * Successful Response - */ - 200: Array; + /** + * Response Get Call History Call History Get + * + * Successful Response + */ + 200: Array; }; -export type GetCallHistoryCallHistoryGetResponse = GetCallHistoryCallHistoryGetResponses[keyof GetCallHistoryCallHistoryGetResponses]; +export type GetCallHistoryCallHistoryGetResponse = + GetCallHistoryCallHistoryGetResponses[keyof GetCallHistoryCallHistoryGetResponses]; export type StreamEventsEventsGetData = { - body?: never; - path?: never; - query?: never; - url: '/events'; + body?: never; + path?: never; + query?: never; + url: "/events"; }; export type StreamEventsEventsGetResponses = { - /** - * Successful Response - */ - 200: unknown; + /** + * Successful Response + */ + 200: unknown; }; diff --git a/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentTable.test.tsx b/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentTable.test.tsx index 2b625a81..62054178 100644 --- a/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentTable.test.tsx +++ b/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentTable.test.tsx @@ -18,11 +18,11 @@ vi.mock("../../queue/queueService", async (importOriginal) => { await importOriginal(); return { ...actual, - useSumbitTask: vi.fn(), + useSumbitQueueTask: vi.fn(), }; }); -const mockedUseSubmitTask = queueService.useSumbitTask as unknown as Mock; +const mockedUseSubmitTask = queueService.useSumbitQueueTask as unknown as Mock; const mockedUseQuery = apollo.useQuery as unknown as Mock; afterEach(() => { @@ -190,15 +190,17 @@ describe("ExperimentList", () => { await waitFor(() => { expect(mutateAsync).toHaveBeenCalledTimes(1); expect(mutateAsync).toHaveBeenCalledWith({ - taskPosition: 0, - taskParams: { - experimentName: "Exp 1", - sampleName: "Sample A", - density: 1.2, - composition: "H2O", - beamEnergy: 20, - timePerPDF: 10, - beamSize: 5, + experiment: { + name: "Exp 1", + instrument_session: "", + experiment_definition: { + data: { beam_energy: 20, focused_beam_size: 5, time_per_pdf: 10 }, + name: "Def 1", + }, + sample: { + data: { composition: "H2O", density: 1.2 }, + name: "Sample A", + }, }, }); }); @@ -224,27 +226,31 @@ describe("ExperimentList", () => { await waitFor(() => { expect(mutateAsync).toHaveBeenCalledTimes(2); expect(mutateAsync).toHaveBeenNthCalledWith(1, { - taskPosition: 0, - taskParams: { - experimentName: "Exp 1", - sampleName: "Sample A", - density: 1.2, - composition: "H2O", - beamEnergy: 20, - timePerPDF: 10, - beamSize: 5, + experiment: { + name: "Exp 1", + instrument_session: "", + experiment_definition: { + data: { beam_energy: 20, focused_beam_size: 5, time_per_pdf: 10 }, + name: "Def 1", + }, + sample: { + data: { composition: "H2O", density: 1.2 }, + name: "Sample A", + }, }, }); expect(mutateAsync).toHaveBeenNthCalledWith(2, { - taskPosition: 1, - taskParams: { - experimentName: "Exp 2", - sampleName: "Sample B", - density: 1.2, - composition: "CO2", - beamEnergy: 20, - timePerPDF: 10, - beamSize: 5, + experiment: { + name: "Exp 2", + instrument_session: "", + experiment_definition: { + data: { beam_energy: 20, focused_beam_size: 5, time_per_pdf: 10 }, + name: "Def 2", + }, + sample: { + data: { composition: "CO2", density: 1.2 }, + name: "Sample B", + }, }, }); }); diff --git a/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentsTable.tsx b/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentsTable.tsx index 6e83bce3..45b2ef9c 100644 --- a/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentsTable.tsx +++ b/apps/i15-1/src/components/ExperimentTable/ULIMSExperimentsTable.tsx @@ -9,15 +9,16 @@ import { columns, type ExperimentTableData } from "./columns"; import { useLocation } from "react-router-dom"; import { useMemo } from "react"; import QueueIcon from "@mui/icons-material/Queue"; -import { useSumbitTask } from "../../queue/queueService"; +import { useSumbitQueueTask } from "../../queue/queueService"; import { getSessionPlaylistQuery } from "../../graphql/getSessionPlaylistQuery"; import { type ExperimentNode } from "../../graphql/getSessionPlaylistQueryTyped"; import type { GetSessionPlaylistQueryVariables, GetSessionPlaylistQuery, } from "../../graphql/getSessionPlaylistQuery.generated"; +import type { ExperimentDefinition, Sample } from "../../../generated/queue"; -type ExperimentDefinitionData = { +export type ExperimentDefinitionData = { q_max: number; frames: number; beam_energy: number; @@ -25,7 +26,7 @@ type ExperimentDefinitionData = { focused_beam_size: number; }; -type SampleData = { +export type SampleData = { density: number; capillary: string; composition: string; @@ -35,6 +36,7 @@ type SampleData = { const convertNodeToTableData = ( node: ExperimentNode, ): ExperimentTableData => ({ + experiment: node, experimentName: node.name, sampleName: node.sample.name, density: node.sample.data.density, @@ -51,14 +53,21 @@ const GET_EXPERIMENTS: TypedDocumentNode< export function ExperimentList() { const location = useLocation(); - const { mutateAsync: submitTaskAsync } = useSumbitTask(); + const { mutateAsync: submitTaskAsync } = useSumbitQueueTask(); - async function submitTasks(selected: ExperimentTableData[]) { + async function submitQueueTasks(selected: ExperimentTableData[]) { await Promise.all( - selected.map((exp, index) => + selected.map((exp) => submitTaskAsync({ - taskPosition: index, - taskParams: exp, + experiment: { + name: exp.experiment.name, + experiment_definition: exp.experiment + .experimentDefinition as ExperimentDefinition, + sample: exp.experiment.sample as Sample, + instrument_session: + exp.experiment.sample.instrumentSessions?.[0]?.instrumentSessionReference?.toLowerCase() ?? + "", + }, }), ), ); @@ -118,7 +127,7 @@ export function ExperimentList() { const selected = table .getSelectedRowModel() .rows.map((row) => row.original); - await submitTasks(selected); + await submitQueueTasks(selected); }} > Add selected {selectedCount} to queue @@ -134,7 +143,7 @@ export function ExperimentList() { .getPrePaginationRowModel() .rows.map((row) => row.original); - await submitTasks(allRows); + await submitQueueTasks(allRows); }} > Add all to queue diff --git a/apps/i15-1/src/components/ExperimentTable/columns.tsx b/apps/i15-1/src/components/ExperimentTable/columns.tsx index e3a8089d..2108d679 100644 --- a/apps/i15-1/src/components/ExperimentTable/columns.tsx +++ b/apps/i15-1/src/components/ExperimentTable/columns.tsx @@ -1,6 +1,12 @@ import type { MRT_ColumnDef } from "material-react-table"; +import type { ExperimentNode } from "../../graphql/getSessionPlaylistQueryTyped"; +import type { + ExperimentDefinitionData, + SampleData, +} from "./ULIMSExperimentsTable"; export type ExperimentTableData = { + experiment: ExperimentNode; experimentName: string; sampleName: string; composition: string; diff --git a/apps/i15-1/src/graphql/getSessionPlaylistQuery.generated.ts b/apps/i15-1/src/graphql/getSessionPlaylistQuery.generated.ts index 2c0db079..1c58afe2 100644 --- a/apps/i15-1/src/graphql/getSessionPlaylistQuery.generated.ts +++ b/apps/i15-1/src/graphql/getSessionPlaylistQuery.generated.ts @@ -1,11 +1,44 @@ /** Internal type. DO NOT USE DIRECTLY. */ type Exact = { [K in keyof T]: T[K] }; /** Internal type. DO NOT USE DIRECTLY. */ -export type Incremental = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never }; +export type Incremental = + | T + | { + [P in keyof T]?: P extends " $fragmentName" | "__typename" ? T[P] : never; + }; export type GetSessionPlaylistQueryVariables = Exact<{ proposal: number; session: number; }>; - -export type GetSessionPlaylistQuery = { instrumentSession: { __typename: 'InstrumentSession', experiments: { __typename: 'ExperimentConnection', edges: Array<{ __typename: 'ExperimentEdge', node: { __typename: 'Experiment', name: string, sample: { __typename: 'Sample', name: string, data: unknown }, experimentDefinition: { __typename: 'ExperimentDefinition', name: string, data: unknown } } }> } } | null }; +export type GetSessionPlaylistQuery = { + instrumentSession: { + __typename: "InstrumentSession"; + experiments: { + __typename: "ExperimentConnection"; + edges: Array<{ + __typename: "ExperimentEdge"; + node: { + __typename: "Experiment"; + name: string; + sample: { + __typename: "Sample"; + name: string; + id: unknown; + data: unknown; + instrumentSessions: Array<{ + __typename: "InstrumentSession"; + instrumentSessionReference: string | null; + }>; + }; + experimentDefinition: { + __typename: "ExperimentDefinition"; + name: string; + id: unknown; + data: unknown; + }; + }; + }>; + }; + } | null; +}; diff --git a/apps/i15-1/src/graphql/getSessionPlaylistQuery.ts b/apps/i15-1/src/graphql/getSessionPlaylistQuery.ts index e60f7dd6..5cc1b3bb 100644 --- a/apps/i15-1/src/graphql/getSessionPlaylistQuery.ts +++ b/apps/i15-1/src/graphql/getSessionPlaylistQuery.ts @@ -12,10 +12,15 @@ export const getSessionPlaylistQuery = gql` name sample { name + id + instrumentSessions { + instrumentSessionReference + } data } experimentDefinition { name + id data } } diff --git a/apps/i15-1/src/mocks/handlers.ts b/apps/i15-1/src/mocks/handlers.ts index 0a5b6bb5..7a4db548 100644 --- a/apps/i15-1/src/mocks/handlers.ts +++ b/apps/i15-1/src/mocks/handlers.ts @@ -16,6 +16,12 @@ const fakeExperiments = { name: "Test experiment", sample: { name: "Test_8_1", + id: "a47cd8af-03f4-430b-9858-749c61f6e14c", + instrumentSessions: [ + { + instrumentSessionReference: "CM44163-3", + }, + ], data: { density: 56, capillary: "bs1.5", @@ -24,7 +30,8 @@ const fakeExperiments = { }, }, experimentDefinition: { - name: "My Experiment", + name: "run_full_collection", + id: "62b75b2f-8401-4230-b7ef-a4e577af598a", data: { q_max: 67, frames: 90, @@ -40,6 +47,12 @@ const fakeExperiments = { name: "Test experiment 2", sample: { name: "Test_8_2", + id: "19ad91f0-a155-4c5c-b5ba-175bb6f7c057", + instrumentSessions: [ + { + instrumentSessionReference: "CM44163-3", + }, + ], data: { density: 56, capillary: "bs1.5", @@ -48,7 +61,8 @@ const fakeExperiments = { }, }, experimentDefinition: { - name: "My Experiment", + name: "run_full_collection", + id: "b645e887-85b4-40d6-a8f0-500a436bc395", data: { q_max: 67, frames: 100, @@ -173,6 +187,13 @@ const fakeQueue = [ export const handlers = [ ...(USE_LOCAL ? [http.all("/api/blueapi/*", () => passthrough())] : []), + ...(USE_LOCAL + ? [ + http.all("http://127.0.0.1:8001/*", () => passthrough()), + http.all("http://localhost:8001/*", () => passthrough()), + ] + : []), + http.put("/api/blueapi/worker/task", () => { workerStatus.status = "RUNNING"; return HttpResponse.json({ diff --git a/apps/i15-1/src/queue/queueService.ts b/apps/i15-1/src/queue/queueService.ts index 027aca94..1554b85a 100644 --- a/apps/i15-1/src/queue/queueService.ts +++ b/apps/i15-1/src/queue/queueService.ts @@ -6,6 +6,7 @@ import type { QueueState, TaskCancelRequest, AddTasksToQueueQueuePostData, + Experiment, } from "../../generated/queue"; import { addTasksToQueueQueuePost } from "../../generated/queue"; import { client } from "../../generated/queue/client.gen"; @@ -251,41 +252,28 @@ export const clearHistory = async (): Promise => { return response.data; }; -export const submitTask = async ({ +export const submitQueueTask = async ({ + experiment, taskPosition, - taskParams, }: { - taskPosition: number; - taskParams: Record; + experiment: Experiment; + taskPosition?: number; }) => { - const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); - const sampleId = `test_1_${timestamp}`; - const data: AddTasksToQueueQueuePostData = { url: `/queue`, - body: [ - { - plan_name: "run_full_collection", - sample_id: sampleId, - params: taskParams, - instrument_session: "cm44163-3", - }, - ], + body: [experiment], query: { position: taskPosition, - // @ts-expect-error - validation is still a bit in flux, - // see https://github.com/DiamondLightSource/daq-queuing-service/issues/42 - validate_with_blueapi: false, }, }; return await addTasksToQueueQueuePost(data); }; -export function useSumbitTask() { +export function useSumbitQueueTask() { const client = useQueryClient(); return useMutation({ - mutationFn: submitTask, + mutationFn: submitQueueTask, onSuccess: async () => { await Promise.all([ client.invalidateQueries({ queryKey: ["queue"] }), diff --git a/apps/i15-1/src/queue/queueUtils.ts b/apps/i15-1/src/queue/queueUtils.ts index 91247ae1..b87f422d 100644 --- a/apps/i15-1/src/queue/queueUtils.ts +++ b/apps/i15-1/src/queue/queueUtils.ts @@ -7,3 +7,8 @@ export function calculateNewPosition( return newPosition; } + +export function positionFromName(name: string): string { + const parts = name.split("_"); + return "Puck " + parts[1] + " | Pin " + parts[2]; +} diff --git a/apps/i15-1/src/queue/tableData.ts b/apps/i15-1/src/queue/tableData.ts index 50ff6781..4df585cf 100644 --- a/apps/i15-1/src/queue/tableData.ts +++ b/apps/i15-1/src/queue/tableData.ts @@ -1,12 +1,14 @@ -import type { BlueapiCallResponse, Status } from "../../generated/queue"; +import type { Status } from "../../generated/queue"; export type QueueTableData = { position: number | null; + name: string; id: string; instrumentSession: string; sampleId: string; - planRunning: string; - parameters: string; + samplePosition: string; + density: number | null; + beamSize: number | null; + timePerPDF: number | null; status: Status; - blueapTasks: BlueapiCallResponse[]; }; diff --git a/apps/i15-1/src/routes/QueueView.test.tsx b/apps/i15-1/src/routes/QueueView.test.tsx index ad973af5..bd1c4ab0 100644 --- a/apps/i15-1/src/routes/QueueView.test.tsx +++ b/apps/i15-1/src/routes/QueueView.test.tsx @@ -8,6 +8,7 @@ import type { QueuedTasks } from "../queue/tasks"; type MockRow = { id: string; sampleId: string; + instrumentSession: string; }; type MockTableOptions = { @@ -24,7 +25,7 @@ vi.mock("material-react-table", () => ({
{table.options.data.map((row: MockRow) => ( -
{row.sampleId}
+
{row.instrumentSession}
))}
@@ -53,13 +54,18 @@ describe("QueueView", () => { id: "1", position: 0, status: "Queued", - experiment_definition: { + experiment: { + name: "Exp 1", instrument_session: "session2", - sample_id: "sample2", - plan_name: "planB", - params: { time: 1 }, + sample: { id: "sample2", name: "my_sample", data: {} }, + experiment_definition: { + name: "PlanB", + id: "123", + data: { time: 1 }, + }, }, blueapi_calls: [], + kind: "Experiment", }, ], } as Partial> as UseQueryResult< @@ -73,25 +79,29 @@ describe("QueueView", () => { id: "0", position: null, status: "Complete", - experiment_definition: { + experiment: { instrument_session: "session1", - sample_id: "sample1", - plan_name: "planA", + name: "planA", params: { time: 1 }, }, blueapi_calls: [], + kind: "Plan", }, { id: "1", position: 0, status: "Queued", - experiment_definition: { + experiment: { instrument_session: "session2", - sample_id: "sample2", - plan_name: "planB", - params: { time: 1 }, + sample: { id: "sample2", name: "my_sample", data: {} }, + experiment_definition: { + name: "planB", + id: "123", + data: { time: 1 }, + }, }, blueapi_calls: [], + kind: "Experiment", }, ], } as Partial> as UseQueryResult< @@ -111,8 +121,8 @@ describe("QueueView", () => { render(); expect(screen.getByTestId("mock-table")).toBeInTheDocument(); - expect(screen.queryByText("sample1")).not.toBeInTheDocument(); - expect(screen.getByText("sample2")).toBeInTheDocument(); + expect(screen.queryByText("session1")).not.toBeInTheDocument(); + expect(screen.getByText("session2")).toBeInTheDocument(); }); it("renders all tasks if Show historic tasks is on", () => { @@ -123,8 +133,8 @@ describe("QueueView", () => { expect(showHistory).toBeChecked(); expect(screen.getByTestId("mock-table")).toBeInTheDocument(); - expect(screen.getByText("sample1")).toBeInTheDocument(); - expect(screen.getByText("sample2")).toBeInTheDocument(); + expect(screen.getByText("session1")).toBeInTheDocument(); + expect(screen.getByText("session2")).toBeInTheDocument(); }); it("shows QueueStatusPanel", () => { diff --git a/apps/i15-1/src/routes/QueueView.tsx b/apps/i15-1/src/routes/QueueView.tsx index 05407619..ce34e406 100644 --- a/apps/i15-1/src/routes/QueueView.tsx +++ b/apps/i15-1/src/routes/QueueView.tsx @@ -25,8 +25,8 @@ import type { QueueTableData } from "../queue/tableData"; import { QueueStatusPanel } from "../queue/QueueStatusPanel"; import type { QueuedTasks } from "../queue/tasks"; import type { UseQueryResult } from "@tanstack/react-query"; -import { calculateNewPosition } from "../queue/queueUtils"; -import type { Status } from "../../generated/queue"; +import { calculateNewPosition, positionFromName } from "../queue/queueUtils"; +import type { Experiment, Status, TaskRequest } from "../../generated/queue"; function getChipColorMap(): Record { return { @@ -34,6 +34,7 @@ function getChipColorMap(): Record { "In progress": "info", Complete: "success", Cancelled: "warning", + Error: "error", }; } @@ -52,17 +53,40 @@ export function QueueView() { const data = useMemo(() => { return ( - tasksToDisplay.data?.map((task) => ({ - position: task.position, - id: task.id, - instrumentSession: task.experiment_definition.instrument_session, - sampleId: task.experiment_definition.sample_id, - planRunning: task.experiment_definition.plan_name, - // Should investigate a nicer way to display params, see https://github.com/DiamondLightSource/atlas/issues/52 - parameters: JSON.stringify(task.experiment_definition.params), - status: task.status, - blueapTasks: task.blueapi_calls, - })) ?? [] + tasksToDisplay.data?.map((task) => { + if (task.kind === "Experiment") { + const exp = task.experiment as Experiment; + + return { + position: task.position, + name: exp.name, + id: task.id, + instrumentSession: task.experiment.instrument_session, + sampleId: exp.sample.id, + samplePosition: positionFromName(exp.sample.name), + density: exp.sample.data.density as number, + beamSize: exp.experiment_definition.data + .focused_beam_size as number, + timePerPDF: exp.experiment_definition.data.time_per_pdf as number, + status: task.status, + }; + } else { + const plan = task.experiment as TaskRequest; + + return { + position: task.position, + name: plan.name, + id: task.id, + instrumentSession: task.experiment.instrument_session, + sampleId: "", + samplePosition: "", + density: null, + beamSize: null, + timePerPDF: null, + status: task.status, + }; + } + }) ?? [] ); }, [tasksToDisplay.data]); @@ -71,14 +95,16 @@ export function QueueView() { const columns = useMemo[]>( () => [ { accessorKey: "position", header: "Position", size: 100 }, + { accessorKey: "name", header: "Name", size: 100 }, { accessorKey: "instrumentSession", header: "Instrument Session", size: 150, }, - { accessorKey: "sampleId", header: "Sample ID", size: 150 }, - { accessorKey: "planRunning", header: "Plan", size: 150 }, - { accessorKey: "parameters", header: "Plan parameters", size: 150 }, + { accessorKey: "samplePosition", header: "Sample Position", size: 150 }, + { accessorKey: "density", header: "Density", size: 150 }, + { accessorKey: "beamSize", header: "Beam size (μm)", size: 150 }, + { accessorKey: "timePerPDF", header: "Time per PDF (sec)", size: 150 }, { accessorKey: "status", header: "Status", @@ -92,7 +118,6 @@ export function QueueView() { > ), }, - { accessorKey: "calls", header: "BlueAPI tasks", size: 150 }, { accessorKey: "cancel", header: "",