зеркало из https://github.com/Azure/ARO-RP.git
Added the Actions Icons on Cluster Detail Page (#3051)
* Added the Actions Icons on Cluster Detail Page * Added Action Icon Button on Cluster Detail Page * Added Action Icon Button on Cluster Detail Page
This commit is contained in:
Родитель
6413c3f1f7
Коммит
28d48702b5
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"files": {
|
||||
"main.js": "/static/js/main.f27c737c.js",
|
||||
"main.js": "/static/js/main.f1999c11.js",
|
||||
"index.html": "/index.html",
|
||||
"main.f27c737c.js.map": "/static/js/main.f27c737c.js.map"
|
||||
"main.f1999c11.js.map": "/static/js/main.f1999c11.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/main.f27c737c.js"
|
||||
"static/js/main.f1999c11.js"
|
||||
]
|
||||
}
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>ARO Portal</title><script defer="defer" src="/static/js/main.f27c737c.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>ARO Portal</title><script defer="defer" src="/static/js/main.f1999c11.js"></script></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -158,7 +158,7 @@ registerIcons({
|
|||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="22"
|
||||
height="22"
|
||||
height="16"
|
||||
style={{ overflow: "visible" }}>
|
||||
<g id="svgg" transform="translate(0.000000,18.000000) scale(0.05000000,-0.05000000)">
|
||||
<path
|
||||
|
@ -331,6 +331,7 @@ function App(props: { params: any }) {
|
|||
<Stack.Item grow>
|
||||
<ClusterDetailPanel
|
||||
csrfToken={csrfRef}
|
||||
sshBox={sshRef}
|
||||
loaded={fetching}
|
||||
currentCluster={currentCluster}
|
||||
onClose={_onCloseDetailPanel}
|
||||
|
@ -343,4 +344,4 @@ function App(props: { params: any }) {
|
|||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
export default App
|
|
@ -16,6 +16,7 @@ import { AxiosResponse } from "axios"
|
|||
import { fetchClusterInfo } from "./Request"
|
||||
import { ICluster, headerStyles } from "./App"
|
||||
import { Nav, INavLink, INavStyles } from "@fluentui/react/lib/Nav"
|
||||
import { ToolIcons } from "./ToolIcons"
|
||||
import { ClusterDetailComponent, MemoisedClusterDetailListComponent } from "./ClusterDetailList"
|
||||
import React from "react"
|
||||
|
||||
|
@ -79,6 +80,7 @@ const errorBarStyles: Partial<IMessageBarStyles> = { root: { marginBottom: 15 }
|
|||
export function ClusterDetailPanel(props: {
|
||||
csrfToken: MutableRefObject<string>
|
||||
currentCluster: ICluster | null
|
||||
sshBox: any
|
||||
onClose: any
|
||||
loaded: string
|
||||
}) {
|
||||
|
@ -183,7 +185,8 @@ export function ClusterDetailPanel(props: {
|
|||
|
||||
const _dismissPanel = () => {
|
||||
dismissPanel()
|
||||
props.onClose() // useEffect?
|
||||
props.sshBox.current.hidePopup()
|
||||
props.onClose()
|
||||
setData([])
|
||||
setFetching("")
|
||||
setDataLoaded(false)
|
||||
|
@ -261,7 +264,7 @@ export function ClusterDetailPanel(props: {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const onRenderHeader = (): ReactElement => {
|
||||
return (
|
||||
<>
|
||||
|
@ -280,7 +283,8 @@ export function ClusterDetailPanel(props: {
|
|||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<div className={headerStyles.titleText}>{props.currentCluster?.name}</div>
|
||||
<div className={headerStyles.subtitleText}>Cluster</div>
|
||||
<div className={headerStyles.subtitleText}>Cluster</div>
|
||||
<ToolIcons resourceId={props.currentCluster? props.currentCluster?.resourceId:""} version={Number(props.currentCluster?.version) !== undefined ? Number(props.currentCluster?.version) : 0} csrfToken={props.csrfToken} sshBox={props.sshBox}/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</>
|
||||
|
@ -321,4 +325,4 @@ export function ClusterDetailPanel(props: {
|
|||
</Stack>
|
||||
</Panel>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useState, useEffect, useRef, MutableRefObject, Component } from "react"
|
||||
import {
|
||||
Stack,
|
||||
IconButton,
|
||||
Stack,
|
||||
MessageBarType,
|
||||
MessageBar,
|
||||
CommandBar,
|
||||
|
@ -9,8 +8,7 @@ import {
|
|||
Separator,
|
||||
Text,
|
||||
IMessageBarStyles,
|
||||
mergeStyleSets,
|
||||
TooltipHost,
|
||||
mergeStyleSets,
|
||||
TextField,
|
||||
Link,
|
||||
Layer,
|
||||
|
@ -27,7 +25,7 @@ import {
|
|||
} from "@fluentui/react/lib/DetailsList"
|
||||
import { useBoolean } from "@fluentui/react-hooks"
|
||||
import { fetchClusters } from "./Request"
|
||||
import { KubeconfigButton } from "./Kubeconfig"
|
||||
import { ToolIcons } from "./ToolIcons"
|
||||
import { AxiosResponse } from "axios"
|
||||
import { ICluster, headerStyles } from "./App"
|
||||
|
||||
|
@ -287,45 +285,8 @@ class ClusterListComponent extends Component<ClusterListComponentProps, ICluster
|
|||
data: "string",
|
||||
isPadded: true,
|
||||
onRender: (item: ICluster) => (
|
||||
<Stack horizontal verticalAlign="center" className={classNames.iconContainer}>
|
||||
<TooltipHost content={`Copy Resource ID`}>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "Copy" }}
|
||||
aria-label="Copy Resource ID"
|
||||
onClick={() => this._onCopyResourceID(item)}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<TooltipHost content={`Prometheus`}>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "BIDashboard" }}
|
||||
aria-label="Prometheus"
|
||||
href={
|
||||
item.resourceId + (+item.version >= 4.11 ? `/prometheus` : `/prometheus/graph`)
|
||||
}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<TooltipHost content={`SSH`}>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "CommandPrompt" }}
|
||||
aria-label="SSH"
|
||||
onClick={() => this._onSSHClick(item)}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<KubeconfigButton resourceId={item.resourceId} csrfToken={props.csrfToken} />
|
||||
{/* <TooltipHost content={`Geneva`}>
|
||||
<IconButton
|
||||
iconProps={{iconName: "Health"}}
|
||||
aria-label="Geneva"
|
||||
href={item.resourceId + `/geneva`}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<TooltipHost content={`Feature Flags`}>
|
||||
<IconButton
|
||||
iconProps={{iconName: "IconSetsFlag"}}
|
||||
aria-label="featureFlags"
|
||||
href={item.resourceId + `/feature-flags`}
|
||||
/>
|
||||
</TooltipHost> */}
|
||||
<Stack horizontal verticalAlign="center" className={classNames.iconContainer}>
|
||||
<ToolIcons resourceId={item.resourceId} csrfToken={props.csrfToken} version={Number(item.version)} sshBox={props.sshModalRef}/>
|
||||
</Stack>
|
||||
),
|
||||
},
|
||||
|
@ -380,17 +341,6 @@ class ClusterListComponent extends Component<ClusterListComponentProps, ICluster
|
|||
})
|
||||
}
|
||||
|
||||
private _onSSHClick(item: any): void {
|
||||
const modal = this._sshModal
|
||||
if (modal && modal.current) {
|
||||
modal.current.LoadSSH(item.resourceId)
|
||||
}
|
||||
}
|
||||
|
||||
private _onCopyResourceID(item: any): void {
|
||||
navigator.clipboard.writeText(item.resourceId)
|
||||
}
|
||||
|
||||
private _onClusterInfoLinkClick(item: ICluster): void {
|
||||
this.props.setCurrentCluster(item)
|
||||
}
|
||||
|
@ -523,4 +473,4 @@ export function ClusterList(props: {
|
|||
/>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import { useId, useBoolean } from "@fluentui/react-hooks"
|
||||
import {
|
||||
Modal,
|
||||
Popup,
|
||||
Layer,
|
||||
getTheme,
|
||||
mergeStyleSets,
|
||||
FontWeights,
|
||||
|
@ -38,10 +39,15 @@ type SSHModalProps = {
|
|||
|
||||
const theme = getTheme()
|
||||
const contentStyles = mergeStyleSets({
|
||||
container: {
|
||||
display: "flex",
|
||||
flexFlow: "column nowrap",
|
||||
alignItems: "stretch",
|
||||
root: {
|
||||
background: 'white',
|
||||
left: '50%',
|
||||
maxWidth: '500px',
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
border: '1px solid #CCC',
|
||||
boxShadow: 'rgba(0, 0, 0, 0.22) 0px 25.6px 57.6px 0px, rgba(0, 0, 0, 0.18) 0px 4.8px 14.4px 0px',
|
||||
},
|
||||
header: [
|
||||
{
|
||||
|
@ -67,6 +73,7 @@ const contentStyles = mergeStyleSets({
|
|||
},
|
||||
})
|
||||
|
||||
|
||||
const iconButtonStyles = {
|
||||
root: {
|
||||
color: theme.palette.neutralPrimary,
|
||||
|
@ -83,8 +90,7 @@ const sshDocs: string =
|
|||
"https://msazure.visualstudio.com/AzureRedHatOpenShift/_wiki/wikis/ARO.wiki/136823/ARO-SRE-portal?anchor=ssh-(elevated)"
|
||||
|
||||
export const SSHModal = forwardRef<any, SSHModalProps>(({ csrfToken }, ref) => {
|
||||
const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false)
|
||||
|
||||
const [isPopupVisible, { setTrue: showPopup, setFalse: hidePopup }] = useBoolean(false);
|
||||
const titleId = useId("title")
|
||||
const [update, { setTrue: requestSSH, setFalse: sshRequested }] = useBoolean(false)
|
||||
const [resourceID, setResourceID] = useState("")
|
||||
|
@ -98,9 +104,9 @@ export const SSHModal = forwardRef<any, SSHModalProps>(({ csrfToken }, ref) => {
|
|||
setUnrequestable()
|
||||
setData(null)
|
||||
setError(null)
|
||||
showModal()
|
||||
showPopup()
|
||||
setResourceID(item)
|
||||
},
|
||||
},hidePopup
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -207,33 +213,37 @@ export const SSHModal = forwardRef<any, SSHModalProps>(({ csrfToken }, ref) => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<Modal
|
||||
titleAriaId={titleId}
|
||||
isOpen={isModalOpen}
|
||||
onDismiss={hideModal}
|
||||
isModeless={true}
|
||||
containerClassName={contentStyles.container}>
|
||||
<div className={contentStyles.header} id="sshModal">
|
||||
<span id={titleId}>SSH Access</span>
|
||||
<IconButton
|
||||
styles={iconButtonStyles}
|
||||
iconProps={cancelIcon}
|
||||
ariaLabel="Close popup modal"
|
||||
onClick={hideModal}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={contentStyles.body}>
|
||||
<p>
|
||||
Before requesting SSH access, please ensure you have read the{" "}
|
||||
<a href={sshDocs}>SSH docs</a>.
|
||||
</p>
|
||||
{error && errorBar()}
|
||||
{data ? dataResult() : selectionField()}
|
||||
</div>
|
||||
</Modal>
|
||||
{isPopupVisible && (
|
||||
<Layer>
|
||||
<Popup
|
||||
className={contentStyles.root}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
onDismiss={hidePopup}
|
||||
enableAriaHiddenSiblings={true}
|
||||
>
|
||||
<div className={contentStyles.header} id="sshModal">
|
||||
<span id={titleId}>SSH Access</span>
|
||||
<IconButton
|
||||
styles={iconButtonStyles}
|
||||
iconProps={cancelIcon}
|
||||
ariaLabel="Close popup modal"
|
||||
onClick={hidePopup}
|
||||
/>
|
||||
</div>
|
||||
<div className={contentStyles.body}>
|
||||
<p>
|
||||
Before requesting SSH access, please ensure you have read the{" "}
|
||||
<a href={sshDocs}>SSH docs</a>.
|
||||
</p>
|
||||
{error && errorBar()}
|
||||
{data ? dataResult() : selectionField()}
|
||||
</div>
|
||||
</Popup>
|
||||
</Layer>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
SSHModal.displayName = "sshmodal"
|
||||
SSHModal.displayName = "sshmodal"
|
|
@ -7,9 +7,11 @@ import { useRef } from "react"
|
|||
import { forwardRef } from "react"
|
||||
import { parse as parseContentDisposition } from "content-disposition"
|
||||
|
||||
type KubeconfigButtonProps = {
|
||||
type ToolIconsProps = {
|
||||
csrfToken: MutableRefObject<string>
|
||||
resourceId: string
|
||||
version: number
|
||||
sshBox: any
|
||||
}
|
||||
|
||||
type FileDownload = {
|
||||
|
@ -17,8 +19,8 @@ type FileDownload = {
|
|||
content: string
|
||||
}
|
||||
|
||||
export const KubeconfigButton = forwardRef<any, KubeconfigButtonProps>(
|
||||
({ csrfToken, resourceId }) => {
|
||||
export const ToolIcons = forwardRef<any, ToolIconsProps>(
|
||||
({ csrfToken, resourceId, version, sshBox }) => {
|
||||
const [data, setData] = useState<FileDownload>({ name: "", content: "" })
|
||||
const [error, setError] = useState<AxiosResponse | null>(null)
|
||||
const [fetching, setFetching] = useState("DONE")
|
||||
|
@ -44,6 +46,17 @@ export const KubeconfigButton = forwardRef<any, KubeconfigButtonProps>(
|
|||
}
|
||||
}, [fetching, error, data, resourceId, csrfToken])
|
||||
|
||||
const _onCopyResourceID = (resourceId: any) => {
|
||||
navigator.clipboard.writeText(resourceId)
|
||||
}
|
||||
|
||||
const _onSSHClick = (resourceId: any) => {
|
||||
const modal = sshBox
|
||||
if (modal && modal.current) {
|
||||
modal.current.LoadSSH(resourceId)
|
||||
}
|
||||
}
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (data.content && buttonRef && buttonRef.current) {
|
||||
buttonRef.current.href = data.content
|
||||
|
@ -56,6 +69,29 @@ export const KubeconfigButton = forwardRef<any, KubeconfigButtonProps>(
|
|||
|
||||
return (
|
||||
<>
|
||||
<TooltipHost content={`Copy Resource ID`}>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "Copy" }}
|
||||
aria-label="Copy Resource ID"
|
||||
onClick={_onCopyResourceID.bind({},resourceId)}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<TooltipHost content={`Prometheus`}>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "BIDashboard" }}
|
||||
aria-label="Prometheus"
|
||||
href={
|
||||
resourceId + (+(version) >= 4.11 ? `/prometheus` : `/prometheus/graph`)
|
||||
}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<TooltipHost content={`SSH`}>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "CommandPrompt" }}
|
||||
aria-label="SSH"
|
||||
onClick={() => _onSSHClick(resourceId)}
|
||||
/>
|
||||
</TooltipHost>
|
||||
<TooltipHost content={`Download Kubeconfig`}>
|
||||
<IconButton
|
||||
iconProps={{ iconName: "kubernetes-svg" }}
|
||||
|
@ -72,4 +108,4 @@ export const KubeconfigButton = forwardRef<any, KubeconfigButtonProps>(
|
|||
}
|
||||
)
|
||||
|
||||
KubeconfigButton.displayName = "kubeconfigbutton"
|
||||
ToolIcons.displayName = "toolicons"
|
|
@ -443,4 +443,39 @@ var _ = Describe("Admin Portal E2E Testing", func() {
|
|||
SaveScreenshotAndExit(wd, err)
|
||||
}
|
||||
})
|
||||
|
||||
It("Should display the action icons on cluster detail page", func() {
|
||||
wd.Get(host + "/" + "?resourceid=" + resourceIDFromEnv())
|
||||
wd.WaitWithTimeout(conditions.ElementIsLocated(selenium.ByID, "ClusterDetailPanel"), time.Second*3)
|
||||
|
||||
detailPanel, err := wd.FindElement(selenium.ByID, "ClusterDetailPanel")
|
||||
if err != nil {
|
||||
SaveScreenshotAndExit(wd, err)
|
||||
}
|
||||
Expect(detailPanel.IsDisplayed()).To(BeTrue())
|
||||
|
||||
resourceButton, err := wd.FindElement(selenium.ByCSSSelector, "button[aria-label='Copy Resource ID']")
|
||||
if err != nil {
|
||||
SaveScreenshotAndExit(wd, err)
|
||||
}
|
||||
Expect(resourceButton.IsDisplayed()).To(BeTrue())
|
||||
|
||||
prometheusButton, err := wd.FindElement(selenium.ByCSSSelector, "a[aria-label='Prometheus']")
|
||||
if err != nil {
|
||||
SaveScreenshotAndExit(wd, err)
|
||||
}
|
||||
Expect(prometheusButton.IsDisplayed()).To(BeTrue())
|
||||
|
||||
sshbutton, err := wd.FindElement(selenium.ByCSSSelector, "button[aria-label='SSH']")
|
||||
if err != nil {
|
||||
SaveScreenshotAndExit(wd, err)
|
||||
}
|
||||
Expect(sshbutton.IsDisplayed()).To(BeTrue())
|
||||
|
||||
kubeconfigButton, err := wd.FindElement(selenium.ByCSSSelector, "button[aria-label='Download Kubeconfig']")
|
||||
if err != nil {
|
||||
SaveScreenshotAndExit(wd, err)
|
||||
}
|
||||
Expect(kubeconfigButton.IsDisplayed()).To(BeTrue())
|
||||
})
|
||||
})
|
||||
|
|
Загрузка…
Ссылка в новой задаче