UI: secrets-aware env editor, issue hiding, and adapter env bindings
Replace plain text env var editor with structured EnvVarEditor supporting plain values and secret references with inline "Seal" to convert a value to a managed secret. Add issue hide action via popover menu on issue detail. Adapters now emit envBindings with typed plain/secret_ref entries instead of raw KEY=VALUE strings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,14 @@ function shouldRedactSecretValue(key: string, value: unknown): boolean {
|
||||
}
|
||||
|
||||
function redactEnvValue(key: string, value: unknown): string {
|
||||
if (
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
!Array.isArray(value) &&
|
||||
(value as { type?: unknown }).type === "secret_ref"
|
||||
) {
|
||||
return "***SECRET_REF***";
|
||||
}
|
||||
if (shouldRedactSecretValue(key, value)) return REDACTED_ENV_VALUE;
|
||||
if (value === null || value === undefined) return "";
|
||||
if (typeof value === "string") return value;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useParams, Link } from "react-router-dom";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useParams, Link, useNavigate } from "react-router-dom";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { issuesApi } from "../api/issues";
|
||||
import { activityApi } from "../api/activity";
|
||||
@@ -18,7 +18,9 @@ import { PriorityIcon } from "../components/PriorityIcon";
|
||||
import { StatusBadge } from "../components/StatusBadge";
|
||||
import { Identity } from "../components/Identity";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ChevronRight, MoreHorizontal, EyeOff } from "lucide-react";
|
||||
import type { ActivityEvent } from "@paperclip/shared";
|
||||
import type { Agent } from "@paperclip/shared";
|
||||
|
||||
@@ -94,6 +96,8 @@ export function IssueDetail() {
|
||||
const { openPanel, closePanel } = usePanel();
|
||||
const { setBreadcrumbs } = useBreadcrumbs();
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
const [moreOpen, setMoreOpen] = useState(false);
|
||||
|
||||
const { data: issue, isLoading, error } = useQuery({
|
||||
queryKey: queryKeys.issues.detail(issueId!),
|
||||
@@ -242,6 +246,29 @@ export function IssueDetail() {
|
||||
onChange={(priority) => updateIssue.mutate({ priority })}
|
||||
/>
|
||||
<span className="text-xs font-mono text-muted-foreground">{issue.identifier ?? issue.id.slice(0, 8)}</span>
|
||||
|
||||
<Popover open={moreOpen} onOpenChange={setMoreOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="ghost" size="icon-xs">
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-44 p-1" align="end">
|
||||
<button
|
||||
className="flex items-center gap-2 w-full px-2 py-1.5 text-xs rounded hover:bg-accent/50 text-destructive"
|
||||
onClick={() => {
|
||||
updateIssue.mutate(
|
||||
{ hiddenAt: new Date().toISOString() },
|
||||
{ onSuccess: () => navigate("/issues") },
|
||||
);
|
||||
setMoreOpen(false);
|
||||
}}
|
||||
>
|
||||
<EyeOff className="h-3 w-3" />
|
||||
Hide this Issue
|
||||
</button>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<InlineEditor
|
||||
|
||||
Reference in New Issue
Block a user