Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
web: add custom navbar button support (#4723)
Render `Global:nav` buttons in the global nav. User-defined buttons show up first, then the built-ins (Tilt version, snapshot, help, account). The backend enforces that `Global:nav` buttons have an icon defined, though there is no practical way on either backend or frontend to determine that the icon name is valid; if it's not a real material icon, you'll get a blank space, so it should be fairly straightforward to debug regardless. Log output (via backend) ends up in the `(global)` span viewable by "All Resources" in the web interface.
- Loading branch information
Showing
8 changed files
with
133 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { Icon } from "@material-ui/core" | ||
import moment from "moment" | ||
import React, { useState } from "react" | ||
import { InstrumentedButton } from "./instrumentedComponents" | ||
|
||
type UIButton = Proto.v1alpha1UIButton | ||
|
||
type ApiButtonProps = { className?: string; button: UIButton } | ||
|
||
export const ApiButton: React.FC<ApiButtonProps> = (props) => { | ||
const [loading, setLoading] = useState(false) | ||
const onClick = async () => { | ||
const toUpdate = { | ||
metadata: { ...props.button.metadata }, | ||
status: { ...props.button.status }, | ||
} as UIButton | ||
// apiserver's date format time is _extremely_ strict to the point that it requires the full | ||
// six-decimal place microsecond precision, e.g. .000Z will be rejected, it must be .000000Z | ||
// so use an explicit RFC3339 moment format to ensure it passes | ||
toUpdate.status!.lastClickedAt = moment().format( | ||
"YYYY-MM-DDTHH:mm:ss.SSSSSSZ" | ||
) | ||
|
||
// TODO(milas): currently the loading state just disables the button for the duration of | ||
// the AJAX request to avoid duplicate clicks - there is no progress tracking at the | ||
// moment, so there's no fancy spinner animation or propagation of result of action(s) | ||
// that occur as a result of click right now | ||
setLoading(true) | ||
const url = `/proxy/apis/tilt.dev/v1alpha1/uibuttons/${ | ||
toUpdate.metadata!.name | ||
}/status` | ||
try { | ||
await fetch(url, { | ||
method: "PUT", | ||
headers: { | ||
Accept: "application/json", | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify(toUpdate), | ||
}) | ||
} finally { | ||
setLoading(false) | ||
} | ||
} | ||
// button text is not included in analytics name since that can be user data | ||
return ( | ||
<InstrumentedButton | ||
analyticsName={"ui.web.uibutton"} | ||
onClick={onClick} | ||
disabled={loading} | ||
className={props.className} | ||
> | ||
{props.children || ( | ||
<> | ||
{props.button.spec?.iconName && ( | ||
<Icon>{props.button.spec?.iconName}</Icon> | ||
)} | ||
{props.button.spec?.text ?? "Button"} | ||
</> | ||
)} | ||
</InstrumentedButton> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { Icon } from "@material-ui/core" | ||
import React from "react" | ||
import styled from "styled-components" | ||
import { ApiButton } from "./ApiButton" | ||
import { MenuButtonLabel, MenuButtonMixin } from "./GlobalNav" | ||
|
||
type CustomNavProps = { | ||
view: Proto.webviewView | ||
} | ||
|
||
const CustomNavButton = styled(ApiButton)` | ||
${MenuButtonMixin} | ||
.apibtn-label { | ||
display: none; | ||
} | ||
` | ||
|
||
export function CustomNav(props: CustomNavProps) { | ||
const buttons = | ||
props.view.uiButtons?.filter( | ||
(b) => | ||
b.spec?.location && | ||
(b.spec.location.componentType ?? "").toLowerCase() === "global" && | ||
(b.spec.location.componentID ?? "").toLowerCase() === "nav" | ||
) || [] | ||
|
||
return ( | ||
<React.Fragment> | ||
{buttons.map((b) => ( | ||
<CustomNavButton key={b.metadata?.name} button={b}> | ||
<Icon>{b.spec?.iconName}</Icon> | ||
<MenuButtonLabel>{b.spec?.text}</MenuButtonLabel> | ||
</CustomNavButton> | ||
))} | ||
</React.Fragment> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters