diff --git a/src/common/routes/port-forwards.ts b/src/common/routes/port-forwards.ts index d05b8583ab..bf644e5003 100644 --- a/src/common/routes/port-forwards.ts +++ b/src/common/routes/port-forwards.ts @@ -23,10 +23,11 @@ import type { RouteProps } from "react-router"; import { buildURL } from "../utils/buildUrl"; export const portForwardsRoute: RouteProps = { - path: "/port-forwards" + path: "/port-forwards/:forwardport?" }; export interface PortForwardsRouteParams { + forwardport?: string; } export const portForwardsURL = buildURL(portForwardsRoute.path); diff --git a/src/renderer/components/+network-port-forwards/port-forward-details.scss b/src/renderer/components/+network-port-forwards/port-forward-details.scss new file mode 100644 index 0000000000..6fcc501884 --- /dev/null +++ b/src/renderer/components/+network-port-forwards/port-forward-details.scss @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +.PortForwardDetails { + .SubTitle { + text-transform: none + } + + .status { + @include port-forward-status-colors; + } +} \ No newline at end of file diff --git a/src/renderer/components/+network-port-forwards/port-forward-details.tsx b/src/renderer/components/+network-port-forwards/port-forward-details.tsx new file mode 100644 index 0000000000..4fa4b395f7 --- /dev/null +++ b/src/renderer/components/+network-port-forwards/port-forward-details.tsx @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import "./port-forward-details.scss"; + +import React from "react"; +import { Link } from "react-router-dom"; +import type { PortForwardItem } from "../../port-forward"; +import { Drawer, DrawerItem } from "../drawer"; +import { cssNames } from "../../utils"; +import { podsApi, serviceApi } from "../../../common/k8s-api/endpoints"; +import { getDetailsUrl } from "../kube-detail-params"; +import { PortForwardMenu } from "./port-forward-menu"; + +interface Props { + portForward: PortForwardItem; + hideDetails(): void; +} + +export class PortForwardDetails extends React.Component { + + renderResourceName() { + const { portForward } = this.props; + const name = portForward.getName(); + const api = { + "service": serviceApi, + "pod": podsApi + }[portForward.kind]; + + if (!api) { + return ( + {name} + ); + } + + return ( + + {name} + + ); + } + + renderContent() { + const { portForward } = this.props; + + if (!portForward) return null; + + return ( +
+ + {this.renderResourceName()} + + + {portForward.getNs()} + + + {portForward.getKind()} + + + {portForward.getPort()} + + + {portForward.getForwardPort()} + + + {portForward.getStatus()} + +
+ ); + } + + render() { + const { hideDetails, portForward } = this.props; + const toolbar = ; + + return ( + + {this.renderContent()} + + ); + } +} diff --git a/src/renderer/components/+network-port-forwards/port-forwards.tsx b/src/renderer/components/+network-port-forwards/port-forwards.tsx index fb5a1e89ac..9fdeec4f6a 100644 --- a/src/renderer/components/+network-port-forwards/port-forwards.tsx +++ b/src/renderer/components/+network-port-forwards/port-forwards.tsx @@ -23,9 +23,13 @@ import "./port-forwards.scss"; import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; +import type { RouteComponentProps } from "react-router-dom"; import { ItemListLayout } from "../item-object-list/item-list-layout"; import { PortForwardItem, portForwardStore } from "../../port-forward"; import { PortForwardMenu } from "./port-forward-menu"; +import { PortForwardsRouteParams, portForwardsURL } from "../../../common/routes"; +import { PortForwardDetails } from "./port-forward-details"; +import { navigation } from "../../navigation"; enum columnId { name = "name", @@ -36,8 +40,11 @@ enum columnId { status = "status", } +interface Props extends RouteComponentProps { +} + @observer -export class PortForwards extends React.Component { +export class PortForwards extends React.Component { componentDidMount() { disposeOnUnmount(this, [ @@ -45,6 +52,32 @@ export class PortForwards extends React.Component { ]); } + get selectedPortForward() { + const { match: { params: { forwardport } } } = this.props; + + return portForwardStore.getById(forwardport); + } + + onDetails = (item: PortForwardItem) => { + if (item === this.selectedPortForward) { + this.hideDetails(); + } else { + this.showDetails(item); + } + }; + + showDetails = (item: PortForwardItem) => { + navigation.push(portForwardsURL({ + params: { + forwardport: String(item.getForwardPort()), + } + })); + }; + + hideDetails = () => { + navigation.push(portForwardsURL()); + }; + renderRemoveDialogMessage(selectedItems: PortForwardItem[]) { const forwardPorts = selectedItems.map(item => item.getForwardPort()).join(", "); @@ -100,7 +133,15 @@ export class PortForwards extends React.Component { customizeRemoveDialog={selectedItems => ({ message: this.renderRemoveDialogMessage(selectedItems) })} + detailsItem={this.selectedPortForward} + onDetails={this.onDetails} /> + {this.selectedPortForward && ( + + )} ); } diff --git a/src/renderer/port-forward/port-forward.store.ts b/src/renderer/port-forward/port-forward.store.ts index 49ebee61d4..7731d5e087 100644 --- a/src/renderer/port-forward/port-forward.store.ts +++ b/src/renderer/port-forward/port-forward.store.ts @@ -81,6 +81,16 @@ export class PortForwardStore extends ItemStore { async removeSelectedItems() { return Promise.all(this.selectedItems.map(removePortForward)); } + + getById(id: string) { + const index = this.getIndexById(id); + + if (index === -1) { + return null; + } + + return this.getItems()[index]; + } } interface PortForwardResult {