diff --git a/app/forms/firewall-rules-common.tsx b/app/forms/firewall-rules-common.tsx index b0935c893..da348ee21 100644 --- a/app/forms/firewall-rules-common.tsx +++ b/app/forms/firewall-rules-common.tsx @@ -36,8 +36,10 @@ import { useVpcSelector } from '~/hooks/use-params' import { Badge } from '~/ui/lib/Badge' import { toComboboxItems, type ComboboxItem } from '~/ui/lib/Combobox' import { FormDivider } from '~/ui/lib/Divider' +import { FieldLabel } from '~/ui/lib/FieldLabel' import { Message } from '~/ui/lib/Message' import * as MiniTable from '~/ui/lib/MiniTable' +import { SideModal } from '~/ui/lib/SideModal' import { TextInputHint } from '~/ui/lib/TextInput' import { KEYS } from '~/ui/util/keys' import { ALL_ISH } from '~/util/consts' @@ -415,46 +417,50 @@ export const CommonFields = ({ control, nameTaken, error }: CommonFieldsProps) = {/* Really this should be its own
, but you can't have a form inside a form, so we just stick the submit handler in a button onClick */} -
-

Targets

- + Targets + + +

Targets determine the instances to which this rule applies. You can target - instances directly by name, or specify a VPC, VPC subnet, IP, or IP subnet, - which will apply the rule to traffic going to all matching instances. Targets - are additive: the rule applies to instances matching{' '} + instances directly or specify a VPC, VPC subnet, IP, or IP subnet, which will + apply the rule to traffic going to all matching instances. +

+

+ Targets are additive: the rule applies to instances matching{' '} any target. - - } - /> - - targetForm.reset({ type: targetForm.getValues('type'), value: '' }) - } - onInputChange={(value) => targetForm.setValue('value', value)} - onSubmitTextField={submitTarget} - /> - targetForm.reset()} - onSubmit={submitTarget} - /> -

+

+ + } + /> + + + targetForm.reset({ type: targetForm.getValues('type'), value: '' }) + } + onInputChange={(value) => targetForm.setValue('value', value)} + onSubmitTextField={submitTarget} + /> + targetForm.reset()} + onSubmit={submitTarget} + /> {!!targets.value.length && } -

Filters

+ Filters
- {/* We have to blow this up instead of using TextField to get better + {/* We have to blow this up instead of using TextField to get better text styling on the label */}
- + A single destination port (1234) or a range (1234–2345) @@ -523,45 +529,47 @@ export const CommonFields = ({ control, nameTaken, error }: CommonFieldsProps) = )}
- Protocol filters + {/* todo: abstract this label and checkbox pattern */} + + Protocol filters +
-
-

Host filters

- - Host filters match the “other end” of traffic from the - target’s perspective: for an inbound rule, they match the source of - traffic. For an outbound rule, they match the destination. - - } - /> - - hostForm.reset({ type: hostForm.getValues('type'), value: '' }) - } - onInputChange={(value) => hostForm.setValue('value', value)} - onSubmitTextField={submitHost} - /> - hostForm.reset()} - onSubmit={submitHost} - /> -
+ + + Host filters + + + Host filters match the “other end” of traffic from the + target’s perspective: for an inbound rule, they match the source of + traffic. For an outbound rule, they match the destination. + + } + /> + hostForm.reset({ type: hostForm.getValues('type'), value: '' })} + onInputChange={(value) => hostForm.setValue('value', value)} + onSubmitTextField={submitHost} + /> + hostForm.reset()} + onSubmit={submitHost} + /> {!!hosts.value.length && } {error && ( diff --git a/app/forms/idp/create.tsx b/app/forms/idp/create.tsx index 42004e88e..1d97d53ca 100644 --- a/app/forms/idp/create.tsx +++ b/app/forms/idp/create.tsx @@ -18,6 +18,8 @@ import { SideModalForm } from '~/components/form/SideModalForm' import { HL } from '~/components/HL' import { useSiloSelector } from '~/hooks/use-params' import { addToast } from '~/stores/toast' +import { FormDivider } from '~/ui/lib/Divider' +import { SideModal } from '~/ui/lib/SideModal' import { readBlobAsBase64 } from '~/util/file' import { pb } from '~/util/path-builder' @@ -109,21 +111,15 @@ export function CreateIdpSideModalForm() { - {/* TODO: help text */} - - + + + + Service provider {/* TODO: help text */} - {/* TODO: Email field, probably */} - + {/* We don't bother validating that you have both of these or neither even - though the API requires that because we are going to change the API to - always require both, at which point these become simple `required` fields */} + though the API requires that because we are going to change the API to + always require both, at which point these become simple `required` fields */} + + + + Identity Provider + {/* TODO: help text */} + + + ) } diff --git a/app/forms/idp/edit.tsx b/app/forms/idp/edit.tsx index b51d1d904..966aace09 100644 --- a/app/forms/idp/edit.tsx +++ b/app/forms/idp/edit.tsx @@ -17,8 +17,9 @@ import { TextField } from '~/components/form/fields/TextField' import { SideModalForm } from '~/components/form/SideModalForm' import { getIdpSelector, useIdpSelector } from '~/hooks/use-params' import { DateTime } from '~/ui/lib/DateTime' +import { FormDivider } from '~/ui/lib/Divider' import { PropertiesTable } from '~/ui/lib/PropertiesTable' -import { ResourceLabel } from '~/ui/lib/SideModal' +import { ResourceLabel, SideModal } from '~/ui/lib/SideModal' import { Truncate } from '~/ui/lib/Truncate' import { pb } from '~/util/path-builder' @@ -73,17 +74,28 @@ export function EditIdpSideModalForm() { + + + + Service provider {/* TODO: help text */} + + + + + Identity Provider {/* TODO: help text */} - {/* TODO: Email field, probably */} - ) } diff --git a/app/pages/system/silos/SiloPage.tsx b/app/pages/system/silos/SiloPage.tsx index db8bf4c64..65a634a7d 100644 --- a/app/pages/system/silos/SiloPage.tsx +++ b/app/pages/system/silos/SiloPage.tsx @@ -62,7 +62,12 @@ export function SiloPage() { heading="silos" icon={} summary="Silos provide strict tenancy separation between groups of users. Each silo has its own resource limits and access policies as well as its own subdomain for the web console and API." - links={[docLinks.systemSilo, docLinks.systemIpPools, docLinks.access]} + links={[ + docLinks.systemSilo, + docLinks.identityProviders, + docLinks.systemIpPools, + docLinks.access, + ]} /> diff --git a/app/ui/lib/SideModal.tsx b/app/ui/lib/SideModal.tsx index 63b1d8926..62d478c5e 100644 --- a/app/ui/lib/SideModal.tsx +++ b/app/ui/lib/SideModal.tsx @@ -170,6 +170,8 @@ function SideModalBody({ children }: { children?: ReactNode }) { SideModal.Body = SideModalBody +SideModal.Heading = classed.div`text-sans-semi-xl` + SideModal.Section = classed.div`p-8 space-y-6 border-secondary` SideModal.Footer = ({ children, error }: { children: ReactNode; error?: boolean }) => ( diff --git a/app/util/links.ts b/app/util/links.ts index 48c88d5ee..ef5a5aec4 100644 --- a/app/util/links.ts +++ b/app/util/links.ts @@ -19,6 +19,8 @@ export const links = { imagesDocs: 'https://docs.oxide.computer/guides/creating-and-sharing-images', preparingImagesDocs: 'https://docs.oxide.computer/guides/creating-and-sharing-images#_preparing_images_for_import', + identityProvidersDocs: + 'https://docs.oxide.computer/guides/system/completing-rack-config#_configure_silo_identity_provider', instanceActionsDocs: 'https://docs.oxide.computer/guides/managing-instances', // TODO: link to section instanceBootDiskDocs: 'https://docs.oxide.computer/guides/deploying-workloads', @@ -72,6 +74,10 @@ export const docLinks = { href: links.keyConceptsIamPolicyDocs, linkText: 'Key Concepts', }, + identityProviders: { + href: links.identityProvidersDocs, + linkText: 'Identity Providers', + }, images: { href: links.imagesDocs, linkText: 'Images',