Fix UI, documentation and the product update of Laboratory (#6232)

This commit is contained in:
Kamil Kisiela 2024-12-30 15:33:30 +01:00 committed by GitHub
parent 7b0c920c57
commit ff44b62aeb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 107 additions and 72 deletions

View file

@ -0,0 +1,5 @@
---
'hive': patch
---
Improvements to UI of Preflight Script (Laboratory)

View file

@ -68,7 +68,7 @@ function Header({
<A.Trigger
className={clsx(
'group',
'radix-state-open:rounded-t-lg radix-state-closed:rounded-lg',
'data-[state=closed]:rounded-lg data-[state=open]:rounded-t-lg',
'focus:outline-none',
'inline-flex w-full items-center justify-between px-4 py-2 text-left',
triggerClassName,
@ -78,7 +78,7 @@ function Header({
<ChevronDownIcon
className={clsx(
'ml-2 size-5 shrink-0 text-gray-700 ease-in-out dark:text-gray-400',
'group-radix-state-open:rotate-180 group-radix-state-open:duration-300',
'group-data-[state=open]:rotate-180 group-data-[state=open]:duration-300',
)}
/>
</A.Trigger>

View file

@ -307,8 +307,8 @@ export function Content() {
<AccordionItem key={collection.id} value={collection.id} className="border-b-0">
<AccordionHeader className="flex items-center justify-between">
<AccordionTriggerPrimitive className="group flex w-full items-center gap-x-3 rounded p-2 text-left font-medium text-white hover:bg-gray-100/10">
<FolderIcon className="group-radix-state-open:hidden size-4" />
<FolderOpenIcon className="group-radix-state-closed:hidden size-4" />
<FolderIcon className="size-4 group-data-[state=open]:hidden" />
<FolderOpenIcon className="size-4 group-data-[state=closed]:hidden" />
{collection.name}
</AccordionTriggerPrimitive>
{shouldShowMenu && (

View file

@ -1,6 +1,7 @@
import {
ComponentPropsWithoutRef,
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
@ -8,6 +9,7 @@ import {
useState,
} from 'react';
import { clsx } from 'clsx';
import { PowerIcon } from 'lucide-react';
import type { editor } from 'monaco-editor';
import { useMutation } from 'urql';
import { Badge } from '@/components/ui/badge';
@ -20,8 +22,7 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Subtitle, Title } from '@/components/ui/page';
import { Switch } from '@/components/ui/switch';
import { Subtitle } from '@/components/ui/page';
import { useToast } from '@/components/ui/use-toast';
import { FragmentType, graphql, useFragment } from '@/gql';
import { useLocalStorage, useToggle } from '@/lib/hooks';
@ -36,6 +37,7 @@ import {
TriangleRightIcon,
} from '@radix-ui/react-icons';
import { useParams } from '@tanstack/react-router';
import { cn } from '../utils';
import type { LogMessage } from './preflight-script-worker';
export const preflightScriptPlugin: GraphiQLPlugin = {
@ -63,6 +65,14 @@ const classes = {
icon: clsx('absolute -left-5 top-px'),
};
function EditorTitle(props: { children: ReactNode; className?: string }) {
return (
<div className={cn('cursor-default text-base font-semibold tracking-tight', props.className)}>
{props.children}
</div>
);
}
const sharedMonacoProps = {
theme: 'vs-dark',
className: classes.monaco,
@ -397,43 +407,69 @@ function PreflightScriptContent() {
</Button>
</div>
<Subtitle>
This script is run before each operation submitted, e.g. for automated authentication.
Before each GraphQL request begins, this script is executed automatically - for example, to
handle authentication.
</Subtitle>
<div className="flex items-center gap-2 text-sm">
<Switch
checked={preflightScript.isPreflightScriptEnabled}
onCheckedChange={v => preflightScript.setIsPreflightScriptEnabled(v)}
className="my-4"
<div>
<Button
size="sm"
variant="outline"
className="mt-3"
onClick={() =>
preflightScript.setIsPreflightScriptEnabled(!preflightScript.isPreflightScriptEnabled)
}
data-cy="toggle-preflight-script"
/>
<span className="w-6">{preflightScript.isPreflightScriptEnabled ? 'ON' : 'OFF'}</span>
>
<PowerIcon className="mr-2 size-4" />
{preflightScript.isPreflightScriptEnabled ? 'On' : 'Off'}
</Button>
</div>
{preflightScript.isPreflightScriptEnabled && (
<EditorTitle className="mt-6 flex cursor-not-allowed items-center gap-2">
Script{' '}
<Badge className="text-xs" variant="outline">
JavaScript
</Badge>
</EditorTitle>
<Subtitle className="mb-3 cursor-not-allowed">Read-only view of the script</Subtitle>
<div className="relative">
{preflightScript.isPreflightScriptEnabled ? null : (
<div className="absolute inset-0 z-20 flex items-center justify-center bg-[#030711]/90 p-4 text-white">
<div className="rounded-md bg-[#0f1520] p-4 text-sm">
Preflight Script is disabled and will not be executed
</div>
</div>
)}
<MonacoEditor
height={128}
value={preflightScript.script}
{...monacoProps.script}
className={classes.monacoMini}
className={cn(classes.monacoMini, 'z-10')}
wrapperProps={{
['data-cy']: 'preflight-script-editor-mini',
}}
options={{
...monacoProps.script.options,
lineNumbers: 'off',
domReadOnly: true,
readOnly: true,
hover: {
enabled: false,
},
}}
/>
)}
</div>
<Title className="mt-6 flex items-center gap-2">
<EditorTitle className="mt-6 flex items-center gap-2">
Environment variables{' '}
<Badge className="text-xs" variant="outline">
JSON
</Badge>
</Title>
<Subtitle>Define variables to use in your Headers</Subtitle>
</EditorTitle>
<Subtitle className="mb-3">
Declare variables that can be used by both the script and headers.
</Subtitle>
<MonacoEditor
height={128}
value={preflightScript.environmentVariables}
@ -526,12 +562,12 @@ function PreflightScriptModal({
<div className="grid h-[60vh] grid-cols-2 [&_section]:grow">
<div className="mr-4 flex flex-col">
<div className="flex justify-between p-2">
<Title className="flex gap-2">
<EditorTitle className="flex gap-2">
Script Editor
<Badge className="text-xs" variant="outline">
JavaScript
</Badge>
</Title>
</EditorTitle>
<Button
variant="orangeLink"
size="icon-sm"
@ -575,7 +611,7 @@ function PreflightScriptModal({
</div>
<div className="flex h-[inherit] flex-col">
<div className="flex justify-between p-2">
<Title>Console Output</Title>
<EditorTitle>Console Output</EditorTitle>
<Button
variant="orangeLink"
size="icon-sm"
@ -627,12 +663,12 @@ function PreflightScriptModal({
return <hr key={index} className="my-2 border-dashed border-current" />;
})}
</section>
<Title className="flex gap-2 p-2">
<EditorTitle className="flex gap-2 p-2">
Environment Variables
<Badge className="text-xs" variant="outline">
JSON
</Badge>
</Title>
</EditorTitle>
<MonacoEditor
value={envValue}
onChange={value => onEnvValueChange(value ?? '')}

View file

@ -515,22 +515,37 @@ function LaboratoryPageContent(props: {
.graphiql-dialog a {
--color-primary: 40, 89%, 60% !important;
}
.graphiql-container {
overflow: unset; /* remove default overflow */
}
.graphiql-doc-explorer-title,
.doc-explorer-title {
font-size: 1.125rem !important;
line-height: 1.75rem !important;
color: white;
}
.graphiql-container,
.graphiql-dialog,
.CodeMirror-info {
--color-base: 223, 70%, 3.9% !important;
}
.graphiql-tooltip,
.graphiql-dropdown-content,
.CodeMirror-lint-tooltip {
background: #030711;
}
.graphiql-tab {
white-space: nowrap;
}
.graphiql-sidebar > button.active {
background-color: hsla(var(--color-neutral),var(--alpha-background-light))
}
`}</style>
</Helmet>
{!query.fetching && !query.stale && (

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 KiB

View file

@ -10,34 +10,26 @@ import { Screenshot } from '../../../../components/screenshot'
export const figcaptionClass = 'text-center text-sm mt-2'
These scripts allow you to automatically run custom authentication processes before executing your
GraphQL operations. They're especially useful for handling authentication flows like OAuth, where
you may need to refresh an access token. Let's explore how it works.
**Preflight Scripts** is a feature that enables you to automatically execute custom code before each
GraphQL request is made. They're especially useful for handling authentication flows like OAuth,
where you may need to claim or refresh an access token, validate credentials, or set up custom
headers - all before the request is sent.
## Configuring Preflight Script
To create a script click on the command line icon (right after Operation Collections plugin icon) in
GraphiQL sidebar section.
Navigate to the sidebar section and click the terminal icon to create a preflight script.
<figure className="mt-6">
<Screenshot>![Command line icon](./command-line-icon.png)</Screenshot>
{/* prettier-ignore */}
<figcaption className={figcaptionClass}>The preflight script is accessible by clicking on the Command line icon in the GraphiQL sidebar</figcaption>
</figure>
The interface displays two editors:
You will see Script editor (JavaScript language) which is read-only and present for a quick view of
your saved script and Environment variables editor (JSON language) which is persistent in
localStorage.
- a **read-only Script editor** in JavaScript for viewing the saved script,
- an **Environment Variables editor** in JSON that persists data in localStorage.
<figure className="mt-6">
<Screenshot>![](./preflight-script-plugin.png)</Screenshot>
<figcaption className={figcaptionClass}>Preflight script plugin view</figcaption>
</figure>
<Screenshot>![Active Preflight Script](./active-preflight-script.png)</Screenshot>
## Editing Preflight Script
Clicking on the `Edit` button will open Modal where you can edit, test and save your script in
database.
Clicking the "Edit" button opens a window that allows you to edit, test, and save your script in
Hive.
<Callout type="warning">
**Note**: Your script will stored as plain text in our database, don't put any secrets there, use
@ -46,7 +38,7 @@ database.
</Callout>
You can use any JavaScript syntax (including top-level `await`) in the Script editor. Getting and
Setting environment variables is done by accessing the `environment` property on the `lab` global
setting environment variables is done by accessing the `environment` property on the `lab` global
variable.
```js
@ -56,32 +48,23 @@ lab.environment.get('myKey')
lab.environment.set('myKey', myValue)
```
<figure className="mt-6">
<Screenshot>![](./get-and-set-env-vars.png)</Screenshot>
<figcaption className={figcaptionClass}>Demo how to get and set environment variables</figcaption>
</figure>
<Screenshot>![](./editing.png)</Screenshot>
## CryptoJS
### CryptoJS
Additionally, you can access [the CryptoJS library](https://github.com/brix/crypto-js) by accessing
the `CryptoJS` property on the `lab` global variable.
<figure className="mt-6">
<Screenshot>![](./crypto-js.png)</Screenshot>
<figcaption className={figcaptionClass}>CryptoJS</figcaption>
</figure>
<Screenshot>![](./crypto-js.png)</Screenshot>
## Global Variables and Errors
### Global Variables and Errors
Access to global variables such as `this`, `window` or `globalThis` is restricted. Errors thrown by
the script will be displayed in Console Output.
<figure className="mt-6">
<Screenshot>![](./unable-to-access-global-variables.png)</Screenshot>
<figcaption className={figcaptionClass}>Demo restricted access to global variables</figcaption>
</figure>
<Screenshot>![](./unable-to-access-global-variables.png)</Screenshot>
## Using Environment Variables
### Using Environment Variables
To use your environment variables in GraphiQL headers editor wraps environment keys with
double-curly braces, e.g.:
@ -92,8 +75,4 @@ double-curly braces, e.g.:
}
```
<figure className="mt-6">
<Screenshot>![Replace syntax in action](./replace-syntax.png)</Screenshot>
{/* prettier-ignore */}
<figcaption className={figcaptionClass}>Replace syntax is done via double open/closed curly braces, e.g. `{{ myEnvVar }}`</figcaption>
</figure>
<Screenshot>![](./headers.png)</Screenshot>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

View file

@ -11,14 +11,14 @@ import { Callout } from '@theguild/components'
export const figcaptionClass = 'text-center text-sm mt-2'
We've added Preflight Scripts to Laboratory! These scripts allow you to automatically run custom
authentication processes before executing your GraphQL operations. They're especially useful for
handling authentication flows like OAuth, where you may need to refresh an access token.
We've added Preflight Scripts our GraphQL IDE - Laboratory!
<figure className="mt-6">
<>![](private-next-pages/docs/dashboard/laboratory/get-and-set-env-vars.png)</>
<figcaption className={figcaptionClass}>Demo of Preflight Scripts</figcaption>
</figure>
**Preflight Scripts** is a feature that enables you to automatically execute custom code before each
GraphQL request is made. They're especially useful for handling authentication flows like OAuth,
where you may need to claim or refresh an access token, validate credentials, or set up custom
headers - all before the request is sent.
![Demo of Preflight Scripts](../../docs/dashboard/laboratory/editing.png)
Check out [the documentation on Preflight Scripts](/docs/dashboard/laboratory/preflight-scripts) for
information on how to configure, edit, and use them.