mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Merge pull request #2498 from scott-ray-wilson/various-ui-improvements
Fix: Various UI Improvements, Fixes and Backend Refactoring
This commit is contained in:
@@ -17,6 +17,20 @@ import { AuthMode } from "@app/services/auth/auth-type";
|
||||
import { SecretsOrderBy } from "@app/services/secret/secret-types";
|
||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
// handle querystring boolean values
|
||||
const booleanSchema = z
|
||||
.union([z.boolean(), z.string().trim()])
|
||||
.transform((value) => {
|
||||
if (typeof value === "string") {
|
||||
// ie if not empty, 0 or false, return true
|
||||
return Boolean(value) && Number(value) !== 0 && value.toLowerCase() !== "false";
|
||||
}
|
||||
|
||||
return value;
|
||||
})
|
||||
.optional()
|
||||
.default(true);
|
||||
|
||||
export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "GET",
|
||||
@@ -57,21 +71,9 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
.describe(DASHBOARD.SECRET_OVERVIEW_LIST.orderDirection)
|
||||
.optional(),
|
||||
search: z.string().trim().describe(DASHBOARD.SECRET_OVERVIEW_LIST.search).optional(),
|
||||
includeSecrets: z.coerce
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeSecrets),
|
||||
includeFolders: z.coerce
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeFolders),
|
||||
includeDynamicSecrets: z.coerce
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeDynamicSecrets)
|
||||
includeSecrets: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeSecrets),
|
||||
includeFolders: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeFolders),
|
||||
includeDynamicSecrets: booleanSchema.describe(DASHBOARD.SECRET_OVERVIEW_LIST.includeDynamicSecrets)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -354,26 +356,10 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
|
||||
.optional(),
|
||||
search: z.string().trim().describe(DASHBOARD.SECRET_DETAILS_LIST.search).optional(),
|
||||
tags: z.string().trim().transform(decodeURIComponent).describe(DASHBOARD.SECRET_DETAILS_LIST.tags).optional(),
|
||||
includeSecrets: z.coerce
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.describe(DASHBOARD.SECRET_DETAILS_LIST.includeSecrets),
|
||||
includeFolders: z.coerce
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.describe(DASHBOARD.SECRET_DETAILS_LIST.includeFolders),
|
||||
includeDynamicSecrets: z.coerce
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.describe(DASHBOARD.SECRET_DETAILS_LIST.includeDynamicSecrets),
|
||||
includeImports: z.coerce
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.describe(DASHBOARD.SECRET_DETAILS_LIST.includeImports)
|
||||
includeSecrets: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeSecrets),
|
||||
includeFolders: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeFolders),
|
||||
includeDynamicSecrets: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeDynamicSecrets),
|
||||
includeImports: booleanSchema.describe(DASHBOARD.SECRET_DETAILS_LIST.includeImports)
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -1,3 +1,5 @@
|
||||
import { registerDashboardRouter } from "@app/server/routes/v1/dashboard-router";
|
||||
|
||||
import { registerAdminRouter } from "./admin-router";
|
||||
import { registerAuthRoutes } from "./auth-router";
|
||||
import { registerProjectBotRouter } from "./bot-router";
|
||||
@@ -101,4 +103,6 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
||||
await server.register(registerIdentityRouter, { prefix: "/identities" });
|
||||
await server.register(registerSecretSharingRouter, { prefix: "/secret-sharing" });
|
||||
await server.register(registerUserEngagementRouter, { prefix: "/user-engagement" });
|
||||
|
||||
await server.register(registerDashboardRouter, { prefix: "/dashboard" });
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { registerDashboardRouter } from "./dashboard-router";
|
||||
import { registerLoginRouter } from "./login-router";
|
||||
import { registerSecretBlindIndexRouter } from "./secret-blind-index-router";
|
||||
import { registerSecretRouter } from "./secret-router";
|
||||
@@ -11,5 +10,4 @@ export const registerV3Routes = async (server: FastifyZodProvider) => {
|
||||
await server.register(registerUserRouter, { prefix: "/users" });
|
||||
await server.register(registerSecretRouter, { prefix: "/secrets" });
|
||||
await server.register(registerSecretBlindIndexRouter, { prefix: "/workspaces" });
|
||||
await server.register(registerDashboardRouter, { prefix: "/dashboard" });
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ export const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuConten
|
||||
{...props}
|
||||
ref={forwardedRef}
|
||||
className={twMerge(
|
||||
"z-30 min-w-[220px] rounded-md border border-mineshaft-600 bg-mineshaft-900 text-bunker-300 shadow will-change-auto data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade",
|
||||
"z-30 min-w-[220px] overflow-y-auto rounded-md border border-mineshaft-600 bg-mineshaft-900 text-bunker-300 shadow will-change-auto data-[side=top]:animate-slideDownAndFade data-[side=left]:animate-slideRightAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade",
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -48,21 +48,15 @@ export const dashboardKeys = {
|
||||
};
|
||||
|
||||
export const fetchProjectSecretsOverview = async ({
|
||||
includeFolders,
|
||||
includeSecrets,
|
||||
includeDynamicSecrets,
|
||||
environments,
|
||||
...params
|
||||
}: TGetDashboardProjectSecretsOverviewDTO) => {
|
||||
const { data } = await apiRequest.get<DashboardProjectSecretsOverviewResponse>(
|
||||
"/api/v3/dashboard/secrets-overview",
|
||||
"/api/v1/dashboard/secrets-overview",
|
||||
{
|
||||
params: {
|
||||
...params,
|
||||
environments: encodeURIComponent(environments.join(",")),
|
||||
includeFolders: includeFolders ? "1" : "",
|
||||
includeSecrets: includeSecrets ? "1" : "",
|
||||
includeDynamicSecrets: includeDynamicSecrets ? "1" : ""
|
||||
environments: encodeURIComponent(environments.join(","))
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -71,22 +65,14 @@ export const fetchProjectSecretsOverview = async ({
|
||||
};
|
||||
|
||||
export const fetchProjectSecretsDetails = async ({
|
||||
includeFolders,
|
||||
includeImports,
|
||||
includeSecrets,
|
||||
includeDynamicSecrets,
|
||||
tags,
|
||||
...params
|
||||
}: TGetDashboardProjectSecretsDetailsDTO) => {
|
||||
const { data } = await apiRequest.get<DashboardProjectSecretsDetailsResponse>(
|
||||
"/api/v3/dashboard/secrets-details",
|
||||
"/api/v1/dashboard/secrets-details",
|
||||
{
|
||||
params: {
|
||||
...params,
|
||||
includeImports: includeImports ? "1" : "",
|
||||
includeFolders: includeFolders ? "1" : "",
|
||||
includeSecrets: includeSecrets ? "1" : "",
|
||||
includeDynamicSecrets: includeDynamicSecrets ? "1" : "",
|
||||
tags: encodeURIComponent(
|
||||
Object.entries(tags)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
|
||||
@@ -17,6 +17,7 @@ import { useCreateIntegration } from "@app/hooks/api";
|
||||
import { useGetIntegrationAuthAwsKmsKeys } from "@app/hooks/api/integrationAuth/queries";
|
||||
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
@@ -245,8 +246,8 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{awsRegions.map((awsRegion) => (
|
||||
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}>
|
||||
{awsRegion.name}
|
||||
<SelectItem value={awsRegion.slug} key={`aws-environment-${awsRegion.slug}`}>
|
||||
{awsRegion.name} <Badge variant="success">{awsRegion.slug}</Badge>
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
@@ -18,6 +18,7 @@ import { useGetIntegrationAuthAwsKmsKeys } from "@app/hooks/api/integrationAuth/
|
||||
import { IntegrationMappingBehavior } from "@app/hooks/api/integrations/types";
|
||||
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
@@ -267,8 +268,12 @@ export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{awsRegions.map((awsRegion) => (
|
||||
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}>
|
||||
{awsRegion.name}
|
||||
<SelectItem
|
||||
value={awsRegion.slug}
|
||||
className="flex w-full justify-between"
|
||||
key={`aws-environment-${awsRegion.slug}`}
|
||||
>
|
||||
{awsRegion.name} <Badge variant="success">{awsRegion.slug}</Badge>
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
@@ -73,7 +73,7 @@ export const SecretOverviewTableRow = ({
|
||||
>
|
||||
<div className="h-full w-full border-r border-mineshaft-600 py-2.5 px-5">
|
||||
<div className="flex items-center space-x-5">
|
||||
<div className="text-blue-300/70">
|
||||
<div className="text-bunker-300">
|
||||
<Checkbox
|
||||
id={`checkbox-${secretKey}`}
|
||||
isChecked={isSelected}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { faFileImport, faFingerprint, faFolder, faKey } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { Tooltip } from "@app/components/v2";
|
||||
|
||||
type Props = {
|
||||
folderCount?: number;
|
||||
importCount?: number;
|
||||
@@ -17,28 +19,68 @@ export const SecretTableResourceCount = ({
|
||||
return (
|
||||
<div className="flex items-center gap-2 divide-x divide-mineshaft-500 text-sm text-mineshaft-400">
|
||||
{importCount > 0 && (
|
||||
<div className="flex items-center gap-2">
|
||||
<FontAwesomeIcon icon={faFileImport} className=" text-green-700" />
|
||||
<span>{importCount}</span>
|
||||
</div>
|
||||
<Tooltip
|
||||
className="max-w-sm"
|
||||
content={
|
||||
<p className="whitespace-nowrap text-center">
|
||||
Total import count{" "}
|
||||
<span className="text-center text-mineshaft-400">(matching filters)</span>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<FontAwesomeIcon icon={faFileImport} className=" text-green-700" />
|
||||
<span>{importCount}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
{folderCount > 0 && (
|
||||
<div className="flex items-center gap-2 pl-2">
|
||||
<FontAwesomeIcon icon={faFolder} className="text-yellow-700" />
|
||||
<span>{folderCount}</span>
|
||||
</div>
|
||||
<Tooltip
|
||||
className="max-w-sm"
|
||||
content={
|
||||
<p className="whitespace-nowrap text-center">
|
||||
Total folder count{" "}
|
||||
<span className="text-center text-mineshaft-400">(matching filters)</span>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2 pl-2">
|
||||
<FontAwesomeIcon icon={faFolder} className="text-yellow-700" />
|
||||
<span>{folderCount}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
{dynamicSecretCount > 0 && (
|
||||
<div className="flex items-center gap-2 pl-2">
|
||||
<FontAwesomeIcon icon={faFingerprint} className="text-yellow-700" />
|
||||
<span>{dynamicSecretCount}</span>
|
||||
</div>
|
||||
<Tooltip
|
||||
className="max-w-sm"
|
||||
content={
|
||||
<p className="whitespace-nowrap text-center">
|
||||
Total dynamic secret count{" "}
|
||||
<span className="text-center text-mineshaft-400">(matching filters)</span>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2 pl-2">
|
||||
<FontAwesomeIcon icon={faFingerprint} className="text-yellow-700" />
|
||||
<span>{dynamicSecretCount}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
{secretCount > 0 && (
|
||||
<div className="flex items-center gap-2 pl-2">
|
||||
<FontAwesomeIcon icon={faKey} className="text-bunker-300" />
|
||||
<span>{secretCount}</span>
|
||||
</div>
|
||||
<Tooltip
|
||||
className="max-w-sm"
|
||||
content={
|
||||
<p className="whitespace-nowrap text-center">
|
||||
Total secret count{" "}
|
||||
<span className="text-center text-mineshaft-400">(matching filters)</span>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
<div className="flex items-center gap-2 pl-2">
|
||||
<FontAwesomeIcon icon={faKey} className="text-bunker-300" />
|
||||
<span>{secretCount}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Controller, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { Button, FormControl, Input, Select, SelectItem } from "@app/components/v2";
|
||||
import { Badge, Button, FormControl, Input, Select, SelectItem } from "@app/components/v2";
|
||||
import { useOrganization } from "@app/context";
|
||||
import { useAddExternalKms, useUpdateExternalKms } from "@app/hooks/api";
|
||||
import {
|
||||
@@ -244,7 +244,7 @@ export const AwsKmsForm = ({ onCompleted, onCancel, kms }: Props) => {
|
||||
>
|
||||
{AWS_REGIONS.map((awsRegion) => (
|
||||
<SelectItem value={awsRegion.slug} key={`kms-aws-region-${awsRegion.slug}`}>
|
||||
{awsRegion.name} ({awsRegion.slug})
|
||||
{awsRegion.name} <Badge variant="success">{awsRegion.slug}</Badge>
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
Reference in New Issue
Block a user