UNPKG

@kui-shell/plugin-kubectl

Version:

Kubernetes visualization plugin for kubernetes

295 lines (293 loc) 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireDefault(require("react")); var _Icons = _interopRequireDefault(require("@kui-shell/plugin-client-common/mdist/components/spi/Icons")); var _Select = _interopRequireDefault(require("@kui-shell/plugin-client-common/mdist/components/spi/Select")); var _TextWithIconWidget = _interopRequireDefault(require("@kui-shell/plugin-client-common/mdist/components/Client/StatusStripe/TextWithIconWidget")); var _core = require("@kui-shell/core"); var _CurrentContext = require("./CurrentContext"); var _heuristics = require("@kui-shell/plugin-kubectl/heuristics"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * Copyright 2020 The Kubernetes 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. */ var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; const strings = (0, _core.i18n)('plugin-kubectl'); class CurrentNamespace extends _react.default.PureComponent { constructor(props) { super(props); this.handler = this.reportCurrentNamespace.bind(this); this.handlerForCommandComplete = this.reportCurrentNamespaceFromCommandComplete.bind(this); this.handlerNotCallingKubectl = this.getCurrentNamespaceFromTab.bind(this); /** So we don't handle events after unmounting */ this._unmounted = true; this.state = { currentNamespace: null, allNamespaces: [], viewLevel: 'loading' }; } /** @return a short string that we can fit into a context UI widget */ renderNamespace(context) { return context.metadata.namespace; } debounce() { const now = Date.now(); const last = this.last; this.last = now; return last && now - last < 250; } reportCurrentNamespaceFromCommandComplete(evt) { return __awaiter(this, void 0, void 0, function* () { this.reportCurrentNamespace(evt.tab); }); } reportCurrentNamespace(idx) { return __awaiter(this, void 0, void 0, function* () { if (this.unmounted) { return; } const tab = (0, _core.getTab)(typeof idx === 'string' ? undefined : idx); if (!tab || !tab.REPL) { if (tab && !tab.REPL) { _core.Events.eventChannelUnsafe.once(`/tab/new/${tab.uuid}`, () => this.reportCurrentNamespace()); } return; } else if (this.debounce()) { return; } try { const { kubectl, getCurrentDefaultNamespace } = yield Promise.resolve().then(() => require('@kui-shell/plugin-kubectl')); if (this.unmounted) { return; } const [currentNamespace, allNamespaces] = yield Promise.all([getCurrentDefaultNamespace(tab), tab.REPL.qexec(`${kubectl} get ns -o name`).then(_ => _.split(/\n/).map(_ => _.replace(/^namespace\//, '')))]); if (this.unmounted) { return; } if (currentNamespace) { this.setState({ currentNamespace, allNamespaces, viewLevel: 'normal' // only show normally if we succeed; see https://github.com/IBM/kui/issues/3537 }); } } catch (err) { console.error(err); this.last = undefined; this.setState({ currentNamespace: '', allNamespaces: [], viewLevel: 'hidden' // only show normally if we succeed; see https://github.com/IBM/kui/issues/3537 }); } }); } getCurrentNamespaceFromTab(args) { return __awaiter(this, void 0, void 0, function* () { if (this.unmounted) { return; } const { tab } = args; if (tab) { const { getTabState } = yield Promise.resolve().then(() => require('@kui-shell/plugin-kubectl')); if (this.unmounted) { return; } const currentNamespace = getTabState(tab, 'namespace'); if (currentNamespace) { this.setState({ currentNamespace, viewLevel: 'normal' }); } } }); } setLoadingMessage() { setTimeout(() => { if (!this.unmounted) { this.setState(curState => { if (curState.currentNamespace === null) { return { currentNamespace: strings('Loading...') }; } else { return null; } }); } }, 2000); } /** * Once we have mounted, we immediately check the current branch, * and schedule an update based on standard REPL events. * */ componentDidMount() { this.unmounted = false; this.setLoadingMessage(); if (!_CurrentContext.ready) { _core.Events.eventBus.once('/tab/new', this.handler); } else { this.handler(); } _core.Events.eventBus.on('/tab/switch/request/done', this.handlerNotCallingKubectl); _core.Events.eventBus.onAnyCommandComplete(this.handlerForCommandComplete); Promise.resolve().then(() => require('@kui-shell/plugin-kubectl')).then(_ => _.onKubectlConfigChangeEvents(this.handler)); } get unmounted() { return this._unmounted; } set unmounted(umm) { this._unmounted = umm; } /** Bye! */ componentWillUnmount() { this.unmounted = true; _core.Events.eventBus.off('/tab/new', this.handler); _core.Events.eventBus.off('/tab/switch/request/done', this.handlerNotCallingKubectl); _core.Events.eventBus.offAnyCommandComplete(this.handlerForCommandComplete); Promise.resolve().then(() => require('@kui-shell/plugin-kubectl')).then(_ => _.offKubectlConfigChangeEvents(this.handler)); } kubectl() { return __awaiter(this, void 0, void 0, function* () { const { kubectl } = yield Promise.resolve().then(() => require('@kui-shell/plugin-kubectl')); return kubectl; }); } listNamespace() { return _react.default.createElement("a", { href: "#", onClick: () => __awaiter(this, void 0, void 0, function* () { return (0, _core.pexecInCurrentTab)(`${yield this.kubectl()} get namespace`); }) }, strings('Show Full Details')); } popoverHeader() { return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement("div", null, strings('Kubernetes Namespace')), _react.default.createElement("div", { className: "do-not-overflow" }, _react.default.createElement("strong", null, this.state.currentNamespace)), _react.default.createElement("div", { className: "sub-text even-smaller-text" }, this.listNamespace())); } /** @return the options model for the given namespace named `ns` */ optionFor(ns) { const isSelected = ns === this.state.currentNamespace; return { label: ns, isSelected, description: isSelected ? strings('This is your current namespace') : undefined, quietExec: true, command: () => __awaiter(this, void 0, void 0, function* () { const kubectl = yield this.kubectl(); return `${kubectl} config set-context --current --namespace=${ns}`; }) }; } switchNamespace() { if (this.state.allNamespaces.length === 0) { return; } const internalNs = this.state.allNamespaces.filter(_ => (0, _heuristics.isInternalNamespace)(_)).map(_ => this.optionFor(_)); const regularNs = this.state.allNamespaces.filter(_ => !(0, _heuristics.isInternalNamespace)(_)).map(_ => this.optionFor(_)); const options = internalNs.length > 0 ? undefined : regularNs; const groups = internalNs.length === 0 ? undefined : [{ label: strings('User Namespaces'), options: regularNs }, { divider: true }, { label: strings('System Namespaces'), options: internalNs }]; return _react.default.createElement(_react.default.Suspense, { fallback: _react.default.createElement("div", null) }, _react.default.createElement(_Select.default, { key: this.state.currentNamespace /* pf 4.152.4 regression? "This is the current" does not show on change */, variant: "typeahead", maxHeight: "15rem", selected: this.state.currentNamespace, options: options, groups: groups, isOpen: true, isClosable: false })); } popoverBody() { return _react.default.createElement("div", { className: "top-pad bottom-pad" }, this.switchNamespace()); } popover() { return { className: 'kui--popover-select', bodyContent: this.popoverBody(), headerContent: this.popoverHeader() }; } render() { return this.state.currentNamespace === null ? _react.default.createElement(_react.default.Fragment, null) : _react.default.createElement(_TextWithIconWidget.default, Object.assign({ className: this.props.className, text: this.state.currentNamespace, viewLevel: this.state.viewLevel, id: "kui--plugin-kubeui--current-namespace", title: strings('Kubernetes namespace') }, this.props, { popover: this.popover() }), _react.default.createElement(_Icons.default, { icon: "At" })); } } exports.default = CurrentNamespace;