From 7032c214f3b450993157e2b3dca24638630bb8a7 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Fri, 1 Sep 2023 15:25:32 -0500 Subject: [PATCH 1/8] feat: Add a Web Shell terminal to Pod's Container Cards Signed-off-by: Carlos Esteban Lopez Update .changeset/forty-rocks-jog.md Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo fix: Address PR comments Signed-off-by: Carlos Esteban Lopez fix: Use sh instead of bash Signed-off-by: Carlos Esteban Lopez fix: Move K8sTerminal into a dialog Signed-off-by: Carlos Esteban Lopez fix: Use discoveryApi instead of configApi Signed-off-by: Carlos Esteban Lopez fix: Update api-report.md Signed-off-by: Carlos Esteban Lopez fix: Revert PodDrawer.tsx Signed-off-by: Carlos Esteban Lopez test: Polyfill TextEncoder Signed-off-by: Carlos Esteban Lopez feat: Refactor K8sTerminal inputs to receive only what it needs Signed-off-by: Carlos Esteban Lopez test: Add tests Signed-off-by: Carlos Esteban Lopez Update plugins/kubernetes/src/components/K8sTerminal/K8sTerminal.test.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo test: Fix tests for K8sTerminal Signed-off-by: Carlos Esteban Lopez test: Fix isolated modules error Signed-off-by: Carlos Esteban Lopez fix: Update api reports Signed-off-by: Carlos Esteban Lopez Update plugins/kubernetes/src/components/K8sTerminal/K8sTerminalDialog.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo Update plugins/kubernetes/src/components/K8sTerminal/K8sTerminal.test.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo fix: Check for cluster size 1 & small refactors Signed-off-by: Carlos Esteban Lopez chore: Update changeset Signed-off-by: Carlos Esteban Lopez fix: Check client side auth providers to disable web shell Signed-off-by: Carlos Esteban Lopez fix: Move K8sAPI logic to custom hook with mock Signed-off-by: Carlos Esteban Lopez test: Fix hook mock warning & add internal tag for mock Signed-off-by: Carlos Esteban Lopez Update plugins/kubernetes/src/components/K8sTerminal/K8sTerminal.test.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo Update .changeset/forty-rocks-jog.md Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo Update plugins/kubernetes/src/components/K8sTerminal/K8sTerminal.test.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo refactor: Rename stuff as requested in PR Signed-off-by: Carlos Esteban Lopez chore: Update API Reports Signed-off-by: Carlos Esteban Lopez test: Fix mocked hook that was renamed Signed-off-by: Carlos Esteban Lopez --- .changeset/forty-rocks-jog.md | 6 + packages/app/src/setupTests.ts | 6 + .../test-utils/src/testUtils/appWrappers.tsx | 3 +- plugins/kubernetes/api-report.md | 20 +++ plugins/kubernetes/package.json | 7 +- .../PodExecTerminal/PodExecTerminal.test.tsx | 97 +++++++++++++ .../PodExecTerminal/PodExecTerminal.tsx | 131 ++++++++++++++++++ .../PodExecTerminalAttachAddon.ts | 46 ++++++ .../PodExecTerminal/PodExecTerminalDialog.tsx | 110 +++++++++++++++ .../src/components/PodExecTerminal/index.ts | 17 +++ .../PodExecTerminal/matchMedia.mock.ts | 31 +++++ .../Pods/PodDrawer/ContainerCard.test.tsx | 2 + .../Pods/PodDrawer/ContainerCard.tsx | 23 +-- .../Pods/PodDrawer/PodDrawer.test.tsx | 107 +++++++------- plugins/kubernetes/src/components/index.ts | 1 + .../useIsPodExecTerminalSupported.ts | 20 +++ plugins/kubernetes/src/hooks/index.ts | 1 + .../useIsPodExecTerminalSupported.test.ts | 83 +++++++++++ .../hooks/useIsPodExecTerminalSupported.ts | 43 ++++++ yarn.lock | 104 ++++++++++---- 20 files changed, 769 insertions(+), 89 deletions(-) create mode 100644 .changeset/forty-rocks-jog.md create mode 100644 plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx create mode 100644 plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx create mode 100644 plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts create mode 100644 plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx create mode 100644 plugins/kubernetes/src/components/PodExecTerminal/index.ts create mode 100644 plugins/kubernetes/src/components/PodExecTerminal/matchMedia.mock.ts create mode 100644 plugins/kubernetes/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts create mode 100644 plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.test.ts create mode 100644 plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts diff --git a/.changeset/forty-rocks-jog.md b/.changeset/forty-rocks-jog.md new file mode 100644 index 0000000000..aff3d34a4a --- /dev/null +++ b/.changeset/forty-rocks-jog.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes': patch +'@backstage/test-utils': patch +--- + +Add pod exec terminal to Container Card diff --git a/packages/app/src/setupTests.ts b/packages/app/src/setupTests.ts index 23fcbe9676..d6dc983b17 100644 --- a/packages/app/src/setupTests.ts +++ b/packages/app/src/setupTests.ts @@ -19,3 +19,9 @@ // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom'; + +// Do not remove, patching jsdom environment to support TextEncoder, refer to https://github.com/jsdom/jsdom/issues/2524 +// eslint-disable-next-line no-restricted-imports +import { TextEncoder } from 'util'; + +global.TextEncoder = TextEncoder; diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index 6545cc312a..0aec9ff4f8 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -255,7 +255,8 @@ export const textContentMatcher = return false; } - const hasText = (textNode: Element) => textNode?.textContent === text; + const hasText = (textNode: Element) => + textNode?.textContent?.includes(text) ?? false; const childrenDontHaveText = (containerNode: Element) => Array.from(containerNode?.children).every(child => !hasText(child)); diff --git a/plugins/kubernetes/api-report.md b/plugins/kubernetes/api-report.md index 3c91de02ac..f29d2fb958 100644 --- a/plugins/kubernetes/api-report.md +++ b/plugins/kubernetes/api-report.md @@ -347,6 +347,18 @@ export const JobsAccordions: ({ jobs, }: JobsAccordionsProps) => React_2.JSX.Element; +// @public +export interface K8sTerminalProps { + // (undocumented) + clusterName: string; + // (undocumented) + containerName: string; + // (undocumented) + podName: string; + // (undocumented) + podNamespace: string; +} + // Warning: (ae-missing-release-tag) "KubernetesApi" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -631,6 +643,14 @@ export const PodDrawer: ({ open, }: PodDrawerProps) => React_2.JSX.Element; +// @public +export const PodExecTerminal: (props: K8sTerminalProps) => React_2.JSX.Element; + +// @public +export const PodExecTerminalDialog: ( + props: K8sTerminalProps, +) => React_2.JSX.Element; + // @public export const PodLogs: React_2.FC; diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 865ba42106..a40b589b14 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -53,7 +53,10 @@ "kubernetes-models": "^4.1.0", "lodash": "^4.17.21", "luxon": "^3.0.0", - "react-use": "^17.2.4" + "react-use": "^17.2.4", + "xterm": "^5.2.1", + "xterm-addon-attach": "^0.8.0", + "xterm-addon-fit": "^0.7.0" }, "peerDependencies": { "react": "^16.13.1 || ^17.0.0", @@ -70,6 +73,8 @@ "@testing-library/react": "^12.1.3", "@testing-library/react-hooks": "^8.0.0", "@testing-library/user-event": "^14.0.0", + "@types/node": "^16.11.26", + "jest-websocket-mock": "^2.4.1", "msw": "^1.0.0" }, "files": [ diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx new file mode 100644 index 0000000000..c634321a7d --- /dev/null +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx @@ -0,0 +1,97 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import './matchMedia.mock'; +import '@testing-library/jest-dom'; + +import { DiscoveryApi, discoveryApiRef } from '@backstage/core-plugin-api'; +import { + renderWithEffects, + TestApiProvider, + textContentMatcher, + wrapInTestApp, +} from '@backstage/test-utils'; +import { waitFor } from '@testing-library/react'; +import WS from 'jest-websocket-mock'; +import React from 'react'; + +import { PodExecTerminal } from './PodExecTerminal'; + +const textEncoder = new TextEncoder(); + +describe('K8sTerminal', () => { + const clusterName = 'cluster1'; + const containerName = 'container2'; + const podName = 'pod1'; + const podNamespace = 'podNamespace'; + + const mockDiscoveryApi: Partial = { + getBaseUrl: () => Promise.resolve('http://localhost'), + }; + + it('Should render an XTerm web terminal', async () => { + const { getByText } = await renderWithEffects( + wrapInTestApp( + + + , + ), + ); + + expect( + getByText(textContentMatcher('Starting terminal, please wait...')), + ).toBeInTheDocument(); + }); + + it('Should connect to WebSocket server & render response', async () => { + const server = new WS( + 'ws://localhost/proxy/api/v1/namespaces/podNamespace/pods/pod1/exec?container=container2&stdin=true&stdout=true&stderr=true&tty=true&command=%2Fbin%2Fsh', + ); + + const { getByText } = await renderWithEffects( + wrapInTestApp( + + + , + ), + ); + + // xterm uses a "W" character as a "measure element" -- if it exists, the terminal rendered correctly + expect(getByText(textContentMatcher('W'))).toBeInTheDocument(); + + await server.connected; + + const { buffer } = Uint8Array.from([ + 1, + ...textEncoder.encode('hello world'), + ]); + + server.send(buffer); + + await waitFor(() => + expect(getByText(textContentMatcher('hello world'))).toBeInTheDocument(), + ); + }); +}); diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx new file mode 100644 index 0000000000..204f8fca59 --- /dev/null +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx @@ -0,0 +1,131 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import 'xterm/css/xterm.css'; + +import { discoveryApiRef, useApi } from '@backstage/core-plugin-api'; +import React, { useEffect, useMemo, useState } from 'react'; +import { Terminal } from 'xterm'; +import { FitAddon } from 'xterm-addon-fit'; + +import { PodExecTerminalAttachAddon } from './PodExecTerminalAttachAddon'; + +/** + * Props drilled down to the K8sTerminal component + * + * @public + */ +export interface K8sTerminalProps { + clusterName: string; + containerName: string; + podName: string; + podNamespace: string; +} + +const hasSocketProtocol = (url: string | URL) => + /wss?:\/\//.test(url.toString()); + +/** + * Opens a Terminal shell to the given pod's container in a Dialog + * + * @public + */ +export const PodExecTerminal = (props: K8sTerminalProps) => { + const { containerName, podNamespace, podName } = props; + + const [baseUrl, setBaseUrl] = useState(window.location.host); + + const terminalRef = React.useRef(null); + const discoveryApi = useApi(discoveryApiRef); + const namespace = podNamespace ?? 'default'; + + useEffect(() => { + discoveryApi + .getBaseUrl('kubernetes') + .then(url => url ?? window.location.host) + .then(url => url.replace(/^http(s?):\/\//, 'ws$1://')) + .then(url => setBaseUrl(url)); + }, [discoveryApi]); + + const urlParams = useMemo(() => { + const params = new URLSearchParams({ + container: containerName, + stdin: 'true', + stdout: 'true', + stderr: 'true', + tty: 'true', + command: '/bin/sh', + }); + return params; + }, [containerName]); + + const socketUrl = useMemo(() => { + if (!hasSocketProtocol(baseUrl)) { + return ''; + } + + return new URL( + `${baseUrl}/proxy/api/v1/namespaces/${namespace}/pods/${podName}/exec?${urlParams}`, + ); + }, [baseUrl, namespace, podName, urlParams]); + + useEffect(() => { + if (!hasSocketProtocol(socketUrl)) { + return () => {}; + } + + const terminal = new Terminal(); + const fitAddon = new FitAddon(); + terminal.loadAddon(fitAddon); + + if (terminalRef.current) { + terminal.open(terminalRef.current); + fitAddon.fit(); + } + + terminal.writeln('Starting terminal, please wait...'); + + const socket = new WebSocket(socketUrl, ['channel.k8s.io']); + + socket.onopen = () => { + terminal.clear(); + const attachAddon = new PodExecTerminalAttachAddon(socket, { + bidirectional: true, + }); + + terminal.loadAddon(attachAddon); + }; + + socket.onclose = () => { + terminal.writeln('Socket connection closed'); + }; + + return () => { + terminal?.clear(); + socket?.close(); + }; + }, [baseUrl, socketUrl]); + + return ( +
+ ); +}; diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts new file mode 100644 index 0000000000..fb80472f73 --- /dev/null +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalAttachAddon.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { AttachAddon, IAttachOptions } from 'xterm-addon-attach'; + +const textEncoder = new TextEncoder(); + +export class PodExecTerminalAttachAddon extends AttachAddon { + constructor(socket: WebSocket, options?: IAttachOptions) { + super(socket, options); + + const thisAddon = this as any; + + // These methods are private in the original AttachAddon, + // thus have to override at runtime like this + thisAddon._sendBinary = (data: string) => { + if (!thisAddon._checkOpenSocket()) { + return; + } + + const buffer = Uint8Array.from([0, ...textEncoder.encode(data)]); + + thisAddon._socket.send(buffer); + }; + + thisAddon._sendData = (data: string) => { + if (!thisAddon._checkOpenSocket()) { + return; + } + + thisAddon._sendBinary(data); + }; + } +} diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx new file mode 100644 index 0000000000..4c250168cc --- /dev/null +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx @@ -0,0 +1,110 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + Button, + createStyles, + Dialog, + DialogContent, + DialogTitle, + IconButton, + makeStyles, + Theme, +} from '@material-ui/core'; +import CloseIcon from '@material-ui/icons/Close'; +import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; +import React, { useState } from 'react'; + +import { useIsPodExecTerminalSupported } from '../../hooks'; +import { PodExecTerminal, K8sTerminalProps } from './PodExecTerminal'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + dialogPaper: { minHeight: 'calc(100% - 64px)' }, + dialogContent: { flexBasis: 0 }, + closeButton: { + position: 'absolute', + right: theme.spacing(1), + top: theme.spacing(1), + color: theme.palette.grey[500], + }, + }), +); + +/** + * Opens a Terminal shell to the given pod's container in a Dialog + * + * @public + */ +export const PodExecTerminalDialog = (props: K8sTerminalProps) => { + const classes = useStyles(); + const { clusterName, containerName, podName } = props; + + const [open, setOpen] = useState(false); + + const isPodExecTerminalSupported = useIsPodExecTerminalSupported(); + + const openDialog = () => { + setOpen(true); + }; + + const closeDialog = () => { + setOpen(false); + }; + + return ( + <> + {!isPodExecTerminalSupported.loading && + isPodExecTerminalSupported.value && ( + + + {podName} - {containerName} terminal shell on cluster{' '} + {clusterName} + + + + + + + + + )} + + + + ); +}; diff --git a/plugins/kubernetes/src/components/PodExecTerminal/index.ts b/plugins/kubernetes/src/components/PodExecTerminal/index.ts new file mode 100644 index 0000000000..2581a35669 --- /dev/null +++ b/plugins/kubernetes/src/components/PodExecTerminal/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './PodExecTerminal'; +export * from './PodExecTerminalDialog'; diff --git a/plugins/kubernetes/src/components/PodExecTerminal/matchMedia.mock.ts b/plugins/kubernetes/src/components/PodExecTerminal/matchMedia.mock.ts new file mode 100644 index 0000000000..52661d07e8 --- /dev/null +++ b/plugins/kubernetes/src/components/PodExecTerminal/matchMedia.mock.ts @@ -0,0 +1,31 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); + +export {}; diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.test.tsx b/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.test.tsx index 7bc7c989ed..bdea9dd0be 100644 --- a/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.test.tsx +++ b/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.test.tsx @@ -22,6 +22,8 @@ import { wrapInTestApp } from '@backstage/test-utils'; import { ContainerCard } from './ContainerCard'; import { DateTime } from 'luxon'; +jest.mock('../../../hooks/useIsPodExecTerminalSupported'); + const now = DateTime.now(); const oneHourAgo = now.minus({ hours: 1 }).toISO(); const twoHoursAgo = now.minus({ hours: 2 }).toISO(); diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.tsx b/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.tsx index 44a9c57ae5..db70f92160 100644 --- a/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.tsx +++ b/plugins/kubernetes/src/components/Pods/PodDrawer/ContainerCard.tsx @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; - -import { IContainer, IContainerStatus } from 'kubernetes-models/v1'; +import { StructuredMetadataTable } from '@backstage/core-components'; +import { ClientContainerStatus } from '@backstage/plugin-kubernetes-common'; import { Card, CardActions, @@ -24,14 +23,14 @@ import { Grid, Typography, } from '@material-ui/core'; - +import { IContainer, IContainerStatus } from 'kubernetes-models/v1'; import { DateTime } from 'luxon'; +import React from 'react'; -import { PodScope, PodLogsDialog } from '../PodLogs'; -import { StructuredMetadataTable } from '@backstage/core-components'; -import { ClientContainerStatus } from '@backstage/plugin-kubernetes-common'; -import { ResourceUtilization } from '../../ResourceUtilization'; import { bytesToMiB, formatMillicores } from '../../../utils/resources'; +import { PodExecTerminalDialog } from '../../PodExecTerminal/PodExecTerminalDialog'; +import { ResourceUtilization } from '../../ResourceUtilization'; +import { PodLogsDialog, PodScope } from '../PodLogs'; const getContainerHealthChecks = ( containerSpec: IContainer, @@ -222,13 +221,19 @@ export const ContainerCard: React.FC = ({ )} - + + ); diff --git a/plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.test.tsx b/plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.test.tsx index 9dcb77018b..393b834392 100644 --- a/plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.test.tsx +++ b/plugins/kubernetes/src/components/Pods/PodDrawer/PodDrawer.test.tsx @@ -17,66 +17,75 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInTestApp } from '@backstage/test-utils'; +import { TestApiProvider, wrapInTestApp } from '@backstage/test-utils'; import '@testing-library/jest-dom'; import { PodDrawer } from '.'; +import { DiscoveryApi, discoveryApiRef } from '@backstage/core-plugin-api'; + +jest.mock('../../../hooks/useIsPodExecTerminalSupported'); describe('PodDrawer', () => { it('Should show title and container names', async () => { + const mockDiscoveryApi: Partial = { + getBaseUrl: () => Promise.resolve('http://localhost'), + }; + const { getAllByText, getByText } = render( wrapInTestApp( - + , + errors: [ + { + type: 'some-error', + severity: 10, + message: 'some error message', + occurrenceCount: 1, + sourceRef: { + name: 'some-pod', + namespace: 'some-namespace', + kind: 'Pod', + apiGroup: 'v1', + }, + proposedFix: [ + { + type: 'logs', + container: 'some-container', + errorType: 'some error type', + rootCauseExplanation: 'some root cause', + actions: ['fix1', 'fix2'], + }, + ], + }, + ], + }, + } as any)} + /> + , ), ); diff --git a/plugins/kubernetes/src/components/index.ts b/plugins/kubernetes/src/components/index.ts index e0583a1f9e..18b75247e5 100644 --- a/plugins/kubernetes/src/components/index.ts +++ b/plugins/kubernetes/src/components/index.ts @@ -27,3 +27,4 @@ export * from './Pods'; export * from './ServicesAccordions'; export * from './KubernetesContent'; export * from './ResourceUtilization'; +export * from './PodExecTerminal'; diff --git a/plugins/kubernetes/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts b/plugins/kubernetes/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts new file mode 100644 index 0000000000..e1dc3b4fc5 --- /dev/null +++ b/plugins/kubernetes/src/hooks/__mocks__/useIsPodExecTerminalSupported.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { AsyncState } from 'react-use/lib/useAsync'; + +export const useIsPodExecTerminalSupported: () => AsyncState = jest.fn( + () => ({ loading: false, value: false } as AsyncState), +); diff --git a/plugins/kubernetes/src/hooks/index.ts b/plugins/kubernetes/src/hooks/index.ts index 12400132aa..141bc3815b 100644 --- a/plugins/kubernetes/src/hooks/index.ts +++ b/plugins/kubernetes/src/hooks/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './useIsPodExecTerminalSupported'; export * from './useKubernetesObjects'; export * from './useCustomResources'; export * from './PodNamesWithErrors'; diff --git a/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.test.ts b/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.test.ts new file mode 100644 index 0000000000..1772e0d4f2 --- /dev/null +++ b/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useApi } from '@backstage/core-plugin-api'; +import { renderHook } from '@testing-library/react-hooks'; + +import { useIsPodExecTerminalSupported } from './useIsPodExecTerminalSupported'; + +jest.mock('@backstage/core-plugin-api'); + +describe('useIsClusterShellEnabled', () => { + let clusters: { authProvider: string }[] = []; + + beforeEach(() => { + (useApi as any).mockReturnValue({ + getClusters: () => Promise.resolve(clusters), + }); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it.each([ + { + condition: 'valid Shell setup', + returnValue: true, + testClusters: [{ authProvider: 'localKubectlProxy' }], + }, + { condition: 'clusters empty', returnValue: false, testClusters: [] }, + { + condition: 'multi cluster setup', + returnValue: false, + testClusters: [ + { authProvider: 'localKubectlProxy' }, + { authProvider: 'serviceAccount' }, + ], + }, + { + condition: 'AuthProvider is aks', + returnValue: false, + testClusters: [{ authProvider: 'aks' }], + }, + { + condition: 'AuthProvider is google', + returnValue: false, + testClusters: [{ authProvider: 'google' }], + }, + { + condition: 'AuthProvider start with oidc', + returnValue: false, + testClusters: [{ authProvider: 'oidc.okta' }], + }, + ])( + 'Should return $returnValue if $condition', + async ({ testClusters, returnValue }) => { + clusters = testClusters; + + const { result, waitForNextUpdate } = renderHook(() => + useIsPodExecTerminalSupported(), + ); + + expect(result.current.loading).toEqual(true); + + await waitForNextUpdate(); + + expect(result.current.loading).toEqual(false); + expect(result.current.value).toBe(returnValue); + }, + ); +}); diff --git a/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts b/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts new file mode 100644 index 0000000000..b68b45fe19 --- /dev/null +++ b/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts @@ -0,0 +1,43 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { useApi } from '@backstage/core-plugin-api'; +import useAsync, { AsyncState } from 'react-use/lib/useAsync'; + +import { kubernetesApiRef } from '../api'; + +/** + * Check if conditions for K8sTerminal through K8sProxy are met + * + * @internal + */ +export const useIsPodExecTerminalSupported = (): AsyncState => { + const kubernetesApi = useApi(kubernetesApiRef); + + return useAsync(async () => { + const clusters = await kubernetesApi.getClusters(); + + if (clusters.length !== 1) { + return false; + } + + const { authProvider } = clusters[0]; + const isClientAuthProvider = ['aks', 'google', 'oidc'].some( + authProviderName => authProvider.includes(authProviderName), + ); + + return !isClientAuthProvider; + }); +}; diff --git a/yarn.lock b/yarn.lock index 51e3d9e383..33e955b776 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7653,12 +7653,16 @@ __metadata: "@testing-library/user-event": ^14.0.0 "@types/react": ^16.13.1 || ^17.0.0 cronstrue: ^2.2.0 + jest-websocket-mock: ^2.4.1 js-yaml: ^4.0.0 kubernetes-models: ^4.1.0 lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 react-use: ^17.2.4 + xterm: ^5.2.1 + xterm-addon-attach: ^0.8.0 + xterm-addon-fit: ^0.7.0 peerDependencies: react: ^16.13.1 || ^17.0.0 react-dom: ^16.13.1 || ^17.0.0 @@ -12564,12 +12568,12 @@ __metadata: languageName: node linkType: hard -"@jest/schemas@npm:^29.4.3": - version: 29.4.3 - resolution: "@jest/schemas@npm:29.4.3" +"@jest/schemas@npm:^29.4.3, @jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" dependencies: - "@sinclair/typebox": ^0.25.16 - checksum: ac754e245c19dc39e10ebd41dce09040214c96a4cd8efa143b82148e383e45128f24599195ab4f01433adae4ccfbe2db6574c90db2862ccd8551a86704b5bebd + "@sinclair/typebox": ^0.27.8 + checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 languageName: node linkType: hard @@ -15035,10 +15039,10 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.25.16": - version: 0.25.23 - resolution: "@sinclair/typebox@npm:0.25.23" - checksum: 5720daec6e604be9ac849e6361cfa30d19f4d01934c9b79a3a5f5290dfcefaa300192ea0d384bb5dd0104432d88447bbad27adfacdf0b0f042b510bf15fbd5db +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 languageName: node linkType: hard @@ -23829,10 +23833,10 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^29.4.3": - version: 29.4.3 - resolution: "diff-sequences@npm:29.4.3" - checksum: 28b265e04fdddcf7f9f814effe102cc95a9dec0564a579b5aed140edb24fc345c611ca52d76d725a3cab55d3888b915b5e8a4702e0f6058968a90fa5f41fcde7 +"diff-sequences@npm:^29.6.3": + version: 29.6.3 + resolution: "diff-sequences@npm:29.6.3" + checksum: f4914158e1f2276343d98ff5b31fc004e7304f5470bf0f1adb2ac6955d85a531a6458d33e87667f98f6ae52ebd3891bb47d420bb48a5bd8b7a27ee25b20e33aa languageName: node linkType: hard @@ -29850,15 +29854,15 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-diff@npm:29.4.3" +"jest-diff@npm:^29.2.0, jest-diff@npm:^29.4.3": + version: 29.6.3 + resolution: "jest-diff@npm:29.6.3" dependencies: chalk: ^4.0.0 - diff-sequences: ^29.4.3 - jest-get-type: ^29.4.3 - pretty-format: ^29.4.3 - checksum: 877fd1edffef6b319688c27b152e5b28e2bc4bcda5ce0ca90d7e137f9fafda4280bae25403d4c0bfd9806c2c0b15d966aa2dfaf5f9928ec8f1ccea7fa1d08ed6 + diff-sequences: ^29.6.3 + jest-get-type: ^29.6.3 + pretty-format: ^29.6.3 + checksum: 23b0a88efeab36566386f059f3da340754d2860969cbc34805154e2377714e37e3130e21a791fc68008fb460bbf5edd7ec43c16d96d15797b32ccfae5160fe37 languageName: node linkType: hard @@ -29926,10 +29930,10 @@ __metadata: languageName: node linkType: hard -"jest-get-type@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-get-type@npm:29.4.3" - checksum: 6ac7f2dde1c65e292e4355b6c63b3a4897d7e92cb4c8afcf6d397f2682f8080e094c8b0b68205a74d269882ec06bf696a9de6cd3e1b7333531e5ed7b112605ce +"jest-get-type@npm:^29.4.3, jest-get-type@npm:^29.6.3": + version: 29.6.3 + resolution: "jest-get-type@npm:29.6.3" + checksum: 88ac9102d4679d768accae29f1e75f592b760b44277df288ad76ce5bf038c3f5ce3719dea8aa0f035dac30e9eb034b848ce716b9183ad7cc222d029f03e92205 languageName: node linkType: hard @@ -30230,6 +30234,16 @@ __metadata: languageName: node linkType: hard +"jest-websocket-mock@npm:^2.4.1": + version: 2.4.1 + resolution: "jest-websocket-mock@npm:2.4.1" + dependencies: + jest-diff: ^29.2.0 + mock-socket: ^9.1.0 + checksum: 5091bfc1baef36146ea1d0f7e16c591d8f8cd9604b7daaeb3d61d98cb1034f4ea3825c122477eb15d55f7d7fe6ec93a8e7b58d54f39838238d7345675d0afb37 + languageName: node + linkType: hard + "jest-when@npm:^3.1.0": version: 3.6.0 resolution: "jest-when@npm:3.6.0" @@ -33417,6 +33431,13 @@ __metadata: languageName: node linkType: hard +"mock-socket@npm:^9.1.0": + version: 9.2.1 + resolution: "mock-socket@npm:9.2.1" + checksum: daf07689563163dbcefbefe23b2a9784a75d0af31706f23ad535c6ab2abbcdefa2e91acddeb50a3c39009139e47a8f909cbb38e8137452193ccb9331637fee3e + languageName: node + linkType: hard + "moment@npm:^2.29.1": version: 2.29.4 resolution: "moment@npm:2.29.4" @@ -36308,14 +36329,14 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.4.3": - version: 29.4.3 - resolution: "pretty-format@npm:29.4.3" +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.4.3, pretty-format@npm:^29.6.3": + version: 29.6.3 + resolution: "pretty-format@npm:29.6.3" dependencies: - "@jest/schemas": ^29.4.3 + "@jest/schemas": ^29.6.3 ansi-styles: ^5.0.0 react-is: ^18.0.0 - checksum: 3258b9a010bd79b3cf73783ad1e4592b6326fc981b6e31b742f316f14e7fbac09b48a9dbf274d092d9bde404db9fe16f518370e121837dc078a597392e6e5cc5 + checksum: 4e1c0db48e65571c22e80ff92123925ff8b3a2a89b71c3a1683cfde711004d492de32fe60c6bc10eea8bf6c678e5cbe544ac6c56cb8096e1eb7caf856928b1c4 languageName: node linkType: hard @@ -43360,6 +43381,31 @@ __metadata: languageName: node linkType: hard +"xterm-addon-attach@npm:^0.8.0": + version: 0.8.0 + resolution: "xterm-addon-attach@npm:0.8.0" + peerDependencies: + xterm: ^5.0.0 + checksum: 2ac70bdd1c97eb05b83b4573132ed9d3686c07ed14212e273800a5693bb0f3ea41c570b49ac90cb95a1e593d5a2764a28c13b649c596054bf5aa87c8489069eb + languageName: node + linkType: hard + +"xterm-addon-fit@npm:^0.7.0": + version: 0.7.0 + resolution: "xterm-addon-fit@npm:0.7.0" + peerDependencies: + xterm: ^5.0.0 + checksum: 512d41f80d6f9427ba02dab4e6fd642e94775a9cf7ef72ae4b55eab2a36856b5c67069bfc66b4af412fdce29a0842f9c6382af3672f0b514c4352dfd47defe8f + languageName: node + linkType: hard + +"xterm@npm:^5.2.1": + version: 5.2.1 + resolution: "xterm@npm:5.2.1" + checksum: 3a9de30e772c7ae30895ec97fcfb3b0906429c5ea0cddf8948e8e30301385f82e467c6e6aca28ae50a48300ce795381d83fe35b4e17886ab4a1357054a15f68f + languageName: node + linkType: hard + "y18n@npm:^4.0.0": version: 4.0.3 resolution: "y18n@npm:4.0.3" From 6da1a1e74b69fd49deafe555f575b3352feb75df Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Fri, 1 Sep 2023 16:07:50 -0500 Subject: [PATCH 2/8] chore: Update lock file Signed-off-by: Carlos Esteban Lopez --- yarn.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn.lock b/yarn.lock index 33e955b776..ab8855bbef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7651,6 +7651,7 @@ __metadata: "@testing-library/react": ^12.1.3 "@testing-library/react-hooks": ^8.0.0 "@testing-library/user-event": ^14.0.0 + "@types/node": ^16.11.26 "@types/react": ^16.13.1 || ^17.0.0 cronstrue: ^2.2.0 jest-websocket-mock: ^2.4.1 From b5e3733987603aa50286938a23ee40e184fcbb91 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Jaramillo Date: Tue, 5 Sep 2023 10:06:58 -0500 Subject: [PATCH 3/8] Update plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo --- .../src/components/PodExecTerminal/PodExecTerminal.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx index c634321a7d..00be5c453c 100644 --- a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.test.tsx @@ -31,7 +31,7 @@ import { PodExecTerminal } from './PodExecTerminal'; const textEncoder = new TextEncoder(); -describe('K8sTerminal', () => { +describe('PodExecTerminal', () => { const clusterName = 'cluster1'; const containerName = 'container2'; const podName = 'pod1'; From d421fea9c978be6333ab56ca83f0a4a6433eb41a Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Jaramillo Date: Tue, 5 Sep 2023 10:07:49 -0500 Subject: [PATCH 4/8] Update plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo --- .../src/components/PodExecTerminal/PodExecTerminal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx index 204f8fca59..bd0cbe39ad 100644 --- a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx @@ -38,7 +38,7 @@ const hasSocketProtocol = (url: string | URL) => /wss?:\/\//.test(url.toString()); /** - * Opens a Terminal shell to the given pod's container in a Dialog + * Executes a `/bin/sh` process in the given pod's container and opens a terminal connected to it * * @public */ From ea09246e40d2308ff2cd2f2c40d1b11f1aad899e Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Jaramillo Date: Tue, 5 Sep 2023 10:08:34 -0500 Subject: [PATCH 5/8] Update plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo --- plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts b/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts index b68b45fe19..17f64bf0dd 100644 --- a/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts +++ b/plugins/kubernetes/src/hooks/useIsPodExecTerminalSupported.ts @@ -19,7 +19,7 @@ import useAsync, { AsyncState } from 'react-use/lib/useAsync'; import { kubernetesApiRef } from '../api'; /** - * Check if conditions for K8sTerminal through K8sProxy are met + * Check if conditions for a pod exec call through the proxy endpoint are met * * @internal */ From eb9fdf1187d6d829ee127ece519c6598dab2293d Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Jaramillo Date: Tue, 5 Sep 2023 10:08:50 -0500 Subject: [PATCH 6/8] Update plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx Co-authored-by: Jamie Klassen Signed-off-by: Carlos Esteban Lopez Jaramillo --- .../src/components/PodExecTerminal/PodExecTerminalDialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx index 4c250168cc..b793cd7eb9 100644 --- a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx @@ -44,7 +44,7 @@ const useStyles = makeStyles((theme: Theme) => ); /** - * Opens a Terminal shell to the given pod's container in a Dialog + * Opens a terminal connected to the given pod's container in a dialog * * @public */ From 8127cc5fa4ba2973908d4c71d10d0c20cdc8095d Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Tue, 5 Sep 2023 10:13:20 -0500 Subject: [PATCH 7/8] fix: Finish rename refactors suggested in PR Signed-off-by: Carlos Esteban Lopez --- .../src/components/PodExecTerminal/PodExecTerminal.tsx | 6 +++--- .../components/PodExecTerminal/PodExecTerminalDialog.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx index bd0cbe39ad..a741f4e189 100644 --- a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminal.tsx @@ -23,11 +23,11 @@ import { FitAddon } from 'xterm-addon-fit'; import { PodExecTerminalAttachAddon } from './PodExecTerminalAttachAddon'; /** - * Props drilled down to the K8sTerminal component + * Props drilled down to the PodExecTerminal component * * @public */ -export interface K8sTerminalProps { +export interface PodExecTerminalProps { clusterName: string; containerName: string; podName: string; @@ -42,7 +42,7 @@ const hasSocketProtocol = (url: string | URL) => * * @public */ -export const PodExecTerminal = (props: K8sTerminalProps) => { +export const PodExecTerminal = (props: PodExecTerminalProps) => { const { containerName, podNamespace, podName } = props; const [baseUrl, setBaseUrl] = useState(window.location.host); diff --git a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx index b793cd7eb9..5ed8c8c0d1 100644 --- a/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx +++ b/plugins/kubernetes/src/components/PodExecTerminal/PodExecTerminalDialog.tsx @@ -28,7 +28,7 @@ import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; import React, { useState } from 'react'; import { useIsPodExecTerminalSupported } from '../../hooks'; -import { PodExecTerminal, K8sTerminalProps } from './PodExecTerminal'; +import { PodExecTerminal, PodExecTerminalProps } from './PodExecTerminal'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -48,7 +48,7 @@ const useStyles = makeStyles((theme: Theme) => * * @public */ -export const PodExecTerminalDialog = (props: K8sTerminalProps) => { +export const PodExecTerminalDialog = (props: PodExecTerminalProps) => { const classes = useStyles(); const { clusterName, containerName, podName } = props; From 99b692072265ae443c05e5b7ff472a010ae5d6da Mon Sep 17 00:00:00 2001 From: Carlos Esteban Lopez Date: Tue, 5 Sep 2023 11:30:07 -0500 Subject: [PATCH 8/8] chore: Update API Reports Signed-off-by: Carlos Esteban Lopez --- plugins/kubernetes/api-report.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/plugins/kubernetes/api-report.md b/plugins/kubernetes/api-report.md index f29d2fb958..77ec8dd19c 100644 --- a/plugins/kubernetes/api-report.md +++ b/plugins/kubernetes/api-report.md @@ -347,18 +347,6 @@ export const JobsAccordions: ({ jobs, }: JobsAccordionsProps) => React_2.JSX.Element; -// @public -export interface K8sTerminalProps { - // (undocumented) - clusterName: string; - // (undocumented) - containerName: string; - // (undocumented) - podName: string; - // (undocumented) - podNamespace: string; -} - // Warning: (ae-missing-release-tag) "KubernetesApi" is part of the package's API, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -644,13 +632,27 @@ export const PodDrawer: ({ }: PodDrawerProps) => React_2.JSX.Element; // @public -export const PodExecTerminal: (props: K8sTerminalProps) => React_2.JSX.Element; +export const PodExecTerminal: ( + props: PodExecTerminalProps, +) => React_2.JSX.Element; // @public export const PodExecTerminalDialog: ( - props: K8sTerminalProps, + props: PodExecTerminalProps, ) => React_2.JSX.Element; +// @public +export interface PodExecTerminalProps { + // (undocumented) + clusterName: string; + // (undocumented) + containerName: string; + // (undocumented) + podName: string; + // (undocumented) + podNamespace: string; +} + // @public export const PodLogs: React_2.FC;