mirror of
https://github.com/tale/headplane.git
synced 2026-08-24 19:46:29 +00:00
feat: swap button and decompose dialog components
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import Dialog from "~/components/Dialog";
|
||||
import Button from "~/components/button";
|
||||
import Dialog, { DialogPanel } from "~/components/Dialog";
|
||||
import Input from "~/components/Input";
|
||||
import Text from "~/components/Text";
|
||||
import Title from "~/components/Title";
|
||||
|
||||
interface CreateUserProps {
|
||||
isOidc?: boolean;
|
||||
@@ -9,15 +12,15 @@ interface CreateUserProps {
|
||||
export default function CreateUser({ isOidc, isDisabled }: CreateUserProps) {
|
||||
return (
|
||||
<Dialog>
|
||||
<Dialog.Button isDisabled={isDisabled}>Add user</Dialog.Button>
|
||||
<Dialog.Panel>
|
||||
<Dialog.Title>Create a Headscale user</Dialog.Title>
|
||||
<Dialog.Text className="mb-6">
|
||||
<Button isDisabled={isDisabled}>Add user</Button>
|
||||
<DialogPanel>
|
||||
<Title>Create a Headscale user</Title>
|
||||
<Text className="mb-6">
|
||||
This creates a new user in Headscale. The user will appear in the “Unlinked
|
||||
Headscale Users” section until they sign in
|
||||
{isOidc ? " through your OIDC provider" : ""} and are automatically linked to a Headplane
|
||||
account.
|
||||
</Dialog.Text>
|
||||
</Text>
|
||||
<input name="action_id" type="hidden" value="create_user" />
|
||||
<div className="flex flex-col gap-4">
|
||||
<Input
|
||||
@@ -54,7 +57,7 @@ export default function CreateUser({ isOidc, isDisabled }: CreateUserProps) {
|
||||
validationBehavior="native"
|
||||
/>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import Dialog from "~/components/Dialog";
|
||||
import Dialog, { DialogPanel } from "~/components/Dialog";
|
||||
import Text from "~/components/Text";
|
||||
import Title from "~/components/Title";
|
||||
import type { Machine, User } from "~/types";
|
||||
|
||||
interface DeleteProps {
|
||||
@@ -13,15 +15,15 @@ export default function DeleteUser({ user, machines, isOpen, setIsOpen }: Delete
|
||||
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<Dialog.Panel variant={machines.length > 0 ? "unactionable" : "normal"}>
|
||||
<Dialog.Title>Delete {name}?</Dialog.Title>
|
||||
<DialogPanel variant={machines.length > 0 ? "unactionable" : "normal"}>
|
||||
<Title>Delete {name}?</Title>
|
||||
{machines.length > 0 ? (
|
||||
<Dialog.Text className="mb-6">
|
||||
<Text className="mb-6">
|
||||
Users cannot be deleted if they have machines. Please delete or re-assign their machines
|
||||
to other users before proceeding.
|
||||
</Dialog.Text>
|
||||
</Text>
|
||||
) : (
|
||||
<Dialog.Text className="mb-6">
|
||||
<Text className="mb-6">
|
||||
Deleted users cannot be recovered.
|
||||
{user.provider === "oidc" && (
|
||||
<p className="mt-4 text-sm text-mist-600 dark:text-mist-300">
|
||||
@@ -29,11 +31,11 @@ export default function DeleteUser({ user, machines, isOpen, setIsOpen }: Delete
|
||||
they sign in again.
|
||||
</p>
|
||||
)}
|
||||
</Dialog.Text>
|
||||
</Text>
|
||||
)}
|
||||
<input name="action_id" type="hidden" value="delete_user" />
|
||||
<input name="user_id" type="hidden" value={user.id} />
|
||||
</Dialog.Panel>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import Dialog from "~/components/Dialog";
|
||||
import Dialog, { DialogPanel } from "~/components/Dialog";
|
||||
import Notice from "~/components/Notice";
|
||||
import Text from "~/components/Text";
|
||||
import Title from "~/components/Title";
|
||||
import cn from "~/utils/cn";
|
||||
|
||||
interface LinkUserProps {
|
||||
@@ -21,12 +23,12 @@ export default function LinkUser({
|
||||
}: LinkUserProps) {
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<Dialog.Panel>
|
||||
<Dialog.Title>Link Headscale user for {displayName}</Dialog.Title>
|
||||
<Dialog.Text className="mb-6">
|
||||
<DialogPanel>
|
||||
<Title>Link Headscale user for {displayName}</Title>
|
||||
<Text className="mb-6">
|
||||
Select which Headscale user this identity should be linked to. This controls which
|
||||
machines they can manage and enables self-service features.
|
||||
</Dialog.Text>
|
||||
</Text>
|
||||
{headscaleUsers.length === 0 ? (
|
||||
<Notice>All Headscale users are already linked to other accounts.</Notice>
|
||||
) : (
|
||||
@@ -53,7 +55,7 @@ export default function LinkUser({
|
||||
</select>
|
||||
</>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import Dialog from "~/components/Dialog";
|
||||
import Dialog, { DialogPanel } from "~/components/Dialog";
|
||||
import Link from "~/components/link";
|
||||
import Notice from "~/components/Notice";
|
||||
import RadioGroup from "~/components/RadioGroup";
|
||||
import Text from "~/components/Text";
|
||||
import Title from "~/components/Title";
|
||||
import { Roles } from "~/server/web/roles";
|
||||
import type { Role } from "~/server/web/roles";
|
||||
|
||||
@@ -22,15 +24,15 @@ export default function ReassignUser({
|
||||
}: ReassignProps) {
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<Dialog.Panel variant={role === "owner" ? "unactionable" : "normal"}>
|
||||
<Dialog.Title>Change role for {displayName}?</Dialog.Title>
|
||||
<Dialog.Text className="mb-6">
|
||||
<DialogPanel variant={role === "owner" ? "unactionable" : "normal"}>
|
||||
<Title>Change role for {displayName}?</Title>
|
||||
<Text className="mb-6">
|
||||
Roles control what the user can access in Headplane. Each role grants a specific set of
|
||||
capabilities.{" "}
|
||||
<Link external styled to="https://tailscale.com/kb/1138/user-roles">
|
||||
Learn More
|
||||
</Link>
|
||||
</Dialog.Text>
|
||||
</Text>
|
||||
{role === "owner" ? (
|
||||
<Notice>The Tailnet owner cannot be reassigned.</Notice>
|
||||
) : (
|
||||
@@ -60,7 +62,7 @@ export default function ReassignUser({
|
||||
</RadioGroup>
|
||||
</>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
import Dialog from '~/components/Dialog';
|
||||
import Input from '~/components/Input';
|
||||
import { User } from '~/types';
|
||||
import Dialog, { DialogPanel } from "~/components/Dialog";
|
||||
import Input from "~/components/Input";
|
||||
import Text from "~/components/Text";
|
||||
import Title from "~/components/Title";
|
||||
import { User } from "~/types";
|
||||
|
||||
interface RenameProps {
|
||||
user: User;
|
||||
isOpen: boolean;
|
||||
setIsOpen: (isOpen: boolean) => void;
|
||||
user: User;
|
||||
isOpen: boolean;
|
||||
setIsOpen: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
// TODO: Server side validation before submitting
|
||||
export default function RenameUser({ user, isOpen, setIsOpen }: RenameProps) {
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<Dialog.Panel>
|
||||
<Dialog.Title>Rename {user.name || user.displayName}?</Dialog.Title>
|
||||
<Dialog.Text className="mb-6">
|
||||
Enter a new username for {user.name || user.displayName}. Changing a
|
||||
username will not update any ACL policies that may refer to this user
|
||||
by their old username.
|
||||
</Dialog.Text>
|
||||
<input name="action_id" type="hidden" value="rename_user" />
|
||||
<input name="user_id" type="hidden" value={user.id} />
|
||||
<Input
|
||||
defaultValue={user.name}
|
||||
isRequired
|
||||
label="Username"
|
||||
name="new_name"
|
||||
placeholder="my-new-name"
|
||||
/>
|
||||
</Dialog.Panel>
|
||||
</Dialog>
|
||||
);
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<DialogPanel>
|
||||
<Title>Rename {user.name || user.displayName}?</Title>
|
||||
<Text className="mb-6">
|
||||
Enter a new username for {user.name || user.displayName}. Changing a username will not
|
||||
update any ACL policies that may refer to this user by their old username.
|
||||
</Text>
|
||||
<input name="action_id" type="hidden" value="rename_user" />
|
||||
<input name="user_id" type="hidden" value={user.id} />
|
||||
<Input
|
||||
defaultValue={user.name}
|
||||
isRequired
|
||||
label="Username"
|
||||
name="new_name"
|
||||
placeholder="my-new-name"
|
||||
/>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import Dialog from "~/components/Dialog";
|
||||
import Dialog, { DialogPanel } from "~/components/Dialog";
|
||||
import Notice from "~/components/Notice";
|
||||
import Text from "~/components/Text";
|
||||
import Title from "~/components/Title";
|
||||
|
||||
interface TransferOwnershipProps {
|
||||
targetUserId: string;
|
||||
@@ -16,19 +18,19 @@ export default function TransferOwnership({
|
||||
}: TransferOwnershipProps) {
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<Dialog.Panel variant="destructive">
|
||||
<Dialog.Title>Transfer ownership to {targetDisplayName}?</Dialog.Title>
|
||||
<Dialog.Text className="mb-6">
|
||||
<DialogPanel variant="destructive">
|
||||
<Title>Transfer ownership to {targetDisplayName}?</Title>
|
||||
<Text className="mb-6">
|
||||
This will make {targetDisplayName} the new owner of this Headplane instance. You will be
|
||||
demoted to an Admin. This action cannot be easily undone.
|
||||
</Dialog.Text>
|
||||
</Text>
|
||||
<Notice variant="warning">
|
||||
Only the owner can transfer ownership. After this, you will no longer be able to manage
|
||||
ownership.
|
||||
</Notice>
|
||||
<input name="action_id" type="hidden" value="transfer_ownership" />
|
||||
<input name="user_id" type="hidden" value={targetUserId} />
|
||||
</Dialog.Panel>
|
||||
</DialogPanel>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user