Line data Source code
1 : /*
2 : * Copyright (C) 2019 Red Hat, Inc.
3 : * SPDX-License-Identifier: LGPL-2.1-or-later
4 : */
5 138 : 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 138 : 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 127 : export function Privileged({
23 127 : excuse,
24 127 : allowed,
25 127 : placement,
26 127 : tooltipId,
27 127 : children
28 127 : }: {
29 : excuse: React.ReactNode;
30 : allowed: boolean | null;
31 : placement?: TooltipPosition | `${TooltipPosition}` | undefined;
32 : tooltipId?: string | undefined;
33 : children: React.ReactNode;
34 127 : }) {
35 : // wrap into extra <span> so that a disabled child keeps the tooltip working
36 71 : let contents = <span id={allowed ? undefined : tooltipId}>{ children }</span>;
37 100 : if (!allowed) {
38 100 : contents = (
39 100 : <Tooltip position={ placement || TooltipPosition.top} id={ tooltipId + "_tooltip" }
40 100 : content={ excuse }>
41 100 : { contents }
42 100 : </Tooltip>);
43 100 : }
44 127 : return contents;
45 127 : }
46 :
47 : /**
48 : * Convenience element for a Privilege wrapped Button
49 : */
50 74 : export const PrivilegedButton = ({
51 74 : tooltipId,
52 74 : placement,
53 74 : excuse,
54 74 : buttonId,
55 74 : onClick,
56 74 : ariaLabel,
57 74 : variant,
58 74 : isDanger,
59 74 : children
60 74 : }: {
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 74 : }) => {
71 74 : const user = useLoggedInUser();
72 74 : useEvent(superuser, "changed");
73 :
74 74 : return (
75 74 : <Privileged allowed={ superuser.allowed } tooltipId={ tooltipId } placement={ placement }
76 12 : excuse={ cockpit.format(excuse, user?.name ?? '') }>
77 74 : <Button isInline isDisabled={ !superuser.allowed }
78 74 : {...(buttonId !== undefined && { id: buttonId })}
79 74 : {...(variant !== undefined && { variant })}
80 12 : {...(isDanger !== undefined && { isDanger })}
81 74 : {...(onClick !== undefined && { onClick })}
82 12 : {...(ariaLabel !== undefined && { "aria-label": ariaLabel })}
83 : >
84 74 : { children }
85 74 : </Button>
86 74 : </Privileged>
87 : );
88 74 : };
|