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:
Amit Arora 2023-09-11 12:38:27 +05:30 коммит произвёл GitHub
Родитель 6413c3f1f7
Коммит 28d48702b5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 145 добавлений и 109 удалений

Просмотреть файл

@ -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())
})
})