Improve documentation (#1549)

This commit is contained in:
Dotan Simha 2023-03-08 18:17:43 +09:00 committed by GitHub
parent b40c76a9aa
commit 8fd6410aed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
187 changed files with 5257 additions and 2055 deletions

2
.gitignore vendored
View file

@ -127,3 +127,5 @@ packages/web/app/next.config.mjs
packages/web/app/environment-*.mjs
packages/web/app/src/gql/*.ts
packages/web/app/src/graphql/*.ts
_redirects

View file

@ -16,7 +16,7 @@ GraphQL Hive has been built with 3 main objectives in mind:
Registry, Performance Monitoring, Alerts, and Integrations.
- **Support all kinds of GraphQL APIs**, from Federation, and Stitching, to standalone APIs.
- **Open Source at the heart**: 100% open-source and build in public with the community.
- **A plug and play SaaS solution**: to give access to Hive to most people with a generous free
- **A plug and play Cloud solution**: to give access to Hive to most people with a generous free
"Hobby plan"
## Features Overview
@ -75,10 +75,10 @@ See you in Hive! 🐝
- General: NodeJS, TypeScript
- Authentication: SuperTokens
- HTTP Server: Fastify
- APIs: GraphQL, GraphQL-Yoga, GraphQL-Codegen, GraphQL Inspector, GraphQL-Modules
- APIs: GraphQL, GraphQL-Yoga, GraphQL-Codegen, GraphQL-Inspector, GraphQL-Modules
- App: React, Next.js, Tailwind CSS, Radix Primitives
- CLI: Oclif
- Deployment (SaaS): Pulumi, K8s, Contour (Envoy), Azure Cloud, CloudFlare Workers, KV Cache, R2
- Deployment (Cloud): Pulumi, K8s, Contour (Envoy), Azure Cloud, CloudFlare Workers, CloudFlare R2
- Monitoring: Prometheus, Grafana, Sentry
- Databases: Postgres, Redis, ClickHouse

View file

@ -10,6 +10,7 @@ const currentPackage = packagesMetadata.packages.find(p => p.dir === libDir);
export const commonWatchList = () => {
return [
libDir + '/src/**/*',
libDir + '/.env',
libDir + '/tsconfig.json',
rootDir + '/tsconfig.json',
rootDir + '/tsup.config.*',

View file

@ -125,11 +125,11 @@ export DOCKER_TAG=":IMAGE_TAG_HERE"
Keep in mind that integration tests are running a combination of 2 Docker Compose files:
1. `docker-compose.community.yml` - this is also used for self-hosting Hive, so this file contains
all services and configurations needed for running Hive core (without SaaS-specific services,
all services and configurations needed for running Hive core (without Cloud-specific services,
like billing).
2. `docker-compose.integration.yaml` - An extension and overrides file: we are using that file to
run local services such as CloudFlare CDN mock, external composition service and so on - this is
done in order to mock a complete Hive SaaS environment and test all features. **This file also
done in order to mock a complete Hive Cloud environment and test all features. **This file also
includes overrides such as environment variables that are specific only for integration testing -
so make sure to choose wisely where to add environment variables!**

View file

@ -1,6 +1,6 @@
# Note: this is an overrides file for ./docker/docker-compose.community.yml:
# It's used for setting special environment and configurations for running integration tests.
# This file also includes services that only exists in Hive's SaaS version, and are not available in the self-hosted version.
# This file also includes services that only exists in Hive's Cloud version, and are not available in the self-hosted version.
# Please refer to TESTING.md for more information.
version: '3.8'

View file

@ -1,38 +1,36 @@
# GraphQL Hive CLI
# Hive CLI (Command Line Interface)
A CLI util to manage and control your GraphQL Hive
A CLI util to manage and control your GraphQL Hive. You can perform
[schema-registry actions](https://docs.graphql-hive.com/features/schema-registry#actions-on-schemas)
on your Hive targets using the Hive CLI.
[![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
[![Version](https://img.shields.io/npm/v/@graphql-hive/cli.svg)](https://npmjs.org/package/@graphql-hive/cli)
[![Downloads/week](https://img.shields.io/npm/dw/@graphql-hive/cli.svg)](https://npmjs.org/package/@graphql-hive/cli)
<!-- toc -->
## Installation
- [GraphQL Hive CLI](#graphql-hive-cli)
- [Usage](#usage)
- [Commands](#commands)
- [Config](#config)
<!-- tocstop -->
### NodeJS
# Usage
If you are running a JavaScript/NodeJS project, you can install Hive CLI from the `npm` registry:
<!-- usage -->
```sh-session
$ npm install -g @graphql-hive/cli
$ hive COMMAND
running command...
$ hive (--version)
@graphql-hive/cli/0.20.0 darwin-arm64 node-v18.14.0
$ hive --help [COMMAND]
USAGE
$ hive COMMAND
...
```
pnpm install -D @graphql-hive/cli
yarn add -D @graphql-hive/cli
npm install -D @graphql-hive/cli
```
<!-- usagestop -->
> We recommend installing Hive CLI as part of your project, under `devDependencies`, instead of
> using a global installation.
# Commands
### Binary
If you are running a non-JavaScript project, you can download the prebuilt binary of Hive CLI using
the following command:
```bash
curl -sSL https://graphql-hive.com/install.sh | sh
```
## Commands
<!-- commands -->
@ -55,7 +53,7 @@ deletes specific cli configuration
```
USAGE
$ hive config:delete [KEY]
$ hive config:delete KEY
ARGUMENTS
KEY config key
@ -65,7 +63,7 @@ DESCRIPTION
```
_See code:
[dist/commands/config/delete.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/config/delete.js)_
[dist/commands/config/delete.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/config/delete.js)_
## `hive config:get KEY`
@ -73,7 +71,7 @@ prints specific cli configuration
```
USAGE
$ hive config:get [KEY]
$ hive config:get KEY
ARGUMENTS
KEY config key
@ -83,7 +81,7 @@ DESCRIPTION
```
_See code:
[dist/commands/config/get.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/config/get.js)_
[dist/commands/config/get.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/config/get.js)_
## `hive config:reset`
@ -98,7 +96,7 @@ DESCRIPTION
```
_See code:
[dist/commands/config/reset.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/config/reset.js)_
[dist/commands/config/reset.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/config/reset.js)_
## `hive config:set KEY VALUE`
@ -106,7 +104,7 @@ updates specific cli configuration
```
USAGE
$ hive config:set [KEY] [VALUE]
$ hive config:set KEY VALUE
ARGUMENTS
KEY config key
@ -117,7 +115,7 @@ DESCRIPTION
```
_See code:
[dist/commands/config/set.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/config/set.js)_
[dist/commands/config/set.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/config/set.js)_
## `hive help [COMMANDS]`
@ -138,7 +136,7 @@ DESCRIPTION
```
_See code:
[@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v5.2.4/src/commands/help.ts)_
[@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v5.2.6/src/commands/help.ts)_
## `hive operations:check FILE`
@ -146,7 +144,7 @@ checks operations against a published schema
```
USAGE
$ hive operations:check [FILE] [--registry <value>] [--token <value>] [--require <value>]
$ hive operations:check FILE [--registry <value>] [--token <value>] [--require <value>]
ARGUMENTS
FILE Glob pattern to find the operations
@ -161,7 +159,7 @@ DESCRIPTION
```
_See code:
[dist/commands/operations/check.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/operations/check.js)_
[dist/commands/operations/check.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/operations/check.js)_
## `hive operations:publish FILE`
@ -169,7 +167,7 @@ saves operations to the store
```
USAGE
$ hive operations:publish [FILE] [--registry <value>] [--token <value>] [--require <value>]
$ hive operations:publish FILE [--registry <value>] [--token <value>] [--require <value>]
ARGUMENTS
FILE Glob pattern to find the operations
@ -185,7 +183,7 @@ DESCRIPTION
```
_See code:
[dist/commands/operations/publish.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/operations/publish.js)_
[dist/commands/operations/publish.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/operations/publish.js)_
## `hive schema:check FILE`
@ -193,7 +191,7 @@ checks schema
```
USAGE
$ hive schema:check [FILE] [--service <value>] [--registry <value>] [--token <value>] [--forceSafe] [--github]
$ hive schema:check FILE [--service <value>] [--registry <value>] [--token <value>] [--forceSafe] [--github]
[--require <value>]
ARGUMENTS
@ -213,7 +211,7 @@ DESCRIPTION
```
_See code:
[dist/commands/schema/check.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/schema/check.js)_
[dist/commands/schema/check.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/schema/check.js)_
## `hive schema:delete SERVICE`
@ -221,7 +219,7 @@ deletes a schema
```
USAGE
$ hive schema:delete [SERVICE] [--registry <value>] [--token <value>] [--dryRun] [--confirm]
$ hive schema:delete SERVICE [--registry <value>] [--token <value>] [--dryRun] [--confirm]
ARGUMENTS
SERVICE name of the service
@ -237,7 +235,7 @@ DESCRIPTION
```
_See code:
[dist/commands/schema/delete.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/schema/delete.js)_
[dist/commands/schema/delete.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/schema/delete.js)_
## `hive schema:publish FILE`
@ -245,8 +243,8 @@ publishes schema
```
USAGE
$ hive schema:publish [FILE] [--service <value>] [--url <value>] [--metadata <value>] [--registry <value>]
[--token <value>] [--author <value>] [--commit <value>] [--github] [--force] [--experimental_acceptBreakingChanges]
$ hive schema:publish FILE [--service <value>] [--url <value>] [--metadata <value>] [--registry <value>] [--token
<value>] [--author <value>] [--commit <value>] [--github] [--force] [--experimental_acceptBreakingChanges]
[--require <value>]
ARGUMENTS
@ -273,7 +271,7 @@ DESCRIPTION
```
_See code:
[dist/commands/schema/publish.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/schema/publish.js)_
[dist/commands/schema/publish.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/schema/publish.js)_
## `hive update [CHANNEL]`
@ -311,7 +309,7 @@ EXAMPLES
```
_See code:
[@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v3.1.3/src/commands/update.ts)_
[@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v3.1.6/src/commands/update.ts)_
## `hive whoami`
@ -330,30 +328,25 @@ DESCRIPTION
```
_See code:
[dist/commands/whoami.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.0/dist/commands/whoami.js)_
[dist/commands/whoami.js](https://github.com/kamilkisiela/graphql-hive/blob/v0.20.2/dist/commands/whoami.js)_
<!-- commandsstop -->
<!-- config -->
## Configuration
# Config
### Environment Variables
In addition to using the CLI args, you can also define your configuration in a JSON file which the
CLI would pick up when it runs.
You may set the `HIVE_TOKEN` environment variable while running the Hive CLI, in order to set it
globally.
You can use the `HIVE_CONFIG` environment variable to define the path to the JSON file as follows:
### Config file (`hive.json`)
`HIVE_CONFIG=/path/to/hive.json hive schema:publish --author Vignesh path/to/file.gql`
Note that the CLI args will override the values in config if both are specified.
This is how the structure of the config file should look like:
You can create a `hive.json` file to manage your Hive configuration, you may use the following JSON
keys:
```json
{
"registry": "<yourRegistryURL>",
"token": "<yourtoken>"
"registry": "<HIVE_REGISTRY_URL_GRAPHQL_ENDPOINT>",
"token": "<HIVE_REGISTRY_TOKEN>"
}
```
<!-- configstop -->

View file

@ -116,6 +116,7 @@ export default gql`
id: ID!
cleanId: ID!
name: String!
project: Project!
}
type TargetSettings {

View file

@ -1,6 +1,7 @@
import { z } from 'zod';
import { createConnection } from '../../shared/schema';
import { OrganizationManager } from '../organization/providers/organization-manager';
import { ProjectManager } from '../project/providers/project-manager';
import { IdTranslator } from '../shared/providers/id-translator';
import type { TargetModule } from './__generated__/types';
import { TargetManager } from './providers/target-manager';
@ -9,6 +10,13 @@ const TargetNameModel = z.string().min(2).max(30);
const PercentageModel = z.number().min(0).max(100);
export const resolvers: TargetModule.Resolvers = {
Target: {
project: (target, args, { injector }) =>
injector.get(ProjectManager).getProject({
project: target.projectId,
organization: target.orgId,
}),
},
Query: {
async target(_, { selector }, { injector }) {
const translator = injector.get(IdTranslator);

View file

@ -0,0 +1,5 @@
S3_ENDPOINT=http://localhost:9000
S3_ACCESS_KEY_ID="minioadmin"
S3_SECRET_ACCESS_KEY="minioadmin"
S3_BUCKET_NAME="artifacts"
S3_PUBLIC_URL="http://localhost:9000"

View file

@ -22,6 +22,7 @@
"@types/service-worker-mock": "2.0.1",
"@whatwg-node/fetch": "0.8.2",
"@whatwg-node/server": "0.7.4",
"dotenv": "16.0.3",
"esbuild": "0.17.11",
"fastify": "3.29.5",
"itty-router": "2.6.6",

View file

@ -1,3 +1,4 @@
import 'dotenv/config';
import { crypto, Headers, ReadableStream, Request, Response } from '@whatwg-node/fetch';
if (!globalThis.Response) {

View file

@ -6,7 +6,7 @@ Hive comes with support for Apollo Federation v2, based on
[external composition](https://docs.graphql-hive.com/features/external-schema-composition).
This package provides a reference for running external composition as a NodeJS service, on your
local infrastructure, and connect GraphQL Hive (SaaS or self-service).
local infrastructure, and connect GraphQL Hive (Cloud or self-service).
# Usage
@ -31,8 +31,8 @@ docker run -p 3069 -e SECRET="MY_SECRET_HERE" ghcr.io/kamilkisiela/graphql-hive/
The container runs on port `3069` by default (you can chnage it using `PORT` env var), and listens
to `POST /compose` requests coming from Hive platform.
You should make this service publicly available and accessible to use it with Hive SaaS platform, or
make it availble in your local/private network if you are using Hive on-prem.
You should make this service publicly available and accessible to use it with Hive Cloud platform,
or make it availble in your local/private network if you are using Hive on-prem.
## Running from source code

View file

@ -2,7 +2,7 @@
"name": "@hive/rate-limit",
"version": "0.0.0",
"type": "module",
"description": "A microservice for Hive SaaS, that exposes information about rate limits per given org/target.",
"description": "A microservice for Hive Cloud, that exposes information about rate limits per given org/target.",
"license": "MIT",
"private": true,
"scripts": {

View file

@ -25,7 +25,8 @@ INTEGRATION_GITHUB_APP_ID="<sync>"
INTEGRATION_GITHUB_APP_PRIVATE_KEY="<sync>"
# CDN Configuration
CDN='1'
CDN_CF='1'
CDN_CF_BASE_URL=http://localhost:4010
CDN_CF_BASE_PATH=http://localhost:4010
CDN_CF_ACCOUNT_ID=103df45224310d669213971ce28b5b70
CDN_CF_AUTH_TOKEN=85e20c26c03759603c0f45884824a1c3

View file

@ -50,7 +50,7 @@ The GraphQL API for GraphQL Hive.
## Hive Hosted Configuration
If you are self-hosting GraphQL Hive, you can ignore this section. It is only required for the SaaS
If you are self-hosting GraphQL Hive, you can ignore this section. It is only required for the Cloud
version.
| Name | Required | Description | Example Value |

View file

@ -2,7 +2,7 @@
"name": "@hive/stripe-billing",
"version": "0.0.0",
"type": "module",
"description": "A microservice for Hive SaaS, that syncs usage information to Stripe (metered billing)",
"description": "A microservice for Hive Cloud, that syncs usage information to Stripe (metered billing)",
"license": "MIT",
"private": true,
"scripts": {

View file

@ -2,7 +2,7 @@
"name": "@hive/usage-estimator",
"version": "0.0.0",
"type": "module",
"description": "A microservice for Hive SaaS, that calculates and exposes usage information.",
"description": "A microservice for Hive Cloud, that calculates and exposes usage information.",
"license": "MIT",
"private": true,
"scripts": {

View file

@ -21,7 +21,7 @@ import { graphql } from '@/gql';
import { CompareDocument, VersionsDocument } from '@/graphql';
import { useRouteSelector } from '@/lib/hooks/use-route-selector';
import { withSessionProtection } from '@/lib/supertokens/guard';
import { CrossCircledIcon, RowsIcon } from '@radix-ui/react-icons';
import { CrossCircledIcon, ExternalLinkIcon, RowsIcon } from '@radix-ui/react-icons';
function DiffView({
view,
@ -94,11 +94,13 @@ function DiffView({
// URQL's Infinite scrolling pattern
// https://formidable.com/open-source/urql/docs/basics/ui-patterns/#infinite-scrolling
function ListPage({
gitRepository,
variables,
isLastPage,
onLoadMore,
versionId,
}: {
gitRepository?: string;
variables: { after: string; limit: number };
isLastPage: boolean;
onLoadMore: (after: string) => void;
@ -125,36 +127,51 @@ function ListPage({
return (
<>
{versions?.nodes.map(version => (
<NextLink
key={version.id}
href={`/${router.organizationId}/${router.projectId}/${router.targetId}/history/${version.id}`}
scroll={false} // disable the scroll to top on page
<div
className={clsx(
'flex flex-col rounded-md p-2.5 hover:bg-gray-800/40',
versionId === version.id && 'bg-gray-800/40',
)}
>
<h3 className="truncate font-bold">
{'commit' in version.log ? version.log.commit : `Deleted ${version.log.deletedService}`}
</h3>
{'author' in version.log ? (
<div className="truncate text-xs font-medium text-gray-500">
<span className="overflow-hidden truncate">{version.log.author}</span>
</div>
) : null}
<div className="mt-2.5 mb-1.5 flex align-middle text-xs font-medium text-[#c4c4c4]">
<div className={clsx('w-1/2 ', !version.valid && 'text-red-500')}>
<Badge color={version.valid ? 'green' : 'red'} /> Published{' '}
<TimeAgo date={version.date} />
</div>
{'service' in version.log && version.log.service ? (
<div className="ml-auto mr-0 w-1/2 overflow-hidden text-ellipsis whitespace-nowrap text-right font-bold">
{version.log.service}
<NextLink
key={version.id}
href={`/${router.organizationId}/${router.projectId}/${router.targetId}/history/${version.id}`}
scroll={false} // disable the scroll to top on page
>
<h3 className="truncate font-bold">
{'commit' in version.log
? version.log.commit
: `Deleted ${version.log.deletedService}`}
</h3>
{'author' in version.log ? (
<div className="truncate text-xs font-medium text-gray-500">
<span className="overflow-hidden truncate">{version.log.author}</span>
</div>
) : null}
</div>
</NextLink>
<div className="mt-2.5 mb-1.5 flex align-middle text-xs font-medium text-[#c4c4c4]">
<div className={clsx('w-1/2 ', !version.valid && 'text-red-500')}>
<Badge color={version.valid ? 'green' : 'red'} /> Published{' '}
<TimeAgo date={version.date} />
</div>
{'service' in version.log && version.log.service ? (
<div className="ml-auto mr-0 w-1/2 overflow-hidden text-ellipsis whitespace-nowrap text-right font-bold">
{version.log.service}
</div>
) : null}
</div>
</NextLink>
{gitRepository && 'commit' in version.log && version.log.commit ? (
<a
className="text-xs font-medium text-gray-500 hover:text-gray-400"
target="_blank"
rel="noreferrer"
href={`https://github.com/${gitRepository}/commit/${version.log.commit}`}
>
<ExternalLinkIcon className="inline" /> associated with Git commit
</a>
) : null}
</div>
))}
{isLastPage && hasMore && (
<Button
@ -175,7 +192,7 @@ function ListPage({
type View = 'SDL' | 'list';
function Page({ versionId }: { versionId: string }) {
function Page({ versionId, gitRepository }: { versionId: string; gitRepository?: string }) {
const [pageVariables, setPageVariables] = useState([{ limit: 10, after: '' }]);
const [view, setView] = useState<View>('list');
@ -190,6 +207,7 @@ function Page({ versionId }: { versionId: string }) {
<div className="flex h-0 min-w-[420px] grow flex-col gap-2.5 overflow-y-auto rounded-md border border-gray-800/50 p-2.5">
{pageVariables.map((variables, i) => (
<ListPage
gitRepository={gitRepository}
key={variables.after}
variables={variables}
isLastPage={i === pageVariables.length - 1}
@ -242,6 +260,7 @@ const TargetHistoryPageQuery = graphql(`
}
project(selector: { organization: $organizationId, project: $projectId }) {
...TargetLayout_ProjectFragment
gitRepository
}
targets(selector: { organization: $organizationId, project: $projectId }) {
...TargetLayout_TargetConnectionFragment
@ -267,9 +286,13 @@ function HistoryPage(): ReactElement {
className="flex h-full items-stretch gap-x-5"
query={TargetHistoryPageQuery}
>
{({ target }) => {
{({ target, project }) => {
const versionId = router.versionId ?? target?.latestSchemaVersion?.id;
return versionId ? <Page versionId={versionId} /> : noSchemaVersion;
return versionId ? (
<Page gitRepository={project?.gitRepository ?? undefined} versionId={versionId} />
) : (
noSchemaVersion
);
}}
</TargetLayout>
</>

View file

@ -2,7 +2,7 @@ import { ReactElement } from 'react';
import { GraphiQL } from 'graphiql';
import { authenticated } from '@/components/authenticated-container';
import { TargetLayout } from '@/components/layouts';
import { Button, Title } from '@/components/v2';
import { Button, DocsLink, DocsNote, Title } from '@/components/v2';
import { HiveLogo, Link2Icon } from '@/components/v2/icon';
import { ConnectLabModal } from '@/components/v2/modals/connect-lab';
import { graphql } from '@/gql';
@ -14,13 +14,14 @@ import 'graphiql/graphiql.css';
const Page = ({ endpoint }: { endpoint: string }): ReactElement => {
return (
<>
<p className="mb-5 font-light text-gray-500">
Experiment, mock and create live environment for your schema, without running any backend.
</p>
<DocsNote>
Explore your GraphQL schema and run queries against a mocked version of your GraphQL
service. <DocsLink href="/features/laboratory">Learn more about the Laboratory</DocsLink>
</DocsNote>
<style global jsx>{`
body.graphiql-dark .graphiql-container {
--color-base: transparent;
--color-primary: 40, 89%, 60%;
.graphiql-container {
--color-base: transparent !important;
--color-primary: 40, 89%, 60% !important;
}
`}</style>
<GraphiQL fetcher={createGraphiQLFetcher({ url: endpoint })}>
@ -67,7 +68,7 @@ function LaboratoryPage(): ReactElement {
connect={
<>
<Button size="large" variant="primary" onClick={toggleModalOpen} className="ml-auto">
Connect
Use Schema Externally
<Link2Icon className="ml-8 h-4 w-4" />
</Button>
<ConnectLabModal

View file

@ -8,7 +8,6 @@ import { OperationsList } from '@/components/target/operations/List';
import { OperationsStats } from '@/components/target/operations/Stats';
import { EmptyList, RadixSelect, Title } from '@/components/v2';
import { graphql } from '@/gql';
import { getDocsUrl } from '@/lib/docs-url';
import { withSessionProtection } from '@/lib/supertokens/guard';
function floorDate(date: Date): Date {
@ -131,9 +130,6 @@ function OperationsPage(): ReactElement {
{({ organization, project, target, hasCollectedOperations }) =>
organization && project && target ? (
<div className="relative">
<p className="mb-5 font-light text-gray-500">
Data collected based on operation executed against your GraphQL schema.
</p>
{hasCollectedOperations ? (
<OperationsView
organizationCleanId={organization.organization.cleanId}
@ -144,7 +140,7 @@ function OperationsPage(): ReactElement {
<EmptyList
title="Hive is waiting for your first collected operation"
description="You can collect usage of your GraphQL API with Hive Client"
docsUrl={getDocsUrl('/features/monitoring')}
docsUrl="/features/usage-reporting"
/>
)}
</div>

View file

@ -12,6 +12,8 @@ import {
Button,
Card,
Checkbox,
DocsLink,
DocsNote,
Heading,
Input,
Spinner,
@ -25,7 +27,6 @@ import {
Tr,
} from '@/components/v2';
import { Combobox } from '@/components/v2/combobox';
import { AlertTriangleIcon } from '@/components/v2/icon';
import { CreateAccessTokenModal, DeleteTargetModal } from '@/components/v2/modals';
import { FragmentType, graphql, useFragment } from '@/gql';
import { DeleteTokensDocument, SetTargetValidationDocument, TokensDocument } from '@/graphql';
@ -81,6 +82,14 @@ function RegistryAccessTokens(props: {
<p className="mb-3 font-light text-gray-300">
Be careful! These tokens allow to read and write your target data.
</p>
<DocsNote>
Registry Access Tokens are used to access to Hive Registry and perform actions on your
targets/projects. In most cases, this token is used from the Hive CLI.
<br />
<DocsLink href="/management/targets#registry-access-tokens">
Learn more about Registry Access Token
</DocsLink>
</DocsNote>
{canManage && (
<div className="my-3.5 flex justify-between">
<Button variant="secondary" onClick={toggleModalOpen} size="large" className="px-5">
@ -162,11 +171,14 @@ const ExtendBaseSchema = (props: { baseSchema: string }): ReactElement => {
return (
<Card>
<Heading className="mb-2">Extend Your Schema</Heading>
<p className="mb-3 font-light text-gray-300">
Define a piece of SDL that will be added to every published schema.
<DocsNote>
Schema Extensions is pre-defined GraphQL schema that is automatically merged with your
published schemas, before being checked and validated.
<br />
Useful for AWS AppSync users to not send platform-specific part of schema to Hive.
</p>
<DocsLink href="/management/targets#schema-extensions">
You can find more details and examples in the documentation
</DocsLink>
</DocsNote>
<SchemaEditor
theme="vs-dark"
options={{ readOnly: mutation.fetching }}
@ -424,9 +436,14 @@ const ConditionalBreakingChanges = (): ReactElement => {
/>
)}
</Heading>
<DocsNote>
Conditional Breaking Changes can change the behavior of schema checks, based on real
traffic data sent to Hive.{' '}
<DocsLink href="/management/targets#conditional-breaking-changes">Learn more</DocsLink>
</DocsNote>
<div
className={clsx(
'mb-3 flex flex-col items-start gap-3 font-light text-gray-300',
'mb-3 mt-4 flex flex-col items-start gap-3 font-light text-gray-300',
!isEnabled && 'pointer-events-none opacity-25',
)}
>
@ -652,10 +669,15 @@ const Page = (props: {
return (
<>
<Card>
<Heading className="mb-2">Target Info</Heading>
<p className="mb-3 font-light text-gray-300">
Name of your target visible within organization.
</p>
<Heading className="mb-2">Target Name</Heading>
<DocsNote warn>
Changing the name of your target will also change the slug of your target URL, and will
invalidate any existing links to your target.
<br />
<DocsLink href="/management/targets#rename-a-target">
You can read more about it in the documentation
</DocsLink>
</DocsNote>
<form onSubmit={handleSubmit} className="flex gap-x-2">
<Input
placeholder="Target name"
@ -699,22 +721,29 @@ const Page = (props: {
{canDelete && (
<Card>
<Heading className="mb-2">Delete Target</Heading>
<p className="mb-3 font-light text-gray-300">Permanently remove your Target</p>
<div className="flex items-center gap-x-2">
<Button
variant="primary"
size="large"
danger
onClick={toggleModalOpen}
className="px-5"
>
Delete Target
</Button>
<Tag color="yellow" className="py-2.5 px-4">
<AlertTriangleIcon className="h-5 w-5" />
This action is not reversible!
</Tag>
<div className="flex items-center justify-between">
<div>
<Heading className="mb-2">Delete Target</Heading>
<DocsNote warn>
Deleting an project also delete all schemas and data associated with it.
<br />
<DocsLink href="/management/targets#delete-a-target">
<strong>This action is not reversible!</strong> You can find more information
about this process in the documentation
</DocsLink>
</DocsNote>
</div>
<div className="flex items-center gap-x-2">
<Button
variant="primary"
size="large"
danger
onClick={toggleModalOpen}
className="px-5"
>
Delete Target
</Button>
</div>
</div>
</Card>
)}

View file

@ -23,7 +23,6 @@ import {
import { LinkIcon, MoreIcon, SettingsIcon } from '@/components/v2/icon';
import { graphql } from '@/gql';
import { TargetQuery, TargetsDocument, VersionsDocument } from '@/graphql';
import { getDocsUrl } from '@/lib/docs-url';
import { useClipboard } from '@/lib/hooks/use-clipboard';
import { useRouteSelector } from '@/lib/hooks/use-route-selector';
import { withSessionProtection } from '@/lib/supertokens/guard';
@ -130,7 +129,7 @@ const Page = () => {
<EmptyList
title="Hive is waiting for your first target"
description='You can create a target by clicking the "New Target" button'
docsUrl={getDocsUrl('/get-started/targets')}
docsUrl="/management/targets#create-a-new-target"
/>
) : (
targets?.nodes.map(target => <TargetCard key={target.id} target={target} />)

View file

@ -2,7 +2,20 @@ import { ReactElement, useState } from 'react';
import { useMutation, useQuery } from 'urql';
import { authenticated } from '@/components/authenticated-container';
import { ProjectLayout } from '@/components/layouts';
import { Button, Card, Checkbox, Heading, Table, Tag, TBody, Td, Title, Tr } from '@/components/v2';
import {
Button,
Card,
Checkbox,
DocsLink,
DocsNote,
Heading,
Table,
Tag,
TBody,
Td,
Title,
Tr,
} from '@/components/v2';
import { CreateAlertModal, CreateChannelModal } from '@/components/v2/modals';
import { FragmentType, graphql, useFragment } from '@/gql';
import {
@ -37,7 +50,11 @@ function Channels(): ReactElement {
return (
<Card>
<Heading className="mb-2">Available Channels</Heading>
<p className="mb-3 font-light text-gray-300">Channel represents a form of communication</p>
<DocsNote>
Alert Channels are a way to configure <strong>how</strong> you want to receive alerts and
notifications from Hive.{' '}
<DocsLink href="/management/projects#alert-channels">Learn more</DocsLink>
</DocsNote>
<Table>
<TBody>
{channelAlerts.map(channelAlert => (
@ -139,8 +156,12 @@ const Page = (props: {
<>
<Channels />
<Card>
<Heading className="mb-2">Active Alerts</Heading>
<p className="mb-3 font-light text-gray-300">Alerts are sent over the Channels</p>
<Heading className="mb-2">Active Alerts and Notifications</Heading>
<DocsNote>
Alerts are a way to configure <strong>when</strong> you want to receive alerts and
notifications from Hive.{' '}
<DocsLink href="/management/projects#alerts-and-notifications-1">Learn more</DocsLink>
</DocsNote>
<Table>
<TBody>
{alerts.map(alert => (

View file

@ -6,8 +6,18 @@ import { authenticated } from '@/components/authenticated-container';
import { ProjectLayout } from '@/components/layouts';
import { ExternalCompositionSettings } from '@/components/project/settings/external-composition';
import { ModelMigrationSettings } from '@/components/project/settings/model-migration';
import { Button, Card, Heading, Input, Link, Select, Tag, Title } from '@/components/v2';
import { AlertTriangleIcon } from '@/components/v2/icon';
import {
Button,
Card,
DocsLink,
DocsNote,
Heading,
Input,
Link,
Select,
Tag,
Title,
} from '@/components/v2';
import { DeleteProjectModal } from '@/components/v2/modals';
import { FragmentType, graphql, useFragment } from '@/gql';
import { GetGitHubIntegrationDetailsDocument, ProjectType } from '@/graphql';
@ -212,9 +222,14 @@ const Page = (props: {
<ModelMigrationSettings project={project} organizationId={organization.cleanId} />
<Card>
<Heading className="mb-2">Project Name</Heading>
<p className="mb-3 font-light text-gray-300">
Name of your project visible within organization
</p>
<DocsNote warn>
Changing the name of your project will also change the slug of your project URL, and will
invalidate any existing links to your project.
<br />
<DocsLink href="/management/projects#rename-a-project">
You can read more about it in the documentation
</DocsLink>
</DocsNote>
<form onSubmit={handleSubmit} className="flex gap-x-2">
<Input
placeholder="Project name"
@ -248,9 +263,14 @@ const Page = (props: {
<Card>
<Heading className="mb-2">Git Repository</Heading>
<p className="mb-3 font-light text-gray-300">
Connect the project with your Git repository
</p>
<DocsNote>
Associate your project with a Git repository to enable commit linking and to allow CI
integration.
<br />
<DocsLink href="/management/projects#github-repository">
Learn more about GitHub integration
</DocsLink>
</DocsNote>
<GitHubIntegration gitRepository={project.gitRepository ?? null} />
</Card>
@ -260,24 +280,30 @@ const Page = (props: {
{canAccessProject(ProjectAccessScope.Delete, organization.me) && (
<Card>
<Heading className="mb-2">Delete Project</Heading>
<p className="mb-3 font-light text-gray-300">
Permanently remove your Project and all targets from the Organization
</p>
<div className="flex items-center gap-x-2">
<Button
variant="primary"
size="large"
danger
onClick={toggleModalOpen}
className="px-5"
>
Delete Project
</Button>
<Tag color="yellow" className="py-2.5 px-4">
<AlertTriangleIcon className="h-5 w-5" />
This action is not reversible!
</Tag>
<div className="flex items-center justify-between">
<div>
<Heading className="mb-2">Delete Project</Heading>
<DocsNote warn>
Deleting an project will delete all the targets, schemas and data associated with
it.
<br />
<DocsLink href="/management/projects#delete-a-project">
<strong>This action is not reversible!</strong> You can find more information
about this process in the documentation
</DocsLink>
</DocsNote>
</div>
<div className="flex items-center gap-x-2">
<Button
variant="primary"
size="large"
danger
onClick={toggleModalOpen}
className="px-5"
>
Delete Project
</Button>
</div>
</div>
</Card>
)}

View file

@ -26,7 +26,6 @@ import { FragmentType, graphql, useFragment } from '@/gql';
import { ProjectActivitiesDocument } from '@/graphql';
import { canAccessProject, ProjectAccessScope } from '@/lib/access/project';
import { writeLastVisitedOrganization } from '@/lib/cookies';
import { getDocsUrl } from '@/lib/docs-url';
import { fixDuplicatedFragments } from '@/lib/graphql';
import { useClipboard } from '@/lib/hooks/use-clipboard';
import { useRouteSelector } from '@/lib/hooks/use-route-selector';
@ -162,7 +161,7 @@ function ProjectsPage(): ReactElement {
<EmptyList
title="Hive is waiting for your first project"
description='You can create a project by clicking the "Create Project" button'
docsUrl={getDocsUrl('/get-started/projects')}
docsUrl="/management/projects#create-a-new-project"
/>
) : (
<div className="grid grid-cols-2 gap-5 items-stretch">

View file

@ -4,7 +4,17 @@ import { useMutation, useQuery } from 'urql';
import * as Yup from 'yup';
import { authenticated } from '@/components/authenticated-container';
import { OrganizationLayout } from '@/components/layouts';
import { Avatar, Button, Card, Checkbox, Input, Title } from '@/components/v2';
import {
Avatar,
Button,
Card,
Checkbox,
DocsLink,
DocsNote,
Heading,
Input,
Title,
} from '@/components/v2';
import {
DropdownMenu,
DropdownMenuContent,
@ -256,7 +266,7 @@ const OrganizationInvitations = (props: {
return org.invitations.nodes.length ? (
<div className="pt-3">
<div className="border-t-4 border-solid pb-6" />
<Heading className="mb-2">Pending Invitations</Heading>
{org.invitations.nodes.map(node => (
<Invitation key={node.id} invitation={node} organizationCleanId={org.cleanId} />
))}
@ -300,9 +310,12 @@ function Page(props: { organization: FragmentType<typeof Page_OrganizationFragme
return (
<>
<p className="mb-3 font-light text-gray-300">
Invite others to your organization and manage access
</p>
<DocsNote>
You may invite other members to collaborate with you on this organization.{' '}
<DocsLink href="/management/organizations#members">
Learn more about membership and invitations
</DocsLink>
</DocsNote>
{selectedMember && (
<ChangePermissionsModal
isOpen={isPermissionsModalOpen}

View file

@ -5,8 +5,8 @@ import * as Yup from 'yup';
import { authenticated } from '@/components/authenticated-container';
import { OrganizationLayout } from '@/components/layouts';
import { OIDCIntegrationSection } from '@/components/organization/settings/oidc-integration-section';
import { Button, Card, Heading, Input, Tag, Title } from '@/components/v2';
import { AlertTriangleIcon, GitHubIcon, SlackIcon } from '@/components/v2/icon';
import { Button, Card, DocsLink, DocsNote, Heading, Input, Tag, Title } from '@/components/v2';
import { GitHubIcon, SlackIcon } from '@/components/v2/icon';
import {
DeleteOrganizationModal,
TransferOrganizationOwnershipModal,
@ -197,9 +197,6 @@ const SettingsPageRenderer = (props: {
<>
<Card>
<Heading className="mb-2">Organization Name</Heading>
<p className="mb-3 font-light text-gray-300">
Name of your organization visible within Hive
</p>
<form onSubmit={handleSubmit} className="flex gap-x-2">
<Input
placeholder="Organization name"
@ -232,12 +229,27 @@ const SettingsPageRenderer = (props: {
{mutation.error && (
<div>{mutation.error.graphQLErrors[0]?.message ?? mutation.error.message}</div>
)}
<DocsNote warn>
Changing the name of your organization will also change the slug of your organization URL,
and will invalidate any existing links to your organization.
<br />
<DocsLink href="/management/organizations#rename-an-organization">
You can read more about it in the documentation
</DocsLink>
</DocsNote>
</Card>
{canAccessOrganization(OrganizationAccessScope.Integrations, organization.me) && (
<Card>
<Heading className="mb-2">Integrations</Heading>
<p className="mb-3 font-light text-gray-300">Connect Hive to other services</p>
<DocsNote>
Authorize external services to make them available for your the projects under this
organization.
<br />
<DocsLink href="/management/organizations#integrations">
You can find here instructions and full documentation for the available integration
</DocsLink>
</DocsNote>
<div className="flex flex-col gap-y-4 text-gray-500">
<Integrations />
</div>
@ -249,7 +261,14 @@ const SettingsPageRenderer = (props: {
<div className="flex items-center justify-between">
<div>
<Heading className="mb-2">Transfer Ownership</Heading>
<p className="font-light text-gray-300">Transfer this organization to another user</p>
<DocsNote>
<strong>You are currently the owner of the organization.</strong> You can transfer
the organization to another member of the organization, or to an external user.
<br />
<DocsLink href="/management/organizations#transfer-ownership">
Learn more about the process
</DocsLink>
</DocsNote>
</div>
<div>
<Button
@ -259,7 +278,7 @@ const SettingsPageRenderer = (props: {
onClick={toggleTransferModalOpen}
className="px-5"
>
Transfer
Transfer Ownership
</Button>
<TransferOrganizationOwnershipModal
isOpen={isTransferModalOpen}
@ -276,13 +295,17 @@ const SettingsPageRenderer = (props: {
<div className="flex items-center justify-between">
<div>
<Heading className="mb-2">Delete Organization</Heading>
<p className="font-light text-gray-300">Permanently remove your organization</p>
<DocsNote warn>
Deleting an organization will delete all the projects, targets, schemas and data
associated with it.
<br />
<DocsLink href="/management/organizations#delete-an-organization">
<strong>This action is not reversible!</strong> You can find more information
about this process in the documentation
</DocsLink>
</DocsNote>
</div>
<div className="flex items-center gap-x-2">
<Tag color="yellow" className="py-2.5 px-4">
<AlertTriangleIcon className="h-5 w-5" />
This action is not reversible!
</Tag>
<Button
variant="primary"
size="large"

View file

@ -80,12 +80,9 @@ function Page(props: {
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="overview">
<p className="mb-3 font-light text-gray-300">
Information about your Hive plan, subscription, usage and data ingestion
</p>
<RateLimitWarn organization={organization} />
<Card className="mt-8">
<Heading className="mb-2">Plan and Reserved Volume</Heading>
<Heading className="mb-2">Your current plan</Heading>
<div>
<BillingView organization={organization} query={query}>
{organization.billingConfiguration?.upcomingInvoice && (

View file

@ -233,6 +233,7 @@ function Inner(props: {
<Card className="w-full">
<Heading className="mb-4">Choose Your Plan</Heading>
<BillingPlanPicker
disabled={organization.plan === BillingPlanType.Enterprise}
activePlan={organization.plan}
value={plan}
plans={billingPlans}

View file

@ -77,28 +77,37 @@ function GetStartedWizard({
<Drawer.Title>Get Started</Drawer.Title>
<p>Complete these steps to experience the full power of GraphQL Hive</p>
<div className="mt-4 flex flex-col divide-y-2 divide-gray-900">
<Task link={getDocsUrl('/get-started/projects')} completed={tasks.creatingProject}>
<Task
link={getDocsUrl('/management/projects#create-a-new-project')}
completed={tasks.creatingProject}
>
Create a project
</Task>
<Task link={getDocsUrl('/features/publish-schema')} completed={tasks.publishingSchema}>
<Task
link={getDocsUrl('/features/schema-registry#publish-a-schema')}
completed={tasks.publishingSchema}
>
Publish a schema
</Task>
<Task link={getDocsUrl('/features/checking-schema')} completed={tasks.checkingSchema}>
<Task
link={getDocsUrl('/features/schema-registry#check-a-schema')}
completed={tasks.checkingSchema}
>
Check a schema
</Task>
{'invitingMembers' in tasks && typeof tasks.invitingMembers === 'boolean' ? (
<Task
link={getDocsUrl('/get-started/organizations#members')}
link={getDocsUrl('/management/organizations#members')}
completed={tasks.invitingMembers}
>
Invite members
</Task>
) : null}
<Task link={getDocsUrl('/features/monitoring')} completed={tasks.reportingOperations}>
<Task link={getDocsUrl('/features/usage-reporting')} completed={tasks.reportingOperations}>
Report operations
</Task>
<Task
link={getDocsUrl('/features/checking-schema#with-usage-enabled')}
link={getDocsUrl('/management/targets#conditional-breaking-changes')}
completed={tasks.enablingUsageBasedBreakingChanges}
>
Enable usage-based breaking changes

View file

@ -199,7 +199,7 @@ export const TargetLayout = <
onClick={toggleModalOpen}
className="ml-auto"
>
Connect
Connect to CDN
<Link2Icon className="ml-8 h-4 w-4" />
</Button>
<ConnectSchemaModal isOpen={isModalOpen} toggleModalOpen={toggleModalOpen} />

View file

@ -117,8 +117,10 @@ export function BillingPlanPicker({
value,
onPlanChange,
activePlan,
disabled,
...props
}: {
disabled?: boolean;
value: BillingPlanType;
activePlan: BillingPlanType;
plans: ReadonlyArray<FragmentType<typeof BillingPlanPicker_PlanFragment>>;
@ -128,7 +130,12 @@ export function BillingPlanPicker({
return (
<RadioGroup value={value} onValueChange={onPlanChange} className="flex gap-4 md:!flex-row">
{plans.map(plan => (
<Radio value={plan.planType} key={plan.id} className="!rounded-md border p-4 md:w-1/3">
<Radio
disabled={disabled}
value={plan.planType}
key={plan.id}
className="!rounded-md border p-4 md:w-1/3"
>
<Plan
key={plan.id}
name={plan.name}

View file

@ -94,10 +94,8 @@ export function PlanSummary({
<Stat.Label>Plan Type</Stat.Label>
<Stat.Number>{plan.planType}</Stat.Number>
<Stat.HelpText>
Enterprise plan is for organizations that needs to ship and ingest large amount of data.
<br />
If you wish to upgrade to Enterprise, or you can't find the plan for you, please contact
us and we'll find the right plan for your organization.
Enterprise plan is for organizations that needs to ship and ingest large amount of data,
and needs ongoing support around GraphQL APIs.
</Stat.HelpText>
</Stat>
);

View file

@ -2,7 +2,17 @@ import { useCallback, useState } from 'react';
import { useFormik } from 'formik';
import { useMutation, useQuery } from 'urql';
import * as Yup from 'yup';
import { Button, Card, Heading, Input, Spinner, Switch, Tooltip } from '@/components/v2';
import {
Button,
Card,
DocsLink,
DocsNote,
Heading,
Input,
Spinner,
Switch,
Tooltip,
} from '@/components/v2';
import { FragmentType, graphql, useFragment } from '@/gql';
import { useNotifications } from '@/lib/hooks';
import { CheckIcon, Cross2Icon, UpdateIcon } from '@radix-ui/react-icons';
@ -332,9 +342,13 @@ export const ExternalCompositionSettings = (props: {
)}
</div>
</Heading>
<p className="mb-3 font-light text-gray-300">
Compose and validate schema outside GraphQL Hive
</p>
<DocsNote>
External Schema Composition is required for using Apollo Federation 2 with Hive.
<br />
<DocsLink href="/management/external-schema-composition">
Learn more about Apollo Federation 2 support
</DocsLink>
</DocsNote>
{isFormVisible ? (
<ExternalCompositionForm
project={project}

View file

@ -6,6 +6,8 @@ import * as Yup from 'yup';
import {
Button,
Card,
DocsLink,
DocsNote,
Heading,
Input,
Modal,
@ -111,7 +113,7 @@ function CreateCDNAccessTokenModal(props: {
<div className="mt-auto flex w-full gap-2 self-end">
<Button size="large" className="ml-auto" onClick={props.onClose}>
Abort
Cancel
</Button>
<Button
@ -224,7 +226,7 @@ function DeleteCDNAccessTokenModal(props: {
<div className="mt-auto flex w-full gap-2 self-end">
<Button variant="primary" size="large" className="ml-auto" onClick={onClose}>
Abort
Cancel
</Button>
<Button
disabled={deleteCdnAccessToken.fetching}
@ -380,9 +382,14 @@ export function CDNAccessTokens(props: {
<Heading id="cdn-access-tokens" className="mb-2">
CDN Access Token
</Heading>
<p className="mb-3 font-light text-gray-300">
Be careful! These tokens allow accessing the schema artifacts of your target.
</p>
<DocsNote>
CDN Access Tokens are used to access to Hive High-Availability CDN and read your schema
artifacts.
<br />
<DocsLink href="/management/targets#cdn-access-tokens">
Learn more about CDN Access Token
</DocsLink>
</DocsNote>
{canManage && (
<div className="my-3.5 flex justify-between">
<Button

View file

@ -1,6 +1,7 @@
import { ReactElement, ReactNode } from 'react';
import clsx from 'clsx';
import { Fallback, Image, Root } from '@radix-ui/react-avatar';
import { Image, Root } from '@radix-ui/react-avatar';
import { PersonIcon } from '@radix-ui/react-icons';
type Size = 'lg' | 'md' | 'sm' | 'xs';
// 50 40 34 20
@ -18,7 +19,6 @@ export const Avatar = ({
alt,
shape = 'square',
size = 'md',
fallback,
className,
...props
}: AvatarProps & { className?: string }): ReactElement => {
@ -38,8 +38,17 @@ export const Avatar = ({
)}
{...props}
>
<Image src={src ?? undefined} alt={alt} className="drag-none h-full w-full object-cover" />
{fallback && <Fallback delayMs={500}>{fallback}</Fallback>}
{src ? (
<>
<Image
src={src ?? undefined}
alt={alt}
className="drag-none h-full w-full object-cover"
/>
</>
) : (
<PersonIcon />
)}
</Root>
);
};

View file

@ -0,0 +1,29 @@
import { getDocsUrl } from '@/lib/docs-url';
import { ExclamationTriangleIcon, ExternalLinkIcon, InfoCircledIcon } from '@radix-ui/react-icons';
import { Link } from './link';
export const DocsNote = ({ children, warn }: { warn?: boolean; children: React.ReactNode }) => {
return (
<div className="flex my-2">
<div className="items-center align-middle pr-2 flex">
{warn ? (
<ExclamationTriangleIcon className="text-orange-500" />
) : (
<InfoCircledIcon className="text-current" />
)}
</div>
<div className="grow text-gray-500 text-sm align-middle">{children}</div>
</div>
);
};
export const DocsLink = ({ href, children }: { href: string; children: React.ReactNode }) => {
const fullUrl = getDocsUrl(href) || 'https://docs.graphql-hive.com/';
return (
<Link className="text-orange-500" href={fullUrl} target="_blank" rel="noreferrer">
{children}
<ExternalLinkIcon className="inline pl-1" />
</Link>
);
};

View file

@ -1,7 +1,6 @@
import { ReactElement } from 'react';
import Image from 'next/image';
import { Card, Heading, Link } from '@/components/v2/index';
import { getDocsUrl } from '@/lib/docs-url';
import { Card, DocsLink, Heading } from '@/components/v2/index';
import magnifier from '../../../public/images/figures/magnifier.svg';
export const EmptyList = ({
@ -25,9 +24,7 @@ export const EmptyList = ({
<Heading>{title}</Heading>
<span className="text-center text-sm font-medium text-gray-500">{description}</span>
{docsUrl === null ? null : (
<Link variant="primary" href={docsUrl} target="_blank" rel="noreferrer" className="my-5">
Read about it in the documentation
</Link>
<DocsLink href={docsUrl}>Read about it in the documentation</DocsLink>
)}
</Card>
);
@ -37,7 +34,7 @@ export const noSchema = (
<EmptyList
title="Schema Registry contains no schema"
description="You can publish a schema with Hive CLI and Hive Client"
docsUrl={getDocsUrl('/features/publish-schema')}
docsUrl="/features/schema-registry#publish-a-schema"
/>
);
@ -45,6 +42,6 @@ export const noSchemaVersion = (
<EmptyList
title="Hive is waiting for your first schema"
description="You can publish a schema with Hive CLI and Hive Client"
docsUrl={getDocsUrl('/features/publish-schema')}
docsUrl="/features/schema-registry#publish-a-schema"
/>
);

View file

@ -38,3 +38,4 @@ export { TimeAgo } from '@/components/v2/time-ago';
export { Title } from '@/components/v2/title';
export { ToggleGroup, ToggleGroupItem } from '@/components/v2/toggle-group';
export { Tooltip } from '@/components/v2/tooltip';
export { DocsNote, DocsLink } from '@/components/v2/docs-note';

View file

@ -11,18 +11,19 @@ export const ConnectLabModal = ({
toggleModalOpen: () => void;
endpoint: string;
}): ReactElement => {
const docsUrl = getDocsUrl('/features/tokens') || '';
const docsUrl = getDocsUrl('/management/targets#registry-access-tokens') || '';
return (
<Modal open={isOpen} onOpenChange={toggleModalOpen} className="flex w-[650px] flex-col gap-5">
<Heading className="text-center">Connect to Lab</Heading>
<Modal open={isOpen} onOpenChange={toggleModalOpen} className="flex w-[750px] flex-col gap-5">
<Heading className="text-center">Use GraphQL Schema Externally</Heading>
<p className="text-sm text-gray-500">
Hive allow you to consume and use this schema with your configured mocks while developing.
Hive allow you to consume and use the Laboratory schema with your configured mocks while
developing.
</p>
<span className="text-sm text-gray-500">You can use the following endpoint:</span>
<CopyValue value={endpoint} />
<span className="text-sm text-gray-500">
To authenticate, use the following HTTP headers:
To authenticate, use the following HTTP headers, with a token that has `target:read` scope:
</span>
<Tag>
X-Hive-Key:{' '}
@ -35,7 +36,7 @@ export const ConnectLabModal = ({
<Link variant="primary" target="_blank" rel="noreferrer" href={docsUrl}>
Managing Tokens
</Link>{' '}
chapter in our documentation.
chapter in our documentation to create a Registry Access Token.
</p>
<Button
type="button"

View file

@ -1,7 +1,17 @@
import { ReactElement } from 'react';
import { ReactElement, useState } from 'react';
import { useQuery } from 'urql';
import { Button, CopyValue, Heading, Link, Modal, Tag } from '@/components/v2';
import {
Button,
CopyValue,
DocsLink,
Heading,
Link,
Modal,
RadixSelect,
Tag,
} from '@/components/v2';
import { graphql } from '@/gql';
import { ProjectType } from '@/graphql';
import { getDocsUrl } from '@/lib/docs-url';
import { useRouteSelector } from '@/lib/hooks';
@ -9,11 +19,34 @@ const ConnectSchemaModalQuery = graphql(`
query ConnectSchemaModal($targetSelector: TargetSelectorInput!) {
target(selector: $targetSelector) {
id
project {
id
type
}
cdnUrl
}
}
`);
type CdnArtifactType = 'sdl' | 'services' | 'supergraph' | 'metadata';
const ArtifactToProjectTypeMapping: Record<ProjectType, CdnArtifactType[]> = {
[ProjectType.Single]: ['sdl', 'metadata'],
[ProjectType.Stitching]: ['sdl', 'services'],
[ProjectType.Federation]: ['sdl', 'services', 'supergraph'],
};
const ArtifactTypeToDisplayName: Record<CdnArtifactType, string> = {
sdl: 'GraphQL SDL',
services: 'Services Definition and SDL',
supergraph: 'Apollo Federation Supergraph',
metadata: 'Hive Schema Metadata',
};
function composeEndpoint(baseUrl: string, artifactType: CdnArtifactType): string {
return `${baseUrl}/${artifactType}`;
}
export const ConnectSchemaModal = ({
isOpen,
toggleModalOpen,
@ -21,6 +54,7 @@ export const ConnectSchemaModal = ({
isOpen: boolean;
toggleModalOpen: () => void;
}): ReactElement => {
const [selectedArtifact, setSelectedArtifact] = useState<CdnArtifactType>('sdl');
const router = useRouteSelector();
const [query] = useQuery({
query: ConnectSchemaModalQuery,
@ -35,55 +69,82 @@ export const ConnectSchemaModal = ({
});
return (
<Modal open={isOpen} onOpenChange={toggleModalOpen} className="flex w-[650px] flex-col gap-5">
<Heading className="text-center">Connect to Hive</Heading>
<Modal open={isOpen} onOpenChange={toggleModalOpen} className="flex w-[800px] flex-col gap-5">
<Heading className="text-center">Hive CDN Access</Heading>
{query.data?.target && (
<>
<p className="text-sm text-gray-500">
With high-availability and multi-zone CDN service based on Cloudflare, Hive allows you
to access the schema of your API, through a secured external service, that's always up
regardless of Hive.
Hive leverages the{' '}
<Link
variant="primary"
className="font-bold underline"
href="https://www.cloudflare.com/network"
target="_blank"
rel="noreferrer"
>
CloudFlare Global Network
</Link>{' '}
to deliver your GraphQL schema and schema metadata. This means that your schema will be
available from the nearest location to your GraphQL gateway, with 100% uptime,
regardless of Hive's status.
</p>
<span className="text-sm text-gray-500">You can use the following endpoint:</span>
<CopyValue value={query.data.target.cdnUrl} />
<p className="text-sm text-gray-500">
Based on your project type, you can access different artifacts from Hive's CDN:
</p>
<div>
<RadixSelect
placeholder="Select Artifact"
name="artifact-select"
position="popper"
value={selectedArtifact}
options={ArtifactToProjectTypeMapping[query.data.target.project.type].map(t => ({
value: t,
label: ArtifactTypeToDisplayName[t],
}))}
onChange={setSelectedArtifact}
/>
</div>
<span className="text-sm text-gray-500">
To authenticate, use the access HTTP headers. <br />
To access your schema from Hive's CDN, use the following endpoint:
</span>
<CopyValue value={composeEndpoint(query.data.target.cdnUrl, selectedArtifact)} />
<span className="text-sm text-gray-500">
To authenticate,{' '}
<Link
variant="primary"
className="font-bold underline"
href={`/${router.organizationId}/${router.projectId}/${router.targetId}/settings#cdn-access-tokens`}
target="_blank"
rel="noreferrer"
>
create a CDN Access Token from your target's Settings page
</Link>{' '}
use the CDN access token in your HTTP headers:
<br />
</span>
<p className="text-sm text-gray-500">
<Tag>
X-Hive-CDN-Key: {'<'}Your Access Token{'>'}
</Tag>
</p>
<p className="text-sm text-gray-500">
You can manage and generate CDN access tokens in the{' '}
<Link
variant="primary"
href={
'/' +
[
router.organizationId,
router.projectId,
router.targetId,
'settings#cdn-access-tokens',
].join('/')
}
>
target settings
</Link>
</p>
<p className="text-sm text-gray-500">
Read the{' '}
<Link
variant="primary"
target="_blank"
rel="noreferrer"
href={getDocsUrl('/features/registry-usage#apollo-federation') ?? ''}
>
Using the Registry with a Apollo Gateway
</Link>{' '}
chapter in our documentation.
</p>
<DocsLink href="/features/high-availability-cdn">
Learn more about Hive High-Availability CDN
</DocsLink>
{query.data.target.project.type === ProjectType.Federation ? (
<p className="text-sm text-gray-500">
Read the{' '}
<Link
variant="primary"
target="_blank"
rel="noreferrer"
href={getDocsUrl('/integrations/apollo-gateway#supergraph-sdl-from-the-cdn') ?? ''}
>
Using the Registry with a Apollo Gateway
</Link>{' '}
chapter in our documentation.
</p>
) : null}
</>
)}
<Button

View file

@ -4,4 +4,71 @@ export default withGuildDocs({
eslint: {
ignoreDuringBuilds: true,
},
redirects: async () => [
{
source: '/get-started/organizations',
destination: '/management/organizations',
permanent: true,
},
{
source: '/get-started/projects',
destination: '/management/projects',
permanent: true,
},
{
source: '/get-started/targets',
destination: '/management/targets',
permanent: true,
},
{
source: '/features/tokens',
destination: '/management/targets#manage-tokens',
permanent: true,
},
{
source: '/features/publish-schema',
destination: '/features/schema-registry#publish-a-schema',
permanent: true,
},
{
source: '/features/checking-schema',
destination: '/features/schema-registry#check-a-schema',
permanent: true,
},
{
source: '/features/delete-schema',
destination: '/features/schema-registry#delete-a-service',
permanent: true,
},
{
source: '/features/registry-usage',
destination: '/features/high-availability-cdn',
permanent: true,
},
{
source: '/features/monitoring',
destination: '/features/usage-reporting',
permanent: true,
},
{
source: '/features/schema-history',
destination: '/features/schema-registry#schema-history-and-changelog',
permanent: true,
},
{
source: '/features/integrations',
destination: '/management/organizations#integrations',
permanent: true,
},
{
source: '/features/alerts-notifications',
destination: '/management/projects#alerts-and-notifications',
permanent: true,
},
{
source: '/features/external-schema-composition',
destination: '/management/external-schema-composition',
permanent: true,
},
],
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

View file

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View file

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Some files were not shown because too many files have changed in this diff Show more