mirror of
https://github.com/graphql-hive/console
synced 2026-05-24 01:28:32 +00:00
feat: Add resource ID to pages (#6584)
This commit is contained in:
parent
cbf8b935f0
commit
d1e6ab094b
6 changed files with 49 additions and 2 deletions
5
.changeset/purple-bats-thank.md
Normal file
5
.changeset/purple-bats-thank.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'hive': patch
|
||||
---
|
||||
|
||||
Add readonly resource ID to settings pages
|
||||
|
|
@ -4,7 +4,7 @@ import { Button } from '@/components/ui/button';
|
|||
import { Input } from '@/components/ui/input';
|
||||
import { useClipboard } from '@/lib/hooks';
|
||||
|
||||
export function InputCopy(props: { value: string }) {
|
||||
export function InputCopy(props: { value: string; className?: string }) {
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
const copyToClipboard = useClipboard();
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ export function InputCopy(props: { value: string }) {
|
|||
type="text"
|
||||
value={props.value}
|
||||
readOnly
|
||||
className="bg-secondary truncate text-white"
|
||||
className={`bg-secondary truncate text-white ${props.className}`}
|
||||
onFocus={ev => ev.target.select()}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
27
packages/web/app/src/components/ui/resource-details.tsx
Normal file
27
packages/web/app/src/components/ui/resource-details.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { ReactElement } from 'react';
|
||||
import { InfoCircledIcon } from '@radix-ui/react-icons';
|
||||
import { InputCopy } from './input-copy';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './tooltip';
|
||||
|
||||
/** Renders readonly properties for resources. Used on settings pages. */
|
||||
export function ResourceDetails(props: { id: string }): ReactElement {
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<div className="border-input text-muted-foreground h-10 whitespace-nowrap rounded-md rounded-r-none border-y border-l bg-gray-900 px-3 py-2 text-sm">
|
||||
Resource ID
|
||||
</div>
|
||||
<InputCopy value={props.id} className="rounded-l-none" />
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoCircledIcon className="ml-2 size-4" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="max-w-sm text-pretty">
|
||||
This UUID can be used in API calls or CLI commands to Hive instead of passing the full
|
||||
resource path. I.e. "org/project/target".
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ import { Input } from '@/components/ui/input';
|
|||
import { Meta } from '@/components/ui/meta';
|
||||
import { NavLayout, PageLayout, PageLayoutContent } from '@/components/ui/page-content-layout';
|
||||
import { QueryError } from '@/components/ui/query-error';
|
||||
import { ResourceDetails } from '@/components/ui/resource-details';
|
||||
import { useToast } from '@/components/ui/use-toast';
|
||||
import { TransferOrganizationOwnershipModal } from '@/components/v2/modals';
|
||||
import { env } from '@/env/frontend';
|
||||
|
|
@ -263,6 +264,7 @@ const SettingsPageRenderer = (props: {
|
|||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<ResourceDetails id={organization.id} />
|
||||
{organization.viewerCanModifySlug && (
|
||||
<Form {...slugForm}>
|
||||
<form onSubmit={slugForm.handleSubmit(onSlugFormSubmit)}>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { Input } from '@/components/ui/input';
|
|||
import { Meta } from '@/components/ui/meta';
|
||||
import { Subtitle, Title } from '@/components/ui/page';
|
||||
import { QueryError } from '@/components/ui/query-error';
|
||||
import { ResourceDetails } from '@/components/ui/resource-details';
|
||||
import { useToast } from '@/components/ui/use-toast';
|
||||
import { env } from '@/env/frontend';
|
||||
import { graphql, useFragment } from '@/gql';
|
||||
|
|
@ -319,6 +320,7 @@ const ProjectSettingsPage_OrganizationFragment = graphql(`
|
|||
|
||||
const ProjectSettingsPage_ProjectFragment = graphql(`
|
||||
fragment ProjectSettingsPage_ProjectFragment on Project {
|
||||
id
|
||||
slug
|
||||
type
|
||||
isProjectNameInGitHubCheckEnabled
|
||||
|
|
@ -399,6 +401,7 @@ function ProjectSettingsContent(props: { organizationSlug: string; projectSlug:
|
|||
<div className="flex flex-col gap-y-4">
|
||||
{project && organization ? (
|
||||
<>
|
||||
<ResourceDetails id={project.id} />
|
||||
<ProjectSettingsPage_SlugForm
|
||||
organizationSlug={props.organizationSlug}
|
||||
projectSlug={props.projectSlug}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import {
|
|||
} from '@/components/ui/page-content-layout';
|
||||
import { QueryError } from '@/components/ui/query-error';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
import { ResourceDetails } from '@/components/ui/resource-details';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { TimeAgo } from '@/components/ui/time-ago';
|
||||
import { useToast } from '@/components/ui/use-toast';
|
||||
|
|
@ -1169,6 +1170,14 @@ const TargetSettingsPageQuery = graphql(`
|
|||
}
|
||||
`);
|
||||
|
||||
function TargetInfo(props: { targetId: string }) {
|
||||
return (
|
||||
<div>
|
||||
<ResourceDetails id={props.targetId} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TargetSettingsContent(props: {
|
||||
organizationSlug: string;
|
||||
projectSlug: string;
|
||||
|
|
@ -1313,6 +1322,7 @@ function TargetSettingsContent(props: {
|
|||
<div className="space-y-12">
|
||||
{resolvedPage.key === 'general' ? (
|
||||
<>
|
||||
<TargetInfo targetId={currentTarget.id} />
|
||||
<TargetSlug
|
||||
targetSlug={props.targetSlug}
|
||||
projectSlug={props.projectSlug}
|
||||
|
|
|
|||
Loading…
Reference in a new issue