Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(laboratory): preflight editor components #6498

Open
wants to merge 23 commits into
base: main
Choose a base branch
from

Conversation

jasonkuhrt
Copy link
Member

@jasonkuhrt jasonkuhrt commented Feb 11, 2025

Follow up from #6476 (review)

closes console-1035

This PR refactors the very large graphiql module into separate concerns. It also tweaks the e2e tests file organization.

Main changes:

  1. Dedicated components for different preflight editors that co-locate concerns about those editors
  2. Dedicated modules for hooks

Minor Changes:

  1. Tweaked various props interfaces
  2. Reduced reliance on useRef
  3. Removed useless cases of useCallback

Copy link
Contributor

coderabbitai bot commented Feb 11, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Introduced an enhanced preflight modal interface for managing and executing scripts with dedicated editors for code and environment variables.
    • Added visual components that improve the display of editor headers and log messages.
  • Refactor

    • Consolidated and streamlined testing utilities and integration for the GraphiQL interface.
    • Restructured preflight and code editor functionalities for improved maintainability.
  • Chores

    • Updated project configurations and added a new dependency to support advanced code editing features.

Walkthrough

The changes introduce a new namespace, cyLaboratory, which encapsulates functions for managing interactions with a GraphiQL editor within a Cypress testing environment. This includes methods for updating editor values, managing tabs, and handling preflight scripts. Existing test files are refactored to utilize the cyLaboratory namespace, replacing the old laboratory module. Additionally, several new React components, hooks, and type definitions related to preflight functionality are introduced, alongside updates to TypeScript configurations and the addition of a monaco-editor dependency.

Changes

File(s) Change Summary
cypress/e2e/laboratory/_cy.ts, collections.cy.ts, preflight.cy.ts, tabs.cy.ts Introduced and refactored to use the new cyLaboratory namespace and its nested preflight namespace; replaced calls from the old laboratory module with updated methods.
cypress/support/dedent.ts, monaco.ts, testkit.ts, tsconfig.json Added new helper functions (dedent and setMonacoEditorContents), removed legacy laboratory functions and dedent implementation, and updated TS configuration (added monaco-editor type and moduleResolution).
package.json Added monaco-editor dependency (0.52.2) to devDependencies.
packages/web/app/src/lib/MonacoEditorReact/index.ts Imported and exported MonacoEditorReact from @monaco-editor/react for usage in environments like Storybook.
packages/web/app/src/lib/preflight/components/EditorTitle.tsx, EnvironmentEditor.tsx, LogLine.tsx, PreflightModal.tsx, ScriptEditor.tsx, _defaultEditorProps.ts Added several new preflight-related React components and constants to support script and environment editing, log rendering, and modal functionalities.
packages/web/app/src/lib/preflight/graphiql-plugin.tsx Refactored the plugin by removing the old PreflightContent function in favor of a new content function, with updated state management using the new preflight context.
packages/web/app/src/lib/preflight/hooks/usePreflight.tsx, usePreflightContext.ts Introduced a custom hook and context to manage execution of preflight scripts and provide shared preflight data to components.
packages/web/app/src/lib/preflight/index.ts, shared-types.ts Consolidated exports for preflight modules and updated type definitions (e.g., new enum for worker states).
packages/web/app/src/pages/target-laboratory.tsx Updated import paths to reflect the new module re-exports for preflight functionalities.

Sequence Diagram(s)

sequenceDiagram
    participant T as Cypress Test
    participant CL as cyLaboratory
    participant E as CodeMirror Editor

    T->>CL: updateEditorValue("new value")
    CL->>E: Set editor content
    E-->>CL: Confirm update

    T->>CL: getEditorValue()
    CL->>E: Retrieve current value
    E-->>CL: Send value back
Loading
sequenceDiagram
    participant U as User
    participant M as PreflightModal
    participant H as usePreflight Hook
    participant F as Execution Iframe

    U->>M: Input script & environment variables
    M->>H: Submit editor values for execution
    H->>F: Execute the preflight script
    F-->>H: Return logs/results/errors
    H->>M: Update modal state and display outputs
    M->>U: Render feedback in modal
Loading

Possibly related PRs


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

github-actions bot commented Feb 11, 2025

📚 Storybook Deployment

The latest changes are available as preview in: https://a092f61f.hive-storybook.pages.dev

Copy link
Contributor

github-actions bot commented Feb 11, 2025

🐋 This PR was built and pushed to the following Docker images:

Targets: build

Platforms: linux/arm64

Image Tag: 65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c

Docker Bake metadata
{
"app": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/api/health",
          "build-arg:IMAGE_DESCRIPTION": "The app of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/app",
          "build-arg:PORT": "3000",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/app",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/bbr0r89f3h44xgxrxxpu3gq3n",
  "containerimage.config.digest": "sha256:3fee26df63b9cc221728d2ea783218f90b206cfc82e47ba4b00115b90514799b",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:c7482a24efbbb05b5b1e1bb0a7688dfc5f6209c0bac046087c69279d9b3c8c47",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:c7482a24efbbb05b5b1e1bb0a7688dfc5f6209c0bac046087c69279d9b3c8c47",
  "image.name": "ghcr.io/graphql-hive/app:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/app:refactor_laboratory_preflight_modules-arm64"
},
"buildx.build.warnings": [
  {
    "vertex": "sha256:d154a028047cd011f0dee4016aaff1ef34fc7dc89ac6f63fb0b8778394d633c0",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEyKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 12
        },
        "end": {
          "line": 12
        }
      }
    ]
  },
  {
    "vertex": "sha256:d154a028047cd011f0dee4016aaff1ef34fc7dc89ac6f63fb0b8778394d633c0",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTcp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 17
        },
        "end": {
          "line": 17
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTIp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 12
        },
        "end": {
          "line": 12
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMyk=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 13
        },
        "end": {
          "line": 13
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTQp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 14
        },
        "end": {
          "line": 14
        }
      }
    ]
  },
  {
    "vertex": "sha256:d154a028047cd011f0dee4016aaff1ef34fc7dc89ac6f63fb0b8778394d633c0",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDExKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 11
        },
        "end": {
          "line": 11
        }
      }
    ]
  },
  {
    "vertex": "sha256:d154a028047cd011f0dee4016aaff1ef34fc7dc89ac6f63fb0b8778394d633c0",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMik=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 12
        },
        "end": {
          "line": 12
        }
      }
    ]
  },
  {
    "vertex": "sha256:d154a028047cd011f0dee4016aaff1ef34fc7dc89ac6f63fb0b8778394d633c0",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTUp",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 15
        },
        "end": {
          "line": 15
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIwKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 20
        },
        "end": {
          "line": 20
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIxKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 21
        },
        "end": {
          "line": 21
        }
      }
    ]
  },
  {
    "vertex": "sha256:d154a028047cd011f0dee4016aaff1ef34fc7dc89ac6f63fb0b8778394d633c0",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEwKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "migrations.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 10
        },
        "end": {
          "line": 10
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAyMSk=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 21
        },
        "end": {
          "line": 21
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRQT1JUJyAobGluZSAyMik=",
    "detail": [
      "VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 22
        },
        "end": {
          "line": 22
        }
      }
    ]
  },
  {
    "vertex": "sha256:e3182d8dd6287818f20839b0ca486015bfc0dbe5065c6e1266b6b05afe173917",
    "level": 1,
    "short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIyKQ==",
    "detail": [
      "TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
    ],
    "url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
    "sourceInfo": {
      "filename": "services.dockerfile",
      "data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
      "language": "Dockerfile"
    },
    "range": [
      {
        "start": {
          "line": 22
        },
        "end": {
          "line": 22
        }
      }
    ]
  }
],
"composition-federation-2": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "Federation 2 Composition Service for GraphQL Hive.",
          "build-arg:IMAGE_TITLE": "graphql-hive/composition-federation-2",
          "build-arg:PORT": "3069",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/external-composition",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/xod2de3whgd4qt1ipjglazrnv",
  "containerimage.config.digest": "sha256:4d9034178975b69ff5df72a02c553a0e5e061f5b3fdde264faebcba0c42f6f05",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:23671e1c1e4258c41c93b1025493790c5d3edd4c36895cef5d7a09600401ea3c",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:23671e1c1e4258c41c93b1025493790c5d3edd4c36895cef5d7a09600401ea3c",
  "image.name": "ghcr.io/graphql-hive/composition-federation-2:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/composition-federation-2:refactor_laboratory_preflight_modules-arm64"
},
"emails": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The emails service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/emails",
          "build-arg:PORT": "3006",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/emails",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/vj6s2vc55kkhht1s5ilaezvm6",
  "containerimage.config.digest": "sha256:f059ea02af12c7ee073b4a1384a0687dff032566bddbc7f2ee84159aa829df71",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:41c235a74180c03bc46dcb9494c938d6ef3dc5a40a48fad4968e5078579667db",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:41c235a74180c03bc46dcb9494c938d6ef3dc5a40a48fad4968e5078579667db",
  "image.name": "ghcr.io/graphql-hive/emails:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/emails:refactor_laboratory_preflight_modules-arm64"
},
"policy": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The policy service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/policy",
          "build-arg:PORT": "3012",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/policy",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/e7gdfvctcyf4zes2mee3zdfzn",
  "containerimage.config.digest": "sha256:9ebb18ccb6628b06c530758f38286c23f107d5d29b26a44694ea1bfb35720df6",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:1ac742c471c5ebd2a1247be5d4828e44ddb78ee3b7c7bdb9c9b378350963f4f3",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:1ac742c471c5ebd2a1247be5d4828e44ddb78ee3b7c7bdb9c9b378350963f4f3",
  "image.name": "ghcr.io/graphql-hive/policy:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/policy:refactor_laboratory_preflight_modules-arm64"
},
"rate-limit": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The rate limit service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/rate-limit",
          "build-arg:PORT": "3009",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/rate-limit",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/rsqvwz79e3rcrxmhmhr5libyz",
  "containerimage.config.digest": "sha256:965f0b08fa9458e48307f4357c5e6830c26fb20d45d6d86564f564c1081feaac",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:6376192625cf8bac9e1e1779a0538648b9f99204e396f04fe67816c659e5ace8",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:6376192625cf8bac9e1e1779a0538648b9f99204e396f04fe67816c659e5ace8",
  "image.name": "ghcr.io/graphql-hive/rate-limit:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/rate-limit:refactor_laboratory_preflight_modules-arm64"
},
"schema": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The schema service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/schema",
          "build-arg:PORT": "3002",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/schema",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/8akynflf9fhq1ha6153stx5to",
  "containerimage.config.digest": "sha256:3e8803d4505fecbb32574e4bc4c39405e38269b6cd4294266d6c948dcc7267ce",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:4f20b54af883a0ac4e8d777059f26405a1e9c935c17badd4a9854d690a5db96c",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:4f20b54af883a0ac4e8d777059f26405a1e9c935c17badd4a9854d690a5db96c",
  "image.name": "ghcr.io/graphql-hive/schema:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/schema:refactor_laboratory_preflight_modules-arm64"
},
"server": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The server service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/server",
          "build-arg:PORT": "3001",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/server",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/ikkelsgc3o8pdv3vvivfz31zl",
  "containerimage.config.digest": "sha256:933f9944fbaba74f6e422fd8d96822ccc68855e96ab412b795e73cdef9aa542e",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:fc66bafce15c545293f67dcf08d006f8138acdb690e132d64c4aa82d61694750",
    "size": 2076,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:fc66bafce15c545293f67dcf08d006f8138acdb690e132d64c4aa82d61694750",
  "image.name": "ghcr.io/graphql-hive/server:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/server:refactor_laboratory_preflight_modules-arm64"
},
"storage": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "migrations.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:IMAGE_DESCRIPTION": "The migrations service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/storage",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/ilfouo8mn09e439gbvtpegtbv",
  "containerimage.config.digest": "sha256:dada9ccee79f3835322d54ef3b45cfbb777e3e65e2a5aa99b763b1276b9c6fcb",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:f4019899646bcccb0e028e14709632ecf1a3126cb33b91ff5da265b0ef50ed34",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:f4019899646bcccb0e028e14709632ecf1a3126cb33b91ff5da265b0ef50ed34",
  "image.name": "ghcr.io/graphql-hive/storage:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/storage:refactor_laboratory_preflight_modules-arm64"
},
"stripe-billing": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The stripe billing service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/stripe-billing",
          "build-arg:PORT": "3010",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/stripe-billing",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/7lugk1beh05ipjac5lm6vcb6a",
  "containerimage.config.digest": "sha256:df9fe26cc53720f37be4be912a4c5ae6e2de07796bed3a8226ece58ec5651f5e",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:793c6da995f02d46be0cdccdf2b8a9c47bd7f98a4107b114bf506fbec06a5a42",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:793c6da995f02d46be0cdccdf2b8a9c47bd7f98a4107b114bf506fbec06a5a42",
  "image.name": "ghcr.io/graphql-hive/stripe-billing:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/stripe-billing:refactor_laboratory_preflight_modules-arm64"
},
"tokens": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The tokens service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/tokens",
          "build-arg:PORT": "3003",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/tokens",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/80nnrht2s23vu5hvvh2z385z5",
  "containerimage.config.digest": "sha256:25504e05ee3d485a61cfabb81cbadca0098246cbce025b2facd0369c9ecf6ca4",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:1542a18972521f070af7aa0bbb32691259e9e56a61d3a244db9bdf94ddf9fb46",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:1542a18972521f070af7aa0bbb32691259e9e56a61d3a244db9bdf94ddf9fb46",
  "image.name": "ghcr.io/graphql-hive/tokens:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/tokens:refactor_laboratory_preflight_modules-arm64"
},
"usage": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/usage",
          "build-arg:PORT": "3006",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/usage",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/qpyrffxaqzovpyjfgri6as3vs",
  "containerimage.config.digest": "sha256:ce7f7039045947737fba8e72c4e54f122575fbb65925e350dab64c715d133de4",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:40a82d6304f2219a42134266d40d9827ccd3c2a8aaab99195bc01082e3aaaa05",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:40a82d6304f2219a42134266d40d9827ccd3c2a8aaab99195bc01082e3aaaa05",
  "image.name": "ghcr.io/graphql-hive/usage:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/usage:refactor_laboratory_preflight_modules-arm64"
},
"usage-estimator": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The usage estimator service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/usage-estimator",
          "build-arg:PORT": "3008",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/usage-estimator",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/zv6zjlcea9ytfd8h7bc81256p",
  "containerimage.config.digest": "sha256:192ce249784d9131bf2d78583355b1299dc448a57f062746fc13f57e8bb66d6a",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:824daba5812413ee7a247499ecefaa0b830cf0cf9e7cbb21696b3019dfda1680",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:824daba5812413ee7a247499ecefaa0b830cf0cf9e7cbb21696b3019dfda1680",
  "image.name": "ghcr.io/graphql-hive/usage-estimator:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/usage-estimator:refactor_laboratory_preflight_modules-arm64"
},
"usage-ingestor": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/usage-ingestor",
          "build-arg:PORT": "3007",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/usage-ingestor",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/pau9thb4y1axnt7sqt02mavxb",
  "containerimage.config.digest": "sha256:2372b1a178ae4509f16d92965c0fda523ba470b4285da6c4e0638a720ea357ce",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:580a3f6ba31bc076328efcc6bc873a6bc34b1289dd926e9a14c01eee5d17faea",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:580a3f6ba31bc076328efcc6bc873a6bc34b1289dd926e9a14c01eee5d17faea",
  "image.name": "ghcr.io/graphql-hive/usage-ingestor:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/usage-ingestor:refactor_laboratory_preflight_modules-arm64"
},
"webhooks": {
  "buildx.build.provenance": {
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
        "digest": {
          "sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
        }
      }
    ],
    "invocation": {
      "configSource": {
        "entryPoint": "services.dockerfile"
      },
      "parameters": {
        "frontend": "dockerfile.v0",
        "args": {
          "build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
          "build-arg:IMAGE_DESCRIPTION": "The webhooks ingestor service of the GraphQL Hive project.",
          "build-arg:IMAGE_TITLE": "graphql-hive/webhooks",
          "build-arg:PORT": "3005",
          "build-arg:RELEASE": "65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c",
          "build-arg:SERVICE_DIR_NAME": "@hive/webhooks",
          "context:dist": "local:dist",
          "context:shared": "local:shared",
          "frontend.caps": "moby.buildkit.frontend.contexts+forward",
          "local-sessionid:context": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:dockerfile": "uoa69pj82elevo5n96job48iv",
          "local-sessionid:shared": "uoa69pj82elevo5n96job48iv"
        },
        "locals": [
          {
            "name": "context"
          },
          {
            "name": "dist"
          },
          {
            "name": "dockerfile"
          },
          {
            "name": "shared"
          }
        ]
      },
      "environment": {
        "platform": "linux/arm64"
      }
    }
  },
  "buildx.build.ref": "builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f44/builder-b803b07f-72e5-4f94-86c7-df3bfa2f3f440/l3e3uxcocwfau38z66p6re9ms",
  "containerimage.config.digest": "sha256:7961235f54ac36d82a424e8a07cfb643ce506818c174a05b84370d26dee071f2",
  "containerimage.descriptor": {
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "digest": "sha256:0339badfa23d546cfc0457e3d810bab4e28d83975d952e1f2aa363af4bca058d",
    "size": 2075,
    "platform": {
      "architecture": "arm64",
      "os": "linux"
    }
  },
  "containerimage.digest": "sha256:0339badfa23d546cfc0457e3d810bab4e28d83975d952e1f2aa363af4bca058d",
  "image.name": "ghcr.io/graphql-hive/webhooks:65b6fe8e1fbe5fb5e1002d46b1ee924a4216460c-arm64,ghcr.io/graphql-hive/webhooks:refactor_laboratory_preflight_modules-arm64"
}
}

@jasonkuhrt jasonkuhrt marked this pull request as ready for review February 11, 2025 14:48
@jasonkuhrt
Copy link
Member Author

The changes to Cypress could be its own PR. If you prefer that, I'll do it. They were pulled in here from the previous PR #6476

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (12)
packages/web/app/src/lib/preflight/components/EditorTitle.tsx (1)

4-10: Consider accessibility and semantic improvements.

A few suggestions to enhance the component:

  1. Extract the props interface for reusability
  2. Consider using semantic heading elements (h1-h6) based on context
  3. Add ARIA attributes if this acts as a label or heading

Here's a suggested implementation:

+interface EditorTitleProps {
+  children: ReactNode;
+  className?: string;
+  level?: 1 | 2 | 3 | 4 | 5 | 6;
+}
+
-export function EditorTitle(props: { children: ReactNode; className?: string }) {
+export function EditorTitle({ children, className, level = 2 }: EditorTitleProps) {
+  const Component = `h${level}` as const;
   return (
-    <div className={cn('cursor-default text-base font-semibold tracking-tight', props.className)}>
-      {props.children}
-    </div>
+    <Component
+      className={cn('cursor-default text-base font-semibold tracking-tight', className)}
+      aria-level={level}
+    >
+      {children}
+    </Component>
   );
 }
packages/web/app/src/lib/preflight/graphiql-plugin.tsx (1)

20-22: Minor naming suggestion.
The classes.monacoMini key is functional. For clarity, consider a slightly more descriptive name (e.g., monacoEditorMini) to better convey intent.

packages/web/app/src/lib/preflight/hooks/usePreflightContext.ts (1)

1-14: LGTM! Consider adding type safety to the provider.

The implementation follows React context best practices with proper null checks and error messages. However, you could enhance type safety by explicitly typing the provider's value prop.

-export const PreflightProvider = PreflightContext.Provider;
+export const PreflightProvider: React.FC<{
+  value: PreflightObject;
+  children: React.ReactNode;
+}> = PreflightContext.Provider;
packages/web/app/src/lib/preflight/components/EnvironmentEditor.tsx (1)

4-12: LGTM! Consider using a type assertion for better type safety.

The default props are correctly defined and merged. However, you could enhance type safety by using a type assertion to ensure all required props are provided.

-export const defaultProps: Readonly<EditorProps> = {
+export const defaultProps = {
  ...defaultEditorProps,
  defaultLanguage: 'json',
  options: {
    ...defaultEditorProps.options,
    lineNumbers: 'off',
    tabSize: 2,
  },
-};
+} as const satisfies Readonly<EditorProps>;
packages/web/app/src/lib/preflight/components/LogLine.tsx (2)

4-22: LGTM! Consider extracting type guards for better maintainability.

The implementation correctly handles different log types and includes error monitoring. However, the type checking logic could be extracted into separate type guard functions for better maintainability.

+function isSeparator(log: LogRecord): log is { type: 'separator' } {
+  return 'type' in log && log.type === 'separator';
+}

+function isLogMessage(log: LogRecord): log is { level: keyof typeof LOG_COLORS; message: string; line?: number; column?: number } {
+  return 'level' in log && log.level in LOG_COLORS;
+}

 export function LogLine({ log }: { log: LogRecord }) {
-  if ('type' in log && log.type === 'separator') {
+  if (isSeparator(log)) {
     return <hr className="my-2 border-dashed border-current" />;
   }

-  if ('level' in log && log.level in LOG_COLORS) {
+  if (isLogMessage(log)) {
     return (
       <div className={LOG_COLORS[log.level]}>
         {log.level}: {log.message}
         {log.line && log.column ? ` (${log.line}:${log.column})` : ''}
       </div>
     );
   }

24-29: LGTM! Consider using an enum or const assertion for better type safety.

The log colors mapping is correctly defined. However, you could enhance type safety by using an enum or const assertion.

-const LOG_COLORS = {
+const LOG_COLORS = {
  error: 'text-red-400',
  info: 'text-emerald-400',
  warn: 'text-yellow-400',
  log: 'text-gray-400',
-};
+} as const;
cypress/support/monaco.ts (1)

4-20: LGTM! Consider adding retry logic for better test stability.

The implementation correctly handles setting Monaco editor contents. However, since this is used in tests, adding retry logic could improve stability.

 export function setMonacoEditorContents(editorCyName: string, text: string) {
   // wait for textarea appearing which indicates monaco is loaded
   cy.dataCy(editorCyName).find('textarea');
-  cy.window().then((win: Window & typeof globalThis & { monaco: typeof Monaco }) => {
+  cy.window().should(win => {
+    const typedWin = win as Window & typeof globalThis & { monaco: typeof Monaco };
     // First, check if monaco is available on the main window
-    const editor = win.monaco.editor
+    const editor = typedWin.monaco.editor
       .getEditors()
       .find(e => e.getContainerDomNode().parentElement.getAttribute('data-cy') === editorCyName);

     // If Monaco instance is found
     if (editor) {
       editor.setValue(text);
+      return true;
     } else {
-      throw new Error('Monaco editor not found on the window or frames[0]');
+      return false;
     }
-  });
+  }, { timeout: 10000 });
 }
cypress/support/dedent.ts (1)

1-52: Add comprehensive documentation and tests.

While the implementation is solid, consider the following improvements:

  1. Add JSDoc comments describing edge cases and usage examples
  2. Include unit tests to verify behavior with different indentation patterns
  3. Add proper license attribution since the code is from another project
cypress/e2e/laboratory/_cy.ts (2)

52-60: Consider iterative approach for tab management.

The recursive implementation could cause stack overflow with many tabs. Consider using a while loop:

-  export function closeTabsUntilOneLeft() {
-    cy.get('li.graphiql-tab').then($tabs => {
-      if ($tabs.length > 1) {
-        closeActiveTab();
-        // Recurse until there's only one tab left
-        return closeTabsUntilOneLeft();
-      }
-    });
-  }
+  export function closeTabsUntilOneLeft() {
+    cy.get('li.graphiql-tab').then($tabs => {
+      let remainingTabs = $tabs.length;
+      while (remainingTabs > 1) {
+        closeActiveTab();
+        remainingTabs--;
+      }
+    });
+  }

63-80: Consider moving selectors to a separate file.

The selectors object could be moved to a dedicated constants file to improve maintainability and reusability.

packages/web/app/src/lib/preflight/components/PreflightModal.tsx (2)

58-61: Consider using smooth scroll behavior only for larger scroll distances.

The current implementation always uses smooth scrolling, which might feel sluggish for small updates.

Consider this optimization:

-    consoleEl?.scroll({ top: consoleEl.scrollHeight, behavior: 'smooth' });
+    const scrollDistance = consoleEl.scrollHeight - consoleEl.scrollTop;
+    consoleEl?.scroll({
+      top: consoleEl.scrollHeight,
+      behavior: scrollDistance > 100 ? 'smooth' : 'auto'
+    });

75-80: Consider extracting escape key handler to a custom hook.

The escape key handling logic could be reused across other modals.

Consider creating a custom hook:

function usePreventModalClose(condition: (target: EventTarget) => boolean) {
  return (ev: KeyboardEvent) => {
    if (condition(ev.target)) {
      ev.preventDefault();
    }
  };
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5307b0c and ea4dbcb.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • cypress/e2e/laboratory/_cy.ts (1 hunks)
  • cypress/e2e/laboratory/collections.cy.ts (9 hunks)
  • cypress/e2e/laboratory/preflight.cy.ts (18 hunks)
  • cypress/e2e/laboratory/tabs.cy.ts (2 hunks)
  • cypress/support/dedent.ts (1 hunks)
  • cypress/support/monaco.ts (1 hunks)
  • cypress/support/testkit.ts (0 hunks)
  • cypress/tsconfig.json (1 hunks)
  • package.json (1 hunks)
  • packages/web/app/src/lib/MonacoEditorReact/index.ts (1 hunks)
  • packages/web/app/src/lib/preflight/components/EditorTitle.tsx (1 hunks)
  • packages/web/app/src/lib/preflight/components/EnvironmentEditor.tsx (1 hunks)
  • packages/web/app/src/lib/preflight/components/LogLine.tsx (1 hunks)
  • packages/web/app/src/lib/preflight/components/PreflightModal.tsx (1 hunks)
  • packages/web/app/src/lib/preflight/components/ScriptEditor.tsx (1 hunks)
  • packages/web/app/src/lib/preflight/components/_defaultEditorProps.ts (1 hunks)
  • packages/web/app/src/lib/preflight/graphiql-plugin.tsx (7 hunks)
  • packages/web/app/src/lib/preflight/hooks/usePreflight.tsx (1 hunks)
  • packages/web/app/src/lib/preflight/hooks/usePreflightContext.ts (1 hunks)
  • packages/web/app/src/lib/preflight/index.ts (1 hunks)
  • packages/web/app/src/lib/preflight/shared-types.ts (1 hunks)
  • packages/web/app/src/pages/target-laboratory.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • cypress/support/testkit.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/web/app/src/lib/MonacoEditorReact/index.ts
  • packages/web/app/src/lib/preflight/index.ts
  • packages/web/app/src/pages/target-laboratory.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
packages/web/app/src/lib/preflight/shared-types.ts

[error] 6-9: The enum declaration should not be const

Const enums are not supported by bundlers and are incompatible with the 'isolatedModules' mode. Their use can lead to import inexistent values.
See TypeScript Docs for more details.
Safe fix: Turn the const enum into a regular enum.

(lint/suspicious/noConstEnum)

⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: typescript / typecheck
  • GitHub Check: static-analysis / analyze (typescript)
  • GitHub Check: static-analysis / analyze (javascript)
  • GitHub Check: build / dockerize (linux/arm64)
  • GitHub Check: code-style / eslint-and-prettier
  • GitHub Check: build / dockerize (linux/amd64)
  • GitHub Check: alpha / cli-artifacts
  • GitHub Check: SonarCloud
🔇 Additional comments (33)
packages/web/app/src/lib/preflight/components/EditorTitle.tsx (2)

1-2: LGTM! Clean and minimal imports.

The imports are well-organized and specific to the component's needs.


4-10: LGTM! Clean and focused component implementation.

The component is well-structured with good extensibility through className prop and sensible default styles.

packages/web/app/src/lib/preflight/graphiql-plugin.tsx (8)

8-9: Imports appear consistent with existing project structure.
Both the graphql and useToggle imports look valid for their intended usage.


11-11: New icon import is straightforward.
The Pencil1Icon import is properly declared. No issues found.


14-18: Introduced component imports align well with modular approach.
These component imports (EditorTitle, EnvironmentEditor, PreflightModal, ScriptEditor, usePreflightContext) indicate a cleaner design, enhancing maintainability.


40-40: Verified plugin content injection.
Mapping the content property to your new content function is correct and maintains plugin structure.


62-63: New content function integrates hooks for toast and preflight context.
Using useToast and usePreflightContext here is appropriate for cross-cutting concerns like notifications and editor state. The approach appears cohesive and correct.

Also applies to: 65-65


71-72: Consider enforcing validation for environment variables.
While updating environment variables, there's potential for invalid JSON. You might ensure structure correctness or handle parse errors gracefully within this flow.


166-168: Read-only script editor integration is logical.
You correctly pass readOnly options to visually convey an uneditable script while still displaying its content.


193-193: Environment editor addition complements the script editor.
Allowing real-time updates to environment variables helps promote a clear separation of concerns. Implementation appears sound.

packages/web/app/src/lib/preflight/hooks/usePreflight.tsx (12)

1-8: Initial imports and schema references look appropriate.
The combination of react, zod, and your local hooks matches the intended functionality for handling state and validations.


9-22: Type definitions provide clarity.
Defining PreflightResultData, the fragment, and PreflightObject offers a strong foundation for typed interactions.


23-47: Solid foundation for usePreflight initialization.

  • Attaching references to iframeRef and hooking into local storage are sensible.
  • The fallback to an empty string for environment variables is practical.

48-80: Begin execute method with environment variable decoding and early exit.

  • Good approach using JSON parse fallback to an empty object.
  • Early return if preflight is disabled is consistent with a “short-circuit” design.

81-113: Preparing the iframe communication.

  • Generating a random UUID for each run is robust.
  • Event listener setup for message is clear, ensuring the correct postMessage usage.

114-128: Prompt management is well-structured.

  • Opening prompts via promptManager and maintaining IDs in a set ensures concurrency control.
  • Closing prompts if the script finishes early prevents orphan dialogs.

129-190: Handling script result merges environment updates effectively.

  • Merging environment variables and persisting them to local storage fosters a reliable iteration loop.
  • Logging with timestamps is helpful for debugging.

193-214: Error flow captures stack info carefully.

  • Logging the error along with line and column is user-friendly.
  • Closing prompts on error is a nice cleanup step.

216-242: Log messages and no-ops for unrecognized events show defensive coding.

  • Explicit handling of known events plus a safe fallback is good practice.

244-283: Finalizing execution lifecycle.

  • Removal of event listeners and resetting state to ready ensures no leftover side-effects.
  • Graceful fallback if an exception is thrown.

285-295: abortExecution and effect-based cleanup logic.

  • Tying cancellation to a ref, and removing it on unmount, secures the lifecycle.

297-323: Return object is comprehensive.
All necessary states, methods, logs, and references are exposed. This supports flexible integration with the UI.

packages/web/app/src/lib/preflight/components/_defaultEditorProps.ts (1)

1-17: Default editor configurations are concise.

  • The usage of clsx for applying a custom background is flexible.
  • Disabling the minimap and managing scrollbar sizes should enhance readability for short configs.
packages/web/app/src/lib/preflight/components/EnvironmentEditor.tsx (1)

14-25: LGTM! Props spreading and merging is handled correctly.

The component properly merges default props with user-provided props, ensuring proper override behavior.

cypress/e2e/laboratory/tabs.cy.ts (1)

1-35: LGTM! Clean refactor of test utilities.

The changes successfully migrate the test to use the new cyLaboratory namespace while maintaining the same test logic and coverage.

packages/web/app/src/lib/preflight/components/ScriptEditor.tsx (1)

6-29: LGTM! Well-structured editor configuration.

The default props provide comprehensive editor settings and proper TypeScript integration for the lab API.

packages/web/app/src/lib/preflight/shared-types.ts (1)

11-11: LGTM! Clean union type definition.

The LogRecord type union with a separator type provides a clean way to handle different types of log entries.

packages/web/app/src/lib/preflight/components/PreflightModal.tsx (1)

100-126: LGTM! Clean conditional rendering for button states.

The execution button's state management and rendering is well-implemented, with clear visual feedback for running/ready states.

cypress/e2e/laboratory/collections.cy.ts (1)

1-1: LGTM! Consistent usage of cyLaboratory namespace.

The refactoring to use the cyLaboratory namespace is consistent throughout the file, improving maintainability by centralizing laboratory-related functionality.

Also applies to: 19-19, 93-93, 106-106, 130-130, 154-154, 176-176, 182-183, 209-209, 215-216

cypress/e2e/laboratory/preflight.cy.ts (2)

4-6: LGTM! Clean selector organization.

Good practice using a dedicated selectors object and creating a shorthand reference for frequently used namespaces.


23-23: LGTM! Clear test organization.

The test suite is well-organized with descriptive describe blocks that clearly separate different aspects of functionality.

Also applies to: 44-44

cypress/tsconfig.json (1)

5-6: LGTM! TypeScript configuration is properly set up for Monaco editor.

The changes correctly configure TypeScript for Monaco editor integration by:

  1. Setting moduleResolution to "node" which is the recommended setting
  2. Adding monaco-editor to the types array for proper type support
package.json (1)

89-89: Verify Monaco editor version compatibility and security.

The Monaco editor version 0.52.2 is added as a dev dependency. Let's verify if this version is appropriate.

✅ Verification successful

🌐 Web query:

What is the latest version of monaco-editor? Are there any known vulnerabilities in version 0.52.2?

💡 Result:

The latest version of monaco-editor is 0.52.2, released on December 9, 2024[4][8]. This version includes updates such as security fixes for dependencies and general maintenance improvements[4].

Regarding vulnerabilities in version 0.52.2:

  • No direct vulnerabilities are listed in Snyk's database for this specific version[3]
  • A previous security concern (CVE-2024-45801) related to DOMPurify dependencies was resolved before this release[2][6]:
    • The vulnerability involved inefficient regular expression complexity
    • Fixed by updating to DOMPurify v3.1.7 (patched since v3.1.3)[2]
    • Confirmed resolved in monaco-editor v0.52.x through dependency updates[2][6]

Security monitoring platforms like Open Hub show no reported vulnerabilities for monaco-editor versions up to 0.52.2[5]. However, users should always verify dependencies using tools like npm audit or Snyk scans for indirect vulnerabilities[3][8].

Citations:


Monaco Editor Version Verified

  • The latest monaco-editor version is confirmed to be 0.52.2.
  • No known vulnerabilities have been reported for version 0.52.2.

cypress/e2e/laboratory/_cy.ts Show resolved Hide resolved
packages/web/app/src/lib/preflight/shared-types.ts Outdated Show resolved Hide resolved
@jasonkuhrt

This comment was marked as resolved.

@jasonkuhrt jasonkuhrt marked this pull request as draft February 11, 2025 16:20
@jasonkuhrt jasonkuhrt marked this pull request as ready for review February 11, 2025 17:31
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (7)
packages/web/app/src/lib/preflight/graphiql-plugin.tsx (1)

66-66: Remove debugging console.log.

Remove the commented-out console.log statement as it's no longer needed.

-  // console.log(1, preflight.environmentVariables);
cypress/e2e/laboratory/preflight.cy.ts (2)

23-42: Consider adding more assertions for the regression test.

The regression test at line 25 only verifies that the component loads. Consider adding assertions to verify the component's state and functionality after loading.

 it('regression: loads even if local storage is set to {}', () => {
   window.localStorage.setItem('hive:laboratory:environment', '{}');
   cy.visit(`/${data.slug}/laboratory`);
   cy.get(s.buttonGraphiQLPreflight).click();
+  // Verify component state
+  cy.get(s.buttonGraphiQLPreflight).should('be.visible');
+  cy.get(s.buttonGraphiQLPreflight).should('not.be.disabled');
 });

176-250: Consider extracting repeated selectors into setup.

The header-related tests use similar selectors and setup code. Consider extracting common setup into beforeEach or helper functions to reduce duplication.

 describe('Execution', () => {
+  const setupHeaders = (headers: Record<string, string>) => {
+    cy.dataCy(s.buttonToggleCy).click();
+    cy.dataCy(s.buttonModalCy).click();
+    cyp.setEditorContent(`lab.request.headers.append('${Object.keys(headers)[0]}', '${Object.values(headers)[0]}')`);
+    cy.dataCy(s.modal.buttonSubmitCy).click();
+  };
+
   it('result.request.headers are added to the graphiql request base headers', () => {
     const preflightHeaders = {
       foo: 'bar',
     };
-    cy.dataCy(s.buttonToggleCy).click();
-    cy.dataCy(s.buttonModalCy).click();
-    cyp.setEditorContent(`lab.request.headers.append('foo', '${preflightHeaders.foo}')`);
-    cy.dataCy(s.modal.buttonSubmitCy).click();
+    setupHeaders(preflightHeaders);
     // ...
   });
packages/web/app/src/lib/preflight/components/PreflightModal.tsx (4)

24-46: Extract props interface for better reusability.

Consider extracting the props interface to improve code organization and reusability.

+export interface PreflightModalProps {
+  onSubmit?: (values: PreflightModalEditorValue) => void;
+  isOpen: boolean;
+  toggle: () => void;
+  state: PreflightWorkerState;
+  execute: (script: string) => void;
+  abortExecution: () => void;
+  logs: Array<LogRecord>;
+  clearLogs: () => void;
+  value: PreflightModalEditorValue;
+  onChange?: (value: PreflightModalEditorValue) => void;
+}
+
-export function PreflightModal({
+export function PreflightModal(props: PreflightModalProps) {
+  const {
+    isOpen,
+    toggle,
+    onSubmit,
+    state,
+    execute,
+    abortExecution,
+    logs,
+    clearLogs,
+    value,
+    onChange,
+  } = props;

47-49: Remove prettier-ignore comment by reformatting the line.

The prettier-ignore comment can be removed by breaking the line differently.

-  const [environmentVariablesValue, setEnvironmentVariablesValue] = useState(value.environmentVariables); // prettier-ignore
+  const [environmentVariablesValue, setEnvironmentVariablesValue] = useState(
+    value.environmentVariables
+  );

65-68: Extract console scrolling logic into a custom hook.

Consider extracting the console scrolling logic into a reusable custom hook for better code organization and potential reuse.

+function useAutoScroll(ref: React.RefObject<HTMLElement>, deps: any[]) {
+  useEffect(() => {
+    const el = ref.current;
+    el?.scroll({ top: el.scrollHeight, behavior: 'smooth' });
+  }, deps);
+}
+
 // In component:
-useEffect(() => {
-  const consoleEl = consoleRef.current;
-  consoleEl?.scroll({ top: consoleEl.scrollHeight, behavior: 'smooth' });
-}, [logs]);
+useAutoScroll(consoleRef, [logs]);

81-81: Extract magic numbers into named constants.

Consider extracting hardcoded values into named constants for better maintainability.

+const MODAL_WIDTHS = {
+  default: 'w-11/12',
+  xl: 'w-4/5',
+} as const;
+
+const CONSOLE_STYLES = {
+  background: '#10151f',
+  fontSize: 'text-xs',
+  lineHeight: 'leading-[18px]',
+} as const;
+
-className="w-11/12 max-w-[unset] xl:w-4/5"
+className={`${MODAL_WIDTHS.default} max-w-[unset] xl:${MODAL_WIDTHS.xl}`}

-className="h-1/2 overflow-hidden overflow-y-scroll bg-[#10151f] py-2.5 pl-[26px] pr-2.5 font-mono text-xs/[18px]"
+className={`h-1/2 overflow-hidden overflow-y-scroll bg-[${CONSOLE_STYLES.background}] py-2.5 pl-[26px] pr-2.5 font-mono ${CONSOLE_STYLES.fontSize}/${CONSOLE_STYLES.lineHeight}`}

Also applies to: 169-169

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 657d475 and 65b6fe8.

📒 Files selected for processing (5)
  • cypress/e2e/laboratory/preflight.cy.ts (18 hunks)
  • cypress/support/monaco.ts (1 hunks)
  • packages/web/app/src/lib/preflight/components/PreflightModal.tsx (1 hunks)
  • packages/web/app/src/lib/preflight/graphiql-plugin.tsx (7 hunks)
  • packages/web/app/src/lib/preflight/shared-types.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/web/app/src/lib/preflight/shared-types.ts
  • cypress/support/monaco.ts
⏰ Context from checks skipped due to timeout of 90000ms (9)
  • GitHub Check: test / unit
  • GitHub Check: typescript / typecheck
  • GitHub Check: storybook-preview / deployment
  • GitHub Check: static-analysis / analyze (typescript)
  • GitHub Check: static-analysis / analyze (javascript)
  • GitHub Check: build / dockerize (linux/arm64)
  • GitHub Check: build / dockerize (linux/amd64)
  • GitHub Check: alpha / cli-artifacts
  • GitHub Check: code-style / eslint-and-prettier
🔇 Additional comments (10)
packages/web/app/src/lib/preflight/graphiql-plugin.tsx (5)

8-18: LGTM! Well-organized imports and consistent styling.

The imports are logically grouped and the shared Monaco editor styling is properly extracted into a classes object.

Also applies to: 20-22


24-41: LGTM! Clean plugin configuration.

The plugin configuration is concise and follows GraphiQL's plugin API. The SVG icon is accessible with proper stroke attributes.


43-60: LGTM! Well-structured GraphQL mutation.

The mutation is properly defined with comprehensive error handling and type safety.


62-99: LGTM! Clean implementation with good separation of concerns.

The content function effectively manages state and handles updates separately for scripts and environment variables. The error handling is comprehensive and user feedback is provided through toast notifications.


101-208: LGTM! Well-structured UI with good user experience.

The implementation features:

  • Comprehensive modal configuration
  • Properly configured editors with appropriate options
  • Clear visual feedback for disabled state
  • Good accessibility with proper ARIA attributes and data-cy selectors for testing
cypress/e2e/laboratory/preflight.cy.ts (3)

1-7: LGTM! Well-structured module organization.

The refactoring improves maintainability by centralizing selectors and helpers in the cyLaboratory module. The setup is clean and follows best practices.


44-174: LGTM! Comprehensive test coverage with clear scenarios.

The "Preflight Modal" suite effectively tests various scenarios including:

  • Script and environment variable persistence
  • Console output and error handling
  • User prompts and cancellation
  • Environment variable updates
  • Security restrictions

364-452: LGTM! Comprehensive logging tests.

The logging-related tests thoroughly cover:

  • Log visibility states
  • Different log levels
  • Log clearing functionality
  • Error scenarios
packages/web/app/src/lib/preflight/components/PreflightModal.tsx (2)

1-23: LGTM! Well-organized imports and clear type definitions.

The imports are logically grouped, and the PreflightModalEditorValue interface is well-defined with clear properties.


98-199: LGTM! Well-structured layout with proper testing attributes.

The layout is well-organized using CSS Grid, and the testing attributes are properly placed. The button states and icons are handled effectively.

@@ -86,6 +86,7 @@
"graphql": "16.9.0",
"gray-matter": "4.0.3",
"jest-snapshot-serializer-raw": "2.0.0",
"monaco-editor": "0.52.2",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added for static typing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Responding to #6476 (comment)

To have a standard namespace for terms such as Editor and EditorProps. Easy autoimport.

Copy link
Contributor

@n1ru4l n1ru4l left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some comments.

Summed up:

  • We do not use camel case for file names or folder names
  • We do not use _ for file names
  • We use expressive variable names and no abbreviations

I still do not understand why this PR is treated as necessary for moving forward #6476, which should be the priority instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we name this file cypress.ts? I don't understand why we need to use an abbreviation, let alone why we need to prefix it with a underscore.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh happy to explain:

  1. The directory contains test files. I would like to keep this file from being interleaved in them since its not a test file. That is what _ achieves. It could also be nested directory or $ prefix, whereas cypress.ts would not achieve this. Can you propose something that would? Alternatively clarify that you don't care about about my goal here.
  2. The abbreviation is consistent with APIs from Cypress. Cypress uses a global cy namespace and what this module does is provide a kind of cy dedicated for laboratory. If that is not logical to you that's fine, but I think its not as random as your reaction to my change might suggest.

Please let me know how the above changes, if at all, your feedback.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #6476 I have tried to appease the feedback with a name of __cypress__.ts which utilizes a file name pattern that is used elsewhere.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .cy.ts extension does this though right? If this is a utility library for testing rather than a test file, it can have a different extension which is excluded from the test file matching.

Comment on lines +4 to +6
const s = cyLaboratory.preflight.selectors;

const cyp = cyLaboratory.preflight;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If requered to re-assign these namespaces/object whatever s and cyp are not expressive enough for me. Alternative proposal:

  • selectors
  • cypress

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be packages/web/app/src/lib/monaco-editor-react.ts, the index.ts is unnecessary. In general we do not use camel cases for file names (there are a few remaining ones from the past tho)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we do not use camel cases for file names (there are a few remaining ones from the past tho)

Noted!

I saw quite a few modules in the codebase with pascal case naming. I assume that this is still a valid pattern in the codebase, not deprecated. Is that correct?

Copy link
Contributor

@kamilkisiela kamilkisiela Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, there are 10 files that are pascal cased that were manually created, the rest is auto generated by codegen

Comment on lines +1 to +10
import { ReactNode } from 'react';
import { cn } from '@/lib/utils';

export function EditorTitle(props: { children: ReactNode; className?: string }) {
return (
<div className={cn('cursor-default text-base font-semibold tracking-tight', props.className)}>
{props.children}
</div>
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to have a file for these 10 lines?

Copy link
Member Author

@jasonkuhrt jasonkuhrt Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its almost never necessary to have multiple files. Here its motivated by having a set of components, one per module. So its about consistency, not line count. Since our codebase does apply this pattern, could you share how you decide when to use which pattern, because I don't understand your system I guess.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a rule, we usually split when it becomes big and problematic and we definitely don't do one component per file, in most cases it's by domain/feature. Sometimes there's a file with 1 component, just because other were removed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe its time to add some rules.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it can be enforced via a linter then I think it'd be fine to move to a stricter separation of components by file.
But otherwise we can keep it loose b/c i dislike enforcing these sorts of things manually.

I agree that if things become unruly then split.

@jasonkuhrt
Copy link
Member Author

jasonkuhrt commented Feb 12, 2025

I still do not understand why this PR is treated as necessary for moving forward #6476, which should be the priority instead.

Hey, two things:

  1. It was prioritized. It was blocked on product feedback that you or someone else needs to decide on. If I did something wrong, please be specific about what you would like to see next time.
  2. I explained in the previous PR that I was finding the massive graphiql module difficult to follow improve(laboratory): validate editor content with TypeScript #6476 (comment)

@@ -2,7 +2,8 @@
"compilerOptions": {
"target": "es2021",
"lib": ["es2021", "dom"],
"types": ["node", "cypress"]
"moduleResolution": "node",
"types": ["node", "cypress", "monaco-editor"]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think types here are for global definitions.
Is that necessary for your case? Or could you import these on the few files where the monaco-editor is referenced?

): Promise<PreflightResultData> {
const resultEnvironmentVariablesDecoded: PreflightResultData['environmentVariables'] =
Kit.tryOr(
() => JSON.parse(latestEnvironmentVariablesRef.current),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see a few options:

  1. Let wipe env vars (current approach)
  2. prompt the user to fix the env vars or wipe. I.e. Continuing will clear your environment variables because they are in an invalid state. Press "OK" to proceed or "Cancel" to stop
  3. Try to use string manipulation to append the new values without correcting the issue.

I think your approach is fine for now. This is an edge case. But prompting is probably nicer?

id,
promptId,
value,
} satisfies IFrameEvents.Incoming.EventData,
Copy link
Collaborator

@jdolle jdolle Feb 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool. I need to read up more on the newer typescript features...
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator
I'm living in the stone ages

},
{
level: 'log',
message: 'Script failed',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we include the duration here also?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants