diff --git a/.changeset/purple-bats-thank.md b/.changeset/purple-bats-thank.md new file mode 100644 index 000000000..ef809c57b --- /dev/null +++ b/.changeset/purple-bats-thank.md @@ -0,0 +1,5 @@ +--- +'hive': patch +--- + +Add readonly resource ID to settings pages diff --git a/packages/web/app/src/components/ui/input-copy.tsx b/packages/web/app/src/components/ui/input-copy.tsx index d9a9288c2..b839b2e41 100644 --- a/packages/web/app/src/components/ui/input-copy.tsx +++ b/packages/web/app/src/components/ui/input-copy.tsx @@ -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()} /> diff --git a/packages/web/app/src/components/ui/resource-details.tsx b/packages/web/app/src/components/ui/resource-details.tsx new file mode 100644 index 000000000..7ccf56532 --- /dev/null +++ b/packages/web/app/src/components/ui/resource-details.tsx @@ -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 ( +
+
+ Resource ID +
+ + + + + + + + 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". + + + +
+ ); +} diff --git a/packages/web/app/src/pages/organization-settings.tsx b/packages/web/app/src/pages/organization-settings.tsx index b96baa0b8..9ea8defd5 100644 --- a/packages/web/app/src/pages/organization-settings.tsx +++ b/packages/web/app/src/pages/organization-settings.tsx @@ -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 (
+ {organization.viewerCanModifySlug && (
diff --git a/packages/web/app/src/pages/project-settings.tsx b/packages/web/app/src/pages/project-settings.tsx index d7e75e088..00fb686a0 100644 --- a/packages/web/app/src/pages/project-settings.tsx +++ b/packages/web/app/src/pages/project-settings.tsx @@ -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:
{project && organization ? ( <> + + +
+ ); +} + function TargetSettingsContent(props: { organizationSlug: string; projectSlug: string; @@ -1313,6 +1322,7 @@ function TargetSettingsContent(props: {
{resolvedPage.key === 'general' ? ( <> +