From 06cfa36cc19a3434aafce0170ec399fafa2bdd7c Mon Sep 17 00:00:00 2001 From: VictoriaBeilstenEdmands Date: Mon, 24 Nov 2025 11:44:19 +0000 Subject: [PATCH 01/16] feat: migrate to Cosmo Router --- .github/workflows/_actions.yaml | 7 +- .github/workflows/_supergraph_generate.yaml | 41 +++--- .github/workflows/_supergraph_publish.yaml | 12 +- .github/workflows/schema_comparison.yaml | 55 ++++---- README.md | 29 ++-- action.yaml | 85 ++++++------ charts/apps/templates/monitoring.yaml | 16 +-- charts/apps/templates/nightly.yaml | 103 +++++++++----- charts/apps/templates/stable.yaml | 114 +++++++++++----- charts/graph/Chart.lock | 8 +- charts/graph/Chart.yaml | 8 +- .../configmap-router-execution-config.yaml | 8 ++ charts/graph/values.yaml | 126 ++++++++++++------ supergraph-config.yaml | 11 +- 14 files changed, 395 insertions(+), 228 deletions(-) create mode 100644 charts/graph/templates/configmap-router-execution-config.yaml diff --git a/.github/workflows/_actions.yaml b/.github/workflows/_actions.yaml index f67b900..f42062d 100644 --- a/.github/workflows/_actions.yaml +++ b/.github/workflows/_actions.yaml @@ -37,7 +37,9 @@ jobs: routing-url: https://example.com/graphql subgraph-schema-artifact: test-update-schema subgraph-schema-filename: test-schema.graphql - supergraph-schema-artifact: compose-supergraph-without-app + execution-config-artifact: router-exec-config + execution-config-filename: router-execution-config.json + publish: false - name: Check Supergraph with App @@ -47,7 +49,8 @@ jobs: routing-url: https://example.com/graphql subgraph-schema-artifact: test-update-schema subgraph-schema-filename: test-schema.graphql - supergraph-schema-artifact: compose-supergraph-with-app + execution-config-artifact: router-exec-config + execution-config-filename: router-execution-config.json github-app-id: 1010045 github-app-private-key: ${{ secrets.GRAPH_FEDERATOR }} publish: false diff --git a/.github/workflows/_supergraph_generate.yaml b/.github/workflows/_supergraph_generate.yaml index 42ed1fe..1bdd482 100644 --- a/.github/workflows/_supergraph_generate.yaml +++ b/.github/workflows/_supergraph_generate.yaml @@ -6,30 +6,35 @@ on: jobs: generate: runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: - - name: Install Rover CLI - run: | - curl -sSL https://rover.apollo.dev/nix/latest | sh - echo "$HOME/.rover/bin" >> $GITHUB_PATH + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "24" + + - name: Install Cosmo CLI + run: npm install -g wgc@latest - name: Checkout Source uses: actions/checkout@v4.2.2 - - name: Compose Supergraph Schema - run: > - rover supergraph compose - --config supergraph-config.yaml - --elv2-license=accept - > supergraph.graphql + - name: Compose Execution Config + run: | + wgc router compose \ + --input supergraph-config.yaml \ + --out charts/graph/router-execution-config.json - - name: Upload New Schema Artifact - uses: actions/upload-artifact@v4.6.0 + - name: Upload Execution Config Artifact + uses: actions/upload-artifact@v4 with: - name: supergraph.graphql - path: supergraph.graphql - - - name: Release Supergraph Schema - if: github.event_name == 'push' && ( startsWith(github.ref, 'refs/tags/supergraph-schema@') ) + name: router-execution-config.json + path: charts/graph/router-execution-config.json + - name: Release Router Execution Config + if: github.event_name == 'push' && ( startsWith(github.ref, 'refs/tags/router-execution-config@') ) uses: softprops/action-gh-release@v1 with: - files: supergraph.graphql + files: charts/graph/router-execution-config.json diff --git a/.github/workflows/_supergraph_publish.yaml b/.github/workflows/_supergraph_publish.yaml index 417ff63..bb71f66 100644 --- a/.github/workflows/_supergraph_publish.yaml +++ b/.github/workflows/_supergraph_publish.yaml @@ -1,4 +1,4 @@ -name: Publish Supergraph Schema +name: Publish Router Execution Config on: workflow_call: @@ -35,16 +35,16 @@ jobs: if: steps.version.outputs.result != '' uses: azure/setup-helm@v4.2.0 - - name: Download Schema Artifact + - name: Download Router Execution Config Artifact if: steps.version.outputs.result != '' uses: actions/download-artifact@v4.1.8 with: - name: supergraph.graphql - path: charts/supergraph + name: router-execution-config + path: charts/graph - name: Package Chart if: steps.version.outputs.result != '' - run: helm package charts/supergraph --version ${{ steps.version.outputs.result }} + run: helm package charts/graph --version ${{ steps.version.outputs.result }} - name: Generate Image Name if: steps.version.outputs.result != '' @@ -63,4 +63,4 @@ jobs: - name: Publish Chart if: steps.version.outputs.result != '' && github.event_name == 'push' && ( startsWith(github.ref, 'refs/tags') || startsWith(github.ref, 'refs/heads/main') ) - run: helm push $(ls supergraph-*.tgz) ${{ env.IMAGE_REPOSITORY }} + run: helm push $(ls graph-*.tgz) ${{ env.IMAGE_REPOSITORY }} \ No newline at end of file diff --git a/.github/workflows/schema_comparison.yaml b/.github/workflows/schema_comparison.yaml index f443e8b..e48b311 100644 --- a/.github/workflows/schema_comparison.yaml +++ b/.github/workflows/schema_comparison.yaml @@ -4,41 +4,50 @@ on: pull_request: jobs: - compare_schema: + compare_execution_config: runs-on: ubuntu-latest - steps: - - name: Install Rover CLI - run: | - curl -sSL https://rover.apollo.dev/nix/latest | sh - echo "$HOME/.rover/bin" >> $GITHUB_PATH + defaults: + run: + shell: bash - - name: Checkout main branch - uses: actions/checkout@v4.2.2 + steps: + - name: Checkout main + uses: actions/checkout@v4 with: ref: main - - name: Compose old Supergraph Schema - run: > - rover supergraph compose - --config supergraph-config.yaml - --elv2-license=accept - > /tmp/old_supergraph.graphql + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "24" + + - name: Install Cosmo CLI (wgc) + run: npm install -g wgc@latest + + - name: Compose old Execution Config (main) + run: | + wgc router compose \ + --input supergraph-config.yaml \ + --out /tmp/old_router-execution-config.json - name: Checkout Source uses: actions/checkout@v4.2.2 - - name: Compose New Supergraph Schema - run: > - rover supergraph compose - --config supergraph-config.yaml - --elv2-license=accept - > supergraph.graphql + - name: Compose New Execution Config (PR) + run: | + wgc router compose \ + --input supergraph-config.yaml \ + --out router-execution-config.json + + - name: Normalize JSON + run: | + jq -S . /tmp/old_router-execution-config.json > /tmp/old_sorted.json + jq -S . router-execution-config.json > /tmp/new_sorted.json - - name: Generate Schema Diff + - name: Generate Diff run: | - git --no-pager diff --no-index --minimal /tmp/old_supergraph.graphql supergraph.graphql > diff.md || true + git --no-pager diff --no-index --minimal /tmp/old_sorted.json /tmp/new_sorted.json > diff.md || true if [ -s diff.md ]; then echo "has_diff=true" >> $GITHUB_ENV; fi - sed -i 1,4d diff.md sed -i '1s/^/```diff\n/; $a```' diff.md - name: Comment PR with artefact comparison report diff --git a/README.md b/README.md index 6baafa5..3065a74 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,10 @@ Docs can be found [on github pages](https://diamondlightsource.github.io/graph-f ## Structure -- `supergraph-schema.yaml` & `schema/`: A description of how subgraph schemas and how they are composed to produce the supergraph schema. +- `supergraph-config.yaml` & `schema/`: A description of how subgraph schemas and how they are composed a runtime execution configuration for the Cosmo Router. - `apps.yaml` & `charts/apps/`: An [ArgoCD](https://argoproj.github.io/cd/) [App-of-Apps](https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/#app-of-apps-pattern) used to deploy the other charts in various configurations -- `charts/graph`: A Helm chart used to deploy the [Apollo Router](https://www.apollographql.com/docs/router/) +- `charts/graph`: A Helm chart used to deploy the [Cosmo Router](https://wundergraph.com/router-gateway/), including the generated router-execution-config.json, mounted via a ConfigMap. - `charts/monitoring`: A Helm chart used to deploy [Prometheus](https://prometheus.io/) and [Jaeger](https://www.jaegertracing.io/) for observability -- `charts/supergraph`: A Helm chart used to deploy the supergraph schema - `action.yaml`: A [GitHub action](https://github.com/features/actions) used to create subgraph schema update pull requests - `mkdocs.yaml` & `docs/`: User facing documentation, built with [mkdocs](https://www.mkdocs.org/) @@ -20,7 +19,7 @@ Docs can be found [on github pages](https://diamondlightsource.github.io/graph-f ### Update Supergraph Schema -This workflow may be used to create or update a Subgraph Schema by adding the schema to the `schema/` directory and an entry in the `supergraph-config.yaml` of this repository. +This workflow may be used to create or update a Subgraph Schema by adding the schema to the `schema/` directory and an entry in the `supergraph-config.yaml` of this repository. The workflow composes the federated graph using Cosmo's composition pipeline and generates a new router-execution-config.json The action can be used to simply check that the schema will federate by setting `publish` to `false`. #### Usage @@ -46,13 +45,13 @@ The action can be used to simply check that the schema will federate by setting # Required. subgraph-schema-filename: - # The name of the artifact to be created containing the supergraph schema. - # Optional. Default is 'supergraph' - supergraph-schema-artifact: + # The name of the artifact to be created containing the generated router execution config. + # Optional. Default is 'router-execution-config' + execution-config-artifact: - # The name of the supergraph schema file within the created artifact. - # Optional. Default is 'supergraph.graphql' - supergraph-schema-filename: + # The name of the generated execution config within the created artifact. + # Optional. Default is 'router-execution-config.json' + execution-config-filename: # The ID of the GitHub App used to create the commit / pull request # Required when publish is true. @@ -69,10 +68,10 @@ The action can be used to simply check that the schema will federate by setting ##### Outputs -| Name | Description | Example | -| ------------------------------ | -------------------------------------------------------- | --------------------------------------------------------------------------- | -| supergraph-schema-artifact-id | The id of the artifact containing the supergraph schema | 1234 | -| supergraph-schema-artifact-url | The url of the artifact containing the supergraph schema | | +| Name | Description | Example | +| ----------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------- | +| execution-config-artifact-id | The id of the artifact containing the router execution config | 1234 | +| execution-config-artifact-url | The url of the artifact containing the router execution config | | ##### Example @@ -95,7 +94,7 @@ steps: name: test-schema path: test-schema.graphql - - name: Update Supergraph + - name: Update Composition uses: diamondlightsource/graph-federation@main with: name: test diff --git a/action.yaml b/action.yaml index d215a54..a3f0eca 100644 --- a/action.yaml +++ b/action.yaml @@ -1,5 +1,5 @@ name: Update Supergraph -description: Perform Supergraph composition with appropraite subgraph schema and metadata and create PR +description: Perform supergraph composition (Cosmo) and create PR inputs: name: @@ -14,14 +14,14 @@ inputs: subgraph-schema-filename: description: The name of the subgraph schema file within the artifact required: true - supergraph-schema-artifact: - description: The name of the artifact to be created containing the supergraph schema + execution-config-artifact: + description: The name of the artifact to be created that contains the Cosmo router execution config required: true - default: supergraph - supergraph-schema-filename: - description: The name of the supergraph schema file within the created artifact + default: router-execution-config + execution-config-filename: + description: The filename of the execution config JSON required: true - default: supergraph.graphql + default: router-execution-config.json github-app-id: description: The ID of the GitHub App used to create the commit / pull request required: false @@ -29,17 +29,17 @@ inputs: description: The private key of the GitHub App used to create the commit / pull request required: false publish: - description: A boolean value which determines whether a branch and pull request should be created + description: Whether to create a branch and PR required: true default: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags') }} outputs: - supergraph-schema-artifact-id: - description: The id of the artifact containing the supergraph schema - value: ${{ steps.compose.outputs.artifact-id }} - supergraph-schema-artifact-url: - description: The url of the artifact containing the supergraph schema - value: ${{ steps.compose.outputs.artifact-url }} + execution-config-artifact-id: + description: The id of the artifact containing the execution config JSON + value: ${{ steps.upload.outputs.artifact-id }} + execution-config-artifact-url: + description: The url of the artifact containing the execution config JSON + value: ${{ steps.upload.outputs.artifact-url }} runs: using: composite @@ -75,42 +75,41 @@ runs: shell: bash run: mv /tmp/schema/${{ inputs.subgraph-schema-filename}} schema/${{ inputs.name }}.graphql - - name: Add Subgraph workflows to Supergraph config + - name: Update supergraph-config.yaml shell: bash - run: > - yq -i - ' - .subgraphs.${{ inputs.name }}={ - "routing_url":"${{ inputs.routing-url}}", - "schema":{ - "file":"schema/${{ inputs.name }}.graphql" - } - } - ' - supergraph-config.yaml + run: | + yq -i ' + .subgraphs += [{ + "name": "${{ inputs.name }}", + "routing_url": "${{ inputs.routing-url }}", + "schema": { "file": "schema/${{ inputs.name }}.graphql" } + }] + ' supergraph-config.yaml + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "24" - - name: Install Rover CLI + - name: Install Cosmo CLI shell: bash - run: | - if ! command -v rover 2>&1 > /dev/null; then - curl -sSL https://rover.apollo.dev/nix/latest | sh - echo "$HOME/.rover/bin" >> $GITHUB_PATH - fi + run: npm install -g wgc@latest - - name: Compose Supergraph Schema + - name: Compose Execution Config + id: compose shell: bash - run: > - rover supergraph compose - --config supergraph-config.yaml - --elv2-license=accept - > ${{ inputs.supergraph-schema-filename }} + run: | + wgc router compose \ + --input supergraph-config.yaml \ + --out ${{ inputs.execution-config-filename }} - - name: Upload Supergraph Artifact - id: supergraph-artifact - uses: actions/upload-artifact@v4.4.3 + - name: Upload Execution Config Artifact + id: upload + uses: actions/upload-artifact@v4 with: - name: ${{ inputs.supergraph-schema-artifact }} - path: ./${{ inputs.supergraph-schema-filename }} + name: ${{ inputs.execution-config-artifact }} + path: ./${{ inputs.execution-config-filename }} + overwrite: true - name: Configure Git with App shell: bash diff --git a/charts/apps/templates/monitoring.yaml b/charts/apps/templates/monitoring.yaml index c519740..7bf1d7d 100644 --- a/charts/apps/templates/monitoring.yaml +++ b/charts/apps/templates/monitoring.yaml @@ -2,19 +2,19 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: graph-monitoring - namespace: {{ .Release.Namespace }} + namespace: {{.Release.Namespace}} finalizers: - resources-finalizer.argocd.argoproj.io spec: - project: {{ default .Release.Namespace .Values.project }} + project: {{default .Release.Namespace .Values.project}} source: - repoURL: {{ .Values.monitoring.repoURL }} - targetRevision: {{ .Values.monitoring.targetRevision }} - path: {{ .Values.monitoring.path }} + repoURL: {{.Values.monitoring.repoURL}} + targetRevision: {{.Values.monitoring.targetRevision}} + path: {{.Values.monitoring.path}} destination: - name: {{ .Values.destination.name }} - server: {{ .Values.destination.server }} - namespace: {{ default .Release.Namespace .Values.destination.namespace }} + name: {{.Values.destination.name}} + server: {{.Values.destination.server}} + namespace: {{default .Release.Namespace .Values.destination.namespace}} syncPolicy: automated: prune: true diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index 8863cbb..21272e1 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -2,46 +2,86 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: graph-nightly - namespace: {{ .Release.Namespace }} + namespace: {{.Release.Namespace}} finalizers: - resources-finalizer.argocd.argoproj.io spec: - project: {{ default .Release.Namespace .Values.project }} + project: {{default .Release.Namespace .Values.project}} sources: - - repoURL: {{ .Values.graph.repoURL }} - targetRevision: {{ .Values.graph.nightlyRevision }} - path: {{ .Values.graph.path }} + - repoURL: {{.Values.graph.repoURL}} + targetRevision: {{.Values.graph.nightlyRevision}} + path: {{.Values.graph.path}} helm: valuesObject: router: router: configuration: - telemetry: + logLevel: "info" + # routerConfigPath: /etc/cosmo/execution-config.json + + prometheus: + enabled: true + port: 8088 + path: /metrics + + commonConfiguration: |- + version: "1" + log_level: "info" + + listen_addr: "0.0.0.0:4000" + health_check_path: "/health" + readiness_check_path: "/health/ready" + liveness_check_path: "/health/live" + + playground_enabled: true + playground_path: "/" + introspection: + enabled: true + + cors: + allow_origins: + - "*" + + headers: + all: + request: + - op: "propagate" + named: Authorization + - op: "propagate" + named: Cookie + + subgraph_error_propagation: + mode: wrapped + allowed_extension_fields: + - "code" + propagate_status_codes: true + attach_service_name: true + omit_locations: true + omit_extensions: false + default_extension_code: DOWNSTREAM_SERVICE_ERROR + + telemetry: + service_name: "router-nightly" + tracing: + enabled: true exporters: - metrics: - common: - resource: - "service.name": "router-nightly" - otlp: - enabled: true - endpoint: 'graph-monitoring-opentelemetry-collector:4317' - protocol: grpc - tracing: - common: - resource: - "service.name": "router-nightly" - otlp: - enabled: true - endpoint: 'graph-monitoring-opentelemetry-collector:4317' - protocol: grpc - propagation: - trace_context: true + - endpoint: "http://graph-monitoring-opentelemetry-collector:4317" + exporter: "grpc" + metrics: + otlp: + enabled: true + exporters: + - endpoint: "http://graph-monitoring-opentelemetry-collector:4317" + exporter: "grpc" + oauth2-proxy: ingress: + enabled: true hostname: graph-nightly.diamond.ac.uk hosts: - graph-nightly.diamond.ac.uk alphaConfig: + enabled: true configData: providers: - provider: oidc @@ -56,13 +96,16 @@ spec: - aud emailClaim: email userIDClaim: email - - repoURL: {{ .Values.schema.repoURL }} - chart: {{ .Values.schema.chart }} - targetRevision: {{ .Values.schema.nightlyRevision | quote }} + + - repoURL: {{.Values.schema.repoURL}} + chart: {{.Values.schema.chart}} + targetRevision: {{.Values.schema.nightlyRevision | quote}} + destination: - name: {{ .Values.destination.name }} - server: {{ .Values.destination.server }} - namespace: {{ default .Release.Namespace .Values.destination.namespace }} + name: {{.Values.destination.name}} + server: {{.Values.destination.server}} + namespace: {{default .Release.Namespace .Values.destination.namespace}} + syncPolicy: automated: prune: true diff --git a/charts/apps/templates/stable.yaml b/charts/apps/templates/stable.yaml index bc20364..bfb04fb 100644 --- a/charts/apps/templates/stable.yaml +++ b/charts/apps/templates/stable.yaml @@ -2,48 +2,100 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: graph-stable - namespace: {{ .Release.Namespace }} + namespace: {{.Release.Namespace}} finalizers: - resources-finalizer.argocd.argoproj.io spec: - project: {{ default .Release.Namespace .Values.project }} + project: {{default .Release.Namespace .Values.project}} + sources: - - repoURL: {{ .Values.graph.repoURL }} - targetRevision: {{ .Values.graph.stableRevision }} - path: {{ .Values.graph.path }} + - repoURL: {{.Values.graph.repoURL}} + targetRevision: {{.Values.graph.stableRevision}} + path: {{.Values.graph.path}} helm: valuesObject: router: router: + image: + repository: ghcr.io/wundergraph/cosmo/router + tag: "latest" + version: "latest" configuration: - telemetry: + logLevel: "info" + prometheus: + enabled: true + port: 8088 + path: /metrics + podAnnotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8088" + prometheus.io/path: "/metrics" + + commonConfiguration: |- + version: "1" + log_level: "info" + + listen_addr: "0.0.0.0:4000" + health_check_path: "/health" + readiness_check_path: "/health/ready" + liveness_check_path: "/health/live" + + playground_enabled: true + playground_path: "/" + introspection: + enabled: true + + cors: + allow_origins: + - "*" + + headers: + all: + request: + - op: "propagate" + named: Authorization + - op: "propagate" + named: Cookie + + subgraph_error_propagation: + mode: wrapped + allowed_extension_fields: + - "code" + propagate_status_codes: true + attach_service_name: true + omit_locations: true + omit_extensions: false + default_extension_code: DOWNSTREAM_SERVICE_ERROR + + telemetry: + service_name: "router-stable" + tracing: + enabled: true exporters: - metrics: - common: - resource: - "service.name": "router-stable" - otlp: - enabled: true - endpoint: 'graph-monitoring-opentelemetry-collector:4317' - protocol: grpc - tracing: - common: - resource: - "service.name": "router-stable" - otlp: - enabled: true - endpoint: 'graph-monitoring-opentelemetry-collector:4317' - protocol: grpc - propagation: - trace_context: true - - repoURL: {{ .Values.schema.repoURL }} - chart: {{ .Values.schema.chart }} - targetRevision: {{ .Values.schema.stableRevision | quote }} + - endpoint: "http://graph-monitoring-opentelemetry-collector:4317" + exporter: "grpc" + metrics: + otlp: + enabled: true + exporters: + - endpoint: "http://graph-monitoring-opentelemetry-collector:4317" + exporter: "grpc" + + oauth2-proxy: + ingress: + enabled: true + alphaConfig: + enabled: true + + - repoURL: {{.Values.schema.repoURL}} + chart: {{.Values.schema.chart}} + targetRevision: {{.Values.schema.stableRevision | quote}} + destination: - name: {{ .Values.destination.name }} - server: {{ .Values.destination.server }} - namespace: {{ default .Release.Namespace .Values.destination.namespace }} + name: {{.Values.destination.name}} + server: {{.Values.destination.server}} + namespace: {{default .Release.Namespace .Values.destination.namespace}} + syncPolicy: automated: prune: true - selfHeal: true diff --git a/charts/graph/Chart.lock b/charts/graph/Chart.lock index 89564c0..d634add 100644 --- a/charts/graph/Chart.lock +++ b/charts/graph/Chart.lock @@ -1,9 +1,9 @@ dependencies: - name: router - repository: oci://ghcr.io/apollographql/helm-charts - version: 1.49.1 + repository: oci://ghcr.io/wundergraph/cosmo/helm-charts + version: 0.15.0 - name: oauth2-proxy repository: https://oauth2-proxy.github.io/manifests/ version: 7.7.20 -digest: sha256:ef7f61dafc582dce2da679f472c73741081ee522fb61985c8140a017940260e4 -generated: "2024-09-17T15:36:46.159887781+01:00" +digest: sha256:6797287a3b2883c657c871e1aef0675651368cdb1784b1b6cd3665883d092006 +generated: "2026-01-22T09:49:59.620477668Z" diff --git a/charts/graph/Chart.yaml b/charts/graph/Chart.yaml index 180fb8e..ce7f571 100644 --- a/charts/graph/Chart.yaml +++ b/charts/graph/Chart.yaml @@ -2,12 +2,12 @@ apiVersion: v2 name: graph description: The Diamond data Graph type: application -version: 0.12.2 +version: 0.13.0 dependencies: - name: router - repository: oci://ghcr.io/apollographql/helm-charts - version: 1.49.1 - condition: apollo-router.enabled + repository: oci://ghcr.io/wundergraph/cosmo/helm-charts + version: 0.15.0 + condition: cosmo-router.enabled - name: oauth2-proxy repository: https://oauth2-proxy.github.io/manifests/ version: 7.7.20 diff --git a/charts/graph/templates/configmap-router-execution-config.yaml b/charts/graph/templates/configmap-router-execution-config.yaml new file mode 100644 index 0000000..8e1fa68 --- /dev/null +++ b/charts/graph/templates/configmap-router-execution-config.yaml @@ -0,0 +1,8 @@ + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{.Release.Name}}-router-execution-config +data: + execution-config.json: | +{{- .Files.Get "router-execution-config.json" | nindent 4 }} diff --git a/charts/graph/values.yaml b/charts/graph/values.yaml index 137ed10..e7f712f 100644 --- a/charts/graph/values.yaml +++ b/charts/graph/values.yaml @@ -1,51 +1,97 @@ router: - enabled: true + existingConfigmap: "" + configuration: + graphApiToken: "" + routerConfigPath: "/etc/cosmo/execution-config.json" + cdnUrl: "" + controlplaneUrl: "" + otelCollectorUrl: "" + graphqlMetricsCollectorUrl: "" + devMode: false + + image: + registry: ghcr.io + repository: wundergraph/cosmo/router + tag: "latest" + version: "latest" + + env: + - name: ROUTER_CONFIG_PATH + value: "/etc/cosmo/execution-config.json" + podAnnotations: prometheus.io/scrape: "true" - prometheus.io/port: "44180" - router: - args: - - --hot-reload - - --supergraph - - /etc/apollo/supergraph.graphql - configuration: - sandbox: + prometheus.io/port: "8088" + prometheus.io/path: "/metrics" + + commonConfiguration: |- + version: "1" + log_level: "debug" + json_log: true + + listen_addr: "0.0.0.0:3002" + + health_check_path: "/health" + readiness_check_path: "/health/ready" + liveness_check_path: "/health/live" + + query_plans_enabled: true + playground: + enabled: true + path: "/" + + cors: + allow_origins: + - "*" + + headers: + all: + request: + - op: "propagate" + named: Authorization + - op: "propagate" + named: Cookie + + subgraph_error_propagation: + mode: wrapped + allowed_extension_fields: + - "code" + propagate_status_codes: true + attach_service_name: true + omit_locations: true + omit_extensions: false + default_extension_code: DOWNSTREAM_SERVICE_ERROR + + telemetry: + service_name: "cosmo-router" + tracing: enabled: true - homepage: - enabled: false - supergraph: - introspection: true - listen: 0.0.0.0:4000 - query_planning: - experimental_parallelism: auto - include_subgraph_errors: - all: true - headers: - all: - request: - - propagate: - matching: authorization - cors: - match_origins: - - ^https:\/\/([a-zA-Z0-9\-]+\.)*diamond\.ac\.uk\/? - - ^https?:\/\/localhost(:\d+)?\/? - health_check: - listen: 0.0.0.0:8088 - telemetry: - instrumentation: - spans: - mode: spec_compliant + exporters: + - endpoint: "http://graph-monitoring-opentelemetry-collector:4317" + exporter: "grpc" + metrics: + prometheus: + enabled: true + listen_addr: "0.0.0.0:8088" + otlp: + enabled: true + exporters: + - endpoint: "http://graph-monitoring-opentelemetry-collector:4317" + exporter: "grpc" + extraVolumes: - - name: supergraph + - name: router-execution-config configMap: - name: "{{ .Release.Name }}-supergraph-schema" + name: "{{ .Release.Name }}-router-execution-config" items: - - key: supergraph.graphql - path: supergraph.graphql + - key: execution-config.json + path: execution-config.json + extraVolumeMounts: - - name: supergraph - mountPath: /etc/apollo/ - readonly: true + - name: router-execution-config + mountPath: /etc/cosmo + readOnly: true + resources: requests: cpu: 8 diff --git a/supergraph-config.yaml b/supergraph-config.yaml index 469f0f1..41fd22f 100644 --- a/supergraph-config.yaml +++ b/supergraph-config.yaml @@ -1,14 +1,17 @@ -federation_version: =2.8.0 +version: 1 subgraphs: - workflows: + - name: workflows routing_url: https://workflows.diamond.ac.uk/graphql + subscription: + url: wss://workflows.diamond.ac.uk/graphql/ws + protocol: ws schema: file: schema/workflows.graphql - instrument_sessions: + - name: instrument_sessions routing_url: https://instrument-sessions.diamond.ac.uk/api/graphql schema: file: schema/instrument_sessions.graphql - samples: + - name: samples routing_url: https://sample-information.diamond.ac.uk/api/graphql schema: file: schema/samples.graphql From 73a0e974573a16a0897c1d287e945f2919b577aa Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 11:42:24 +0000 Subject: [PATCH 02/16] fix: add router execution config --- charts/graph/charts/router-execution-config.json | 1 + charts/graph/templates/router-execution-config.json | 1 + 2 files changed, 2 insertions(+) create mode 100644 charts/graph/charts/router-execution-config.json create mode 100644 charts/graph/templates/router-execution-config.json diff --git a/charts/graph/charts/router-execution-config.json b/charts/graph/charts/router-execution-config.json new file mode 100644 index 0000000..c1cfdd7 --- /dev/null +++ b/charts/graph/charts/router-execution-config.json @@ -0,0 +1 @@ +{"engineConfig":{"defaultFlushInterval":"500","datasourceConfigurations":[{"kind":"GRAPHQL","rootNodes":[{"typeName":"Mutation","fieldNames":["submitWorkflowTemplate"]},{"typeName":"Query","fieldNames":["workflow","workflows","workflowTemplate","workflowTemplates"]},{"typeName":"Subscription","fieldNames":["logs","workflow"]}],"childNodes":[{"typeName":"Artifact","fieldNames":["name","url","mimeType"]},{"typeName":"LogEntry","fieldNames":["content","podName"]},{"typeName":"PageInfo","fieldNames":["hasPreviousPage","hasNextPage","startCursor","endCursor"]},{"typeName":"Task","fieldNames":["id","name","status","depends","dependencies","artifacts","stepType","startTime","endTime","message"]},{"typeName":"Visit","fieldNames":["proposalCode","proposalNumber","number"]},{"typeName":"Workflow","fieldNames":["name","visit","status","parameters","templateRef","creator"]},{"typeName":"WorkflowConnection","fieldNames":["pageInfo","edges","nodes"]},{"typeName":"WorkflowCreator","fieldNames":["creatorId"]},{"typeName":"WorkflowEdge","fieldNames":["node","cursor"]},{"typeName":"WorkflowErroredStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowFailedStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowPendingStatus","fieldNames":["message"]},{"typeName":"WorkflowRunningStatus","fieldNames":["startTime","message","tasks"]},{"typeName":"WorkflowSucceededStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowTemplate","fieldNames":["name","maintainer","title","description","repository","arguments","uiSchema"]},{"typeName":"WorkflowTemplateConnection","fieldNames":["pageInfo","edges","nodes"]},{"typeName":"WorkflowTemplateEdge","fieldNames":["node","cursor"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://workflows.diamond.ac.uk/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"wss://workflows.diamond.ac.uk/graphql/ws"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"type Artifact {\n\t\"\"\"\n\tThe file name of the artifact\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe download URL for the artifact\n\t\"\"\"\n\turl: Url!\n\t\"\"\"\n\tThe MIME type of the artifact data\n\t\"\"\"\n\tmimeType: String!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"\nA scalar that can represent any JSON value.\n\"\"\"\nscalar JSON\n\n\"\"\"\nA scalar that can represent any JSON Object value.\n\"\"\"\nscalar JSONObject\n\n\"\"\"\nA single log line streamed from a pod\n\"\"\"\ntype LogEntry {\n\t\"\"\"\n\tThe log line content\n\t\"\"\"\n\tcontent: String!\n\t\"\"\"\n\tThe name of the pod producing the log\n\t\"\"\"\n\tpodName: String!\n}\n\n\"\"\"\nThe root mutation of the service\n\"\"\"\ntype Mutation {\n\tsubmitWorkflowTemplate(name: String!, visit: VisitInput!, parameters: JSON!): Workflow!\n}\n\n\"\"\"\nInformation about pagination in a connection\n\"\"\"\ntype PageInfo @shareable {\n\t\"\"\"\n\tWhen paginating backwards, are there more items?\n\t\"\"\"\n\thasPreviousPage: Boolean!\n\t\"\"\"\n\tWhen paginating forwards, are there more items?\n\t\"\"\"\n\thasNextPage: Boolean!\n\t\"\"\"\n\tWhen paginating backwards, the cursor to continue.\n\t\"\"\"\n\tstartCursor: String\n\t\"\"\"\n\tWhen paginating forwards, the cursor to continue.\n\t\"\"\"\n\tendCursor: String\n}\n\n\"\"\"\nThe root query of the service\n\"\"\"\ntype Query {\n\t\"\"\"\n\tGet a single [`Workflow`] by proposal, visit, and name\n\t\"\"\"\n\tworkflow(visit: VisitInput!, name: String!): Workflow!\n\tworkflows(visit: VisitInput!, cursor: String, limit: Int, filter: WorkflowFilter): WorkflowConnection!\n\tworkflowTemplate(name: String!): WorkflowTemplate!\n\tworkflowTemplates(cursor: String, limit: Int, filter: WorkflowTemplatesFilter): WorkflowTemplateConnection!\n}\n\n\"\"\"\nSupported DLS science groups\n\"\"\"\nenum ScienceGroup {\n\t\"\"\"\n\tMacromolecular Crystallography\n\t\"\"\"\n\tMX\n\t\"\"\"\n\tWorkflows Examples\n\t\"\"\"\n\tEXAMPLES\n\t\"\"\"\n\tMagnetic Materials\n\t\"\"\"\n\tMAGNETIC_MATERIALS\n\t\"\"\"\n\tSoft Condensed Matter\n\t\"\"\"\n\tCONDENSED_MATTER\n\t\"\"\"\n\tImaging and Microscopy\n\t\"\"\"\n\tIMAGING\n\t\"\"\"\n\tBiological Cryo-Imaging\n\t\"\"\"\n\tBIO_CRYO_IMAGING\n\t\"\"\"\n\tStructures and Surfaces\n\t\"\"\"\n\tSURFACES\n\t\"\"\"\n\tCrystallography\n\t\"\"\"\n\tCRYSTALLOGRAPHY\n\t\"\"\"\n\tSpectroscopy\n\t\"\"\"\n\tSPECTROSCOPY\n}\n\n\"\"\"\nThe root mutation of the service\n\"\"\"\ntype Subscription {\n\t\"\"\"\n\tProcessing to subscribe to logs for a single pod of a workflow\n\t\"\"\"\n\tlogs(visit: VisitInput!, workflowName: String!, taskId: String!): LogEntry!\n\t\"\"\"\n\tProcessing to subscribe to data for all workflows in a session\n\t\"\"\"\n\tworkflow(visit: VisitInput!, name: String!): Workflow!\n}\n\ntype Task {\n\t\"\"\"\n\tUnique name of the task\n\t\"\"\"\n\tid: String!\n\t\"\"\"\n\tDisplay name of the task\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tCurrent status of a task\n\t\"\"\"\n\tstatus: TaskStatus!\n\t\"\"\"\n\tParent of a task\n\t\"\"\"\n\tdepends: [String!]!\n\t\"\"\"\n\tChildren of a task\n\t\"\"\"\n\tdependencies: [String!]!\n\t\"\"\"\n\tArtifacts produced by a task\n\t\"\"\"\n\tartifacts: [Artifact!]!\n\t\"\"\"\n\tNode type - Pod, DAG, etc\n\t\"\"\"\n\tstepType: String!\n\t\"\"\"\n\tStart time for a task on a workflow\n\t\"\"\"\n\tstartTime: DateTime\n\t\"\"\"\n\tEnd time for a task on a workflow\n\t\"\"\"\n\tendTime: DateTime\n\t\"\"\"\n\tA human readable message indicating details about why this step is in this condition\n\t\"\"\"\n\tmessage: String\n}\n\nenum TaskStatus {\n\tPENDING\n\tRUNNING\n\tSUCCEEDED\n\tSKIPPED\n\tFAILED\n\tERROR\n\tOMITTED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"\nA visit to an instrument as part of a session\n\"\"\"\ntype Visit {\n\t\"\"\"\n\tProject Proposal Code\n\t\"\"\"\n\tproposalCode: String!\n\t\"\"\"\n\tProject Proposal Number\n\t\"\"\"\n\tproposalNumber: Int!\n\t\"\"\"\n\tSession visit Number\n\t\"\"\"\n\tnumber: Int!\n}\n\n\"\"\"\nA visit to an instrument as part of a session\n\"\"\"\ninput VisitInput {\n\t\"\"\"\n\tProject Proposal Code\n\t\"\"\"\n\tproposalCode: String!\n\t\"\"\"\n\tProject Proposal Number\n\t\"\"\"\n\tproposalNumber: Int!\n\t\"\"\"\n\tSession visit Number\n\t\"\"\"\n\tnumber: Int!\n}\n\ntype Workflow {\n\t\"\"\"\n\tThe name given to the workflow, unique within a given visit\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe visit the Workflow was run against\n\t\"\"\"\n\tvisit: Visit!\n\t\"\"\"\n\tThe current status of the workflow\n\t\"\"\"\n\tstatus: WorkflowStatus\n\t\"\"\"\n\tThe top-level workflow parameters\n\t\"\"\"\n\tparameters: JSONObject\n\t\"\"\"\n\tThe name of the template used to run the workflow\n\t\"\"\"\n\ttemplateRef: String\n\t\"\"\"\n\tThe workflow creator\n\t\"\"\"\n\tcreator: WorkflowCreator!\n}\n\ntype WorkflowConnection @shareable {\n\t\"\"\"\n\tInformation to aid in pagination.\n\t\"\"\"\n\tpageInfo: PageInfo!\n\t\"\"\"\n\tA list of edges.\n\t\"\"\"\n\tedges: [WorkflowEdge!]!\n\t\"\"\"\n\tA list of nodes.\n\t\"\"\"\n\tnodes: [Workflow!]!\n}\n\n\"\"\"\nInformation about the creator of a workflow.\n\"\"\"\ntype WorkflowCreator {\n\t\"\"\"\n\tAn identifier unique to the creator of the workflow.\n\tTypically this is the creator's Fed-ID.\n\t\"\"\"\n\tcreatorId: String!\n}\n\n\"\"\"\nAn edge in a connection.\n\"\"\"\ntype WorkflowEdge @shareable {\n\t\"\"\"\n\tThe item at the end of the edge\n\t\"\"\"\n\tnode: Workflow!\n\t\"\"\"\n\tA cursor for use in pagination\n\t\"\"\"\n\tcursor: String!\n}\n\n\"\"\"\nAll tasks in the workflow have errored\n\"\"\"\ntype WorkflowErroredStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nAll tasks in the workflow have failed\n\"\"\"\ntype WorkflowFailedStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nAll the supported Workflows filters\n\"\"\"\ninput WorkflowFilter {\n\t\"\"\"\n\tThe status field for a workflow\n\t\"\"\"\n\tworkflowStatusFilter: WorkflowStatusFilter\n\t\"\"\"\n\tThe fedid of the user who created the workflow\n\t\"\"\"\n\tcreator: Creator\n\t\"\"\"\n\tThe name of the workflow template\n\t\"\"\"\n\ttemplate: Template\n}\n\ntype WorkflowPendingStatus {\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n}\n\ntype WorkflowRunningStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nThe status of a workflow\n\"\"\"\nunion WorkflowStatus = WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus | WorkflowFailedStatus | WorkflowErroredStatus\n\n\"\"\"\nRepresents workflow status filters\n\"\"\"\ninput WorkflowStatusFilter {\n\tpending: Boolean! = false\n\trunning: Boolean! = false\n\tsucceeded: Boolean! = false\n\tfailed: Boolean! = false\n\terror: Boolean! = false\n}\n\n\"\"\"\nAll tasks in the workflow have succeded\n\"\"\"\ntype WorkflowSucceededStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n\t\"\"\"\n\tThe name given to the workflow template, globally unique\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe group who maintains the workflow template\n\t\"\"\"\n\tmaintainer: String!\n\t\"\"\"\n\tA human readable title for the workflow template\n\t\"\"\"\n\ttitle: String\n\t\"\"\"\n\tA human readable description of the workflow which is created\n\t\"\"\"\n\tdescription: String\n\t\"\"\"\n\tThe repository storing the code associated with this template.\n\t\"\"\"\n\trepository: String\n\t\"\"\"\n\tA JSON Schema describing the arguments of a Workflow Template\n\t\"\"\"\n\targuments: JSON!\n\t\"\"\"\n\tA JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n\t\"\"\"\n\tuiSchema: JSON\n}\n\ntype WorkflowTemplateConnection @shareable {\n\t\"\"\"\n\tInformation to aid in pagination.\n\t\"\"\"\n\tpageInfo: PageInfo!\n\t\"\"\"\n\tA list of edges.\n\t\"\"\"\n\tedges: [WorkflowTemplateEdge!]!\n\t\"\"\"\n\tA list of nodes.\n\t\"\"\"\n\tnodes: [WorkflowTemplate!]!\n}\n\n\"\"\"\nAn edge in a connection.\n\"\"\"\ntype WorkflowTemplateEdge @shareable {\n\t\"\"\"\n\tThe item at the end of the edge\n\t\"\"\"\n\tnode: WorkflowTemplate!\n\t\"\"\"\n\tA cursor for use in pagination\n\t\"\"\"\n\tcursor: String!\n}\n\n\"\"\"\nSupported label filters for ClusterWorkflowTemplates\n\"\"\"\ninput WorkflowTemplatesFilter {\n\t\"\"\"\n\tThe science group owning the template eg imaging\n\t\"\"\"\n\tscienceGroup: [ScienceGroup!]\n}\n\n\"\"\"\nDirects the executor to include this field or fragment only when the `if` argument is true.\n\"\"\"\ndirective @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\"\"\"\nDirects the executor to skip this field or fragment when the `if` argument is true.\n\"\"\"\ndirective @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\"\"\"\nProvides a scalar specification URL for specifying the behavior of custom scalar types.\n\"\"\"\ndirective @specifiedBy(url: String!) on SCALAR\nextend schema @link(\n\turl: \"https://specs.apollo.dev/federation/v2.5\",\n\timport: [\"@key\", \"@tag\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@composeDirective\", \"@interfaceObject\", \"@requiresScopes\"]\n)\n"},"upstreamSchema":{"key":"399ecb62e2d8de68392ee3dfb8e088d1edc68f46"}},"requestTimeoutSeconds":"10","id":"0"},{"kind":"GRAPHQL","rootNodes":[{"typeName":"InstrumentSession","fieldNames":["instrumentSessionId","instrumentSessionNumber","startTime","endTime","type","state","riskRating","proposal","instrument","roles"]},{"typeName":"InstrumentSessionMutations","fieldNames":["instrumentSessionNumber","proposalNumber"]},{"typeName":"Mutation","fieldNames":["instrumentSession"]},{"typeName":"Proposal","fieldNames":["proposalNumber","proposalCategory","title","summary","state","instrumentSessions","instruments","roles"]},{"typeName":"Query","fieldNames":["proposal","proposals","instrumentSession","instrumentSessions","instrument","instruments","account"]}],"childNodes":[{"typeName":"Account","fieldNames":["accountId","username","emailAddress","title","givenName","familyName","type","state","proposalRoles","instrumentSessionRoles"]},{"typeName":"Instrument","fieldNames":["name","scienceGroup","description","proposals","instrumentSessions"]},{"typeName":"InstrumentSessionRole","fieldNames":["instrumentSession","account","role","onSite"]},{"typeName":"PageInfo","fieldNames":["startCursor","endCursor","hasNextPage","hasPreviousPage"]},{"typeName":"ProposalAccount","fieldNames":["proposal","account","role"]},{"typeName":"ProposalConnection","fieldNames":["edges","pageInfo"]},{"typeName":"ProposalEdge","fieldNames":["cursor","node"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://instrument-sessions.diamond.ac.uk/api/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"https://instrument-sessions.diamond.ac.uk/api/graphql"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"schema @link(url: \"https://specs.apollo.dev/federation/v2.7\", import: [\"@key\", \"@shareable\"]) {\n query: Query\n mutation: Mutation\n}\n\ntype Account {\n accountId: Int!\n username: String!\n emailAddress: String\n title: String\n givenName: String\n familyName: String\n type: AccountType!\n state: AccountState!\n proposalRoles: [ProposalAccount!]!\n instrumentSessionRoles: [InstrumentSessionRole!]!\n}\n\nenum AccountState {\n enabled\n disabled\n}\n\nenum AccountType {\n user\n staff\n functional\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ntype Instrument {\n name: String!\n scienceGroup: String\n description: String\n proposals: [Proposal!]!\n instrumentSessions: [InstrumentSession!]!\n}\n\ntype InstrumentSession @key(fields: \"instrumentSessionNumber proposal {proposalNumber}\") {\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n startTime: DateTime\n endTime: DateTime\n type: String\n state: String\n riskRating: String\n proposal: Proposal\n instrument: Instrument!\n roles: [InstrumentSessionRole!]!\n}\n\ntype InstrumentSessionMutations @key(fields: \"instrumentSessionNumber proposalNumber\") {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n instrumentSession: InstrumentSession!\n account: Account!\n role: String!\n onSite: Boolean!\n}\n\ntype Mutation {\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSessionMutations\n}\n\ntype PageInfo @shareable {\n startCursor: String\n endCursor: String\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n}\n\ntype Proposal @key(fields: \"proposalNumber\") {\n proposalNumber: Int!\n proposalCategory: String\n title: String\n summary: String\n state: ProposalState!\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n roles: [ProposalAccount!]!\n}\n\ntype ProposalAccount {\n proposal: Proposal!\n account: Account!\n role: String!\n}\n\ntype ProposalConnection @shareable {\n edges: [ProposalEdge!]!\n pageInfo: PageInfo!\n}\n\ntype ProposalEdge @shareable {\n cursor: String!\n node: Proposal!\n}\n\nenum ProposalState {\n Open\n Closed\n Cancelled\n}\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n\n \"\"\"Get a list of proposals\"\"\"\n proposals(proposalCategory: String = null, first: Int = null, last: Int = null, after: String = null, before: String = null): ProposalConnection!\n\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSession\n\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalNumber: Int = null, proposalCategory: String = null): [InstrumentSession!]\n\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n}\n\nscalar _Any\n\nunion _Entity = InstrumentSession | InstrumentSessionMutations | Proposal\n\ntype _Service {\n sdl: String!\n}\n"},"upstreamSchema":{"key":"636412ec8e6e8e278df46ce7da59047a6182733c"}},"requestTimeoutSeconds":"10","id":"1","keys":[{"typeName":"InstrumentSession","selectionSet":"instrumentSessionNumber proposal { proposalNumber }"},{"typeName":"InstrumentSessionMutations","selectionSet":"instrumentSessionNumber proposalNumber"},{"typeName":"Proposal","selectionSet":"proposalNumber"}]},{"kind":"GRAPHQL","rootNodes":[{"typeName":"Mutation","fieldNames":["createSamples","createOrValidateSamples","sample"]},{"typeName":"Query","fieldNames":["sample","samples"]}],"childNodes":[{"typeName":"CreateSamplesResponse","fieldNames":["success","samples","errors"]},{"typeName":"ErrorDetails","fieldNames":["type","location","message"]},{"typeName":"PageInfo","fieldNames":["startCursor","endCursor","hasPreviousPage","hasNextPage"]},{"typeName":"Sample","fieldNames":["id","name","data","createdTime","updatedTime","dataSchemaUrl","parents","children","events","dataSchema"]},{"typeName":"SampleConnection","fieldNames":["edges","pageInfo"]},{"typeName":"SampleEdge","fieldNames":["cursor","node"]},{"typeName":"SampleEvent","fieldNames":["id","timestamp","description"]},{"typeName":"SampleEventConnection","fieldNames":["edges","pageInfo"]},{"typeName":"SampleEventEdge","fieldNames":["cursor","node"]},{"typeName":"SampleMutations","fieldNames":["sampleId","linkInstrumentSessionToSample","addSampleEvent"]},{"typeName":"SampleValidationError","fieldNames":["index","errors"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://sample-information.diamond.ac.uk/api/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"https://sample-information.diamond.ac.uk/api/graphql"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"input AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n proposalNumber: Int!\n instrumentSessionNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n\n \"\"\"A human readable error message.\"\"\"\n message: String!\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Mutation {\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n sample(sampleId: UUID!): SampleMutations\n}\n\ntype PageInfo {\n startCursor: String\n endCursor: String\n hasPreviousPage: Boolean!\n hasNextPage: Boolean!\n}\n\ntype Query {\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(proposalNumber: Int!, instrumentSessionNumber: Int!, first: Int!, filter: SampleFilterInput! = {}, before: String = null, after: String = null, last: Int = null, orderBy: SampleOrder! = {}): SampleConnection!\n}\n\ntype Sample {\n id: UUID!\n name: String!\n data: JSON!\n createdTime: DateTime!\n updatedTime: DateTime!\n dataSchemaUrl: String!\n\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n\n \"\"\"Samples derived from this sample\"\"\"\n children(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n\n \"\"\"Events linked to this sample\"\"\"\n events(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleEventConnection!\n\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n id: UUID!\n timestamp: DateTime!\n description: String!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Name of the sample\"\"\"\n name: String!\n\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n}\n\ninput SampleInLegacy {\n name: String!\n data: JSON!\n dataSchemaUrl: String!\n parentIds: [Int!] = null\n children: [SampleInLegacy!] = null\n}\n\ntype SampleMutations {\n sampleId: UUID!\n linkInstrumentSessionToSample(proposalNumber: Int!, instrumentSessionNumber: Int!): Void\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n}\n\ninput SampleOrder {\n name: SortingOrder = null\n createdTime: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void\n"},"upstreamSchema":{"key":"705aec083991f77f3c89aeff197c6cc302953ec1"}},"requestTimeoutSeconds":"10","id":"2"}],"fieldConfigurations":[{"typeName":"Mutation","fieldName":"submitWorkflowTemplate","argumentsConfiguration":[{"name":"name","sourceType":"FIELD_ARGUMENT"},{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"parameters","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"instrumentSession","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"createSamples","argumentsConfiguration":[{"name":"input","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"createOrValidateSamples","argumentsConfiguration":[{"name":"input","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"sample","argumentsConfiguration":[{"name":"sampleId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflow","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflows","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"cursor","sourceType":"FIELD_ARGUMENT"},{"name":"limit","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflowTemplate","argumentsConfiguration":[{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflowTemplates","argumentsConfiguration":[{"name":"cursor","sourceType":"FIELD_ARGUMENT"},{"name":"limit","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"proposal","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"proposals","argumentsConfiguration":[{"name":"proposalCategory","sourceType":"FIELD_ARGUMENT"},{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrumentSession","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrumentSessions","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"proposalCategory","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrument","argumentsConfiguration":[{"name":"instrumentName","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instruments","argumentsConfiguration":[{"name":"scienceGroup","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"account","argumentsConfiguration":[{"name":"username","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"sample","argumentsConfiguration":[{"name":"sampleId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"samples","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"},{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"},{"name":"orderBy","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Subscription","fieldName":"logs","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"workflowName","sourceType":"FIELD_ARGUMENT"},{"name":"taskId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Subscription","fieldName":"workflow","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"parents","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"children","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"events","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"SampleMutations","fieldName":"linkInstrumentSessionToSample","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"SampleMutations","fieldName":"addSampleEvent","argumentsConfiguration":[{"name":"sampleEvent","sourceType":"FIELD_ARGUMENT"}]}],"graphqlSchema":"schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ntype Artifact {\n \"\"\"The file name of the artifact\"\"\"\n name: String!\n \"\"\"The download URL for the artifact\"\"\"\n url: Url!\n \"\"\"The MIME type of the artifact data\"\"\"\n mimeType: String!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON\n\n\"\"\"A scalar that can represent any JSON Object value.\"\"\"\nscalar JSONObject\n\n\"\"\"A single log line streamed from a pod\"\"\"\ntype LogEntry {\n \"\"\"The log line content\"\"\"\n content: String!\n \"\"\"The name of the pod producing the log\"\"\"\n podName: String!\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Mutation {\n submitWorkflowTemplate(name: String!, visit: VisitInput!, parameters: JSON!): Workflow!\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSessionMutations\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n sample(sampleId: UUID!): SampleMutations\n}\n\n\"\"\"Information about pagination in a connection\"\"\"\ntype PageInfo {\n \"\"\"When paginating backwards, are there more items?\"\"\"\n hasPreviousPage: Boolean!\n \"\"\"When paginating forwards, are there more items?\"\"\"\n hasNextPage: Boolean!\n \"\"\"When paginating backwards, the cursor to continue.\"\"\"\n startCursor: String\n \"\"\"When paginating forwards, the cursor to continue.\"\"\"\n endCursor: String\n}\n\n\"\"\"The root query of the service\"\"\"\ntype Query {\n \"\"\"Get a single [`Workflow`] by proposal, visit, and name\"\"\"\n workflow(visit: VisitInput!, name: String!): Workflow!\n workflows(visit: VisitInput!, cursor: String, limit: Int, filter: WorkflowFilter): WorkflowConnection!\n workflowTemplate(name: String!): WorkflowTemplate!\n workflowTemplates(cursor: String, limit: Int, filter: WorkflowTemplatesFilter): WorkflowTemplateConnection!\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n \"\"\"Get a list of proposals\"\"\"\n proposals(proposalCategory: String = null, first: Int = null, last: Int = null, after: String = null, before: String = null): ProposalConnection!\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSession\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalNumber: Int = null, proposalCategory: String = null): [InstrumentSession!]\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(proposalNumber: Int!, instrumentSessionNumber: Int!, first: Int!, filter: SampleFilterInput! = {schemaUrl: null, createdTime: null, updatedTime: null, name: null}, before: String = null, after: String = null, last: Int = null, orderBy: SampleOrder! = {name: null, createdTime: null, updatedTime: null}): SampleConnection!\n}\n\n\"\"\"Supported DLS science groups\"\"\"\nenum ScienceGroup {\n \"\"\"Macromolecular Crystallography\"\"\"\n MX\n \"\"\"Workflows Examples\"\"\"\n EXAMPLES\n \"\"\"Magnetic Materials\"\"\"\n MAGNETIC_MATERIALS\n \"\"\"Soft Condensed Matter\"\"\"\n CONDENSED_MATTER\n \"\"\"Imaging and Microscopy\"\"\"\n IMAGING\n \"\"\"Biological Cryo-Imaging\"\"\"\n BIO_CRYO_IMAGING\n \"\"\"Structures and Surfaces\"\"\"\n SURFACES\n \"\"\"Crystallography\"\"\"\n CRYSTALLOGRAPHY\n \"\"\"Spectroscopy\"\"\"\n SPECTROSCOPY\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Subscription {\n \"\"\"Processing to subscribe to logs for a single pod of a workflow\"\"\"\n logs(visit: VisitInput!, workflowName: String!, taskId: String!): LogEntry!\n \"\"\"Processing to subscribe to data for all workflows in a session\"\"\"\n workflow(visit: VisitInput!, name: String!): Workflow!\n}\n\ntype Task {\n \"\"\"Unique name of the task\"\"\"\n id: String!\n \"\"\"Display name of the task\"\"\"\n name: String!\n \"\"\"Current status of a task\"\"\"\n status: TaskStatus!\n \"\"\"Parent of a task\"\"\"\n depends: [String!]!\n \"\"\"Children of a task\"\"\"\n dependencies: [String!]!\n \"\"\"Artifacts produced by a task\"\"\"\n artifacts: [Artifact!]!\n \"\"\"Node type - Pod, DAG, etc\"\"\"\n stepType: String!\n \"\"\"Start time for a task on a workflow\"\"\"\n startTime: DateTime\n \"\"\"End time for a task on a workflow\"\"\"\n endTime: DateTime\n \"\"\"\n A human readable message indicating details about why this step is in this condition\n \"\"\"\n message: String\n}\n\nenum TaskStatus {\n PENDING\n RUNNING\n SUCCEEDED\n SKIPPED\n FAILED\n ERROR\n OMITTED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ntype Visit {\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n \"\"\"Session visit Number\"\"\"\n number: Int!\n}\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ninput VisitInput {\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n \"\"\"Session visit Number\"\"\"\n number: Int!\n}\n\ntype Workflow {\n \"\"\"The name given to the workflow, unique within a given visit\"\"\"\n name: String!\n \"\"\"The visit the Workflow was run against\"\"\"\n visit: Visit!\n \"\"\"The current status of the workflow\"\"\"\n status: WorkflowStatus\n \"\"\"The top-level workflow parameters\"\"\"\n parameters: JSONObject\n \"\"\"The name of the template used to run the workflow\"\"\"\n templateRef: String\n \"\"\"The workflow creator\"\"\"\n creator: WorkflowCreator!\n}\n\ntype WorkflowConnection {\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo!\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowEdge!]!\n \"\"\"A list of nodes.\"\"\"\n nodes: [Workflow!]!\n}\n\n\"\"\"Information about the creator of a workflow.\"\"\"\ntype WorkflowCreator {\n \"\"\"\n An identifier unique to the creator of the workflow.\n Typically this is the creator's Fed-ID.\n \"\"\"\n creatorId: String!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowEdge {\n \"\"\"The item at the end of the edge\"\"\"\n node: Workflow!\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String!\n}\n\n\"\"\"All tasks in the workflow have errored\"\"\"\ntype WorkflowErroredStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All tasks in the workflow have failed\"\"\"\ntype WorkflowFailedStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All the supported Workflows filters\"\"\"\ninput WorkflowFilter {\n \"\"\"The status field for a workflow\"\"\"\n workflowStatusFilter: WorkflowStatusFilter\n \"\"\"The fedid of the user who created the workflow\"\"\"\n creator: Creator\n \"\"\"The name of the workflow template\"\"\"\n template: Template\n}\n\ntype WorkflowPendingStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n}\n\ntype WorkflowRunningStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"The status of a workflow\"\"\"\nunion WorkflowStatus = WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus | WorkflowFailedStatus | WorkflowErroredStatus\n\n\"\"\"Represents workflow status filters\"\"\"\ninput WorkflowStatusFilter {\n pending: Boolean! = false\n running: Boolean! = false\n succeeded: Boolean! = false\n failed: Boolean! = false\n error: Boolean! = false\n}\n\n\"\"\"All tasks in the workflow have succeded\"\"\"\ntype WorkflowSucceededStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n \"\"\"The name given to the workflow template, globally unique\"\"\"\n name: String!\n \"\"\"The group who maintains the workflow template\"\"\"\n maintainer: String!\n \"\"\"A human readable title for the workflow template\"\"\"\n title: String\n \"\"\"A human readable description of the workflow which is created\"\"\"\n description: String\n \"\"\"The repository storing the code associated with this template.\"\"\"\n repository: String\n \"\"\"A JSON Schema describing the arguments of a Workflow Template\"\"\"\n arguments: JSON!\n \"\"\"\n A JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n \"\"\"\n uiSchema: JSON\n}\n\ntype WorkflowTemplateConnection {\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo!\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowTemplateEdge!]!\n \"\"\"A list of nodes.\"\"\"\n nodes: [WorkflowTemplate!]!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowTemplateEdge {\n \"\"\"The item at the end of the edge\"\"\"\n node: WorkflowTemplate!\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String!\n}\n\n\"\"\"Supported label filters for ClusterWorkflowTemplates\"\"\"\ninput WorkflowTemplatesFilter {\n \"\"\"The science group owning the template eg imaging\"\"\"\n scienceGroup: [ScienceGroup!]\n}\n\ntype Account {\n accountId: Int!\n username: String!\n emailAddress: String\n title: String\n givenName: String\n familyName: String\n type: AccountType!\n state: AccountState!\n proposalRoles: [ProposalAccount!]!\n instrumentSessionRoles: [InstrumentSessionRole!]!\n}\n\nenum AccountState {\n enabled\n disabled\n}\n\nenum AccountType {\n user\n staff\n functional\n}\n\ntype Instrument {\n name: String!\n scienceGroup: String\n description: String\n proposals: [Proposal!]!\n instrumentSessions: [InstrumentSession!]!\n}\n\ntype InstrumentSession {\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n startTime: DateTime\n endTime: DateTime\n type: String\n state: String\n riskRating: String\n proposal: Proposal\n instrument: Instrument!\n roles: [InstrumentSessionRole!]!\n}\n\ntype InstrumentSessionMutations {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n instrumentSession: InstrumentSession!\n account: Account!\n role: String!\n onSite: Boolean!\n}\n\ntype Proposal {\n proposalNumber: Int!\n proposalCategory: String\n title: String\n summary: String\n state: ProposalState!\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n roles: [ProposalAccount!]!\n}\n\ntype ProposalAccount {\n proposal: Proposal!\n account: Account!\n role: String!\n}\n\ntype ProposalConnection {\n edges: [ProposalEdge!]!\n pageInfo: PageInfo!\n}\n\ntype ProposalEdge {\n cursor: String!\n node: Proposal!\n}\n\nenum ProposalState {\n Open\n Closed\n Cancelled\n}\n\ninput AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n proposalNumber: Int!\n instrumentSessionNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n}\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n \"\"\"A human readable error message.\"\"\"\n message: String!\n}\n\ntype Sample {\n id: UUID!\n name: String!\n data: JSON!\n createdTime: DateTime!\n updatedTime: DateTime!\n dataSchemaUrl: String!\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n \"\"\"Samples derived from this sample\"\"\"\n children(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n \"\"\"Events linked to this sample\"\"\"\n events(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleEventConnection!\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n id: UUID!\n timestamp: DateTime!\n description: String!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Name of the sample\"\"\"\n name: String!\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n}\n\ninput SampleInLegacy {\n name: String!\n data: JSON!\n dataSchemaUrl: String!\n parentIds: [Int!] = null\n children: [SampleInLegacy!] = null\n}\n\ntype SampleMutations {\n sampleId: UUID!\n linkInstrumentSessionToSample(proposalNumber: Int!, instrumentSessionNumber: Int!): Void\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n}\n\ninput SampleOrder {\n name: SortingOrder = null\n createdTime: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void","stringStorage":{"399ecb62e2d8de68392ee3dfb8e088d1edc68f46":"schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ndirective @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA\n\ndirective @shareable repeatable on FIELD_DEFINITION | OBJECT\n\ntype Artifact {\n \"\"\"The MIME type of the artifact data\"\"\"\n mimeType: String!\n \"\"\"The file name of the artifact\"\"\"\n name: String!\n \"\"\"The download URL for the artifact\"\"\"\n url: Url!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"A scalar that can represent any JSON value.\"\"\"\nscalar JSON\n\n\"\"\"A scalar that can represent any JSON Object value.\"\"\"\nscalar JSONObject\n\n\"\"\"A single log line streamed from a pod\"\"\"\ntype LogEntry {\n \"\"\"The log line content\"\"\"\n content: String!\n \"\"\"The name of the pod producing the log\"\"\"\n podName: String!\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Mutation {\n submitWorkflowTemplate(name: String!, parameters: JSON!, visit: VisitInput!): Workflow!\n}\n\n\"\"\"Information about pagination in a connection\"\"\"\ntype PageInfo {\n \"\"\"When paginating forwards, the cursor to continue.\"\"\"\n endCursor: String @shareable\n \"\"\"When paginating forwards, are there more items?\"\"\"\n hasNextPage: Boolean! @shareable\n \"\"\"When paginating backwards, are there more items?\"\"\"\n hasPreviousPage: Boolean! @shareable\n \"\"\"When paginating backwards, the cursor to continue.\"\"\"\n startCursor: String @shareable\n}\n\n\"\"\"The root query of the service\"\"\"\ntype Query {\n \"\"\"Get a single [`Workflow`] by proposal, visit, and name\"\"\"\n workflow(name: String!, visit: VisitInput!): Workflow!\n workflowTemplate(name: String!): WorkflowTemplate!\n workflowTemplates(cursor: String, filter: WorkflowTemplatesFilter, limit: Int): WorkflowTemplateConnection!\n workflows(cursor: String, filter: WorkflowFilter, limit: Int, visit: VisitInput!): WorkflowConnection!\n}\n\n\"\"\"Supported DLS science groups\"\"\"\nenum ScienceGroup {\n \"\"\"Biological Cryo-Imaging\"\"\"\n BIO_CRYO_IMAGING\n \"\"\"Soft Condensed Matter\"\"\"\n CONDENSED_MATTER\n \"\"\"Crystallography\"\"\"\n CRYSTALLOGRAPHY\n \"\"\"Workflows Examples\"\"\"\n EXAMPLES\n \"\"\"Imaging and Microscopy\"\"\"\n IMAGING\n \"\"\"Magnetic Materials\"\"\"\n MAGNETIC_MATERIALS\n \"\"\"Macromolecular Crystallography\"\"\"\n MX\n \"\"\"Spectroscopy\"\"\"\n SPECTROSCOPY\n \"\"\"Structures and Surfaces\"\"\"\n SURFACES\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Subscription {\n \"\"\"Processing to subscribe to logs for a single pod of a workflow\"\"\"\n logs(taskId: String!, visit: VisitInput!, workflowName: String!): LogEntry!\n \"\"\"Processing to subscribe to data for all workflows in a session\"\"\"\n workflow(name: String!, visit: VisitInput!): Workflow!\n}\n\ntype Task {\n \"\"\"Artifacts produced by a task\"\"\"\n artifacts: [Artifact!]!\n \"\"\"Children of a task\"\"\"\n dependencies: [String!]!\n \"\"\"Parent of a task\"\"\"\n depends: [String!]!\n \"\"\"End time for a task on a workflow\"\"\"\n endTime: DateTime\n \"\"\"Unique name of the task\"\"\"\n id: String!\n \"\"\"\n A human readable message indicating details about why this step is in this condition\n \"\"\"\n message: String\n \"\"\"Display name of the task\"\"\"\n name: String!\n \"\"\"Start time for a task on a workflow\"\"\"\n startTime: DateTime\n \"\"\"Current status of a task\"\"\"\n status: TaskStatus!\n \"\"\"Node type - Pod, DAG, etc\"\"\"\n stepType: String!\n}\n\nenum TaskStatus {\n ERROR\n FAILED\n OMITTED\n PENDING\n RUNNING\n SKIPPED\n SUCCEEDED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ntype Visit {\n \"\"\"Session visit Number\"\"\"\n number: Int!\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n}\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ninput VisitInput {\n \"\"\"Session visit Number\"\"\"\n number: Int!\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n}\n\ntype Workflow {\n \"\"\"The workflow creator\"\"\"\n creator: WorkflowCreator!\n \"\"\"The name given to the workflow, unique within a given visit\"\"\"\n name: String!\n \"\"\"The top-level workflow parameters\"\"\"\n parameters: JSONObject\n \"\"\"The current status of the workflow\"\"\"\n status: WorkflowStatus\n \"\"\"The name of the template used to run the workflow\"\"\"\n templateRef: String\n \"\"\"The visit the Workflow was run against\"\"\"\n visit: Visit!\n}\n\ntype WorkflowConnection {\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowEdge!]! @shareable\n \"\"\"A list of nodes.\"\"\"\n nodes: [Workflow!]! @shareable\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo! @shareable\n}\n\n\"\"\"Information about the creator of a workflow.\"\"\"\ntype WorkflowCreator {\n \"\"\"\n An identifier unique to the creator of the workflow.\n Typically this is the creator's Fed-ID.\n \"\"\"\n creatorId: String!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowEdge {\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String! @shareable\n \"\"\"The item at the end of the edge\"\"\"\n node: Workflow! @shareable\n}\n\n\"\"\"All tasks in the workflow have errored\"\"\"\ntype WorkflowErroredStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All tasks in the workflow have failed\"\"\"\ntype WorkflowFailedStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All the supported Workflows filters\"\"\"\ninput WorkflowFilter {\n \"\"\"The fedid of the user who created the workflow\"\"\"\n creator: Creator\n \"\"\"The name of the workflow template\"\"\"\n template: Template\n \"\"\"The status field for a workflow\"\"\"\n workflowStatusFilter: WorkflowStatusFilter\n}\n\ntype WorkflowPendingStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n}\n\ntype WorkflowRunningStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"The status of a workflow\"\"\"\nunion WorkflowStatus = WorkflowErroredStatus | WorkflowFailedStatus | WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus\n\n\"\"\"Represents workflow status filters\"\"\"\ninput WorkflowStatusFilter {\n error: Boolean! = false\n failed: Boolean! = false\n pending: Boolean! = false\n running: Boolean! = false\n succeeded: Boolean! = false\n}\n\n\"\"\"All tasks in the workflow have succeded\"\"\"\ntype WorkflowSucceededStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n \"\"\"A JSON Schema describing the arguments of a Workflow Template\"\"\"\n arguments: JSON!\n \"\"\"A human readable description of the workflow which is created\"\"\"\n description: String\n \"\"\"The group who maintains the workflow template\"\"\"\n maintainer: String!\n \"\"\"The name given to the workflow template, globally unique\"\"\"\n name: String!\n \"\"\"The repository storing the code associated with this template.\"\"\"\n repository: String\n \"\"\"A human readable title for the workflow template\"\"\"\n title: String\n \"\"\"\n A JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n \"\"\"\n uiSchema: JSON\n}\n\ntype WorkflowTemplateConnection {\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowTemplateEdge!]! @shareable\n \"\"\"A list of nodes.\"\"\"\n nodes: [WorkflowTemplate!]! @shareable\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo! @shareable\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowTemplateEdge {\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String! @shareable\n \"\"\"The item at the end of the edge\"\"\"\n node: WorkflowTemplate! @shareable\n}\n\n\"\"\"Supported label filters for ClusterWorkflowTemplates\"\"\"\ninput WorkflowTemplatesFilter {\n \"\"\"The science group owning the template eg imaging\"\"\"\n scienceGroup: [ScienceGroup!]\n}\n\nscalar link__Import\n\nenum link__Purpose {\n EXECUTION\n SECURITY\n}","636412ec8e6e8e278df46ce7da59047a6182733c":"schema @link(url: \"https://specs.apollo.dev/federation/v2.7\", import: [\"@key\", \"@shareable\"]) {\n query: Query\n mutation: Mutation\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ndirective @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA\n\ndirective @shareable repeatable on FIELD_DEFINITION | OBJECT\n\ntype Account {\n accountId: Int!\n emailAddress: String\n familyName: String\n givenName: String\n instrumentSessionRoles: [InstrumentSessionRole!]!\n proposalRoles: [ProposalAccount!]!\n state: AccountState!\n title: String\n type: AccountType!\n username: String!\n}\n\nenum AccountState {\n disabled\n enabled\n}\n\nenum AccountType {\n functional\n staff\n user\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ntype Instrument {\n description: String\n instrumentSessions: [InstrumentSession!]!\n name: String!\n proposals: [Proposal!]!\n scienceGroup: String\n}\n\ntype InstrumentSession @key(fields: \"instrumentSessionNumber proposal {proposalNumber}\") {\n endTime: DateTime\n instrument: Instrument!\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n proposal: Proposal\n riskRating: String\n roles: [InstrumentSessionRole!]!\n startTime: DateTime\n state: String\n type: String\n}\n\ntype InstrumentSessionMutations @key(fields: \"instrumentSessionNumber proposalNumber\") {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n account: Account!\n instrumentSession: InstrumentSession!\n onSite: Boolean!\n role: String!\n}\n\ntype Mutation {\n instrumentSession(instrumentSessionNumber: Int!, proposalNumber: Int!): InstrumentSessionMutations\n}\n\ntype PageInfo {\n endCursor: String @shareable\n hasNextPage: Boolean! @shareable\n hasPreviousPage: Boolean! @shareable\n startCursor: String @shareable\n}\n\ntype Proposal @key(fields: \"proposalNumber\") {\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n proposalCategory: String\n proposalNumber: Int!\n roles: [ProposalAccount!]!\n state: ProposalState!\n summary: String\n title: String\n}\n\ntype ProposalAccount {\n account: Account!\n proposal: Proposal!\n role: String!\n}\n\ntype ProposalConnection {\n edges: [ProposalEdge!]! @shareable\n pageInfo: PageInfo! @shareable\n}\n\ntype ProposalEdge {\n cursor: String! @shareable\n node: Proposal! @shareable\n}\n\nenum ProposalState {\n Cancelled\n Closed\n Open\n}\n\ntype Query {\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(instrumentSessionNumber: Int!, proposalNumber: Int!): InstrumentSession\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalCategory: String = null, proposalNumber: Int = null): [InstrumentSession!]\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n \"\"\"Get a list of proposals\"\"\"\n proposals(after: String = null, before: String = null, first: Int = null, last: Int = null, proposalCategory: String = null): ProposalConnection!\n}\n\nscalar link__Import\n\nenum link__Purpose {\n EXECUTION\n SECURITY\n}\n\nscalar openfed__FieldSet","705aec083991f77f3c89aeff197c6cc302953ec1":"schema {\n query: Query\n mutation: Mutation\n}\n\ninput AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n \"\"\"A human readable error message.\"\"\"\n message: String!\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Mutation {\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n sample(sampleId: UUID!): SampleMutations\n}\n\ntype PageInfo {\n endCursor: String\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n startCursor: String\n}\n\ntype Query {\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(after: String = null, before: String = null, filter: SampleFilterInput! = {createdTime: null, name: null, schemaUrl: null, updatedTime: null}, first: Int!, instrumentSessionNumber: Int!, last: Int = null, orderBy: SampleOrder! = {createdTime: null, name: null, updatedTime: null}, proposalNumber: Int!): SampleConnection!\n}\n\ntype Sample {\n \"\"\"Samples derived from this sample\"\"\"\n children(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleConnection!\n createdTime: DateTime!\n data: JSON!\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n dataSchemaUrl: String!\n \"\"\"Events linked to this sample\"\"\"\n events(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleEventConnection!\n id: UUID!\n name: String!\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleConnection!\n updatedTime: DateTime!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n description: String!\n id: UUID!\n timestamp: DateTime!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n \"\"\"Name of the sample\"\"\"\n name: String!\n}\n\ninput SampleInLegacy {\n children: [SampleInLegacy!] = null\n data: JSON!\n dataSchemaUrl: String!\n name: String!\n parentIds: [Int!] = null\n}\n\ntype SampleMutations {\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n linkInstrumentSessionToSample(instrumentSessionNumber: Int!, proposalNumber: Int!): Void\n sampleId: UUID!\n}\n\ninput SampleOrder {\n createdTime: SortingOrder = null\n name: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void"}},"version":"00000000-0000-0000-0000-000000000000","subgraphs":[{"id":"0","name":"workflows","routingUrl":"https://workflows.diamond.ac.uk/graphql"},{"id":"1","name":"instrument_sessions","routingUrl":"https://instrument-sessions.diamond.ac.uk/api/graphql"},{"id":"2","name":"samples","routingUrl":"https://sample-information.diamond.ac.uk/api/graphql"}],"compatibilityVersion":"1:0.51.0"} \ No newline at end of file diff --git a/charts/graph/templates/router-execution-config.json b/charts/graph/templates/router-execution-config.json new file mode 100644 index 0000000..c1cfdd7 --- /dev/null +++ b/charts/graph/templates/router-execution-config.json @@ -0,0 +1 @@ +{"engineConfig":{"defaultFlushInterval":"500","datasourceConfigurations":[{"kind":"GRAPHQL","rootNodes":[{"typeName":"Mutation","fieldNames":["submitWorkflowTemplate"]},{"typeName":"Query","fieldNames":["workflow","workflows","workflowTemplate","workflowTemplates"]},{"typeName":"Subscription","fieldNames":["logs","workflow"]}],"childNodes":[{"typeName":"Artifact","fieldNames":["name","url","mimeType"]},{"typeName":"LogEntry","fieldNames":["content","podName"]},{"typeName":"PageInfo","fieldNames":["hasPreviousPage","hasNextPage","startCursor","endCursor"]},{"typeName":"Task","fieldNames":["id","name","status","depends","dependencies","artifacts","stepType","startTime","endTime","message"]},{"typeName":"Visit","fieldNames":["proposalCode","proposalNumber","number"]},{"typeName":"Workflow","fieldNames":["name","visit","status","parameters","templateRef","creator"]},{"typeName":"WorkflowConnection","fieldNames":["pageInfo","edges","nodes"]},{"typeName":"WorkflowCreator","fieldNames":["creatorId"]},{"typeName":"WorkflowEdge","fieldNames":["node","cursor"]},{"typeName":"WorkflowErroredStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowFailedStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowPendingStatus","fieldNames":["message"]},{"typeName":"WorkflowRunningStatus","fieldNames":["startTime","message","tasks"]},{"typeName":"WorkflowSucceededStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowTemplate","fieldNames":["name","maintainer","title","description","repository","arguments","uiSchema"]},{"typeName":"WorkflowTemplateConnection","fieldNames":["pageInfo","edges","nodes"]},{"typeName":"WorkflowTemplateEdge","fieldNames":["node","cursor"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://workflows.diamond.ac.uk/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"wss://workflows.diamond.ac.uk/graphql/ws"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"type Artifact {\n\t\"\"\"\n\tThe file name of the artifact\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe download URL for the artifact\n\t\"\"\"\n\turl: Url!\n\t\"\"\"\n\tThe MIME type of the artifact data\n\t\"\"\"\n\tmimeType: String!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"\nA scalar that can represent any JSON value.\n\"\"\"\nscalar JSON\n\n\"\"\"\nA scalar that can represent any JSON Object value.\n\"\"\"\nscalar JSONObject\n\n\"\"\"\nA single log line streamed from a pod\n\"\"\"\ntype LogEntry {\n\t\"\"\"\n\tThe log line content\n\t\"\"\"\n\tcontent: String!\n\t\"\"\"\n\tThe name of the pod producing the log\n\t\"\"\"\n\tpodName: String!\n}\n\n\"\"\"\nThe root mutation of the service\n\"\"\"\ntype Mutation {\n\tsubmitWorkflowTemplate(name: String!, visit: VisitInput!, parameters: JSON!): Workflow!\n}\n\n\"\"\"\nInformation about pagination in a connection\n\"\"\"\ntype PageInfo @shareable {\n\t\"\"\"\n\tWhen paginating backwards, are there more items?\n\t\"\"\"\n\thasPreviousPage: Boolean!\n\t\"\"\"\n\tWhen paginating forwards, are there more items?\n\t\"\"\"\n\thasNextPage: Boolean!\n\t\"\"\"\n\tWhen paginating backwards, the cursor to continue.\n\t\"\"\"\n\tstartCursor: String\n\t\"\"\"\n\tWhen paginating forwards, the cursor to continue.\n\t\"\"\"\n\tendCursor: String\n}\n\n\"\"\"\nThe root query of the service\n\"\"\"\ntype Query {\n\t\"\"\"\n\tGet a single [`Workflow`] by proposal, visit, and name\n\t\"\"\"\n\tworkflow(visit: VisitInput!, name: String!): Workflow!\n\tworkflows(visit: VisitInput!, cursor: String, limit: Int, filter: WorkflowFilter): WorkflowConnection!\n\tworkflowTemplate(name: String!): WorkflowTemplate!\n\tworkflowTemplates(cursor: String, limit: Int, filter: WorkflowTemplatesFilter): WorkflowTemplateConnection!\n}\n\n\"\"\"\nSupported DLS science groups\n\"\"\"\nenum ScienceGroup {\n\t\"\"\"\n\tMacromolecular Crystallography\n\t\"\"\"\n\tMX\n\t\"\"\"\n\tWorkflows Examples\n\t\"\"\"\n\tEXAMPLES\n\t\"\"\"\n\tMagnetic Materials\n\t\"\"\"\n\tMAGNETIC_MATERIALS\n\t\"\"\"\n\tSoft Condensed Matter\n\t\"\"\"\n\tCONDENSED_MATTER\n\t\"\"\"\n\tImaging and Microscopy\n\t\"\"\"\n\tIMAGING\n\t\"\"\"\n\tBiological Cryo-Imaging\n\t\"\"\"\n\tBIO_CRYO_IMAGING\n\t\"\"\"\n\tStructures and Surfaces\n\t\"\"\"\n\tSURFACES\n\t\"\"\"\n\tCrystallography\n\t\"\"\"\n\tCRYSTALLOGRAPHY\n\t\"\"\"\n\tSpectroscopy\n\t\"\"\"\n\tSPECTROSCOPY\n}\n\n\"\"\"\nThe root mutation of the service\n\"\"\"\ntype Subscription {\n\t\"\"\"\n\tProcessing to subscribe to logs for a single pod of a workflow\n\t\"\"\"\n\tlogs(visit: VisitInput!, workflowName: String!, taskId: String!): LogEntry!\n\t\"\"\"\n\tProcessing to subscribe to data for all workflows in a session\n\t\"\"\"\n\tworkflow(visit: VisitInput!, name: String!): Workflow!\n}\n\ntype Task {\n\t\"\"\"\n\tUnique name of the task\n\t\"\"\"\n\tid: String!\n\t\"\"\"\n\tDisplay name of the task\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tCurrent status of a task\n\t\"\"\"\n\tstatus: TaskStatus!\n\t\"\"\"\n\tParent of a task\n\t\"\"\"\n\tdepends: [String!]!\n\t\"\"\"\n\tChildren of a task\n\t\"\"\"\n\tdependencies: [String!]!\n\t\"\"\"\n\tArtifacts produced by a task\n\t\"\"\"\n\tartifacts: [Artifact!]!\n\t\"\"\"\n\tNode type - Pod, DAG, etc\n\t\"\"\"\n\tstepType: String!\n\t\"\"\"\n\tStart time for a task on a workflow\n\t\"\"\"\n\tstartTime: DateTime\n\t\"\"\"\n\tEnd time for a task on a workflow\n\t\"\"\"\n\tendTime: DateTime\n\t\"\"\"\n\tA human readable message indicating details about why this step is in this condition\n\t\"\"\"\n\tmessage: String\n}\n\nenum TaskStatus {\n\tPENDING\n\tRUNNING\n\tSUCCEEDED\n\tSKIPPED\n\tFAILED\n\tERROR\n\tOMITTED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"\nA visit to an instrument as part of a session\n\"\"\"\ntype Visit {\n\t\"\"\"\n\tProject Proposal Code\n\t\"\"\"\n\tproposalCode: String!\n\t\"\"\"\n\tProject Proposal Number\n\t\"\"\"\n\tproposalNumber: Int!\n\t\"\"\"\n\tSession visit Number\n\t\"\"\"\n\tnumber: Int!\n}\n\n\"\"\"\nA visit to an instrument as part of a session\n\"\"\"\ninput VisitInput {\n\t\"\"\"\n\tProject Proposal Code\n\t\"\"\"\n\tproposalCode: String!\n\t\"\"\"\n\tProject Proposal Number\n\t\"\"\"\n\tproposalNumber: Int!\n\t\"\"\"\n\tSession visit Number\n\t\"\"\"\n\tnumber: Int!\n}\n\ntype Workflow {\n\t\"\"\"\n\tThe name given to the workflow, unique within a given visit\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe visit the Workflow was run against\n\t\"\"\"\n\tvisit: Visit!\n\t\"\"\"\n\tThe current status of the workflow\n\t\"\"\"\n\tstatus: WorkflowStatus\n\t\"\"\"\n\tThe top-level workflow parameters\n\t\"\"\"\n\tparameters: JSONObject\n\t\"\"\"\n\tThe name of the template used to run the workflow\n\t\"\"\"\n\ttemplateRef: String\n\t\"\"\"\n\tThe workflow creator\n\t\"\"\"\n\tcreator: WorkflowCreator!\n}\n\ntype WorkflowConnection @shareable {\n\t\"\"\"\n\tInformation to aid in pagination.\n\t\"\"\"\n\tpageInfo: PageInfo!\n\t\"\"\"\n\tA list of edges.\n\t\"\"\"\n\tedges: [WorkflowEdge!]!\n\t\"\"\"\n\tA list of nodes.\n\t\"\"\"\n\tnodes: [Workflow!]!\n}\n\n\"\"\"\nInformation about the creator of a workflow.\n\"\"\"\ntype WorkflowCreator {\n\t\"\"\"\n\tAn identifier unique to the creator of the workflow.\n\tTypically this is the creator's Fed-ID.\n\t\"\"\"\n\tcreatorId: String!\n}\n\n\"\"\"\nAn edge in a connection.\n\"\"\"\ntype WorkflowEdge @shareable {\n\t\"\"\"\n\tThe item at the end of the edge\n\t\"\"\"\n\tnode: Workflow!\n\t\"\"\"\n\tA cursor for use in pagination\n\t\"\"\"\n\tcursor: String!\n}\n\n\"\"\"\nAll tasks in the workflow have errored\n\"\"\"\ntype WorkflowErroredStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nAll tasks in the workflow have failed\n\"\"\"\ntype WorkflowFailedStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nAll the supported Workflows filters\n\"\"\"\ninput WorkflowFilter {\n\t\"\"\"\n\tThe status field for a workflow\n\t\"\"\"\n\tworkflowStatusFilter: WorkflowStatusFilter\n\t\"\"\"\n\tThe fedid of the user who created the workflow\n\t\"\"\"\n\tcreator: Creator\n\t\"\"\"\n\tThe name of the workflow template\n\t\"\"\"\n\ttemplate: Template\n}\n\ntype WorkflowPendingStatus {\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n}\n\ntype WorkflowRunningStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nThe status of a workflow\n\"\"\"\nunion WorkflowStatus = WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus | WorkflowFailedStatus | WorkflowErroredStatus\n\n\"\"\"\nRepresents workflow status filters\n\"\"\"\ninput WorkflowStatusFilter {\n\tpending: Boolean! = false\n\trunning: Boolean! = false\n\tsucceeded: Boolean! = false\n\tfailed: Boolean! = false\n\terror: Boolean! = false\n}\n\n\"\"\"\nAll tasks in the workflow have succeded\n\"\"\"\ntype WorkflowSucceededStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n\t\"\"\"\n\tThe name given to the workflow template, globally unique\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe group who maintains the workflow template\n\t\"\"\"\n\tmaintainer: String!\n\t\"\"\"\n\tA human readable title for the workflow template\n\t\"\"\"\n\ttitle: String\n\t\"\"\"\n\tA human readable description of the workflow which is created\n\t\"\"\"\n\tdescription: String\n\t\"\"\"\n\tThe repository storing the code associated with this template.\n\t\"\"\"\n\trepository: String\n\t\"\"\"\n\tA JSON Schema describing the arguments of a Workflow Template\n\t\"\"\"\n\targuments: JSON!\n\t\"\"\"\n\tA JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n\t\"\"\"\n\tuiSchema: JSON\n}\n\ntype WorkflowTemplateConnection @shareable {\n\t\"\"\"\n\tInformation to aid in pagination.\n\t\"\"\"\n\tpageInfo: PageInfo!\n\t\"\"\"\n\tA list of edges.\n\t\"\"\"\n\tedges: [WorkflowTemplateEdge!]!\n\t\"\"\"\n\tA list of nodes.\n\t\"\"\"\n\tnodes: [WorkflowTemplate!]!\n}\n\n\"\"\"\nAn edge in a connection.\n\"\"\"\ntype WorkflowTemplateEdge @shareable {\n\t\"\"\"\n\tThe item at the end of the edge\n\t\"\"\"\n\tnode: WorkflowTemplate!\n\t\"\"\"\n\tA cursor for use in pagination\n\t\"\"\"\n\tcursor: String!\n}\n\n\"\"\"\nSupported label filters for ClusterWorkflowTemplates\n\"\"\"\ninput WorkflowTemplatesFilter {\n\t\"\"\"\n\tThe science group owning the template eg imaging\n\t\"\"\"\n\tscienceGroup: [ScienceGroup!]\n}\n\n\"\"\"\nDirects the executor to include this field or fragment only when the `if` argument is true.\n\"\"\"\ndirective @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\"\"\"\nDirects the executor to skip this field or fragment when the `if` argument is true.\n\"\"\"\ndirective @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\"\"\"\nProvides a scalar specification URL for specifying the behavior of custom scalar types.\n\"\"\"\ndirective @specifiedBy(url: String!) on SCALAR\nextend schema @link(\n\turl: \"https://specs.apollo.dev/federation/v2.5\",\n\timport: [\"@key\", \"@tag\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@composeDirective\", \"@interfaceObject\", \"@requiresScopes\"]\n)\n"},"upstreamSchema":{"key":"399ecb62e2d8de68392ee3dfb8e088d1edc68f46"}},"requestTimeoutSeconds":"10","id":"0"},{"kind":"GRAPHQL","rootNodes":[{"typeName":"InstrumentSession","fieldNames":["instrumentSessionId","instrumentSessionNumber","startTime","endTime","type","state","riskRating","proposal","instrument","roles"]},{"typeName":"InstrumentSessionMutations","fieldNames":["instrumentSessionNumber","proposalNumber"]},{"typeName":"Mutation","fieldNames":["instrumentSession"]},{"typeName":"Proposal","fieldNames":["proposalNumber","proposalCategory","title","summary","state","instrumentSessions","instruments","roles"]},{"typeName":"Query","fieldNames":["proposal","proposals","instrumentSession","instrumentSessions","instrument","instruments","account"]}],"childNodes":[{"typeName":"Account","fieldNames":["accountId","username","emailAddress","title","givenName","familyName","type","state","proposalRoles","instrumentSessionRoles"]},{"typeName":"Instrument","fieldNames":["name","scienceGroup","description","proposals","instrumentSessions"]},{"typeName":"InstrumentSessionRole","fieldNames":["instrumentSession","account","role","onSite"]},{"typeName":"PageInfo","fieldNames":["startCursor","endCursor","hasNextPage","hasPreviousPage"]},{"typeName":"ProposalAccount","fieldNames":["proposal","account","role"]},{"typeName":"ProposalConnection","fieldNames":["edges","pageInfo"]},{"typeName":"ProposalEdge","fieldNames":["cursor","node"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://instrument-sessions.diamond.ac.uk/api/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"https://instrument-sessions.diamond.ac.uk/api/graphql"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"schema @link(url: \"https://specs.apollo.dev/federation/v2.7\", import: [\"@key\", \"@shareable\"]) {\n query: Query\n mutation: Mutation\n}\n\ntype Account {\n accountId: Int!\n username: String!\n emailAddress: String\n title: String\n givenName: String\n familyName: String\n type: AccountType!\n state: AccountState!\n proposalRoles: [ProposalAccount!]!\n instrumentSessionRoles: [InstrumentSessionRole!]!\n}\n\nenum AccountState {\n enabled\n disabled\n}\n\nenum AccountType {\n user\n staff\n functional\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ntype Instrument {\n name: String!\n scienceGroup: String\n description: String\n proposals: [Proposal!]!\n instrumentSessions: [InstrumentSession!]!\n}\n\ntype InstrumentSession @key(fields: \"instrumentSessionNumber proposal {proposalNumber}\") {\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n startTime: DateTime\n endTime: DateTime\n type: String\n state: String\n riskRating: String\n proposal: Proposal\n instrument: Instrument!\n roles: [InstrumentSessionRole!]!\n}\n\ntype InstrumentSessionMutations @key(fields: \"instrumentSessionNumber proposalNumber\") {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n instrumentSession: InstrumentSession!\n account: Account!\n role: String!\n onSite: Boolean!\n}\n\ntype Mutation {\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSessionMutations\n}\n\ntype PageInfo @shareable {\n startCursor: String\n endCursor: String\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n}\n\ntype Proposal @key(fields: \"proposalNumber\") {\n proposalNumber: Int!\n proposalCategory: String\n title: String\n summary: String\n state: ProposalState!\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n roles: [ProposalAccount!]!\n}\n\ntype ProposalAccount {\n proposal: Proposal!\n account: Account!\n role: String!\n}\n\ntype ProposalConnection @shareable {\n edges: [ProposalEdge!]!\n pageInfo: PageInfo!\n}\n\ntype ProposalEdge @shareable {\n cursor: String!\n node: Proposal!\n}\n\nenum ProposalState {\n Open\n Closed\n Cancelled\n}\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n\n \"\"\"Get a list of proposals\"\"\"\n proposals(proposalCategory: String = null, first: Int = null, last: Int = null, after: String = null, before: String = null): ProposalConnection!\n\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSession\n\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalNumber: Int = null, proposalCategory: String = null): [InstrumentSession!]\n\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n}\n\nscalar _Any\n\nunion _Entity = InstrumentSession | InstrumentSessionMutations | Proposal\n\ntype _Service {\n sdl: String!\n}\n"},"upstreamSchema":{"key":"636412ec8e6e8e278df46ce7da59047a6182733c"}},"requestTimeoutSeconds":"10","id":"1","keys":[{"typeName":"InstrumentSession","selectionSet":"instrumentSessionNumber proposal { proposalNumber }"},{"typeName":"InstrumentSessionMutations","selectionSet":"instrumentSessionNumber proposalNumber"},{"typeName":"Proposal","selectionSet":"proposalNumber"}]},{"kind":"GRAPHQL","rootNodes":[{"typeName":"Mutation","fieldNames":["createSamples","createOrValidateSamples","sample"]},{"typeName":"Query","fieldNames":["sample","samples"]}],"childNodes":[{"typeName":"CreateSamplesResponse","fieldNames":["success","samples","errors"]},{"typeName":"ErrorDetails","fieldNames":["type","location","message"]},{"typeName":"PageInfo","fieldNames":["startCursor","endCursor","hasPreviousPage","hasNextPage"]},{"typeName":"Sample","fieldNames":["id","name","data","createdTime","updatedTime","dataSchemaUrl","parents","children","events","dataSchema"]},{"typeName":"SampleConnection","fieldNames":["edges","pageInfo"]},{"typeName":"SampleEdge","fieldNames":["cursor","node"]},{"typeName":"SampleEvent","fieldNames":["id","timestamp","description"]},{"typeName":"SampleEventConnection","fieldNames":["edges","pageInfo"]},{"typeName":"SampleEventEdge","fieldNames":["cursor","node"]},{"typeName":"SampleMutations","fieldNames":["sampleId","linkInstrumentSessionToSample","addSampleEvent"]},{"typeName":"SampleValidationError","fieldNames":["index","errors"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://sample-information.diamond.ac.uk/api/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"https://sample-information.diamond.ac.uk/api/graphql"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"input AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n proposalNumber: Int!\n instrumentSessionNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n\n \"\"\"A human readable error message.\"\"\"\n message: String!\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Mutation {\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n sample(sampleId: UUID!): SampleMutations\n}\n\ntype PageInfo {\n startCursor: String\n endCursor: String\n hasPreviousPage: Boolean!\n hasNextPage: Boolean!\n}\n\ntype Query {\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(proposalNumber: Int!, instrumentSessionNumber: Int!, first: Int!, filter: SampleFilterInput! = {}, before: String = null, after: String = null, last: Int = null, orderBy: SampleOrder! = {}): SampleConnection!\n}\n\ntype Sample {\n id: UUID!\n name: String!\n data: JSON!\n createdTime: DateTime!\n updatedTime: DateTime!\n dataSchemaUrl: String!\n\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n\n \"\"\"Samples derived from this sample\"\"\"\n children(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n\n \"\"\"Events linked to this sample\"\"\"\n events(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleEventConnection!\n\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n id: UUID!\n timestamp: DateTime!\n description: String!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Name of the sample\"\"\"\n name: String!\n\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n}\n\ninput SampleInLegacy {\n name: String!\n data: JSON!\n dataSchemaUrl: String!\n parentIds: [Int!] = null\n children: [SampleInLegacy!] = null\n}\n\ntype SampleMutations {\n sampleId: UUID!\n linkInstrumentSessionToSample(proposalNumber: Int!, instrumentSessionNumber: Int!): Void\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n}\n\ninput SampleOrder {\n name: SortingOrder = null\n createdTime: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void\n"},"upstreamSchema":{"key":"705aec083991f77f3c89aeff197c6cc302953ec1"}},"requestTimeoutSeconds":"10","id":"2"}],"fieldConfigurations":[{"typeName":"Mutation","fieldName":"submitWorkflowTemplate","argumentsConfiguration":[{"name":"name","sourceType":"FIELD_ARGUMENT"},{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"parameters","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"instrumentSession","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"createSamples","argumentsConfiguration":[{"name":"input","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"createOrValidateSamples","argumentsConfiguration":[{"name":"input","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"sample","argumentsConfiguration":[{"name":"sampleId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflow","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflows","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"cursor","sourceType":"FIELD_ARGUMENT"},{"name":"limit","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflowTemplate","argumentsConfiguration":[{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflowTemplates","argumentsConfiguration":[{"name":"cursor","sourceType":"FIELD_ARGUMENT"},{"name":"limit","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"proposal","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"proposals","argumentsConfiguration":[{"name":"proposalCategory","sourceType":"FIELD_ARGUMENT"},{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrumentSession","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrumentSessions","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"proposalCategory","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrument","argumentsConfiguration":[{"name":"instrumentName","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instruments","argumentsConfiguration":[{"name":"scienceGroup","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"account","argumentsConfiguration":[{"name":"username","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"sample","argumentsConfiguration":[{"name":"sampleId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"samples","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"},{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"},{"name":"orderBy","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Subscription","fieldName":"logs","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"workflowName","sourceType":"FIELD_ARGUMENT"},{"name":"taskId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Subscription","fieldName":"workflow","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"parents","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"children","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"events","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"SampleMutations","fieldName":"linkInstrumentSessionToSample","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"SampleMutations","fieldName":"addSampleEvent","argumentsConfiguration":[{"name":"sampleEvent","sourceType":"FIELD_ARGUMENT"}]}],"graphqlSchema":"schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ntype Artifact {\n \"\"\"The file name of the artifact\"\"\"\n name: String!\n \"\"\"The download URL for the artifact\"\"\"\n url: Url!\n \"\"\"The MIME type of the artifact data\"\"\"\n mimeType: String!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON\n\n\"\"\"A scalar that can represent any JSON Object value.\"\"\"\nscalar JSONObject\n\n\"\"\"A single log line streamed from a pod\"\"\"\ntype LogEntry {\n \"\"\"The log line content\"\"\"\n content: String!\n \"\"\"The name of the pod producing the log\"\"\"\n podName: String!\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Mutation {\n submitWorkflowTemplate(name: String!, visit: VisitInput!, parameters: JSON!): Workflow!\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSessionMutations\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n sample(sampleId: UUID!): SampleMutations\n}\n\n\"\"\"Information about pagination in a connection\"\"\"\ntype PageInfo {\n \"\"\"When paginating backwards, are there more items?\"\"\"\n hasPreviousPage: Boolean!\n \"\"\"When paginating forwards, are there more items?\"\"\"\n hasNextPage: Boolean!\n \"\"\"When paginating backwards, the cursor to continue.\"\"\"\n startCursor: String\n \"\"\"When paginating forwards, the cursor to continue.\"\"\"\n endCursor: String\n}\n\n\"\"\"The root query of the service\"\"\"\ntype Query {\n \"\"\"Get a single [`Workflow`] by proposal, visit, and name\"\"\"\n workflow(visit: VisitInput!, name: String!): Workflow!\n workflows(visit: VisitInput!, cursor: String, limit: Int, filter: WorkflowFilter): WorkflowConnection!\n workflowTemplate(name: String!): WorkflowTemplate!\n workflowTemplates(cursor: String, limit: Int, filter: WorkflowTemplatesFilter): WorkflowTemplateConnection!\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n \"\"\"Get a list of proposals\"\"\"\n proposals(proposalCategory: String = null, first: Int = null, last: Int = null, after: String = null, before: String = null): ProposalConnection!\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSession\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalNumber: Int = null, proposalCategory: String = null): [InstrumentSession!]\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(proposalNumber: Int!, instrumentSessionNumber: Int!, first: Int!, filter: SampleFilterInput! = {schemaUrl: null, createdTime: null, updatedTime: null, name: null}, before: String = null, after: String = null, last: Int = null, orderBy: SampleOrder! = {name: null, createdTime: null, updatedTime: null}): SampleConnection!\n}\n\n\"\"\"Supported DLS science groups\"\"\"\nenum ScienceGroup {\n \"\"\"Macromolecular Crystallography\"\"\"\n MX\n \"\"\"Workflows Examples\"\"\"\n EXAMPLES\n \"\"\"Magnetic Materials\"\"\"\n MAGNETIC_MATERIALS\n \"\"\"Soft Condensed Matter\"\"\"\n CONDENSED_MATTER\n \"\"\"Imaging and Microscopy\"\"\"\n IMAGING\n \"\"\"Biological Cryo-Imaging\"\"\"\n BIO_CRYO_IMAGING\n \"\"\"Structures and Surfaces\"\"\"\n SURFACES\n \"\"\"Crystallography\"\"\"\n CRYSTALLOGRAPHY\n \"\"\"Spectroscopy\"\"\"\n SPECTROSCOPY\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Subscription {\n \"\"\"Processing to subscribe to logs for a single pod of a workflow\"\"\"\n logs(visit: VisitInput!, workflowName: String!, taskId: String!): LogEntry!\n \"\"\"Processing to subscribe to data for all workflows in a session\"\"\"\n workflow(visit: VisitInput!, name: String!): Workflow!\n}\n\ntype Task {\n \"\"\"Unique name of the task\"\"\"\n id: String!\n \"\"\"Display name of the task\"\"\"\n name: String!\n \"\"\"Current status of a task\"\"\"\n status: TaskStatus!\n \"\"\"Parent of a task\"\"\"\n depends: [String!]!\n \"\"\"Children of a task\"\"\"\n dependencies: [String!]!\n \"\"\"Artifacts produced by a task\"\"\"\n artifacts: [Artifact!]!\n \"\"\"Node type - Pod, DAG, etc\"\"\"\n stepType: String!\n \"\"\"Start time for a task on a workflow\"\"\"\n startTime: DateTime\n \"\"\"End time for a task on a workflow\"\"\"\n endTime: DateTime\n \"\"\"\n A human readable message indicating details about why this step is in this condition\n \"\"\"\n message: String\n}\n\nenum TaskStatus {\n PENDING\n RUNNING\n SUCCEEDED\n SKIPPED\n FAILED\n ERROR\n OMITTED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ntype Visit {\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n \"\"\"Session visit Number\"\"\"\n number: Int!\n}\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ninput VisitInput {\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n \"\"\"Session visit Number\"\"\"\n number: Int!\n}\n\ntype Workflow {\n \"\"\"The name given to the workflow, unique within a given visit\"\"\"\n name: String!\n \"\"\"The visit the Workflow was run against\"\"\"\n visit: Visit!\n \"\"\"The current status of the workflow\"\"\"\n status: WorkflowStatus\n \"\"\"The top-level workflow parameters\"\"\"\n parameters: JSONObject\n \"\"\"The name of the template used to run the workflow\"\"\"\n templateRef: String\n \"\"\"The workflow creator\"\"\"\n creator: WorkflowCreator!\n}\n\ntype WorkflowConnection {\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo!\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowEdge!]!\n \"\"\"A list of nodes.\"\"\"\n nodes: [Workflow!]!\n}\n\n\"\"\"Information about the creator of a workflow.\"\"\"\ntype WorkflowCreator {\n \"\"\"\n An identifier unique to the creator of the workflow.\n Typically this is the creator's Fed-ID.\n \"\"\"\n creatorId: String!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowEdge {\n \"\"\"The item at the end of the edge\"\"\"\n node: Workflow!\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String!\n}\n\n\"\"\"All tasks in the workflow have errored\"\"\"\ntype WorkflowErroredStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All tasks in the workflow have failed\"\"\"\ntype WorkflowFailedStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All the supported Workflows filters\"\"\"\ninput WorkflowFilter {\n \"\"\"The status field for a workflow\"\"\"\n workflowStatusFilter: WorkflowStatusFilter\n \"\"\"The fedid of the user who created the workflow\"\"\"\n creator: Creator\n \"\"\"The name of the workflow template\"\"\"\n template: Template\n}\n\ntype WorkflowPendingStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n}\n\ntype WorkflowRunningStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"The status of a workflow\"\"\"\nunion WorkflowStatus = WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus | WorkflowFailedStatus | WorkflowErroredStatus\n\n\"\"\"Represents workflow status filters\"\"\"\ninput WorkflowStatusFilter {\n pending: Boolean! = false\n running: Boolean! = false\n succeeded: Boolean! = false\n failed: Boolean! = false\n error: Boolean! = false\n}\n\n\"\"\"All tasks in the workflow have succeded\"\"\"\ntype WorkflowSucceededStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n \"\"\"The name given to the workflow template, globally unique\"\"\"\n name: String!\n \"\"\"The group who maintains the workflow template\"\"\"\n maintainer: String!\n \"\"\"A human readable title for the workflow template\"\"\"\n title: String\n \"\"\"A human readable description of the workflow which is created\"\"\"\n description: String\n \"\"\"The repository storing the code associated with this template.\"\"\"\n repository: String\n \"\"\"A JSON Schema describing the arguments of a Workflow Template\"\"\"\n arguments: JSON!\n \"\"\"\n A JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n \"\"\"\n uiSchema: JSON\n}\n\ntype WorkflowTemplateConnection {\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo!\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowTemplateEdge!]!\n \"\"\"A list of nodes.\"\"\"\n nodes: [WorkflowTemplate!]!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowTemplateEdge {\n \"\"\"The item at the end of the edge\"\"\"\n node: WorkflowTemplate!\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String!\n}\n\n\"\"\"Supported label filters for ClusterWorkflowTemplates\"\"\"\ninput WorkflowTemplatesFilter {\n \"\"\"The science group owning the template eg imaging\"\"\"\n scienceGroup: [ScienceGroup!]\n}\n\ntype Account {\n accountId: Int!\n username: String!\n emailAddress: String\n title: String\n givenName: String\n familyName: String\n type: AccountType!\n state: AccountState!\n proposalRoles: [ProposalAccount!]!\n instrumentSessionRoles: [InstrumentSessionRole!]!\n}\n\nenum AccountState {\n enabled\n disabled\n}\n\nenum AccountType {\n user\n staff\n functional\n}\n\ntype Instrument {\n name: String!\n scienceGroup: String\n description: String\n proposals: [Proposal!]!\n instrumentSessions: [InstrumentSession!]!\n}\n\ntype InstrumentSession {\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n startTime: DateTime\n endTime: DateTime\n type: String\n state: String\n riskRating: String\n proposal: Proposal\n instrument: Instrument!\n roles: [InstrumentSessionRole!]!\n}\n\ntype InstrumentSessionMutations {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n instrumentSession: InstrumentSession!\n account: Account!\n role: String!\n onSite: Boolean!\n}\n\ntype Proposal {\n proposalNumber: Int!\n proposalCategory: String\n title: String\n summary: String\n state: ProposalState!\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n roles: [ProposalAccount!]!\n}\n\ntype ProposalAccount {\n proposal: Proposal!\n account: Account!\n role: String!\n}\n\ntype ProposalConnection {\n edges: [ProposalEdge!]!\n pageInfo: PageInfo!\n}\n\ntype ProposalEdge {\n cursor: String!\n node: Proposal!\n}\n\nenum ProposalState {\n Open\n Closed\n Cancelled\n}\n\ninput AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n proposalNumber: Int!\n instrumentSessionNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n}\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n \"\"\"A human readable error message.\"\"\"\n message: String!\n}\n\ntype Sample {\n id: UUID!\n name: String!\n data: JSON!\n createdTime: DateTime!\n updatedTime: DateTime!\n dataSchemaUrl: String!\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n \"\"\"Samples derived from this sample\"\"\"\n children(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n \"\"\"Events linked to this sample\"\"\"\n events(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleEventConnection!\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n id: UUID!\n timestamp: DateTime!\n description: String!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Name of the sample\"\"\"\n name: String!\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n}\n\ninput SampleInLegacy {\n name: String!\n data: JSON!\n dataSchemaUrl: String!\n parentIds: [Int!] = null\n children: [SampleInLegacy!] = null\n}\n\ntype SampleMutations {\n sampleId: UUID!\n linkInstrumentSessionToSample(proposalNumber: Int!, instrumentSessionNumber: Int!): Void\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n}\n\ninput SampleOrder {\n name: SortingOrder = null\n createdTime: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void","stringStorage":{"399ecb62e2d8de68392ee3dfb8e088d1edc68f46":"schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ndirective @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA\n\ndirective @shareable repeatable on FIELD_DEFINITION | OBJECT\n\ntype Artifact {\n \"\"\"The MIME type of the artifact data\"\"\"\n mimeType: String!\n \"\"\"The file name of the artifact\"\"\"\n name: String!\n \"\"\"The download URL for the artifact\"\"\"\n url: Url!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"A scalar that can represent any JSON value.\"\"\"\nscalar JSON\n\n\"\"\"A scalar that can represent any JSON Object value.\"\"\"\nscalar JSONObject\n\n\"\"\"A single log line streamed from a pod\"\"\"\ntype LogEntry {\n \"\"\"The log line content\"\"\"\n content: String!\n \"\"\"The name of the pod producing the log\"\"\"\n podName: String!\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Mutation {\n submitWorkflowTemplate(name: String!, parameters: JSON!, visit: VisitInput!): Workflow!\n}\n\n\"\"\"Information about pagination in a connection\"\"\"\ntype PageInfo {\n \"\"\"When paginating forwards, the cursor to continue.\"\"\"\n endCursor: String @shareable\n \"\"\"When paginating forwards, are there more items?\"\"\"\n hasNextPage: Boolean! @shareable\n \"\"\"When paginating backwards, are there more items?\"\"\"\n hasPreviousPage: Boolean! @shareable\n \"\"\"When paginating backwards, the cursor to continue.\"\"\"\n startCursor: String @shareable\n}\n\n\"\"\"The root query of the service\"\"\"\ntype Query {\n \"\"\"Get a single [`Workflow`] by proposal, visit, and name\"\"\"\n workflow(name: String!, visit: VisitInput!): Workflow!\n workflowTemplate(name: String!): WorkflowTemplate!\n workflowTemplates(cursor: String, filter: WorkflowTemplatesFilter, limit: Int): WorkflowTemplateConnection!\n workflows(cursor: String, filter: WorkflowFilter, limit: Int, visit: VisitInput!): WorkflowConnection!\n}\n\n\"\"\"Supported DLS science groups\"\"\"\nenum ScienceGroup {\n \"\"\"Biological Cryo-Imaging\"\"\"\n BIO_CRYO_IMAGING\n \"\"\"Soft Condensed Matter\"\"\"\n CONDENSED_MATTER\n \"\"\"Crystallography\"\"\"\n CRYSTALLOGRAPHY\n \"\"\"Workflows Examples\"\"\"\n EXAMPLES\n \"\"\"Imaging and Microscopy\"\"\"\n IMAGING\n \"\"\"Magnetic Materials\"\"\"\n MAGNETIC_MATERIALS\n \"\"\"Macromolecular Crystallography\"\"\"\n MX\n \"\"\"Spectroscopy\"\"\"\n SPECTROSCOPY\n \"\"\"Structures and Surfaces\"\"\"\n SURFACES\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Subscription {\n \"\"\"Processing to subscribe to logs for a single pod of a workflow\"\"\"\n logs(taskId: String!, visit: VisitInput!, workflowName: String!): LogEntry!\n \"\"\"Processing to subscribe to data for all workflows in a session\"\"\"\n workflow(name: String!, visit: VisitInput!): Workflow!\n}\n\ntype Task {\n \"\"\"Artifacts produced by a task\"\"\"\n artifacts: [Artifact!]!\n \"\"\"Children of a task\"\"\"\n dependencies: [String!]!\n \"\"\"Parent of a task\"\"\"\n depends: [String!]!\n \"\"\"End time for a task on a workflow\"\"\"\n endTime: DateTime\n \"\"\"Unique name of the task\"\"\"\n id: String!\n \"\"\"\n A human readable message indicating details about why this step is in this condition\n \"\"\"\n message: String\n \"\"\"Display name of the task\"\"\"\n name: String!\n \"\"\"Start time for a task on a workflow\"\"\"\n startTime: DateTime\n \"\"\"Current status of a task\"\"\"\n status: TaskStatus!\n \"\"\"Node type - Pod, DAG, etc\"\"\"\n stepType: String!\n}\n\nenum TaskStatus {\n ERROR\n FAILED\n OMITTED\n PENDING\n RUNNING\n SKIPPED\n SUCCEEDED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ntype Visit {\n \"\"\"Session visit Number\"\"\"\n number: Int!\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n}\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ninput VisitInput {\n \"\"\"Session visit Number\"\"\"\n number: Int!\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n}\n\ntype Workflow {\n \"\"\"The workflow creator\"\"\"\n creator: WorkflowCreator!\n \"\"\"The name given to the workflow, unique within a given visit\"\"\"\n name: String!\n \"\"\"The top-level workflow parameters\"\"\"\n parameters: JSONObject\n \"\"\"The current status of the workflow\"\"\"\n status: WorkflowStatus\n \"\"\"The name of the template used to run the workflow\"\"\"\n templateRef: String\n \"\"\"The visit the Workflow was run against\"\"\"\n visit: Visit!\n}\n\ntype WorkflowConnection {\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowEdge!]! @shareable\n \"\"\"A list of nodes.\"\"\"\n nodes: [Workflow!]! @shareable\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo! @shareable\n}\n\n\"\"\"Information about the creator of a workflow.\"\"\"\ntype WorkflowCreator {\n \"\"\"\n An identifier unique to the creator of the workflow.\n Typically this is the creator's Fed-ID.\n \"\"\"\n creatorId: String!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowEdge {\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String! @shareable\n \"\"\"The item at the end of the edge\"\"\"\n node: Workflow! @shareable\n}\n\n\"\"\"All tasks in the workflow have errored\"\"\"\ntype WorkflowErroredStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All tasks in the workflow have failed\"\"\"\ntype WorkflowFailedStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All the supported Workflows filters\"\"\"\ninput WorkflowFilter {\n \"\"\"The fedid of the user who created the workflow\"\"\"\n creator: Creator\n \"\"\"The name of the workflow template\"\"\"\n template: Template\n \"\"\"The status field for a workflow\"\"\"\n workflowStatusFilter: WorkflowStatusFilter\n}\n\ntype WorkflowPendingStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n}\n\ntype WorkflowRunningStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"The status of a workflow\"\"\"\nunion WorkflowStatus = WorkflowErroredStatus | WorkflowFailedStatus | WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus\n\n\"\"\"Represents workflow status filters\"\"\"\ninput WorkflowStatusFilter {\n error: Boolean! = false\n failed: Boolean! = false\n pending: Boolean! = false\n running: Boolean! = false\n succeeded: Boolean! = false\n}\n\n\"\"\"All tasks in the workflow have succeded\"\"\"\ntype WorkflowSucceededStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n \"\"\"A JSON Schema describing the arguments of a Workflow Template\"\"\"\n arguments: JSON!\n \"\"\"A human readable description of the workflow which is created\"\"\"\n description: String\n \"\"\"The group who maintains the workflow template\"\"\"\n maintainer: String!\n \"\"\"The name given to the workflow template, globally unique\"\"\"\n name: String!\n \"\"\"The repository storing the code associated with this template.\"\"\"\n repository: String\n \"\"\"A human readable title for the workflow template\"\"\"\n title: String\n \"\"\"\n A JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n \"\"\"\n uiSchema: JSON\n}\n\ntype WorkflowTemplateConnection {\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowTemplateEdge!]! @shareable\n \"\"\"A list of nodes.\"\"\"\n nodes: [WorkflowTemplate!]! @shareable\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo! @shareable\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowTemplateEdge {\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String! @shareable\n \"\"\"The item at the end of the edge\"\"\"\n node: WorkflowTemplate! @shareable\n}\n\n\"\"\"Supported label filters for ClusterWorkflowTemplates\"\"\"\ninput WorkflowTemplatesFilter {\n \"\"\"The science group owning the template eg imaging\"\"\"\n scienceGroup: [ScienceGroup!]\n}\n\nscalar link__Import\n\nenum link__Purpose {\n EXECUTION\n SECURITY\n}","636412ec8e6e8e278df46ce7da59047a6182733c":"schema @link(url: \"https://specs.apollo.dev/federation/v2.7\", import: [\"@key\", \"@shareable\"]) {\n query: Query\n mutation: Mutation\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ndirective @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA\n\ndirective @shareable repeatable on FIELD_DEFINITION | OBJECT\n\ntype Account {\n accountId: Int!\n emailAddress: String\n familyName: String\n givenName: String\n instrumentSessionRoles: [InstrumentSessionRole!]!\n proposalRoles: [ProposalAccount!]!\n state: AccountState!\n title: String\n type: AccountType!\n username: String!\n}\n\nenum AccountState {\n disabled\n enabled\n}\n\nenum AccountType {\n functional\n staff\n user\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ntype Instrument {\n description: String\n instrumentSessions: [InstrumentSession!]!\n name: String!\n proposals: [Proposal!]!\n scienceGroup: String\n}\n\ntype InstrumentSession @key(fields: \"instrumentSessionNumber proposal {proposalNumber}\") {\n endTime: DateTime\n instrument: Instrument!\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n proposal: Proposal\n riskRating: String\n roles: [InstrumentSessionRole!]!\n startTime: DateTime\n state: String\n type: String\n}\n\ntype InstrumentSessionMutations @key(fields: \"instrumentSessionNumber proposalNumber\") {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n account: Account!\n instrumentSession: InstrumentSession!\n onSite: Boolean!\n role: String!\n}\n\ntype Mutation {\n instrumentSession(instrumentSessionNumber: Int!, proposalNumber: Int!): InstrumentSessionMutations\n}\n\ntype PageInfo {\n endCursor: String @shareable\n hasNextPage: Boolean! @shareable\n hasPreviousPage: Boolean! @shareable\n startCursor: String @shareable\n}\n\ntype Proposal @key(fields: \"proposalNumber\") {\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n proposalCategory: String\n proposalNumber: Int!\n roles: [ProposalAccount!]!\n state: ProposalState!\n summary: String\n title: String\n}\n\ntype ProposalAccount {\n account: Account!\n proposal: Proposal!\n role: String!\n}\n\ntype ProposalConnection {\n edges: [ProposalEdge!]! @shareable\n pageInfo: PageInfo! @shareable\n}\n\ntype ProposalEdge {\n cursor: String! @shareable\n node: Proposal! @shareable\n}\n\nenum ProposalState {\n Cancelled\n Closed\n Open\n}\n\ntype Query {\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(instrumentSessionNumber: Int!, proposalNumber: Int!): InstrumentSession\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalCategory: String = null, proposalNumber: Int = null): [InstrumentSession!]\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n \"\"\"Get a list of proposals\"\"\"\n proposals(after: String = null, before: String = null, first: Int = null, last: Int = null, proposalCategory: String = null): ProposalConnection!\n}\n\nscalar link__Import\n\nenum link__Purpose {\n EXECUTION\n SECURITY\n}\n\nscalar openfed__FieldSet","705aec083991f77f3c89aeff197c6cc302953ec1":"schema {\n query: Query\n mutation: Mutation\n}\n\ninput AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n \"\"\"A human readable error message.\"\"\"\n message: String!\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Mutation {\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n sample(sampleId: UUID!): SampleMutations\n}\n\ntype PageInfo {\n endCursor: String\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n startCursor: String\n}\n\ntype Query {\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(after: String = null, before: String = null, filter: SampleFilterInput! = {createdTime: null, name: null, schemaUrl: null, updatedTime: null}, first: Int!, instrumentSessionNumber: Int!, last: Int = null, orderBy: SampleOrder! = {createdTime: null, name: null, updatedTime: null}, proposalNumber: Int!): SampleConnection!\n}\n\ntype Sample {\n \"\"\"Samples derived from this sample\"\"\"\n children(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleConnection!\n createdTime: DateTime!\n data: JSON!\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n dataSchemaUrl: String!\n \"\"\"Events linked to this sample\"\"\"\n events(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleEventConnection!\n id: UUID!\n name: String!\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleConnection!\n updatedTime: DateTime!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n description: String!\n id: UUID!\n timestamp: DateTime!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n \"\"\"Name of the sample\"\"\"\n name: String!\n}\n\ninput SampleInLegacy {\n children: [SampleInLegacy!] = null\n data: JSON!\n dataSchemaUrl: String!\n name: String!\n parentIds: [Int!] = null\n}\n\ntype SampleMutations {\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n linkInstrumentSessionToSample(instrumentSessionNumber: Int!, proposalNumber: Int!): Void\n sampleId: UUID!\n}\n\ninput SampleOrder {\n createdTime: SortingOrder = null\n name: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void"}},"version":"00000000-0000-0000-0000-000000000000","subgraphs":[{"id":"0","name":"workflows","routingUrl":"https://workflows.diamond.ac.uk/graphql"},{"id":"1","name":"instrument_sessions","routingUrl":"https://instrument-sessions.diamond.ac.uk/api/graphql"},{"id":"2","name":"samples","routingUrl":"https://sample-information.diamond.ac.uk/api/graphql"}],"compatibilityVersion":"1:0.51.0"} \ No newline at end of file From 0aef7ac49181c8a5eba4ae0293350165e666e816 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 11:50:15 +0000 Subject: [PATCH 03/16] fix: move router execution config --- charts/graph/{charts => }/router-execution-config.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename charts/graph/{charts => }/router-execution-config.json (100%) diff --git a/charts/graph/charts/router-execution-config.json b/charts/graph/router-execution-config.json similarity index 100% rename from charts/graph/charts/router-execution-config.json rename to charts/graph/router-execution-config.json From 916ef760e57ad42275db1ca28053c319fce09b47 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 12:03:10 +0000 Subject: [PATCH 04/16] fix: add indent to configmap --- charts/graph/templates/configmap-router-execution-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/graph/templates/configmap-router-execution-config.yaml b/charts/graph/templates/configmap-router-execution-config.yaml index 8e1fa68..0c511d7 100644 --- a/charts/graph/templates/configmap-router-execution-config.yaml +++ b/charts/graph/templates/configmap-router-execution-config.yaml @@ -5,4 +5,4 @@ metadata: name: {{.Release.Name}}-router-execution-config data: execution-config.json: | -{{- .Files.Get "router-execution-config.json" | nindent 4 }} + {{- .Files.Get "router-execution-config.json" | nindent 4 }} From 334e4c3ffc6ba893a597e0c13b8a81be5103e91d Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 12:07:52 +0000 Subject: [PATCH 05/16] fix: remove extra config --- charts/graph/templates/router-execution-config.json | 1 - 1 file changed, 1 deletion(-) delete mode 100644 charts/graph/templates/router-execution-config.json diff --git a/charts/graph/templates/router-execution-config.json b/charts/graph/templates/router-execution-config.json deleted file mode 100644 index c1cfdd7..0000000 --- a/charts/graph/templates/router-execution-config.json +++ /dev/null @@ -1 +0,0 @@ -{"engineConfig":{"defaultFlushInterval":"500","datasourceConfigurations":[{"kind":"GRAPHQL","rootNodes":[{"typeName":"Mutation","fieldNames":["submitWorkflowTemplate"]},{"typeName":"Query","fieldNames":["workflow","workflows","workflowTemplate","workflowTemplates"]},{"typeName":"Subscription","fieldNames":["logs","workflow"]}],"childNodes":[{"typeName":"Artifact","fieldNames":["name","url","mimeType"]},{"typeName":"LogEntry","fieldNames":["content","podName"]},{"typeName":"PageInfo","fieldNames":["hasPreviousPage","hasNextPage","startCursor","endCursor"]},{"typeName":"Task","fieldNames":["id","name","status","depends","dependencies","artifacts","stepType","startTime","endTime","message"]},{"typeName":"Visit","fieldNames":["proposalCode","proposalNumber","number"]},{"typeName":"Workflow","fieldNames":["name","visit","status","parameters","templateRef","creator"]},{"typeName":"WorkflowConnection","fieldNames":["pageInfo","edges","nodes"]},{"typeName":"WorkflowCreator","fieldNames":["creatorId"]},{"typeName":"WorkflowEdge","fieldNames":["node","cursor"]},{"typeName":"WorkflowErroredStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowFailedStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowPendingStatus","fieldNames":["message"]},{"typeName":"WorkflowRunningStatus","fieldNames":["startTime","message","tasks"]},{"typeName":"WorkflowSucceededStatus","fieldNames":["startTime","endTime","message","tasks"]},{"typeName":"WorkflowTemplate","fieldNames":["name","maintainer","title","description","repository","arguments","uiSchema"]},{"typeName":"WorkflowTemplateConnection","fieldNames":["pageInfo","edges","nodes"]},{"typeName":"WorkflowTemplateEdge","fieldNames":["node","cursor"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://workflows.diamond.ac.uk/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"wss://workflows.diamond.ac.uk/graphql/ws"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"type Artifact {\n\t\"\"\"\n\tThe file name of the artifact\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe download URL for the artifact\n\t\"\"\"\n\turl: Url!\n\t\"\"\"\n\tThe MIME type of the artifact data\n\t\"\"\"\n\tmimeType: String!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"\nA scalar that can represent any JSON value.\n\"\"\"\nscalar JSON\n\n\"\"\"\nA scalar that can represent any JSON Object value.\n\"\"\"\nscalar JSONObject\n\n\"\"\"\nA single log line streamed from a pod\n\"\"\"\ntype LogEntry {\n\t\"\"\"\n\tThe log line content\n\t\"\"\"\n\tcontent: String!\n\t\"\"\"\n\tThe name of the pod producing the log\n\t\"\"\"\n\tpodName: String!\n}\n\n\"\"\"\nThe root mutation of the service\n\"\"\"\ntype Mutation {\n\tsubmitWorkflowTemplate(name: String!, visit: VisitInput!, parameters: JSON!): Workflow!\n}\n\n\"\"\"\nInformation about pagination in a connection\n\"\"\"\ntype PageInfo @shareable {\n\t\"\"\"\n\tWhen paginating backwards, are there more items?\n\t\"\"\"\n\thasPreviousPage: Boolean!\n\t\"\"\"\n\tWhen paginating forwards, are there more items?\n\t\"\"\"\n\thasNextPage: Boolean!\n\t\"\"\"\n\tWhen paginating backwards, the cursor to continue.\n\t\"\"\"\n\tstartCursor: String\n\t\"\"\"\n\tWhen paginating forwards, the cursor to continue.\n\t\"\"\"\n\tendCursor: String\n}\n\n\"\"\"\nThe root query of the service\n\"\"\"\ntype Query {\n\t\"\"\"\n\tGet a single [`Workflow`] by proposal, visit, and name\n\t\"\"\"\n\tworkflow(visit: VisitInput!, name: String!): Workflow!\n\tworkflows(visit: VisitInput!, cursor: String, limit: Int, filter: WorkflowFilter): WorkflowConnection!\n\tworkflowTemplate(name: String!): WorkflowTemplate!\n\tworkflowTemplates(cursor: String, limit: Int, filter: WorkflowTemplatesFilter): WorkflowTemplateConnection!\n}\n\n\"\"\"\nSupported DLS science groups\n\"\"\"\nenum ScienceGroup {\n\t\"\"\"\n\tMacromolecular Crystallography\n\t\"\"\"\n\tMX\n\t\"\"\"\n\tWorkflows Examples\n\t\"\"\"\n\tEXAMPLES\n\t\"\"\"\n\tMagnetic Materials\n\t\"\"\"\n\tMAGNETIC_MATERIALS\n\t\"\"\"\n\tSoft Condensed Matter\n\t\"\"\"\n\tCONDENSED_MATTER\n\t\"\"\"\n\tImaging and Microscopy\n\t\"\"\"\n\tIMAGING\n\t\"\"\"\n\tBiological Cryo-Imaging\n\t\"\"\"\n\tBIO_CRYO_IMAGING\n\t\"\"\"\n\tStructures and Surfaces\n\t\"\"\"\n\tSURFACES\n\t\"\"\"\n\tCrystallography\n\t\"\"\"\n\tCRYSTALLOGRAPHY\n\t\"\"\"\n\tSpectroscopy\n\t\"\"\"\n\tSPECTROSCOPY\n}\n\n\"\"\"\nThe root mutation of the service\n\"\"\"\ntype Subscription {\n\t\"\"\"\n\tProcessing to subscribe to logs for a single pod of a workflow\n\t\"\"\"\n\tlogs(visit: VisitInput!, workflowName: String!, taskId: String!): LogEntry!\n\t\"\"\"\n\tProcessing to subscribe to data for all workflows in a session\n\t\"\"\"\n\tworkflow(visit: VisitInput!, name: String!): Workflow!\n}\n\ntype Task {\n\t\"\"\"\n\tUnique name of the task\n\t\"\"\"\n\tid: String!\n\t\"\"\"\n\tDisplay name of the task\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tCurrent status of a task\n\t\"\"\"\n\tstatus: TaskStatus!\n\t\"\"\"\n\tParent of a task\n\t\"\"\"\n\tdepends: [String!]!\n\t\"\"\"\n\tChildren of a task\n\t\"\"\"\n\tdependencies: [String!]!\n\t\"\"\"\n\tArtifacts produced by a task\n\t\"\"\"\n\tartifacts: [Artifact!]!\n\t\"\"\"\n\tNode type - Pod, DAG, etc\n\t\"\"\"\n\tstepType: String!\n\t\"\"\"\n\tStart time for a task on a workflow\n\t\"\"\"\n\tstartTime: DateTime\n\t\"\"\"\n\tEnd time for a task on a workflow\n\t\"\"\"\n\tendTime: DateTime\n\t\"\"\"\n\tA human readable message indicating details about why this step is in this condition\n\t\"\"\"\n\tmessage: String\n}\n\nenum TaskStatus {\n\tPENDING\n\tRUNNING\n\tSUCCEEDED\n\tSKIPPED\n\tFAILED\n\tERROR\n\tOMITTED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"\nA visit to an instrument as part of a session\n\"\"\"\ntype Visit {\n\t\"\"\"\n\tProject Proposal Code\n\t\"\"\"\n\tproposalCode: String!\n\t\"\"\"\n\tProject Proposal Number\n\t\"\"\"\n\tproposalNumber: Int!\n\t\"\"\"\n\tSession visit Number\n\t\"\"\"\n\tnumber: Int!\n}\n\n\"\"\"\nA visit to an instrument as part of a session\n\"\"\"\ninput VisitInput {\n\t\"\"\"\n\tProject Proposal Code\n\t\"\"\"\n\tproposalCode: String!\n\t\"\"\"\n\tProject Proposal Number\n\t\"\"\"\n\tproposalNumber: Int!\n\t\"\"\"\n\tSession visit Number\n\t\"\"\"\n\tnumber: Int!\n}\n\ntype Workflow {\n\t\"\"\"\n\tThe name given to the workflow, unique within a given visit\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe visit the Workflow was run against\n\t\"\"\"\n\tvisit: Visit!\n\t\"\"\"\n\tThe current status of the workflow\n\t\"\"\"\n\tstatus: WorkflowStatus\n\t\"\"\"\n\tThe top-level workflow parameters\n\t\"\"\"\n\tparameters: JSONObject\n\t\"\"\"\n\tThe name of the template used to run the workflow\n\t\"\"\"\n\ttemplateRef: String\n\t\"\"\"\n\tThe workflow creator\n\t\"\"\"\n\tcreator: WorkflowCreator!\n}\n\ntype WorkflowConnection @shareable {\n\t\"\"\"\n\tInformation to aid in pagination.\n\t\"\"\"\n\tpageInfo: PageInfo!\n\t\"\"\"\n\tA list of edges.\n\t\"\"\"\n\tedges: [WorkflowEdge!]!\n\t\"\"\"\n\tA list of nodes.\n\t\"\"\"\n\tnodes: [Workflow!]!\n}\n\n\"\"\"\nInformation about the creator of a workflow.\n\"\"\"\ntype WorkflowCreator {\n\t\"\"\"\n\tAn identifier unique to the creator of the workflow.\n\tTypically this is the creator's Fed-ID.\n\t\"\"\"\n\tcreatorId: String!\n}\n\n\"\"\"\nAn edge in a connection.\n\"\"\"\ntype WorkflowEdge @shareable {\n\t\"\"\"\n\tThe item at the end of the edge\n\t\"\"\"\n\tnode: Workflow!\n\t\"\"\"\n\tA cursor for use in pagination\n\t\"\"\"\n\tcursor: String!\n}\n\n\"\"\"\nAll tasks in the workflow have errored\n\"\"\"\ntype WorkflowErroredStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nAll tasks in the workflow have failed\n\"\"\"\ntype WorkflowFailedStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nAll the supported Workflows filters\n\"\"\"\ninput WorkflowFilter {\n\t\"\"\"\n\tThe status field for a workflow\n\t\"\"\"\n\tworkflowStatusFilter: WorkflowStatusFilter\n\t\"\"\"\n\tThe fedid of the user who created the workflow\n\t\"\"\"\n\tcreator: Creator\n\t\"\"\"\n\tThe name of the workflow template\n\t\"\"\"\n\ttemplate: Template\n}\n\ntype WorkflowPendingStatus {\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n}\n\ntype WorkflowRunningStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\n\"\"\"\nThe status of a workflow\n\"\"\"\nunion WorkflowStatus = WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus | WorkflowFailedStatus | WorkflowErroredStatus\n\n\"\"\"\nRepresents workflow status filters\n\"\"\"\ninput WorkflowStatusFilter {\n\tpending: Boolean! = false\n\trunning: Boolean! = false\n\tsucceeded: Boolean! = false\n\tfailed: Boolean! = false\n\terror: Boolean! = false\n}\n\n\"\"\"\nAll tasks in the workflow have succeded\n\"\"\"\ntype WorkflowSucceededStatus {\n\t\"\"\"\n\tTime at which this workflow started\n\t\"\"\"\n\tstartTime: DateTime!\n\t\"\"\"\n\tTime at which this workflow completed\n\t\"\"\"\n\tendTime: DateTime!\n\t\"\"\"\n\tA human readable message indicating details about why the workflow is in this condition\n\t\"\"\"\n\tmessage: String\n\t\"\"\"\n\tTasks created by the workflow\n\t\"\"\"\n\ttasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n\t\"\"\"\n\tThe name given to the workflow template, globally unique\n\t\"\"\"\n\tname: String!\n\t\"\"\"\n\tThe group who maintains the workflow template\n\t\"\"\"\n\tmaintainer: String!\n\t\"\"\"\n\tA human readable title for the workflow template\n\t\"\"\"\n\ttitle: String\n\t\"\"\"\n\tA human readable description of the workflow which is created\n\t\"\"\"\n\tdescription: String\n\t\"\"\"\n\tThe repository storing the code associated with this template.\n\t\"\"\"\n\trepository: String\n\t\"\"\"\n\tA JSON Schema describing the arguments of a Workflow Template\n\t\"\"\"\n\targuments: JSON!\n\t\"\"\"\n\tA JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n\t\"\"\"\n\tuiSchema: JSON\n}\n\ntype WorkflowTemplateConnection @shareable {\n\t\"\"\"\n\tInformation to aid in pagination.\n\t\"\"\"\n\tpageInfo: PageInfo!\n\t\"\"\"\n\tA list of edges.\n\t\"\"\"\n\tedges: [WorkflowTemplateEdge!]!\n\t\"\"\"\n\tA list of nodes.\n\t\"\"\"\n\tnodes: [WorkflowTemplate!]!\n}\n\n\"\"\"\nAn edge in a connection.\n\"\"\"\ntype WorkflowTemplateEdge @shareable {\n\t\"\"\"\n\tThe item at the end of the edge\n\t\"\"\"\n\tnode: WorkflowTemplate!\n\t\"\"\"\n\tA cursor for use in pagination\n\t\"\"\"\n\tcursor: String!\n}\n\n\"\"\"\nSupported label filters for ClusterWorkflowTemplates\n\"\"\"\ninput WorkflowTemplatesFilter {\n\t\"\"\"\n\tThe science group owning the template eg imaging\n\t\"\"\"\n\tscienceGroup: [ScienceGroup!]\n}\n\n\"\"\"\nDirects the executor to include this field or fragment only when the `if` argument is true.\n\"\"\"\ndirective @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\"\"\"\nDirects the executor to skip this field or fragment when the `if` argument is true.\n\"\"\"\ndirective @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT\n\"\"\"\nProvides a scalar specification URL for specifying the behavior of custom scalar types.\n\"\"\"\ndirective @specifiedBy(url: String!) on SCALAR\nextend schema @link(\n\turl: \"https://specs.apollo.dev/federation/v2.5\",\n\timport: [\"@key\", \"@tag\", \"@shareable\", \"@inaccessible\", \"@override\", \"@external\", \"@provides\", \"@requires\", \"@composeDirective\", \"@interfaceObject\", \"@requiresScopes\"]\n)\n"},"upstreamSchema":{"key":"399ecb62e2d8de68392ee3dfb8e088d1edc68f46"}},"requestTimeoutSeconds":"10","id":"0"},{"kind":"GRAPHQL","rootNodes":[{"typeName":"InstrumentSession","fieldNames":["instrumentSessionId","instrumentSessionNumber","startTime","endTime","type","state","riskRating","proposal","instrument","roles"]},{"typeName":"InstrumentSessionMutations","fieldNames":["instrumentSessionNumber","proposalNumber"]},{"typeName":"Mutation","fieldNames":["instrumentSession"]},{"typeName":"Proposal","fieldNames":["proposalNumber","proposalCategory","title","summary","state","instrumentSessions","instruments","roles"]},{"typeName":"Query","fieldNames":["proposal","proposals","instrumentSession","instrumentSessions","instrument","instruments","account"]}],"childNodes":[{"typeName":"Account","fieldNames":["accountId","username","emailAddress","title","givenName","familyName","type","state","proposalRoles","instrumentSessionRoles"]},{"typeName":"Instrument","fieldNames":["name","scienceGroup","description","proposals","instrumentSessions"]},{"typeName":"InstrumentSessionRole","fieldNames":["instrumentSession","account","role","onSite"]},{"typeName":"PageInfo","fieldNames":["startCursor","endCursor","hasNextPage","hasPreviousPage"]},{"typeName":"ProposalAccount","fieldNames":["proposal","account","role"]},{"typeName":"ProposalConnection","fieldNames":["edges","pageInfo"]},{"typeName":"ProposalEdge","fieldNames":["cursor","node"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://instrument-sessions.diamond.ac.uk/api/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"https://instrument-sessions.diamond.ac.uk/api/graphql"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"schema @link(url: \"https://specs.apollo.dev/federation/v2.7\", import: [\"@key\", \"@shareable\"]) {\n query: Query\n mutation: Mutation\n}\n\ntype Account {\n accountId: Int!\n username: String!\n emailAddress: String\n title: String\n givenName: String\n familyName: String\n type: AccountType!\n state: AccountState!\n proposalRoles: [ProposalAccount!]!\n instrumentSessionRoles: [InstrumentSessionRole!]!\n}\n\nenum AccountState {\n enabled\n disabled\n}\n\nenum AccountType {\n user\n staff\n functional\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ntype Instrument {\n name: String!\n scienceGroup: String\n description: String\n proposals: [Proposal!]!\n instrumentSessions: [InstrumentSession!]!\n}\n\ntype InstrumentSession @key(fields: \"instrumentSessionNumber proposal {proposalNumber}\") {\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n startTime: DateTime\n endTime: DateTime\n type: String\n state: String\n riskRating: String\n proposal: Proposal\n instrument: Instrument!\n roles: [InstrumentSessionRole!]!\n}\n\ntype InstrumentSessionMutations @key(fields: \"instrumentSessionNumber proposalNumber\") {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n instrumentSession: InstrumentSession!\n account: Account!\n role: String!\n onSite: Boolean!\n}\n\ntype Mutation {\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSessionMutations\n}\n\ntype PageInfo @shareable {\n startCursor: String\n endCursor: String\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n}\n\ntype Proposal @key(fields: \"proposalNumber\") {\n proposalNumber: Int!\n proposalCategory: String\n title: String\n summary: String\n state: ProposalState!\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n roles: [ProposalAccount!]!\n}\n\ntype ProposalAccount {\n proposal: Proposal!\n account: Account!\n role: String!\n}\n\ntype ProposalConnection @shareable {\n edges: [ProposalEdge!]!\n pageInfo: PageInfo!\n}\n\ntype ProposalEdge @shareable {\n cursor: String!\n node: Proposal!\n}\n\nenum ProposalState {\n Open\n Closed\n Cancelled\n}\n\ntype Query {\n _entities(representations: [_Any!]!): [_Entity]!\n _service: _Service!\n\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n\n \"\"\"Get a list of proposals\"\"\"\n proposals(proposalCategory: String = null, first: Int = null, last: Int = null, after: String = null, before: String = null): ProposalConnection!\n\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSession\n\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalNumber: Int = null, proposalCategory: String = null): [InstrumentSession!]\n\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n}\n\nscalar _Any\n\nunion _Entity = InstrumentSession | InstrumentSessionMutations | Proposal\n\ntype _Service {\n sdl: String!\n}\n"},"upstreamSchema":{"key":"636412ec8e6e8e278df46ce7da59047a6182733c"}},"requestTimeoutSeconds":"10","id":"1","keys":[{"typeName":"InstrumentSession","selectionSet":"instrumentSessionNumber proposal { proposalNumber }"},{"typeName":"InstrumentSessionMutations","selectionSet":"instrumentSessionNumber proposalNumber"},{"typeName":"Proposal","selectionSet":"proposalNumber"}]},{"kind":"GRAPHQL","rootNodes":[{"typeName":"Mutation","fieldNames":["createSamples","createOrValidateSamples","sample"]},{"typeName":"Query","fieldNames":["sample","samples"]}],"childNodes":[{"typeName":"CreateSamplesResponse","fieldNames":["success","samples","errors"]},{"typeName":"ErrorDetails","fieldNames":["type","location","message"]},{"typeName":"PageInfo","fieldNames":["startCursor","endCursor","hasPreviousPage","hasNextPage"]},{"typeName":"Sample","fieldNames":["id","name","data","createdTime","updatedTime","dataSchemaUrl","parents","children","events","dataSchema"]},{"typeName":"SampleConnection","fieldNames":["edges","pageInfo"]},{"typeName":"SampleEdge","fieldNames":["cursor","node"]},{"typeName":"SampleEvent","fieldNames":["id","timestamp","description"]},{"typeName":"SampleEventConnection","fieldNames":["edges","pageInfo"]},{"typeName":"SampleEventEdge","fieldNames":["cursor","node"]},{"typeName":"SampleMutations","fieldNames":["sampleId","linkInstrumentSessionToSample","addSampleEvent"]},{"typeName":"SampleValidationError","fieldNames":["index","errors"]}],"overrideFieldPathFromAlias":true,"customGraphql":{"fetch":{"url":{"staticVariableContent":"https://sample-information.diamond.ac.uk/api/graphql"},"method":"POST","body":{},"baseUrl":{},"path":{}},"subscription":{"enabled":true,"url":{"staticVariableContent":"https://sample-information.diamond.ac.uk/api/graphql"},"protocol":"GRAPHQL_SUBSCRIPTION_PROTOCOL_WS","websocketSubprotocol":"GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO"},"federation":{"enabled":true,"serviceSdl":"input AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n proposalNumber: Int!\n instrumentSessionNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n\n \"\"\"A human readable error message.\"\"\"\n message: String!\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Mutation {\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n sample(sampleId: UUID!): SampleMutations\n}\n\ntype PageInfo {\n startCursor: String\n endCursor: String\n hasPreviousPage: Boolean!\n hasNextPage: Boolean!\n}\n\ntype Query {\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(proposalNumber: Int!, instrumentSessionNumber: Int!, first: Int!, filter: SampleFilterInput! = {}, before: String = null, after: String = null, last: Int = null, orderBy: SampleOrder! = {}): SampleConnection!\n}\n\ntype Sample {\n id: UUID!\n name: String!\n data: JSON!\n createdTime: DateTime!\n updatedTime: DateTime!\n dataSchemaUrl: String!\n\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n\n \"\"\"Samples derived from this sample\"\"\"\n children(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n\n \"\"\"Events linked to this sample\"\"\"\n events(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleEventConnection!\n\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n id: UUID!\n timestamp: DateTime!\n description: String!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Name of the sample\"\"\"\n name: String!\n\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n}\n\ninput SampleInLegacy {\n name: String!\n data: JSON!\n dataSchemaUrl: String!\n parentIds: [Int!] = null\n children: [SampleInLegacy!] = null\n}\n\ntype SampleMutations {\n sampleId: UUID!\n linkInstrumentSessionToSample(proposalNumber: Int!, instrumentSessionNumber: Int!): Void\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n}\n\ninput SampleOrder {\n name: SortingOrder = null\n createdTime: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void\n"},"upstreamSchema":{"key":"705aec083991f77f3c89aeff197c6cc302953ec1"}},"requestTimeoutSeconds":"10","id":"2"}],"fieldConfigurations":[{"typeName":"Mutation","fieldName":"submitWorkflowTemplate","argumentsConfiguration":[{"name":"name","sourceType":"FIELD_ARGUMENT"},{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"parameters","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"instrumentSession","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"createSamples","argumentsConfiguration":[{"name":"input","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"createOrValidateSamples","argumentsConfiguration":[{"name":"input","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Mutation","fieldName":"sample","argumentsConfiguration":[{"name":"sampleId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflow","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflows","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"cursor","sourceType":"FIELD_ARGUMENT"},{"name":"limit","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflowTemplate","argumentsConfiguration":[{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"workflowTemplates","argumentsConfiguration":[{"name":"cursor","sourceType":"FIELD_ARGUMENT"},{"name":"limit","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"proposal","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"proposals","argumentsConfiguration":[{"name":"proposalCategory","sourceType":"FIELD_ARGUMENT"},{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrumentSession","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrumentSessions","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"proposalCategory","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instrument","argumentsConfiguration":[{"name":"instrumentName","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"instruments","argumentsConfiguration":[{"name":"scienceGroup","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"account","argumentsConfiguration":[{"name":"username","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"sample","argumentsConfiguration":[{"name":"sampleId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Query","fieldName":"samples","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"},{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"filter","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"},{"name":"orderBy","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Subscription","fieldName":"logs","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"workflowName","sourceType":"FIELD_ARGUMENT"},{"name":"taskId","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Subscription","fieldName":"workflow","argumentsConfiguration":[{"name":"visit","sourceType":"FIELD_ARGUMENT"},{"name":"name","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"parents","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"children","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"Sample","fieldName":"events","argumentsConfiguration":[{"name":"first","sourceType":"FIELD_ARGUMENT"},{"name":"before","sourceType":"FIELD_ARGUMENT"},{"name":"after","sourceType":"FIELD_ARGUMENT"},{"name":"last","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"SampleMutations","fieldName":"linkInstrumentSessionToSample","argumentsConfiguration":[{"name":"proposalNumber","sourceType":"FIELD_ARGUMENT"},{"name":"instrumentSessionNumber","sourceType":"FIELD_ARGUMENT"}]},{"typeName":"SampleMutations","fieldName":"addSampleEvent","argumentsConfiguration":[{"name":"sampleEvent","sourceType":"FIELD_ARGUMENT"}]}],"graphqlSchema":"schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ntype Artifact {\n \"\"\"The file name of the artifact\"\"\"\n name: String!\n \"\"\"The download URL for the artifact\"\"\"\n url: Url!\n \"\"\"The MIME type of the artifact data\"\"\"\n mimeType: String!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON\n\n\"\"\"A scalar that can represent any JSON Object value.\"\"\"\nscalar JSONObject\n\n\"\"\"A single log line streamed from a pod\"\"\"\ntype LogEntry {\n \"\"\"The log line content\"\"\"\n content: String!\n \"\"\"The name of the pod producing the log\"\"\"\n podName: String!\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Mutation {\n submitWorkflowTemplate(name: String!, visit: VisitInput!, parameters: JSON!): Workflow!\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSessionMutations\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n sample(sampleId: UUID!): SampleMutations\n}\n\n\"\"\"Information about pagination in a connection\"\"\"\ntype PageInfo {\n \"\"\"When paginating backwards, are there more items?\"\"\"\n hasPreviousPage: Boolean!\n \"\"\"When paginating forwards, are there more items?\"\"\"\n hasNextPage: Boolean!\n \"\"\"When paginating backwards, the cursor to continue.\"\"\"\n startCursor: String\n \"\"\"When paginating forwards, the cursor to continue.\"\"\"\n endCursor: String\n}\n\n\"\"\"The root query of the service\"\"\"\ntype Query {\n \"\"\"Get a single [`Workflow`] by proposal, visit, and name\"\"\"\n workflow(visit: VisitInput!, name: String!): Workflow!\n workflows(visit: VisitInput!, cursor: String, limit: Int, filter: WorkflowFilter): WorkflowConnection!\n workflowTemplate(name: String!): WorkflowTemplate!\n workflowTemplates(cursor: String, limit: Int, filter: WorkflowTemplatesFilter): WorkflowTemplateConnection!\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n \"\"\"Get a list of proposals\"\"\"\n proposals(proposalCategory: String = null, first: Int = null, last: Int = null, after: String = null, before: String = null): ProposalConnection!\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(proposalNumber: Int!, instrumentSessionNumber: Int!): InstrumentSession\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalNumber: Int = null, proposalCategory: String = null): [InstrumentSession!]\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(proposalNumber: Int!, instrumentSessionNumber: Int!, first: Int!, filter: SampleFilterInput! = {schemaUrl: null, createdTime: null, updatedTime: null, name: null}, before: String = null, after: String = null, last: Int = null, orderBy: SampleOrder! = {name: null, createdTime: null, updatedTime: null}): SampleConnection!\n}\n\n\"\"\"Supported DLS science groups\"\"\"\nenum ScienceGroup {\n \"\"\"Macromolecular Crystallography\"\"\"\n MX\n \"\"\"Workflows Examples\"\"\"\n EXAMPLES\n \"\"\"Magnetic Materials\"\"\"\n MAGNETIC_MATERIALS\n \"\"\"Soft Condensed Matter\"\"\"\n CONDENSED_MATTER\n \"\"\"Imaging and Microscopy\"\"\"\n IMAGING\n \"\"\"Biological Cryo-Imaging\"\"\"\n BIO_CRYO_IMAGING\n \"\"\"Structures and Surfaces\"\"\"\n SURFACES\n \"\"\"Crystallography\"\"\"\n CRYSTALLOGRAPHY\n \"\"\"Spectroscopy\"\"\"\n SPECTROSCOPY\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Subscription {\n \"\"\"Processing to subscribe to logs for a single pod of a workflow\"\"\"\n logs(visit: VisitInput!, workflowName: String!, taskId: String!): LogEntry!\n \"\"\"Processing to subscribe to data for all workflows in a session\"\"\"\n workflow(visit: VisitInput!, name: String!): Workflow!\n}\n\ntype Task {\n \"\"\"Unique name of the task\"\"\"\n id: String!\n \"\"\"Display name of the task\"\"\"\n name: String!\n \"\"\"Current status of a task\"\"\"\n status: TaskStatus!\n \"\"\"Parent of a task\"\"\"\n depends: [String!]!\n \"\"\"Children of a task\"\"\"\n dependencies: [String!]!\n \"\"\"Artifacts produced by a task\"\"\"\n artifacts: [Artifact!]!\n \"\"\"Node type - Pod, DAG, etc\"\"\"\n stepType: String!\n \"\"\"Start time for a task on a workflow\"\"\"\n startTime: DateTime\n \"\"\"End time for a task on a workflow\"\"\"\n endTime: DateTime\n \"\"\"\n A human readable message indicating details about why this step is in this condition\n \"\"\"\n message: String\n}\n\nenum TaskStatus {\n PENDING\n RUNNING\n SUCCEEDED\n SKIPPED\n FAILED\n ERROR\n OMITTED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ntype Visit {\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n \"\"\"Session visit Number\"\"\"\n number: Int!\n}\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ninput VisitInput {\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n \"\"\"Session visit Number\"\"\"\n number: Int!\n}\n\ntype Workflow {\n \"\"\"The name given to the workflow, unique within a given visit\"\"\"\n name: String!\n \"\"\"The visit the Workflow was run against\"\"\"\n visit: Visit!\n \"\"\"The current status of the workflow\"\"\"\n status: WorkflowStatus\n \"\"\"The top-level workflow parameters\"\"\"\n parameters: JSONObject\n \"\"\"The name of the template used to run the workflow\"\"\"\n templateRef: String\n \"\"\"The workflow creator\"\"\"\n creator: WorkflowCreator!\n}\n\ntype WorkflowConnection {\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo!\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowEdge!]!\n \"\"\"A list of nodes.\"\"\"\n nodes: [Workflow!]!\n}\n\n\"\"\"Information about the creator of a workflow.\"\"\"\ntype WorkflowCreator {\n \"\"\"\n An identifier unique to the creator of the workflow.\n Typically this is the creator's Fed-ID.\n \"\"\"\n creatorId: String!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowEdge {\n \"\"\"The item at the end of the edge\"\"\"\n node: Workflow!\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String!\n}\n\n\"\"\"All tasks in the workflow have errored\"\"\"\ntype WorkflowErroredStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All tasks in the workflow have failed\"\"\"\ntype WorkflowFailedStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All the supported Workflows filters\"\"\"\ninput WorkflowFilter {\n \"\"\"The status field for a workflow\"\"\"\n workflowStatusFilter: WorkflowStatusFilter\n \"\"\"The fedid of the user who created the workflow\"\"\"\n creator: Creator\n \"\"\"The name of the workflow template\"\"\"\n template: Template\n}\n\ntype WorkflowPendingStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n}\n\ntype WorkflowRunningStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"The status of a workflow\"\"\"\nunion WorkflowStatus = WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus | WorkflowFailedStatus | WorkflowErroredStatus\n\n\"\"\"Represents workflow status filters\"\"\"\ninput WorkflowStatusFilter {\n pending: Boolean! = false\n running: Boolean! = false\n succeeded: Boolean! = false\n failed: Boolean! = false\n error: Boolean! = false\n}\n\n\"\"\"All tasks in the workflow have succeded\"\"\"\ntype WorkflowSucceededStatus {\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n \"\"\"The name given to the workflow template, globally unique\"\"\"\n name: String!\n \"\"\"The group who maintains the workflow template\"\"\"\n maintainer: String!\n \"\"\"A human readable title for the workflow template\"\"\"\n title: String\n \"\"\"A human readable description of the workflow which is created\"\"\"\n description: String\n \"\"\"The repository storing the code associated with this template.\"\"\"\n repository: String\n \"\"\"A JSON Schema describing the arguments of a Workflow Template\"\"\"\n arguments: JSON!\n \"\"\"\n A JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n \"\"\"\n uiSchema: JSON\n}\n\ntype WorkflowTemplateConnection {\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo!\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowTemplateEdge!]!\n \"\"\"A list of nodes.\"\"\"\n nodes: [WorkflowTemplate!]!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowTemplateEdge {\n \"\"\"The item at the end of the edge\"\"\"\n node: WorkflowTemplate!\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String!\n}\n\n\"\"\"Supported label filters for ClusterWorkflowTemplates\"\"\"\ninput WorkflowTemplatesFilter {\n \"\"\"The science group owning the template eg imaging\"\"\"\n scienceGroup: [ScienceGroup!]\n}\n\ntype Account {\n accountId: Int!\n username: String!\n emailAddress: String\n title: String\n givenName: String\n familyName: String\n type: AccountType!\n state: AccountState!\n proposalRoles: [ProposalAccount!]!\n instrumentSessionRoles: [InstrumentSessionRole!]!\n}\n\nenum AccountState {\n enabled\n disabled\n}\n\nenum AccountType {\n user\n staff\n functional\n}\n\ntype Instrument {\n name: String!\n scienceGroup: String\n description: String\n proposals: [Proposal!]!\n instrumentSessions: [InstrumentSession!]!\n}\n\ntype InstrumentSession {\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n startTime: DateTime\n endTime: DateTime\n type: String\n state: String\n riskRating: String\n proposal: Proposal\n instrument: Instrument!\n roles: [InstrumentSessionRole!]!\n}\n\ntype InstrumentSessionMutations {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n instrumentSession: InstrumentSession!\n account: Account!\n role: String!\n onSite: Boolean!\n}\n\ntype Proposal {\n proposalNumber: Int!\n proposalCategory: String\n title: String\n summary: String\n state: ProposalState!\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n roles: [ProposalAccount!]!\n}\n\ntype ProposalAccount {\n proposal: Proposal!\n account: Account!\n role: String!\n}\n\ntype ProposalConnection {\n edges: [ProposalEdge!]!\n pageInfo: PageInfo!\n}\n\ntype ProposalEdge {\n cursor: String!\n node: Proposal!\n}\n\nenum ProposalState {\n Open\n Closed\n Cancelled\n}\n\ninput AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n proposalNumber: Int!\n instrumentSessionNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n}\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n \"\"\"A human readable error message.\"\"\"\n message: String!\n}\n\ntype Sample {\n id: UUID!\n name: String!\n data: JSON!\n createdTime: DateTime!\n updatedTime: DateTime!\n dataSchemaUrl: String!\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n \"\"\"Samples derived from this sample\"\"\"\n children(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleConnection!\n \"\"\"Events linked to this sample\"\"\"\n events(first: Int = null, before: String = null, after: String = null, last: Int = null): SampleEventConnection!\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n id: UUID!\n timestamp: DateTime!\n description: String!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Name of the sample\"\"\"\n name: String!\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n}\n\ninput SampleInLegacy {\n name: String!\n data: JSON!\n dataSchemaUrl: String!\n parentIds: [Int!] = null\n children: [SampleInLegacy!] = null\n}\n\ntype SampleMutations {\n sampleId: UUID!\n linkInstrumentSessionToSample(proposalNumber: Int!, instrumentSessionNumber: Int!): Void\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n}\n\ninput SampleOrder {\n name: SortingOrder = null\n createdTime: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void","stringStorage":{"399ecb62e2d8de68392ee3dfb8e088d1edc68f46":"schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ndirective @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA\n\ndirective @shareable repeatable on FIELD_DEFINITION | OBJECT\n\ntype Artifact {\n \"\"\"The MIME type of the artifact data\"\"\"\n mimeType: String!\n \"\"\"The file name of the artifact\"\"\"\n name: String!\n \"\"\"The download URL for the artifact\"\"\"\n url: Url!\n}\n\nscalar Creator\n\n\"\"\"\nImplement the DateTime scalar\n\nThe input/output is a string in RFC3339 format.\n\"\"\"\nscalar DateTime\n\n\"\"\"A scalar that can represent any JSON value.\"\"\"\nscalar JSON\n\n\"\"\"A scalar that can represent any JSON Object value.\"\"\"\nscalar JSONObject\n\n\"\"\"A single log line streamed from a pod\"\"\"\ntype LogEntry {\n \"\"\"The log line content\"\"\"\n content: String!\n \"\"\"The name of the pod producing the log\"\"\"\n podName: String!\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Mutation {\n submitWorkflowTemplate(name: String!, parameters: JSON!, visit: VisitInput!): Workflow!\n}\n\n\"\"\"Information about pagination in a connection\"\"\"\ntype PageInfo {\n \"\"\"When paginating forwards, the cursor to continue.\"\"\"\n endCursor: String @shareable\n \"\"\"When paginating forwards, are there more items?\"\"\"\n hasNextPage: Boolean! @shareable\n \"\"\"When paginating backwards, are there more items?\"\"\"\n hasPreviousPage: Boolean! @shareable\n \"\"\"When paginating backwards, the cursor to continue.\"\"\"\n startCursor: String @shareable\n}\n\n\"\"\"The root query of the service\"\"\"\ntype Query {\n \"\"\"Get a single [`Workflow`] by proposal, visit, and name\"\"\"\n workflow(name: String!, visit: VisitInput!): Workflow!\n workflowTemplate(name: String!): WorkflowTemplate!\n workflowTemplates(cursor: String, filter: WorkflowTemplatesFilter, limit: Int): WorkflowTemplateConnection!\n workflows(cursor: String, filter: WorkflowFilter, limit: Int, visit: VisitInput!): WorkflowConnection!\n}\n\n\"\"\"Supported DLS science groups\"\"\"\nenum ScienceGroup {\n \"\"\"Biological Cryo-Imaging\"\"\"\n BIO_CRYO_IMAGING\n \"\"\"Soft Condensed Matter\"\"\"\n CONDENSED_MATTER\n \"\"\"Crystallography\"\"\"\n CRYSTALLOGRAPHY\n \"\"\"Workflows Examples\"\"\"\n EXAMPLES\n \"\"\"Imaging and Microscopy\"\"\"\n IMAGING\n \"\"\"Magnetic Materials\"\"\"\n MAGNETIC_MATERIALS\n \"\"\"Macromolecular Crystallography\"\"\"\n MX\n \"\"\"Spectroscopy\"\"\"\n SPECTROSCOPY\n \"\"\"Structures and Surfaces\"\"\"\n SURFACES\n}\n\n\"\"\"The root mutation of the service\"\"\"\ntype Subscription {\n \"\"\"Processing to subscribe to logs for a single pod of a workflow\"\"\"\n logs(taskId: String!, visit: VisitInput!, workflowName: String!): LogEntry!\n \"\"\"Processing to subscribe to data for all workflows in a session\"\"\"\n workflow(name: String!, visit: VisitInput!): Workflow!\n}\n\ntype Task {\n \"\"\"Artifacts produced by a task\"\"\"\n artifacts: [Artifact!]!\n \"\"\"Children of a task\"\"\"\n dependencies: [String!]!\n \"\"\"Parent of a task\"\"\"\n depends: [String!]!\n \"\"\"End time for a task on a workflow\"\"\"\n endTime: DateTime\n \"\"\"Unique name of the task\"\"\"\n id: String!\n \"\"\"\n A human readable message indicating details about why this step is in this condition\n \"\"\"\n message: String\n \"\"\"Display name of the task\"\"\"\n name: String!\n \"\"\"Start time for a task on a workflow\"\"\"\n startTime: DateTime\n \"\"\"Current status of a task\"\"\"\n status: TaskStatus!\n \"\"\"Node type - Pod, DAG, etc\"\"\"\n stepType: String!\n}\n\nenum TaskStatus {\n ERROR\n FAILED\n OMITTED\n PENDING\n RUNNING\n SKIPPED\n SUCCEEDED\n}\n\nscalar Template\n\n\"\"\"\nURL is a String implementing the [URL Standard](http://url.spec.whatwg.org/)\n\"\"\"\nscalar Url\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ntype Visit {\n \"\"\"Session visit Number\"\"\"\n number: Int!\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n}\n\n\"\"\"A visit to an instrument as part of a session\"\"\"\ninput VisitInput {\n \"\"\"Session visit Number\"\"\"\n number: Int!\n \"\"\"Project Proposal Code\"\"\"\n proposalCode: String!\n \"\"\"Project Proposal Number\"\"\"\n proposalNumber: Int!\n}\n\ntype Workflow {\n \"\"\"The workflow creator\"\"\"\n creator: WorkflowCreator!\n \"\"\"The name given to the workflow, unique within a given visit\"\"\"\n name: String!\n \"\"\"The top-level workflow parameters\"\"\"\n parameters: JSONObject\n \"\"\"The current status of the workflow\"\"\"\n status: WorkflowStatus\n \"\"\"The name of the template used to run the workflow\"\"\"\n templateRef: String\n \"\"\"The visit the Workflow was run against\"\"\"\n visit: Visit!\n}\n\ntype WorkflowConnection {\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowEdge!]! @shareable\n \"\"\"A list of nodes.\"\"\"\n nodes: [Workflow!]! @shareable\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo! @shareable\n}\n\n\"\"\"Information about the creator of a workflow.\"\"\"\ntype WorkflowCreator {\n \"\"\"\n An identifier unique to the creator of the workflow.\n Typically this is the creator's Fed-ID.\n \"\"\"\n creatorId: String!\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowEdge {\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String! @shareable\n \"\"\"The item at the end of the edge\"\"\"\n node: Workflow! @shareable\n}\n\n\"\"\"All tasks in the workflow have errored\"\"\"\ntype WorkflowErroredStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All tasks in the workflow have failed\"\"\"\ntype WorkflowFailedStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"All the supported Workflows filters\"\"\"\ninput WorkflowFilter {\n \"\"\"The fedid of the user who created the workflow\"\"\"\n creator: Creator\n \"\"\"The name of the workflow template\"\"\"\n template: Template\n \"\"\"The status field for a workflow\"\"\"\n workflowStatusFilter: WorkflowStatusFilter\n}\n\ntype WorkflowPendingStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n}\n\ntype WorkflowRunningStatus {\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\n\"\"\"The status of a workflow\"\"\"\nunion WorkflowStatus = WorkflowErroredStatus | WorkflowFailedStatus | WorkflowPendingStatus | WorkflowRunningStatus | WorkflowSucceededStatus\n\n\"\"\"Represents workflow status filters\"\"\"\ninput WorkflowStatusFilter {\n error: Boolean! = false\n failed: Boolean! = false\n pending: Boolean! = false\n running: Boolean! = false\n succeeded: Boolean! = false\n}\n\n\"\"\"All tasks in the workflow have succeded\"\"\"\ntype WorkflowSucceededStatus {\n \"\"\"Time at which this workflow completed\"\"\"\n endTime: DateTime!\n \"\"\"\n A human readable message indicating details about why the workflow is in this condition\n \"\"\"\n message: String\n \"\"\"Time at which this workflow started\"\"\"\n startTime: DateTime!\n \"\"\"Tasks created by the workflow\"\"\"\n tasks: [Task!]!\n}\n\ntype WorkflowTemplate {\n \"\"\"A JSON Schema describing the arguments of a Workflow Template\"\"\"\n arguments: JSON!\n \"\"\"A human readable description of the workflow which is created\"\"\"\n description: String\n \"\"\"The group who maintains the workflow template\"\"\"\n maintainer: String!\n \"\"\"The name given to the workflow template, globally unique\"\"\"\n name: String!\n \"\"\"The repository storing the code associated with this template.\"\"\"\n repository: String\n \"\"\"A human readable title for the workflow template\"\"\"\n title: String\n \"\"\"\n A JSON Forms UI Schema describing how to render the arguments of the Workflow Template\n \"\"\"\n uiSchema: JSON\n}\n\ntype WorkflowTemplateConnection {\n \"\"\"A list of edges.\"\"\"\n edges: [WorkflowTemplateEdge!]! @shareable\n \"\"\"A list of nodes.\"\"\"\n nodes: [WorkflowTemplate!]! @shareable\n \"\"\"Information to aid in pagination.\"\"\"\n pageInfo: PageInfo! @shareable\n}\n\n\"\"\"An edge in a connection.\"\"\"\ntype WorkflowTemplateEdge {\n \"\"\"A cursor for use in pagination\"\"\"\n cursor: String! @shareable\n \"\"\"The item at the end of the edge\"\"\"\n node: WorkflowTemplate! @shareable\n}\n\n\"\"\"Supported label filters for ClusterWorkflowTemplates\"\"\"\ninput WorkflowTemplatesFilter {\n \"\"\"The science group owning the template eg imaging\"\"\"\n scienceGroup: [ScienceGroup!]\n}\n\nscalar link__Import\n\nenum link__Purpose {\n EXECUTION\n SECURITY\n}","636412ec8e6e8e278df46ce7da59047a6182733c":"schema @link(url: \"https://specs.apollo.dev/federation/v2.7\", import: [\"@key\", \"@shareable\"]) {\n query: Query\n mutation: Mutation\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ndirective @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA\n\ndirective @shareable repeatable on FIELD_DEFINITION | OBJECT\n\ntype Account {\n accountId: Int!\n emailAddress: String\n familyName: String\n givenName: String\n instrumentSessionRoles: [InstrumentSessionRole!]!\n proposalRoles: [ProposalAccount!]!\n state: AccountState!\n title: String\n type: AccountType!\n username: String!\n}\n\nenum AccountState {\n disabled\n enabled\n}\n\nenum AccountType {\n functional\n staff\n user\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ntype Instrument {\n description: String\n instrumentSessions: [InstrumentSession!]!\n name: String!\n proposals: [Proposal!]!\n scienceGroup: String\n}\n\ntype InstrumentSession @key(fields: \"instrumentSessionNumber proposal {proposalNumber}\") {\n endTime: DateTime\n instrument: Instrument!\n instrumentSessionId: Int!\n instrumentSessionNumber: Int!\n proposal: Proposal\n riskRating: String\n roles: [InstrumentSessionRole!]!\n startTime: DateTime\n state: String\n type: String\n}\n\ntype InstrumentSessionMutations @key(fields: \"instrumentSessionNumber proposalNumber\") {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n}\n\ntype InstrumentSessionRole {\n account: Account!\n instrumentSession: InstrumentSession!\n onSite: Boolean!\n role: String!\n}\n\ntype Mutation {\n instrumentSession(instrumentSessionNumber: Int!, proposalNumber: Int!): InstrumentSessionMutations\n}\n\ntype PageInfo {\n endCursor: String @shareable\n hasNextPage: Boolean! @shareable\n hasPreviousPage: Boolean! @shareable\n startCursor: String @shareable\n}\n\ntype Proposal @key(fields: \"proposalNumber\") {\n instrumentSessions: [InstrumentSession!]!\n instruments: [Instrument!]!\n proposalCategory: String\n proposalNumber: Int!\n roles: [ProposalAccount!]!\n state: ProposalState!\n summary: String\n title: String\n}\n\ntype ProposalAccount {\n account: Account!\n proposal: Proposal!\n role: String!\n}\n\ntype ProposalConnection {\n edges: [ProposalEdge!]! @shareable\n pageInfo: PageInfo! @shareable\n}\n\ntype ProposalEdge {\n cursor: String! @shareable\n node: Proposal! @shareable\n}\n\nenum ProposalState {\n Cancelled\n Closed\n Open\n}\n\ntype Query {\n \"\"\"Get an account\"\"\"\n account(username: String!): Account\n \"\"\"Get an instrument\"\"\"\n instrument(instrumentName: String!): Instrument\n \"\"\"Get a instrument session\"\"\"\n instrumentSession(instrumentSessionNumber: Int!, proposalNumber: Int!): InstrumentSession\n \"\"\"Get a instrument session\"\"\"\n instrumentSessions(proposalCategory: String = null, proposalNumber: Int = null): [InstrumentSession!]\n \"\"\"Get a list of instruments\"\"\"\n instruments(scienceGroup: String = null): [Instrument!]!\n \"\"\"Get a proposal by its number\"\"\"\n proposal(proposalNumber: Int!): Proposal\n \"\"\"Get a list of proposals\"\"\"\n proposals(after: String = null, before: String = null, first: Int = null, last: Int = null, proposalCategory: String = null): ProposalConnection!\n}\n\nscalar link__Import\n\nenum link__Purpose {\n EXECUTION\n SECURITY\n}\n\nscalar openfed__FieldSet","705aec083991f77f3c89aeff197c6cc302953ec1":"schema {\n query: Query\n mutation: Mutation\n}\n\ninput AddSampleEventInput {\n description: String!\n}\n\ninput CreateOrValidateSampleInput {\n \"\"\"URL of the JSON schema the samples' `data` should be validated against\"\"\"\n dataSchemaUrl: String!\n \"\"\"Number of the instrument session the samples should be associated with\"\"\"\n instrumentSessionNumber: Int!\n \"\"\"Number of the proposal the samples should be associated with\"\"\"\n proposalNumber: Int!\n \"\"\"Samples to be created\"\"\"\n samples: [SampleIn!]!\n \"\"\"\n Whether or not the provided samples should only be validated and not created\n \"\"\"\n validateOnly: Boolean! = false\n}\n\ninput CreateSampleInput {\n instrumentSessionNumber: Int!\n proposalNumber: Int!\n samples: [SampleInLegacy!]!\n validateOnly: Boolean! = false\n}\n\n\"\"\"Return type when creating or validating samples\"\"\"\ntype CreateSamplesResponse {\n \"\"\"Errors that occurred during sample validation\"\"\"\n errors: [SampleValidationError!]!\n \"\"\"Samples that have been created\"\"\"\n samples: [Sample!]!\n \"\"\"Whether the operation has succeeded without validation errors\"\"\"\n success: Boolean!\n}\n\n\"\"\"Date with time (isoformat)\"\"\"\nscalar DateTime\n\ninput DatetimeOperatorInput {\n \"\"\"\n Will filter to items where the `DateTime` field is greater than (i.e. after) the provided value\n \"\"\"\n gt: DateTime = null\n \"\"\"\n Will filter to items where the `DateTime` field is less than (i.e. before) the provided value\n \"\"\"\n lt: DateTime = null\n}\n\n\"\"\"The details of sample validation error\"\"\"\ntype ErrorDetails {\n \"\"\"\n Tuple of strings identifying where in the sample schema the error occurred.\n \"\"\"\n location: [String!]!\n \"\"\"A human readable error message.\"\"\"\n message: String!\n \"\"\"The type of error that occurred\"\"\"\n type: String!\n}\n\n\"\"\"\nThe `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf).\n\"\"\"\nscalar JSON @specifiedBy(url: \"https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf\")\n\ntype Mutation {\n createOrValidateSamples(input: CreateOrValidateSampleInput!): CreateSamplesResponse!\n createSamples(input: CreateSampleInput!): [Sample!]! @deprecated(reason: \"Will be replaced by createOrValidateSamples\")\n sample(sampleId: UUID!): SampleMutations\n}\n\ntype PageInfo {\n endCursor: String\n hasNextPage: Boolean!\n hasPreviousPage: Boolean!\n startCursor: String\n}\n\ntype Query {\n \"\"\"Get a sample by its id\"\"\"\n sample(sampleId: UUID!): Sample\n \"\"\"Get a list of samples associated with a given instrument session\"\"\"\n samples(after: String = null, before: String = null, filter: SampleFilterInput! = {createdTime: null, name: null, schemaUrl: null, updatedTime: null}, first: Int!, instrumentSessionNumber: Int!, last: Int = null, orderBy: SampleOrder! = {createdTime: null, name: null, updatedTime: null}, proposalNumber: Int!): SampleConnection!\n}\n\ntype Sample {\n \"\"\"Samples derived from this sample\"\"\"\n children(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleConnection!\n createdTime: DateTime!\n data: JSON!\n \"\"\"The JSON schema that the sample's `data` conforms to\"\"\"\n dataSchema: JSON!\n dataSchemaUrl: String!\n \"\"\"Events linked to this sample\"\"\"\n events(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleEventConnection!\n id: UUID!\n name: String!\n \"\"\"Samples from which this sample is derived\"\"\"\n parents(after: String = null, before: String = null, first: Int = null, last: Int = null): SampleConnection!\n updatedTime: DateTime!\n}\n\ntype SampleConnection {\n edges: [SampleEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEdge {\n cursor: String!\n node: Sample!\n}\n\ntype SampleEvent {\n description: String!\n id: UUID!\n timestamp: DateTime!\n}\n\ntype SampleEventConnection {\n edges: [SampleEventEdge!]!\n pageInfo: PageInfo!\n}\n\ntype SampleEventEdge {\n cursor: String!\n node: SampleEvent!\n}\n\ninput SampleFilterInput {\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n createdTime: DatetimeOperatorInput = null\n \"\"\"Filter on the `name` field of `Sample`\"\"\"\n name: StringOperatorInput = null\n \"\"\"Filter on the `schemaUrl` field of `Sample`\"\"\"\n schemaUrl: StringOperatorInput = null\n \"\"\"Filter on the `createdTime` field of `Sample`\"\"\"\n updatedTime: DatetimeOperatorInput = null\n}\n\ninput SampleIn {\n \"\"\"Data of the sample\"\"\"\n data: JSON!\n \"\"\"Name of the sample\"\"\"\n name: String!\n}\n\ninput SampleInLegacy {\n children: [SampleInLegacy!] = null\n data: JSON!\n dataSchemaUrl: String!\n name: String!\n parentIds: [Int!] = null\n}\n\ntype SampleMutations {\n addSampleEvent(sampleEvent: AddSampleEventInput!): SampleEvent!\n linkInstrumentSessionToSample(instrumentSessionNumber: Int!, proposalNumber: Int!): Void\n sampleId: UUID!\n}\n\ninput SampleOrder {\n createdTime: SortingOrder = null\n name: SortingOrder = null\n updatedTime: SortingOrder = null\n}\n\n\"\"\"The details of errors occurred when validating a sample\"\"\"\ntype SampleValidationError {\n \"\"\"Errors that occurred when validating the sample\"\"\"\n errors: [ErrorDetails!]!\n \"\"\"\n The index of the sample in CreateSampleInput.samples for which the error occurred\n \"\"\"\n index: Int!\n}\n\nenum SortingOrder {\n ASC\n DESC\n}\n\n\"\"\"Conditions used to filter results based on the value of a String field\"\"\"\ninput StringOperatorInput {\n \"\"\"\n Will filter to items where the `String` field is contains the provided value\n \"\"\"\n contains: String = null\n \"\"\"\n Will filter to items where the `String` field is equal to the provided value\n \"\"\"\n eq: String = null\n \"\"\"\n Will filter to items where the `String` field is a member of the provided value\n \"\"\"\n in: [String!] = null\n \"\"\"\n Will filter to items where the `String` field is not equal to the provided value\n \"\"\"\n ne: String = null\n \"\"\"\n Will filter to items where the `String` field is not a member of the provided value\n \"\"\"\n nin: [String!] = null\n}\n\nscalar UUID\n\n\"\"\"Represents NULL values\"\"\"\nscalar Void"}},"version":"00000000-0000-0000-0000-000000000000","subgraphs":[{"id":"0","name":"workflows","routingUrl":"https://workflows.diamond.ac.uk/graphql"},{"id":"1","name":"instrument_sessions","routingUrl":"https://instrument-sessions.diamond.ac.uk/api/graphql"},{"id":"2","name":"samples","routingUrl":"https://sample-information.diamond.ac.uk/api/graphql"}],"compatibilityVersion":"1:0.51.0"} \ No newline at end of file From 5054c49b66d3256a2b279037f0f0a7c027d42076 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 14:03:49 +0000 Subject: [PATCH 06/16] fix: move config to files --- charts/graph/{ => files}/router-execution-config.json | 0 charts/graph/templates/configmap-router-execution-config.yaml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename charts/graph/{ => files}/router-execution-config.json (100%) diff --git a/charts/graph/router-execution-config.json b/charts/graph/files/router-execution-config.json similarity index 100% rename from charts/graph/router-execution-config.json rename to charts/graph/files/router-execution-config.json diff --git a/charts/graph/templates/configmap-router-execution-config.yaml b/charts/graph/templates/configmap-router-execution-config.yaml index 0c511d7..96e17fa 100644 --- a/charts/graph/templates/configmap-router-execution-config.yaml +++ b/charts/graph/templates/configmap-router-execution-config.yaml @@ -5,4 +5,4 @@ metadata: name: {{.Release.Name}}-router-execution-config data: execution-config.json: | - {{- .Files.Get "router-execution-config.json" | nindent 4 }} + {{- .Files.Get "files/router-execution-config.json" | nindent 4 }} From 4014701a25856310b4c20f662736ea9930819919 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 14:29:12 +0000 Subject: [PATCH 07/16] fix: hardcode config path --- charts/graph/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/graph/values.yaml b/charts/graph/values.yaml index e7f712f..0606ba1 100644 --- a/charts/graph/values.yaml +++ b/charts/graph/values.yaml @@ -82,7 +82,7 @@ router: extraVolumes: - name: router-execution-config configMap: - name: "{{ .Release.Name }}-router-execution-config" + name: "graph-nightly-router-execution-config" items: - key: execution-config.json path: execution-config.json From ad8d6290c8d1f1ac8e9a840bea184118ec91e9f3 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 14:40:25 +0000 Subject: [PATCH 08/16] Use port 4000 for listen address --- charts/graph/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/graph/values.yaml b/charts/graph/values.yaml index 0606ba1..76d9d99 100644 --- a/charts/graph/values.yaml +++ b/charts/graph/values.yaml @@ -29,7 +29,7 @@ router: log_level: "debug" json_log: true - listen_addr: "0.0.0.0:3002" + listen_addr: "0.0.0.0:4000" health_check_path: "/health" readiness_check_path: "/health/ready" From 0a5ac997979f93c826c5c048f8b58b8a5a79e424 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 14:59:48 +0000 Subject: [PATCH 09/16] fix: use port 3002 for health checks --- charts/apps/templates/nightly.yaml | 2 +- charts/apps/templates/stable.yaml | 2 +- charts/graph/values.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index 21272e1..1cc5afa 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -28,7 +28,7 @@ spec: version: "1" log_level: "info" - listen_addr: "0.0.0.0:4000" + listen_addr: "0.0.0.0:3002" health_check_path: "/health" readiness_check_path: "/health/ready" liveness_check_path: "/health/live" diff --git a/charts/apps/templates/stable.yaml b/charts/apps/templates/stable.yaml index bfb04fb..a307eda 100644 --- a/charts/apps/templates/stable.yaml +++ b/charts/apps/templates/stable.yaml @@ -35,7 +35,7 @@ spec: version: "1" log_level: "info" - listen_addr: "0.0.0.0:4000" + listen_addr: "0.0.0.0:3002" health_check_path: "/health" readiness_check_path: "/health/ready" liveness_check_path: "/health/live" diff --git a/charts/graph/values.yaml b/charts/graph/values.yaml index 76d9d99..0606ba1 100644 --- a/charts/graph/values.yaml +++ b/charts/graph/values.yaml @@ -29,7 +29,7 @@ router: log_level: "debug" json_log: true - listen_addr: "0.0.0.0:4000" + listen_addr: "0.0.0.0:3002" health_check_path: "/health" readiness_check_path: "/health/ready" From dae9e40e7acaa36bdb44a6ff7b4f136c56549760 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Wed, 11 Feb 2026 15:25:42 +0000 Subject: [PATCH 10/16] fix: update graph nightly oauth2 port to 3002 --- charts/graph/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/graph/values.yaml b/charts/graph/values.yaml index 0606ba1..f430e68 100644 --- a/charts/graph/values.yaml +++ b/charts/graph/values.yaml @@ -150,11 +150,11 @@ oauth2-proxy: upstreams: - id: router path: / - uri: http://{{ .Release.Name }}-router:80 + uri: http://graph-nightly-router:3002 extraVolumes: - name: client-secret secret: - secretName: "{{ .Release.Name }}-oauth2-client" + secretName: "graph-nightly-oauth2-client" items: - key: secret path: client-secret From c84244092ad21551980585768dd28f4d2032cb85 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Thu, 12 Feb 2026 09:12:57 +0000 Subject: [PATCH 11/16] fix: add websocket support --- charts/apps/templates/nightly.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index 1cc5afa..cebb7d2 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -80,8 +80,14 @@ spec: hostname: graph-nightly.diamond.ac.uk hosts: - graph-nightly.diamond.ac.uk + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" + nginx.ingress.kubernetes.io/websocket-services: "graph-nightly-oauth2-proxy" alphaConfig: enabled: true + configData: + proxyWebSockets: true configData: providers: - provider: oidc From 265d34727cb2eea31cf213c400a5b8552742cf91 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Thu, 12 Feb 2026 09:39:37 +0000 Subject: [PATCH 12/16] fix: update annotation label --- charts/apps/templates/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index cebb7d2..f95684e 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -74,7 +74,7 @@ spec: - endpoint: "http://graph-monitoring-opentelemetry-collector:4317" exporter: "grpc" - oauth2-proxy: + "oauth2-proxy": ingress: enabled: true hostname: graph-nightly.diamond.ac.uk From 3e1c6ae3df7df778bfad6e00ea607ea4a3a66a39 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Thu, 12 Feb 2026 09:49:56 +0000 Subject: [PATCH 13/16] fix: proxy web sockets --- charts/apps/templates/nightly.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index f95684e..ad903e9 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -88,7 +88,6 @@ spec: enabled: true configData: proxyWebSockets: true - configData: providers: - provider: oidc scope: "openid profile email fedid" From 27a0837f57ef9bd2b4e3e1ee665cab4d100fa3db Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Thu, 12 Feb 2026 10:10:56 +0000 Subject: [PATCH 14/16] fix:correct proxy websocket flag --- charts/apps/templates/nightly.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index ad903e9..0546088 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -75,6 +75,8 @@ spec: exporter: "grpc" "oauth2-proxy": + extraArgs: + proxy-websockets: "true" ingress: enabled: true hostname: graph-nightly.diamond.ac.uk @@ -87,7 +89,6 @@ spec: alphaConfig: enabled: true configData: - proxyWebSockets: true providers: - provider: oidc scope: "openid profile email fedid" From f1e9720a2481ca3235594a957204df19d89d970d Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Thu, 12 Feb 2026 10:45:22 +0000 Subject: [PATCH 15/16] fix: revert proxyWebsocket --- charts/apps/templates/nightly.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index 0546088..8599d78 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -75,8 +75,6 @@ spec: exporter: "grpc" "oauth2-proxy": - extraArgs: - proxy-websockets: "true" ingress: enabled: true hostname: graph-nightly.diamond.ac.uk From ebc11c7f2f654f81289279c8f39586e03ab0fdd7 Mon Sep 17 00:00:00 2001 From: "Beilsten-Edmands, Victoria (DLSLtd,RAL,LSCI)" Date: Thu, 12 Feb 2026 11:04:53 +0000 Subject: [PATCH 16/16] fix: use debug logging --- charts/apps/templates/nightly.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/apps/templates/nightly.yaml b/charts/apps/templates/nightly.yaml index 8599d78..7aa8ab1 100644 --- a/charts/apps/templates/nightly.yaml +++ b/charts/apps/templates/nightly.yaml @@ -26,7 +26,7 @@ spec: commonConfiguration: |- version: "1" - log_level: "info" + log_level: "debug" listen_addr: "0.0.0.0:3002" health_check_path: "/health"