mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
Console 1383 open non existing schema version results in infinite loading (#7316)
This commit is contained in:
parent
114cd80a8e
commit
0ac46404d5
14 changed files with 91 additions and 66 deletions
|
|
@ -26,7 +26,7 @@ import { CHART_PRIMARY_COLOR } from '@/constants';
|
|||
import { env } from '@/env/frontend';
|
||||
import { DocumentType, FragmentType, graphql, useFragment } from '@/gql';
|
||||
import { theme } from '@/lib/charts';
|
||||
import { useChartStyles } from '@/utils';
|
||||
import { useChartStyles } from '@/lib/utils';
|
||||
import { ChevronUpIcon } from '@radix-ui/react-icons';
|
||||
import {
|
||||
createColumnHelper,
|
||||
|
|
|
|||
|
|
@ -2,17 +2,27 @@ import ghost from '../../../public/images/figures/ghost.svg?url';
|
|||
import { useRouter } from '@tanstack/react-router';
|
||||
import { Button } from '../ui/button';
|
||||
|
||||
export function NotFoundContent(props: { heading: React.ReactNode; subheading: React.ReactNode }) {
|
||||
export function NotFoundContent({
|
||||
heading,
|
||||
subheading,
|
||||
includeBackButton = true,
|
||||
}: {
|
||||
heading: React.ReactNode;
|
||||
subheading: React.ReactNode;
|
||||
includeBackButton?: boolean;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-1 flex-col items-center justify-center gap-2.5 py-6">
|
||||
<img src={ghost} alt="Ghost illustration" width="200" height="200" className="drag-none" />
|
||||
<h2 className="text-xl font-bold">{props.heading}</h2>
|
||||
<h3 className="font-semibold">{props.subheading}</h3>
|
||||
<Button variant="secondary" className="mt-2" onClick={router.history.back}>
|
||||
Go back
|
||||
</Button>
|
||||
<h2 className="text-xl font-bold">{heading}</h2>
|
||||
<h3 className="font-semibold">{subheading}</h3>
|
||||
{includeBackButton && (
|
||||
<Button variant="secondary" className="mt-2" onClick={router.history.back}>
|
||||
Go back
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { OrganizationAccessScope, ProjectAccessScope, TargetAccessScope } from '@/gql/graphql';
|
||||
import { NoAccess, Scope } from '@/lib/access/common';
|
||||
import { truthy } from '@/utils';
|
||||
import { truthy } from '@/lib/utils';
|
||||
|
||||
function isLowerThen<T>(targetScope: T, sourceScope: T, scopesInLowerToHigherOrder: readonly T[]) {
|
||||
const sourceIndex = scopesInLowerToHigherOrder.indexOf(sourceScope);
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
|
|||
import { Markdown } from '@/components/v2/markdown';
|
||||
import { FragmentType, graphql, useFragment } from '@/gql';
|
||||
import { formatNumber, toDecimal } from '@/lib/hooks';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { capitalize } from '@/utils';
|
||||
import { capitalize, cn } from '@/lib/utils';
|
||||
import { Link as NextLink, useRouter } from '@tanstack/react-router';
|
||||
import { useDescriptionsVisibleToggle } from './provider';
|
||||
import { SupergraphMetadataList } from './super-graph-metadata';
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import {
|
|||
useFormattedThroughput,
|
||||
} from '@/lib/hooks';
|
||||
import { pick } from '@/lib/object';
|
||||
import { useChartStyles } from '@/utils';
|
||||
import { useChartStyles } from '@/lib/utils';
|
||||
import { useRouter } from '@tanstack/react-router';
|
||||
import { OperationsFallback } from './Fallback';
|
||||
import { resolutionToMilliseconds } from './utils';
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export function CopyText(props: { children: ReactNode; copy?: string; className?
|
|||
</div>
|
||||
<TooltipProvider delayDuration={0}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
className="invisible -my-3 p-2 py-3 group-hover:visible"
|
||||
variant="link"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,24 @@
|
|||
import { clsx, type ClassValue } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
// Style-related
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
const darkChartStyles = {
|
||||
backgroundColor: 'transparent',
|
||||
textStyle: { color: '#fff' },
|
||||
legend: {
|
||||
textStyle: { color: '#fff' },
|
||||
},
|
||||
};
|
||||
|
||||
export function useChartStyles() {
|
||||
return darkChartStyles;
|
||||
}
|
||||
|
||||
// Strings
|
||||
export function pluralize(count: number, singular: string, plural: string): string {
|
||||
if (count === 1) {
|
||||
return singular;
|
||||
|
|
@ -13,8 +27,24 @@ export function pluralize(count: number, singular: string, plural: string): stri
|
|||
return plural;
|
||||
}
|
||||
|
||||
export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
||||
// Errors
|
||||
export function exhaustiveGuard(_value: never): never {
|
||||
throw new Error(
|
||||
`Reached forbidden guard function with unexpected value: ${JSON.stringify(_value)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Validation
|
||||
export function isValidUUID(value: string): boolean {
|
||||
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
||||
}
|
||||
|
||||
type Truthy<T> = T extends false | '' | 0 | null | undefined ? never : T; // from lodash
|
||||
|
||||
export function truthy<T>(value: T): value is Truthy<T> {
|
||||
return !!value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import { Card } from '@/components/v2/card';
|
|||
import Stat from '@/components/v2/stat';
|
||||
import { graphql, useFragment } from '@/gql';
|
||||
import { formatNumber } from '@/lib/hooks';
|
||||
import { useChartStyles } from '@/utils';
|
||||
import { useChartStyles } from '@/lib/utils';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
|
||||
const DateFormatter = Intl.DateTimeFormat('en-US', {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { ReactElement, useMemo, useState } from 'react';
|
||||
import { CheckIcon, GitCompareIcon } from 'lucide-react';
|
||||
import { useQuery } from 'urql';
|
||||
import { NotFoundContent } from '@/components/common/not-found-content';
|
||||
import {
|
||||
ChangesBlock,
|
||||
CompositionErrorsSection,
|
||||
|
|
@ -15,7 +16,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
|
|||
import { DiffEditor, TimeAgo } from '@/components/v2';
|
||||
import { FragmentType, graphql, useFragment } from '@/gql';
|
||||
import { ProjectType, SeverityLevelType } from '@/gql/graphql';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { cn, isValidUUID } from '@/lib/utils';
|
||||
import {
|
||||
CheckCircledIcon,
|
||||
CrossCircledIcon,
|
||||
|
|
@ -242,15 +243,11 @@ const DefaultSchemaVersionView_SchemaVersionFragment = graphql(`
|
|||
log {
|
||||
... on PushedSchemaLog {
|
||||
id
|
||||
author
|
||||
service
|
||||
commit
|
||||
serviceSdl
|
||||
previousServiceSdl
|
||||
}
|
||||
... on DeletedSchemaLog {
|
||||
id
|
||||
deletedService
|
||||
previousServiceSdl
|
||||
}
|
||||
}
|
||||
|
|
@ -443,9 +440,6 @@ function DefaultSchemaVersionView(props: {
|
|||
const ContractVersionView_ContractVersionFragment = graphql(`
|
||||
fragment ContractVersionView_ContractVersionFragment on ContractVersion {
|
||||
id
|
||||
contractName
|
||||
isComposable
|
||||
hasSchemaChanges
|
||||
isFirstComposableVersion
|
||||
supergraphSDL
|
||||
compositeSchemaSDL
|
||||
|
|
@ -640,6 +634,8 @@ function ActiveSchemaVersion(props: {
|
|||
projectSlug: string;
|
||||
targetSlug: string;
|
||||
}) {
|
||||
const isValidVersionId = isValidUUID(props.versionId);
|
||||
|
||||
const [query] = useQuery({
|
||||
query: ActiveSchemaVersion_SchemaVersionQuery,
|
||||
variables: {
|
||||
|
|
@ -648,6 +644,7 @@ function ActiveSchemaVersion(props: {
|
|||
targetSlug: props.targetSlug,
|
||||
versionId: props.versionId,
|
||||
},
|
||||
pause: !isValidVersionId,
|
||||
});
|
||||
|
||||
const { error } = query;
|
||||
|
|
@ -657,7 +654,28 @@ function ActiveSchemaVersion(props: {
|
|||
const schemaVersion = project?.target?.schemaVersion;
|
||||
const projectType = query.data?.project?.type;
|
||||
|
||||
if (isLoading || !schemaVersion || !projectType) {
|
||||
// Order of these conditionals is important...relocate carefully!
|
||||
if (!isValidVersionId) {
|
||||
return (
|
||||
<NotFoundContent
|
||||
heading="Invalid version ID"
|
||||
subheading="The provided version ID is not a valid UUID format."
|
||||
includeBackButton={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!isLoading && !schemaVersion) {
|
||||
return (
|
||||
<NotFoundContent
|
||||
heading="Version ID does not exist"
|
||||
subheading="The provided version ID is not in our database."
|
||||
includeBackButton={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading || !projectType) {
|
||||
return (
|
||||
<div className="flex size-full flex-col items-center justify-center self-center text-sm text-gray-500">
|
||||
<Spinner className="mb-3 size-8" />
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ const HistoryPage_VersionsPageQuery = graphql(`
|
|||
deletedService
|
||||
}
|
||||
}
|
||||
baseSchema
|
||||
githubMetadata {
|
||||
repository
|
||||
commit
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import { graphql } from '@/gql';
|
|||
import { formatNumber, formatThroughput, toDecimal } from '@/lib/hooks';
|
||||
import { useDateRangeController } from '@/lib/hooks/use-date-range-controller';
|
||||
import { pick } from '@/lib/object';
|
||||
import { useChartStyles } from '@/utils';
|
||||
import { useChartStyles } from '@/lib/utils';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
|
||||
const ClientView_ClientStatsQuery = graphql(`
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import { CHART_PRIMARY_COLOR } from '@/constants';
|
|||
import { graphql } from '@/gql';
|
||||
import { formatNumber, formatThroughput, toDecimal } from '@/lib/hooks';
|
||||
import { useDateRangeController } from '@/lib/hooks/use-date-range-controller';
|
||||
import { useChartStyles } from '@/utils';
|
||||
import { useChartStyles } from '@/lib/utils';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
|
||||
const SchemaCoordinateView_SchemaCoordinateStatsQuery = graphql(`
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
type Truthy<T> = T extends false | '' | 0 | null | undefined ? never : T; // from lodash
|
||||
|
||||
export function truthy<T>(value: T): value is Truthy<T> {
|
||||
return !!value;
|
||||
}
|
||||
|
||||
const darkChartStyles = {
|
||||
backgroundColor: 'transparent',
|
||||
textStyle: { color: '#fff' },
|
||||
legend: {
|
||||
textStyle: { color: '#fff' },
|
||||
},
|
||||
};
|
||||
|
||||
export function useChartStyles() {
|
||||
return darkChartStyles;
|
||||
// TODO: fix it when Hive will have white theme
|
||||
// useColorModeValue(
|
||||
// {
|
||||
// backgroundColor: '#fff',
|
||||
// textStyle: { color: '#52525b' },
|
||||
// legend: {
|
||||
// textStyle: { color: '#52525b' },
|
||||
// },
|
||||
// },
|
||||
// );
|
||||
}
|
||||
|
||||
export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}
|
||||
|
|
@ -19364,8 +19364,8 @@ snapshots:
|
|||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sso-oidc': 3.596.0
|
||||
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
|
||||
'@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0)
|
||||
'@aws-sdk/client-sts': 3.596.0
|
||||
'@aws-sdk/core': 3.592.0
|
||||
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0)
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
|
|
@ -19517,11 +19517,11 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/client-sso-oidc@3.596.0':
|
||||
'@aws-sdk/client-sso-oidc@3.596.0(@aws-sdk/client-sts@3.596.0)':
|
||||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
|
||||
'@aws-sdk/client-sts': 3.596.0
|
||||
'@aws-sdk/core': 3.592.0
|
||||
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0)
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
|
|
@ -19560,6 +19560,7 @@ snapshots:
|
|||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.8.1
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/client-sts'
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/client-sso-oidc@3.723.0(@aws-sdk/client-sts@3.723.0)':
|
||||
|
|
@ -19779,11 +19780,11 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/client-sts@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)':
|
||||
'@aws-sdk/client-sts@3.596.0':
|
||||
dependencies:
|
||||
'@aws-crypto/sha256-browser': 3.0.0
|
||||
'@aws-crypto/sha256-js': 3.0.0
|
||||
'@aws-sdk/client-sso-oidc': 3.596.0
|
||||
'@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0)
|
||||
'@aws-sdk/core': 3.592.0
|
||||
'@aws-sdk/credential-provider-node': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0)
|
||||
'@aws-sdk/middleware-host-header': 3.577.0
|
||||
|
|
@ -19822,7 +19823,6 @@ snapshots:
|
|||
'@smithy/util-utf8': 3.0.0
|
||||
tslib: 2.8.1
|
||||
transitivePeerDependencies:
|
||||
- '@aws-sdk/client-sso-oidc'
|
||||
- aws-crt
|
||||
|
||||
'@aws-sdk/client-sts@3.723.0':
|
||||
|
|
@ -20054,7 +20054,7 @@ snapshots:
|
|||
|
||||
'@aws-sdk/credential-provider-ini@3.596.0(@aws-sdk/client-sso-oidc@3.596.0)(@aws-sdk/client-sts@3.596.0)':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
|
||||
'@aws-sdk/client-sts': 3.596.0
|
||||
'@aws-sdk/credential-provider-env': 3.587.0
|
||||
'@aws-sdk/credential-provider-http': 3.596.0
|
||||
'@aws-sdk/credential-provider-process': 3.587.0
|
||||
|
|
@ -20301,7 +20301,7 @@ snapshots:
|
|||
|
||||
'@aws-sdk/credential-provider-web-identity@3.587.0(@aws-sdk/client-sts@3.596.0)':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sts': 3.596.0(@aws-sdk/client-sso-oidc@3.596.0)
|
||||
'@aws-sdk/client-sts': 3.596.0
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/property-provider': 3.1.11
|
||||
'@smithy/types': 3.7.2
|
||||
|
|
@ -20690,7 +20690,7 @@ snapshots:
|
|||
|
||||
'@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.596.0)':
|
||||
dependencies:
|
||||
'@aws-sdk/client-sso-oidc': 3.596.0
|
||||
'@aws-sdk/client-sso-oidc': 3.596.0(@aws-sdk/client-sts@3.596.0)
|
||||
'@aws-sdk/types': 3.577.0
|
||||
'@smithy/property-provider': 3.1.11
|
||||
'@smithy/shared-ini-file-loader': 3.1.12
|
||||
|
|
|
|||
Loading…
Reference in a new issue