feat: show user-auth provisioners (#14883)

Closes https://github.com/coder/coder/issues/14867

What this changes:
- Displays `user-auth` grouped provisioners
- Added tags to provisioners in cases where it matters

<img width="1378" alt="image"
src="https://github.com/user-attachments/assets/ecc8da0a-24b4-469d-99e7-aa1f183046b7">

---------

Co-authored-by: Ben Potter <ben@coder.com>
Co-authored-by: McKayla Washburn <mckayla@hey.com>
This commit is contained in:
Garrett Delfosse
2024-10-01 13:12:30 -04:00
committed by GitHub
parent 21b92ef893
commit 533d655ac0
5 changed files with 61 additions and 30 deletions

View File

@ -147,9 +147,13 @@ func (api *API) provisionerKeyDaemons(rw http.ResponseWriter, r *http.Request) {
pkDaemons := []codersdk.ProvisionerKeyDaemons{}
for _, key := range sdkKeys {
// currently we exclude user-auth from this list
// The key.OrganizationID for the `user-auth` key is hardcoded to
// the default org in the database and we are overwriting it here
// to be the correct org we used to query the list.
// This will be changed when we update the `user-auth` keys to be
// directly tied to a user ID.
if key.ID.String() == codersdk.ProvisionerKeyIDUserAuth {
continue
key.OrganizationID = organization.ID
}
daemons := []codersdk.ProvisionerDaemon{}
for _, daemon := range recentDaemons {

View File

@ -27,7 +27,7 @@ import { createDayString } from "utils/createDayString";
import { docs } from "utils/docs";
import { ProvisionerTag } from "./ProvisionerTag";
type ProvisionerGroupType = "builtin" | "psk" | "key";
type ProvisionerGroupType = "builtin" | "userAuth" | "psk" | "key";
interface ProvisionerGroupProps {
readonly buildInfo: BuildInfoResponse;
@ -103,7 +103,8 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
: `${provisionersWithWarnings} provisioners`;
const hasMultipleTagVariants =
type === "psk" && provisioners.some((it) => !isSimpleTagSet(it.tags));
(type === "psk" || type === "userAuth") &&
provisioners.some((it) => !isSimpleTagSet(it.tags));
return (
<div
@ -143,6 +144,8 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
</>
)}
{type === "userAuth" && <UserAuthProvisionerTitle />}
{type === "psk" && <PskProvisionerTitle />}
{type === "key" && (
<h4 css={styles.groupTitle}>Key group &ndash; {keyName}</h4>
@ -249,7 +252,7 @@ export const ProvisionerGroup: FC<ProvisionerGroupProps> = ({
</span>
</div>
{hasMultipleTagVariants && (
<PskProvisionerTags tags={provisioner.tags} />
<InlineProvisionerTags tags={provisioner.tags} />
)}
</Stack>
</div>
@ -335,11 +338,11 @@ const ProvisionerVersionPopover: FC<ProvisionerVersionPopoverProps> = ({
);
};
interface PskProvisionerTagsProps {
interface InlineProvisionerTagsProps {
tags: Record<string, string>;
}
const PskProvisionerTags: FC<PskProvisionerTagsProps> = ({ tags }) => {
const InlineProvisionerTags: FC<InlineProvisionerTagsProps> = ({ tags }) => {
const daemonScope = tags.scope || "organization";
const iconScope =
daemonScope === "organization" ? <BusinessIcon /> : <PersonIcon />;
@ -413,6 +416,30 @@ const BuiltinProvisionerTitle: FC = () => {
);
};
const UserAuthProvisionerTitle: FC = () => {
return (
<h4 css={styles.groupTitle}>
<Stack direction="row" alignItems="end" spacing={1}>
<span>User-authenticated provisioners</span>
<HelpTooltip>
<HelpTooltipTrigger />
<HelpTooltipContent>
<HelpTooltipTitle>User-authenticated provisioners</HelpTooltipTitle>
<HelpTooltipText>
These provisioners are connected by users using the{" "}
<code>coder</code> CLI, and are authorized by the users
credentials. They can be tagged to only run provisioner jobs for
that user. User-authenticated provisioners are only available for
the default organization.{" "}
<Link href={docs("/")}>Learn more&hellip;</Link>
</HelpTooltipText>
</HelpTooltipContent>
</HelpTooltip>
</Stack>
</h4>
);
};
const PskProvisionerTitle: FC = () => {
return (
<h4 css={styles.groupTitle}>

View File

@ -7,6 +7,7 @@ import {
MockProvisionerBuiltinKey,
MockProvisionerKey,
MockProvisionerPskKey,
MockProvisionerUserAuthKey,
MockProvisionerWithTags,
MockUserProvisioner,
mockApiError,
@ -79,6 +80,17 @@ export const Provisioners: Story = {
name: `ケイラ-${i}`,
})),
},
{
key: MockProvisionerUserAuthKey,
daemons: [
MockUserProvisioner,
{
...MockUserProvisioner,
id: "mock-user-provisioner-2",
name: "Test User Provisioner 2",
},
],
},
],
},
play: async ({ step }) => {

View File

@ -110,28 +110,16 @@ const ViewContent: FC<ViewContentProps> = ({ buildInfo, provisioners }) => {
</div>
)}
<Stack spacing={4.5}>
{provisioners.map((group) => {
const type = getGroupType(group.key);
// We intentionally hide user-authenticated provisioners for now
// because there are 1. some grouping issues on the backend and 2. we
// should ideally group them by the user who authenticated them, and
// not just lump them all together.
if (type === "userAuth") {
return null;
}
return (
<ProvisionerGroup
key={group.key.id}
buildInfo={buildInfo}
keyName={group.key.name}
keyTags={group.key.tags}
type={type}
provisioners={group.daemons}
/>
);
})}
{provisioners.map((group) => (
<ProvisionerGroup
key={group.key.id}
buildInfo={buildInfo}
keyName={group.key.name}
keyTags={group.key.tags}
type={getGroupType(group.key)}
provisioners={group.daemons}
/>
))}
</Stack>
</>
);

View File

@ -610,7 +610,7 @@ export const MockProvisioner2: TypesGen.ProvisionerDaemon = {
};
export const MockUserProvisioner: TypesGen.ProvisionerDaemon = {
...MockProvisioner,
...MockUserAuthProvisioner,
id: "test-user-provisioner",
name: "Test User Provisioner",
tags: { scope: "user", owner: "12345678-abcd-1234-abcd-1234567890abcd" },