Skip to content

Commit e02ce83

Browse files
committed
prototype
1 parent ed62ddc commit e02ce83

File tree

1 file changed

+167
-6
lines changed

1 file changed

+167
-6
lines changed

site/src/pages/TaskPage/TaskApps.tsx

Lines changed: 167 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import type { WorkspaceApp } from "api/typesGenerated";
22
import { Button } from "components/Button/Button";
3+
import { Input } from "components/Input/Input";
4+
import { Switch } from "components/Switch/Switch";
35
import {
46
DropdownMenu,
57
DropdownMenuContent,
@@ -8,11 +10,18 @@ import {
810
} from "components/DropdownMenu/DropdownMenu";
911
import { ExternalImage } from "components/ExternalImage/ExternalImage";
1012
import { InfoTooltip } from "components/InfoTooltip/InfoTooltip";
11-
import { ChevronDownIcon, LayoutGridIcon } from "lucide-react";
13+
import {
14+
ChevronDownIcon,
15+
LayoutGridIcon,
16+
ShieldIcon,
17+
PlusIcon,
18+
TrashIcon,
19+
SaveIcon,
20+
} from "lucide-react";
1221
import { useAppLink } from "modules/apps/useAppLink";
1322
import type { Task } from "modules/tasks/tasks";
1423
import type React from "react";
15-
import { type FC, useState } from "react";
24+
import { type FC, useState, useCallback } from "react";
1625
import { Link as RouterLink } from "react-router-dom";
1726
import { cn } from "utils/cn";
1827
import { TaskAppIFrame } from "./TaskAppIframe";
@@ -22,6 +31,56 @@ type TaskAppsProps = {
2231
};
2332

2433
export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
34+
const [allowedCommands, setAllowedCommands] = useState<string[]>([
35+
"npm run dev",
36+
"npm run test",
37+
]);
38+
const [allowedHosts, setAllowedHosts] = useState<string[]>([
39+
"artifacts.corporate.com",
40+
]);
41+
const [auditingEnabled, setAuditingEnabled] = useState<boolean>(true);
42+
43+
const handleCommandChange = useCallback((index: number, value: string) => {
44+
setAllowedCommands((prev) => {
45+
const updated = [...prev];
46+
updated[index] = value;
47+
return updated;
48+
});
49+
}, []);
50+
51+
const removeCommand = useCallback((index: number) => {
52+
setAllowedCommands((prev) => prev.filter((_, i) => i !== index));
53+
}, []);
54+
55+
const addCommand = useCallback(() => {
56+
setAllowedCommands((prev) => [...prev, ""]);
57+
}, []);
58+
59+
const handleHostChange = useCallback((index: number, value: string) => {
60+
setAllowedHosts((prev) => {
61+
const updated = [...prev];
62+
updated[index] = value;
63+
return updated;
64+
});
65+
}, []);
66+
67+
const removeHost = useCallback((index: number) => {
68+
setAllowedHosts((prev) => prev.filter((_, i) => i !== index));
69+
}, []);
70+
71+
const addHost = useCallback(() => {
72+
setAllowedHosts((prev) => [...prev, ""]);
73+
}, []);
74+
75+
const saveSettings = useCallback(() => {
76+
// Here you would typically save the settings to your backend
77+
console.log("Saving security settings:", {
78+
allowedCommands,
79+
allowedHosts,
80+
auditingEnabled,
81+
});
82+
// For now, we just log to console as this is a prototype
83+
}, [allowedCommands, allowedHosts, auditingEnabled]);
2584
const agents = task.workspace.latest_build.resources
2685
.flatMap((r) => r.agents)
2786
.filter((a) => !!a);
@@ -75,8 +134,110 @@ export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
75134
))}
76135
</div>
77136

78-
{externalApps.length > 0 && (
79-
<div className="ml-auto">
137+
<div className="ml-auto flex gap-2">
138+
<DropdownMenu>
139+
<DropdownMenuTrigger asChild>
140+
<Button size="sm" variant="subtle">
141+
<ShieldIcon className="mr-1.5 h-4 w-4" />
142+
Security
143+
<ChevronDownIcon className="ml-1" />
144+
</Button>
145+
</DropdownMenuTrigger>
146+
<DropdownMenuContent align="end" className="w-[400px]">
147+
<div className="p-4 space-y-4">
148+
<div className="border-b border-border pb-2 mb-2 flex items-center justify-between">
149+
<h3 className="text-lg font-medium">Security Settings</h3>
150+
</div>
151+
152+
<div>
153+
<h4 className="text-sm font-medium mb-2">Allowed Commands</h4>
154+
<div className="space-y-2">
155+
{allowedCommands.map((command, index) => (
156+
<div key={index} className="flex items-center gap-2">
157+
<Input
158+
className="flex-1 font-mono text-sm"
159+
value={command}
160+
onChange={(e) =>
161+
handleCommandChange(index, e.target.value)
162+
}
163+
/>
164+
<Button
165+
size="icon"
166+
variant="outline"
167+
onClick={() => removeCommand(index)}
168+
>
169+
<TrashIcon className="h-4 w-4" />
170+
<span className="sr-only">Remove</span>
171+
</Button>
172+
</div>
173+
))}
174+
<Button
175+
size="sm"
176+
variant="outline"
177+
className="w-full mt-1"
178+
onClick={addCommand}
179+
>
180+
<PlusIcon className="h-4 w-4 mr-1" />
181+
Add Command
182+
</Button>
183+
</div>
184+
</div>
185+
186+
<div className="mt-4">
187+
<h4 className="text-sm font-medium mb-2">Allowed Hosts</h4>
188+
<div className="space-y-2">
189+
{allowedHosts.map((host, index) => (
190+
<div key={index} className="flex items-center gap-2">
191+
<Input
192+
className="flex-1 font-mono text-sm"
193+
value={host}
194+
onChange={(e) =>
195+
handleHostChange(index, e.target.value)
196+
}
197+
/>
198+
<Button
199+
size="icon"
200+
variant="outline"
201+
onClick={() => removeHost(index)}
202+
>
203+
<TrashIcon className="h-4 w-4" />
204+
<span className="sr-only">Remove</span>
205+
</Button>
206+
</div>
207+
))}
208+
<Button
209+
size="sm"
210+
variant="outline"
211+
className="w-full mt-1"
212+
onClick={addHost}
213+
>
214+
<PlusIcon className="h-4 w-4 mr-1" />
215+
Add Host
216+
</Button>
217+
</div>
218+
</div>
219+
220+
<div className="flex items-center justify-between mt-4">
221+
<span className="text-sm font-medium">Auditing</span>
222+
<Switch
223+
checked={auditingEnabled}
224+
onCheckedChange={setAuditingEnabled}
225+
/>
226+
</div>
227+
228+
<Button
229+
className="w-full mt-4"
230+
size="sm"
231+
onClick={saveSettings}
232+
>
233+
<SaveIcon className="h-4 w-4 mr-1.5" />
234+
Save Settings
235+
</Button>
236+
</div>
237+
</DropdownMenuContent>
238+
</DropdownMenu>
239+
240+
{externalApps.length > 0 && (
80241
<DropdownMenu>
81242
<DropdownMenuTrigger asChild>
82243
<Button size="sm" variant="subtle">
@@ -106,8 +267,8 @@ export const TaskApps: FC<TaskAppsProps> = ({ task }) => {
106267
})}
107268
</DropdownMenuContent>
108269
</DropdownMenu>
109-
</div>
110-
)}
270+
)}
271+
</div>
111272
</div>
112273

113274
<div className="flex-1">

0 commit comments

Comments
 (0)