Line data Source code
1 : /*
2 : * Copyright (C) 2019 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 39 : import React from 'react';
6 :
7 : import { Button, type ButtonProps } from "@patternfly/react-core/dist/esm/components/Button/index.js";
8 : import { Tooltip, TooltipPosition } from "@patternfly/react-core/dist/esm/components/Tooltip/index.js";
9 :
10 39 : import cockpit from "cockpit";
11 : import { superuser } from 'superuser';
12 : import { useEvent, useLoggedInUser } from "hooks";
13 :
14 : /**
15 : * UI element wrapper for something that requires privilege. When access is not
16 : * allowed, then wrap the element into a Tooltip.
17 : *
18 : * Note that the wrapped element itself needs to be disabled explicitly, this
19 : * wrapper cannot do this (unfortunately wrapping it into a disabled span does
20 : * not inherit).
21 : */
22 37 : export function Privileged({
23 37 : excuse,
24 37 : allowed,
25 37 : placement,
26 37 : tooltipId,
27 37 : children
28 37 : }: {
29 : excuse: React.ReactNode;
30 : allowed: boolean | null;
31 : placement?: TooltipPosition | `${TooltipPosition}` | undefined;
32 : tooltipId?: string | undefined;
33 : children: React.ReactNode;
34 37 : }) {
35 : // wrap into extra <span> so that a disabled child keeps the tooltip working
36 30 : let contents = <span id={allowed ? undefined : tooltipId}>{ children }</span>;
37 36 : if (!allowed) {
38 36 : contents = (
39 36 : <Tooltip position={ placement || TooltipPosition.top} id={ tooltipId + "_tooltip" }
40 36 : content={ excuse }>
41 36 : { contents }
42 36 : </Tooltip>);
43 36 : }
44 37 : return contents;
45 37 : }
46 :
47 : /**
48 : * Convenience element for a Privilege wrapped Button
49 : */
50 25 : export const PrivilegedButton = ({
51 25 : tooltipId,
52 25 : placement,
53 25 : excuse,
54 25 : buttonId,
55 25 : onClick,
56 25 : ariaLabel,
57 25 : variant,
58 25 : isDanger,
59 25 : children
60 25 : }: {
61 : excuse: string; // must contain a $0, replaced with user name
62 : onClick?: React.MouseEventHandler<HTMLButtonElement>;
63 : variant?: ButtonProps["variant"];
64 : isDanger?: boolean;
65 : placement?: TooltipPosition | `${TooltipPosition}` | undefined;
66 : buttonId?: string;
67 : tooltipId?: string;
68 : ariaLabel?: string;
69 : children: React.ReactNode;
70 25 : }) => {
71 25 : const user = useLoggedInUser();
72 25 : useEvent(superuser, "changed");
73 :
74 25 : return (
75 25 : <Privileged allowed={ superuser.allowed } tooltipId={ tooltipId } placement={ placement }
76 4 : excuse={ cockpit.format(excuse, user?.name ?? '') }>
77 25 : <Button isInline isDisabled={ !superuser.allowed }
78 25 : {...(buttonId !== undefined && { id: buttonId })}
79 25 : {...(variant !== undefined && { variant })}
80 4 : {...(isDanger !== undefined && { isDanger })}
81 25 : {...(onClick !== undefined && { onClick })}
82 4 : {...(ariaLabel !== undefined && { "aria-label": ariaLabel })}
83 : >
84 25 : { children }
85 25 : </Button>
86 25 : </Privileged>
87 : );
88 25 : };
|