Compare commits

..

1 Commits

Author SHA1 Message Date
7f0f5b130a Make Azure DevOps sync not require project name 2025-07-14 21:14:57 -04:00
11 changed files with 49 additions and 47 deletions

View File

@ -17,7 +17,7 @@ export const AzureDevOpsSyncDestinationConfigSchema = z.object({
.describe(SecretSyncs.DESTINATION_CONFIG.AZURE_DEVOPS?.devopsProjectId || "Azure DevOps Project ID"),
devopsProjectName: z
.string()
.min(1, "Project name required")
.optional()
.describe(SecretSyncs.DESTINATION_CONFIG.AZURE_DEVOPS?.devopsProjectName || "Azure DevOps Project Name")
});

View File

@ -151,7 +151,7 @@ export default function NavHeader({
<div className="flex items-center space-x-2">
<span
className={twMerge(
"text-sm transition-all",
"text-sm font-semibold transition-all",
isHoveringCopyButton ? "text-bunker-200" : "text-bunker-300"
)}
>
@ -198,7 +198,7 @@ export default function NavHeader({
}}
search={(query) => ({ ...query, secretPath: newSecretPath })}
className={twMerge(
"text-sm transition-all hover:text-primary",
"text-sm font-semibold transition-all hover:text-primary",
isHoveringCopyButton ? "text-primary" : "text-primary/80"
)}
>

View File

@ -38,7 +38,7 @@ export const SecretDashboardPathBreadcrumb = ({
<div className="group flex items-center space-x-2">
<span
className={twMerge(
"text-sm transition-all",
"text-sm font-semibold transition-all",
isCopying ? "text-bunker-200" : "text-bunker-300"
)}
>
@ -77,7 +77,7 @@ export const SecretDashboardPathBreadcrumb = ({
}}
search={(query) => ({ ...query, secretPath: newSecretPath })}
className={twMerge(
"text-sm transition-all hover:text-primary",
"text-sm font-semibold transition-all hover:text-primary",
isCopying && "text-primary"
)}
>

View File

@ -11,7 +11,9 @@ export const AzureDevOpsSyncReviewFields = () => {
return (
<>
<GenericFieldLabel label="Project">{devopsProjectName}</GenericFieldLabel>
{devopsProjectName && (
<GenericFieldLabel label="Project">{devopsProjectName}</GenericFieldLabel>
)}
<GenericFieldLabel label="Project ID">{devopsProjectId}</GenericFieldLabel>
</>
);

View File

@ -8,10 +8,7 @@ export const AzureDevOpsSyncDestinationSchema = BaseSecretSyncSchema().merge(
destination: z.literal(SecretSync.AzureDevOps),
destinationConfig: z.object({
devopsProjectId: z.string().trim().min(1, { message: "Azure DevOps Project ID is required" }),
devopsProjectName: z
.string()
.trim()
.min(1, { message: "Azure DevOps Project Name is required" })
devopsProjectName: z.string().trim().optional()
})
})
);

View File

@ -1,6 +1,6 @@
/* eslint-disable react/prop-types */
import React from "react";
import { faCaretDown, faEllipsis } from "@fortawesome/free-solid-svg-icons";
import { faEllipsis, faSort } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, ReactNode } from "@tanstack/react-router";
import { LinkComponentProps } from "node_modules/@tanstack/react-router/dist/esm/link";
@ -27,7 +27,7 @@ const BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWi
<ol
ref={ref}
className={twMerge(
"flex flex-wrap items-center break-words text-sm text-bunker-100",
"flex flex-wrap items-center gap-1.5 break-words text-sm text-bunker-100 sm:gap-2.5",
className
)}
{...props}
@ -56,7 +56,7 @@ const BreadcrumbLink = React.forwardRef<
return (
<div
ref={ref}
className={twMerge("transition-colors hover:text-primary", className)}
className={twMerge("transition-colors hover:text-primary-400", className)}
{...props}
/>
);
@ -79,7 +79,7 @@ BreadcrumbPage.displayName = "BreadcrumbPage";
const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<"li">) => (
<li role="presentation" aria-hidden="true" className={twMerge("", className)} {...props}>
{children ?? <p className="px-3 text-lg text-mineshaft-400/70">/</p>}
{children ?? <p className="px-2 text-lg text-mineshaft-400/70">/</p>}
</li>
);
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
@ -134,17 +134,12 @@ const BreadcrumbContainer = ({ breadcrumbs }: { breadcrumbs: TBreadcrumbFormat[]
<DropdownMenu>
<DropdownMenuTrigger>
<BreadcrumbItem>
<BreadcrumbSegment className="rounded-md py-1 py-2">
{el.label}{" "}
<FontAwesomeIcon
icon={faCaretDown}
size="sm"
className="ml-2 text-bunker-300"
/>
<BreadcrumbSegment className="rounded-md px-2 py-1 py-2 hover:bg-mineshaft-600">
{el.label} <FontAwesomeIcon icon={faSort} size="sm" />
</BreadcrumbSegment>
</BreadcrumbItem>
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" sideOffset={8} align="start">
<DropdownMenuContent side="right" align="start">
{el?.dropdownTitle && <DropdownMenuLabel>{el.dropdownTitle}</DropdownMenuLabel>}
{el.links.map((i, dropIndex) => (
<Link

View File

@ -6,7 +6,7 @@ export type TAzureDevOpsSync = TRootSecretSync & {
destination: SecretSync.AzureDevOps;
destinationConfig: {
devopsProjectId: string;
devopsProjectName: string;
devopsProjectName?: string;
};
connection: {
app: AppConnection.AzureDevOps;

View File

@ -4,13 +4,13 @@ import { faCircleQuestion, faUserCircle } from "@fortawesome/free-regular-svg-ic
import {
faArrowUpRightFromSquare,
faBook,
faBuilding,
faCaretDown,
faCheck,
faCubes,
faEnvelope,
faInfo,
faInfoCircle,
faSignOut,
faSort,
faUser,
faUsers
} from "@fortawesome/free-solid-svg-icons";
@ -186,16 +186,16 @@ export const Navbar = () => {
<img alt="infisical logo" src="/images/logotransparent.png" className="h-4" />
</Link>
</div>
<p className="pl-1 pr-3 text-lg text-mineshaft-400/70">/</p>
<div className="flex items-center">
<p className="pl-2 pr-3 text-lg text-mineshaft-400/70">/</p>
<DropdownMenu modal={false}>
<Link to="/organization/projects">
<div className="group flex cursor-pointer items-center gap-2 text-sm text-white transition-all duration-100 hover:text-primary">
<div className="flex cursor-pointer items-center gap-2 text-sm text-white transition-all duration-100 hover:text-primary-400">
<div>
<FontAwesomeIcon icon={faBuilding} className="text-xs text-bunker-300" />
<FontAwesomeIcon icon={faCubes} className="pr-1 text-xs" />
</div>
<div className="max-w-32 overflow-hidden text-ellipsis">{currentOrg?.name}</div>
<div className="mr-1 rounded border border-mineshaft-500 px-1 text-xs text-bunker-300 !no-underline">
<div className="mr-2 rounded border border-mineshaft-500 px-1 text-xs text-bunker-300">
{getPlan(subscription)}
</div>
</div>
@ -206,9 +206,9 @@ export const Navbar = () => {
variant="plain"
colorSchema="secondary"
ariaLabel="switch-org"
className="px-2 py-1"
className="rounded-md px-2 py-2 hover:bg-mineshaft-600"
>
<FontAwesomeIcon icon={faCaretDown} className="text-xs text-bunker-300" />
<FontAwesomeIcon icon={faSort} className="text-xs text-bunker-300" />
</IconButton>
</div>
</DropdownMenuTrigger>
@ -265,11 +265,13 @@ export const Navbar = () => {
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<p className="px-2 text-lg text-mineshaft-400/70">/</p>
</div>
<div className="pl-2">
{breadcrumbs ? (
<BreadcrumbContainer breadcrumbs={breadcrumbs as TBreadcrumbFormat[]} />
) : null}
</div>
<p className="pl-1 pr-3 text-lg text-mineshaft-400/70">/</p>
{breadcrumbs ? (
<BreadcrumbContainer breadcrumbs={breadcrumbs as TBreadcrumbFormat[]} />
) : null}
<div className="flex-grow" />
<DropdownMenu modal={false}>
<DropdownMenuTrigger>

View File

@ -1,12 +1,12 @@
import { useMemo, useState } from "react";
import { faStar } from "@fortawesome/free-regular-svg-icons";
import {
faCaretDown,
faCheck,
faCube,
faMagnifyingGlass,
faPlus,
faStar as faSolidStar,
faTable
faSort,
faStar as faSolidStar
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, linkOptions } from "@tanstack/react-router";
@ -99,7 +99,7 @@ export const ProjectSelect = () => {
}, [workspaces, projectFavorites, currentWorkspace]);
return (
<div className="-mr-2 flex w-full items-center gap-1">
<div className="flex w-full items-center gap-2">
<DropdownMenu modal={false}>
<Link
to={getProjectHomePage(
@ -109,9 +109,9 @@ export const ProjectSelect = () => {
projectId: currentWorkspace.id
}}
>
<div className="flex cursor-pointer items-center gap-2 text-sm text-white duration-100 hover:text-primary">
<div className="flex cursor-pointer items-center gap-2 text-sm text-white duration-100 hover:text-primary-400">
<div>
<FontAwesomeIcon icon={faTable} className="text-xs text-bunker-300" />
<FontAwesomeIcon icon={faCube} className="text-xs" />
</div>
<Tooltip content={currentWorkspace.name} className="max-w-96">
<div className="max-w-32 overflow-hidden text-ellipsis whitespace-nowrap">
@ -125,10 +125,10 @@ export const ProjectSelect = () => {
<IconButton
variant="plain"
colorSchema="secondary"
ariaLabel="switch-project"
ariaLabel="switch-org"
className="px-2 py-1"
>
<FontAwesomeIcon icon={faCaretDown} className="text-xs text-bunker-300" />
<FontAwesomeIcon icon={faSort} className="text-xs text-bunker-300" />
</IconButton>
</div>
</DropdownMenuTrigger>

View File

@ -115,8 +115,10 @@ export const getSecretSyncDestinationColValues = (secretSync: TSecretSync) => {
secondaryText = "Vault ID";
break;
case SecretSync.AzureDevOps:
primaryText = destinationConfig.devopsProjectName;
secondaryText = destinationConfig.devopsProjectId;
primaryText = destinationConfig.devopsProjectName || destinationConfig.devopsProjectId;
secondaryText = destinationConfig.devopsProjectName
? destinationConfig.devopsProjectId
: "Project ID";
break;
case SecretSync.Heroku:
primaryText = destinationConfig.appName;

View File

@ -7,8 +7,12 @@ type Props = {
export const AzureDevOpsSyncDestinationSection = ({ secretSync }: Props) => {
const {
destinationConfig: { devopsProjectName }
destinationConfig: { devopsProjectName, devopsProjectId }
} = secretSync;
return <GenericFieldLabel label="Project">{devopsProjectName}</GenericFieldLabel>;
return (
<GenericFieldLabel label={devopsProjectName ? "Project" : "Project ID"}>
{devopsProjectName || devopsProjectId}
</GenericFieldLabel>
);
};