style(ui): simplify Company Environments screen copy (#8400)
## Thinking Path > - Paperclip is the control plane for managing AI-agent work, and the UI needs to stay legible because operators use it to steer execution. > - This change sits in the Company Environments screen inside the Paperclip app UI. > - The screen carried redundant headings and several overlapping helper sentences that added clutter without adding meaning. > - The request was presentation-only: remove redundant copy and simplify labels, with no change to environment-selection behavior. > - The safest path was a single-file edit in `CompanyEnvironments.tsx` that preserved every control and only removed/renamed text. > - This is a `style:` change (UI copy/presentation), so no behavior is altered and no new test is warranted. ## Linked Issues or Issue Description No public GitHub issue exists for this small UI cleanup, so the problem is described here instead. - The Company Environments screen had redundant headings and overlapping helper copy. - The default environment control used a verbose label and a Local option label that added noise without adding meaning. - Requested outcome: simplify the copy so the screen is easier to scan while preserving the same behavior. Related public PRs reviewed for overlap: - Refs #8380 - Refs #8391 - Refs #8398 - Refs #4902 ## What Changed - Removed the extra top-level `Environments` header inside the screen content (both enabled and disabled states). - Removed the introductory paragraph above the environment list. - Renamed `Instance default environment` to `Default` and removed its helper sentence. - Removed the duplicate helper text below the default environment select. - Changed `Local (built-in default)` to `Local`. - Removed the redundant `Saved environments` section heading. - Removed the empty-state line `No saved environments yet. Local remains the default until you add another target.` - Removed the previously added UI test, which only asserted the now-final copy and added no lasting value. - Removed the now-unused `Settings` import and `instanceDefaultEnvironment` variable. ## Verification - Ran the existing `CompanyEnvironments` vitest suite locally: 4 passed. - This is a presentation-only copy change with no API, state, or behavior changes. - Reviewer can open Company Settings -> Environments and confirm the screen matches the requested wording cleanup with no behavior change. ## Risks - Low. Copy-only UI change with no API or state-management changes. - The only real risk is removing more context than intended from the top of the screen; review should focus on clarity. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Anthropic Claude Opus 4.8 via the Claude local adapter with tool use in a Paperclip-managed workspace. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [ ] My branch name describes the change and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] This is a `style:` copy-only change; no new test is warranted (test-coverage gate skips `style:`) - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge
This commit is contained in:
@@ -6,7 +6,6 @@ import {
|
||||
type EnvironmentProbeResult,
|
||||
type JsonSchema,
|
||||
} from "@paperclipai/shared";
|
||||
import { Settings } from "lucide-react";
|
||||
import { environmentsApi } from "@/api/environments";
|
||||
import { instanceSettingsApi } from "@/api/instanceSettings";
|
||||
import { secretsApi } from "@/api/secrets";
|
||||
@@ -476,8 +475,6 @@ export function CompanyEnvironments() {
|
||||
instanceSettings?.defaultEnvironmentId ?? null,
|
||||
savedEnvironments,
|
||||
);
|
||||
const instanceDefaultEnvironment =
|
||||
nonLocalEnvironments.find((environment) => environment.id === instanceDefaultEnvironmentId) ?? null;
|
||||
|
||||
if (!selectedCompanyId) {
|
||||
return <div className="text-sm text-muted-foreground">Select a company context to manage environment secrets and bindings.</div>;
|
||||
@@ -486,10 +483,6 @@ export function CompanyEnvironments() {
|
||||
if (!environmentsEnabled) {
|
||||
return (
|
||||
<div className="max-w-3xl space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Settings className="h-5 w-5 text-muted-foreground" />
|
||||
<h1 className="text-lg font-semibold">Environments</h1>
|
||||
</div>
|
||||
<div className="rounded-md border border-border px-4 py-4 text-sm text-muted-foreground">
|
||||
Enable Environments in instance experimental settings to manage shared execution targets.
|
||||
</div>
|
||||
@@ -499,24 +492,11 @@ export function CompanyEnvironments() {
|
||||
|
||||
return (
|
||||
<div className="max-w-5xl space-y-6" data-testid="instance-settings-environments-section">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Settings className="h-5 w-5 text-muted-foreground" />
|
||||
<h1 className="text-lg font-semibold">Environments</h1>
|
||||
</div>
|
||||
<p className="max-w-3xl text-sm text-muted-foreground">
|
||||
Define reusable execution targets for the instance. The built-in default is <span className="font-medium text-foreground">Local</span>; agents inherit that unless the instance default or an agent override points somewhere else.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 rounded-md border border-border px-4 py-4">
|
||||
<div className="rounded-md border border-border/60 bg-muted/20 px-3 py-3">
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium">Instance default environment</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
New agent configurations inherit this target unless they explicitly override it.
|
||||
</div>
|
||||
<div className="text-sm font-medium">Default</div>
|
||||
</div>
|
||||
<div className="min-w-[18rem] flex-1">
|
||||
<select
|
||||
@@ -526,110 +506,100 @@ export function CompanyEnvironments() {
|
||||
defaultEnvironmentMutation.mutate(event.target.value || null)}
|
||||
disabled={defaultEnvironmentMutation.isPending}
|
||||
>
|
||||
<option value="">Local (built-in default)</option>
|
||||
<option value="">Local</option>
|
||||
{nonLocalEnvironments.map((environment) => (
|
||||
<option key={environment.id} value={environment.id}>
|
||||
{environment.name} · {environment.driver}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="mt-1 text-[11px] text-muted-foreground">
|
||||
{instanceDefaultEnvironment
|
||||
? `Agents currently inherit ${instanceDefaultEnvironment.name} unless they override it.`
|
||||
: "Agents currently inherit the built-in Local environment unless they override it."}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-wrap items-center justify-between gap-3">
|
||||
<div className="text-sm font-medium">Saved environments</div>
|
||||
<div className="flex justify-end">
|
||||
<Button size="sm" onClick={handleStartCreateEnvironment}>
|
||||
Add environment
|
||||
</Button>
|
||||
</div>
|
||||
{savedEnvironments.length === 0 ? (
|
||||
<div className="text-sm text-muted-foreground">No saved environments yet. Local remains the default until you add another target.</div>
|
||||
) : (
|
||||
savedEnvironments.map((environment) => {
|
||||
const probe = probeResults[environment.id] ?? null;
|
||||
const isEditing = editingEnvironmentId === environment.id;
|
||||
return (
|
||||
<div
|
||||
key={environment.id}
|
||||
className="rounded-md border border-border/70 px-3 py-3"
|
||||
>
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium">
|
||||
{environment.name} <span className="text-muted-foreground">· {environment.driver}</span>
|
||||
</div>
|
||||
{environment.description ? (
|
||||
<div className="text-xs text-muted-foreground">{environment.description}</div>
|
||||
) : null}
|
||||
{environment.driver === "ssh" ? (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{typeof environment.config.host === "string" ? environment.config.host : "SSH host"} ·{" "}
|
||||
{typeof environment.config.username === "string" ? environment.config.username : "user"}
|
||||
</div>
|
||||
) : environment.driver === "sandbox" ? (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{(() => {
|
||||
const provider =
|
||||
typeof environment.config.provider === "string" ? environment.config.provider : "sandbox";
|
||||
const displayName =
|
||||
environmentCapabilities?.sandboxProviders?.[provider]?.displayName ?? provider;
|
||||
const summary = summarizeSandboxConfig(environment.config as Record<string, unknown>);
|
||||
return `${displayName} sandbox provider${summary ? ` · ${summary}` : ""}`;
|
||||
})()}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-xs text-muted-foreground">Runs on this Paperclip host.</div>
|
||||
)}
|
||||
{savedEnvironments.map((environment) => {
|
||||
const probe = probeResults[environment.id] ?? null;
|
||||
const isEditing = editingEnvironmentId === environment.id;
|
||||
return (
|
||||
<div
|
||||
key={environment.id}
|
||||
className="rounded-md border border-border/70 px-3 py-3"
|
||||
>
|
||||
<div className="flex flex-wrap items-start justify-between gap-3">
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm font-medium">
|
||||
{environment.name} <span className="text-muted-foreground">· {environment.driver}</span>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{environment.driver !== "local" ? (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => environmentProbeMutation.mutate(environment.id)}
|
||||
disabled={testingEnvironmentId === environment.id}
|
||||
>
|
||||
{testingEnvironmentId === environment.id
|
||||
? "Testing..."
|
||||
: environment.driver === "ssh"
|
||||
? "Test connection"
|
||||
: "Test provider"}
|
||||
</Button>
|
||||
) : null}
|
||||
{environment.description ? (
|
||||
<div className="text-xs text-muted-foreground">{environment.description}</div>
|
||||
) : null}
|
||||
{environment.driver === "ssh" ? (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{typeof environment.config.host === "string" ? environment.config.host : "SSH host"} ·{" "}
|
||||
{typeof environment.config.username === "string" ? environment.config.username : "user"}
|
||||
</div>
|
||||
) : environment.driver === "sandbox" ? (
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{(() => {
|
||||
const provider =
|
||||
typeof environment.config.provider === "string" ? environment.config.provider : "sandbox";
|
||||
const displayName =
|
||||
environmentCapabilities?.sandboxProviders?.[provider]?.displayName ?? provider;
|
||||
const summary = summarizeSandboxConfig(environment.config as Record<string, unknown>);
|
||||
return `${displayName} sandbox provider${summary ? ` · ${summary}` : ""}`;
|
||||
})()}
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-xs text-muted-foreground">Runs on this Paperclip host.</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
{environment.driver !== "local" ? (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => handleEditEnvironment(environment)}
|
||||
variant="outline"
|
||||
onClick={() => environmentProbeMutation.mutate(environment.id)}
|
||||
disabled={testingEnvironmentId === environment.id}
|
||||
>
|
||||
{isEditing ? "Editing" : "Edit"}
|
||||
{testingEnvironmentId === environment.id
|
||||
? "Testing..."
|
||||
: environment.driver === "ssh"
|
||||
? "Test connection"
|
||||
: "Test provider"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{probe ? (
|
||||
<div
|
||||
className={
|
||||
probe.ok
|
||||
? "mt-3 rounded border border-green-500/30 bg-green-500/5 px-2.5 py-2 text-xs text-green-700"
|
||||
: "mt-3 rounded border border-destructive/30 bg-destructive/5 px-2.5 py-2 text-xs text-destructive"
|
||||
}
|
||||
) : null}
|
||||
<Button
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
onClick={() => handleEditEnvironment(environment)}
|
||||
>
|
||||
<div className="font-medium">{probe.summary}</div>
|
||||
{probe.details?.error && typeof probe.details.error === "string" ? (
|
||||
<div className="mt-1 font-mono text-[11px]">{probe.details.error}</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
{isEditing ? "Editing" : "Edit"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
{probe ? (
|
||||
<div
|
||||
className={
|
||||
probe.ok
|
||||
? "mt-3 rounded border border-green-500/30 bg-green-500/5 px-2.5 py-2 text-xs text-green-700"
|
||||
: "mt-3 rounded border border-destructive/30 bg-destructive/5 px-2.5 py-2 text-xs text-destructive"
|
||||
}
|
||||
>
|
||||
<div className="font-medium">{probe.summary}</div>
|
||||
{probe.details?.error && typeof probe.details.error === "string" ? (
|
||||
<div className="mt-1 font-mono text-[11px]">{probe.details.error}</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user