Skip to content

Commit b184213

Browse files
committed
feat(ui): Show dropdowns for secret plugin options
For plugin options of the type 'SECRET', show a dropdown with all secrets available in the context of the repository. If no secrets are available, or if the selected secret does not exist, show an error message. Signed-off-by: Martin Nonnenmacher <[email protected]>
1 parent e713fe6 commit b184213

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

ui/src/components/form/plugin-multi-select-field.tsx

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
UseFormReturn,
2828
} from 'react-hook-form';
2929

30-
import { PreconfiguredPluginDescriptor } from '@/api/requests';
30+
import { PreconfiguredPluginDescriptor, Secret } from '@/api/requests';
3131
import { OptionalInput } from '@/components/form/optional-input.tsx';
3232
import { Badge } from '@/components/ui/badge.tsx';
3333
import { Checkbox } from '@/components/ui/checkbox';
@@ -41,6 +41,13 @@ import {
4141
} from '@/components/ui/form';
4242
import { Input } from '@/components/ui/input.tsx';
4343
import { Label } from '@/components/ui/label';
44+
import {
45+
Select,
46+
SelectContent,
47+
SelectItem,
48+
SelectTrigger,
49+
SelectValue,
50+
} from '@/components/ui/select.tsx';
4451
import { Separator } from '@/components/ui/separator';
4552
import { cn } from '@/lib/utils';
4653

@@ -54,6 +61,7 @@ type PluginMultiSelectFieldProps<
5461
label?: string;
5562
description?: React.ReactNode;
5663
plugins: readonly PreconfiguredPluginDescriptor[];
64+
secrets: readonly Secret[];
5765
className?: string;
5866
};
5967

@@ -67,6 +75,7 @@ export const PluginMultiSelectField = <
6775
label,
6876
description,
6977
plugins,
78+
secrets,
7079
className,
7180
}: PluginMultiSelectFieldProps<TFieldValues, TName>) => {
7281
return (
@@ -149,7 +158,7 @@ export const PluginMultiSelectField = <
149158
control={form.control}
150159
key={option.name}
151160
name={
152-
`${configName}.${plugin.id}.options.${option.name}` as Path<TFieldValues>
161+
`${configName}.${plugin.id}.${option.type === 'SECRET' ? 'secrets' : 'options'}.${option.name}` as Path<TFieldValues>
153162
}
154163
render={({ field }) => (
155164
<FormItem className='flex flex-col space-y-1'>
@@ -169,6 +178,47 @@ export const PluginMultiSelectField = <
169178
onCheckedChange={field.onChange}
170179
disabled={option.isFixed}
171180
/>
181+
) : option.type == 'SECRET' ? (
182+
secrets.length === 0 ? (
183+
<FormMessage className='font-semibold text-red-600'>
184+
No secrets available. Create a new secret to
185+
be able to use this option.
186+
</FormMessage>
187+
) : (
188+
<Select
189+
onValueChange={field.onChange}
190+
defaultValue={undefined}
191+
value={field.value}
192+
disabled={option.isFixed}
193+
>
194+
<SelectTrigger>
195+
<SelectValue placeholder='Select a secret' />
196+
</SelectTrigger>
197+
<SelectContent>
198+
{secrets.map((secret) => (
199+
<SelectItem
200+
key={secret.name}
201+
value={secret.name}
202+
>
203+
{secret.name}
204+
</SelectItem>
205+
))}
206+
</SelectContent>
207+
{field.value &&
208+
!secrets.some(
209+
(secret) => secret.name === field.value
210+
) && (
211+
<FormMessage className='font-semibold text-red-600'>
212+
The selected secret '{field.value}' does
213+
not exist. The value could come from a
214+
previous run or could be a default value
215+
set by an administrator. Select a valid
216+
secret or create a new secret with this
217+
name.
218+
</FormMessage>
219+
)}
220+
</Select>
221+
)
172222
) : option.isRequired ? (
173223
<Input
174224
{...field}

ui/src/routes/organizations/$orgId/products/$productId/repositories/$repoId/-components/advisor-fields.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import { UseFormReturn } from 'react-hook-form';
2121

22-
import { PreconfiguredPluginDescriptor } from '@/api/requests';
22+
import { PreconfiguredPluginDescriptor, Secret } from '@/api/requests';
2323
import { PluginMultiSelectField } from '@/components/form/plugin-multi-select-field.tsx';
2424
import {
2525
AccordionContent,
@@ -41,13 +41,15 @@ type AdvisorFieldsProps = {
4141
value: string;
4242
onToggle: () => void;
4343
advisorPlugins: PreconfiguredPluginDescriptor[];
44+
secrets: Secret[];
4445
};
4546

4647
export const AdvisorFields = ({
4748
form,
4849
value,
4950
onToggle,
5051
advisorPlugins,
52+
secrets,
5153
}: AdvisorFieldsProps) => {
5254
return (
5355
<div className='flex flex-row align-middle'>
@@ -95,6 +97,7 @@ export const AdvisorFields = ({
9597
label='Enabled advisors'
9698
description={<>Select the advisors enabled for this run.</>}
9799
plugins={advisorPlugins}
100+
secrets={secrets}
98101
/>
99102
</AccordionContent>
100103
</AccordionItem>

ui/src/routes/organizations/$orgId/products/$productId/repositories/$repoId/_repo-layout/create-run/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ import {
6969
const CreateRunPage = () => {
7070
const navigate = useNavigate();
7171
const params = Route.useParams();
72-
const { ortRun, plugins } = Route.useLoaderData();
72+
const { ortRun, plugins, secrets } = Route.useLoaderData();
7373
const [isTest, setIsTest] = useState(false);
7474

7575
const advisorPlugins =
@@ -427,6 +427,7 @@ const CreateRunPage = () => {
427427
value='advisor'
428428
onToggle={() => toggleAccordionOpen('advisor')}
429429
advisorPlugins={advisorPlugins}
430+
secrets={secrets}
430431
/>
431432
<ScannerFields
432433
form={form}
@@ -534,7 +535,7 @@ export const Route = createFileRoute(
534535
// the query will not be run. This corresponds to the "New run" case, where a new
535536
// ORT Run is created from scratch, using all defaults.
536537
loader: async ({ params, deps: { rerunIndex } }) => {
537-
const [ortRun, plugins] = await Promise.all([
538+
const [ortRun, plugins, secrets] = await Promise.all([
538539
rerunIndex !== undefined
539540
? RepositoriesService.getApiV1RepositoriesByRepositoryIdRunsByOrtRunIndex(
540541
{
@@ -546,11 +547,15 @@ export const Route = createFileRoute(
546547
RepositoriesService.getApiV1RepositoriesByRepositoryIdPlugins({
547548
repositoryId: Number.parseInt(params.repoId),
548549
}),
550+
RepositoriesService.getApiV1RepositoriesByRepositoryIdAvailableSecrets({
551+
repositoryId: Number.parseInt(params.repoId),
552+
}),
549553
]);
550554

551555
return {
552556
ortRun,
553557
plugins,
558+
secrets,
554559
};
555560
},
556561
component: CreateRunPage,

0 commit comments

Comments
 (0)