Fix UI, documentation and the product update of Laboratory (#6232)
5
.changeset/flat-cups-tie.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'hive': patch
|
||||
---
|
||||
|
||||
Improvements to UI of Preflight Script (Laboratory)
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 && (
|
||||
|
|
|
|||
|
|
@ -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 ?? '')}
|
||||
|
|
|
|||
|
|
@ -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 && (
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 397 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 309 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 476 KiB |
|
|
@ -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></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></Screenshot>
|
||||
<figcaption className={figcaptionClass}>Preflight script plugin view</figcaption>
|
||||
</figure>
|
||||
<Screenshot></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></Screenshot>
|
||||
<figcaption className={figcaptionClass}>Demo how to get and set environment variables</figcaption>
|
||||
</figure>
|
||||
<Screenshot></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></Screenshot>
|
||||
<figcaption className={figcaptionClass}>CryptoJS</figcaption>
|
||||
</figure>
|
||||
<Screenshot></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></Screenshot>
|
||||
<figcaption className={figcaptionClass}>Demo restricted access to global variables</figcaption>
|
||||
</figure>
|
||||
<Screenshot></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></Screenshot>
|
||||
{/* prettier-ignore */}
|
||||
<figcaption className={figcaptionClass}>Replace syntax is done via double open/closed curly braces, e.g. `{{ myEnvVar }}`</figcaption>
|
||||
</figure>
|
||||
<Screenshot></Screenshot>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 334 KiB |
|
|
@ -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">
|
||||
<></>
|
||||
<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.
|
||||
|
||||

|
||||
|
||||
Check out [the documentation on Preflight Scripts](/docs/dashboard/laboratory/preflight-scripts) for
|
||||
information on how to configure, edit, and use them.
|
||||
|
|
|
|||