UNPKG

@kui-shell/plugin-git

Version:

Kui plugin that offers git integrations

176 lines 7.76 kB
/* * 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 = (this && this.__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()); }); }; import React from 'react'; import { basename, dirname, join } from 'path'; import Icons from '@kui-shell/plugin-client-common/mdist/components/spi/Icons'; import TextWithIconWidget from '@kui-shell/plugin-client-common/mdist/components/Client/StatusStripe/TextWithIconWidget'; import { Capabilities, Events, getCurrentTab, i18n, encodeComponent, pexecInCurrentTab } from '@kui-shell/core'; const strings = i18n('plugin-bash-like'); const strings2 = i18n('plugin-git'); export default class CurrentGitBranch extends React.PureComponent { constructor(props) { super(props); this.handler = this.reportCurrentBranch.bind(this); /** So we don't handle events after unmounting */ this._unmounted = true; this.state = { text: '', status: '', viewLevel: 'hidden' }; } get unmounted() { return this._unmounted; } set unmounted(umm) { this._unmounted = umm; } debounce() { const now = Date.now(); const last = this.last; this.last = now; return last && now - last < 250; } /** * Check the current branch, and the dirtiness thereof. * */ reportCurrentBranch() { return __awaiter(this, void 0, void 0, function* () { if (this.unmounted) { return; } const tab = getCurrentTab(); if (!tab || !tab.REPL) { return; } else if (this.debounce()) { return; } try { const [isDirty, branch] = yield Promise.all([ // exit 0/1 indicates clean/dirty tab.REPL.qexec('git diff-index --quiet HEAD --') .then(() => false) .catch(() => true), // exits with branch name tab.REPL.qexec('git rev-parse --abbrev-ref HEAD') ]); tab.REPL.qexec('git status -s').then(status => this.setState({ status: status === true ? '' : status })); // is the branch dirty? this.setState({ text: branch, viewLevel: isDirty ? 'warn' : 'normal' }); } catch (error) { const err = error; this.last = undefined; if (err.code !== 128 && !/ambiguous argument 'HEAD'/.test(err.message) && !/not a git repo/.test(err.message)) { // 128: not a git repository; don't report those as errors console.error('unable to determine git branch', err.code, typeof err.code, err); } // but, in either case, hide the entry this.setState({ text: strings('not a repo'), viewLevel: 'hidden' }); } }); } /** * Once we have mounted, we immediately check the current branch, * and schedule an update based on standard REPL events. * */ componentDidMount() { this.unmounted = false; if (Capabilities.inBrowser()) { Events.eventBus.once('/tab/new', this.handler); } else { this.handler(); } Events.wireToStandardEvents(this.handler); } /** Make sure to unsubscribe! */ componentWillUnmount() { this.unmounted = true; Events.unwireToStandardEvents(this.handler); } /** @return the header for the Popover component */ popoverHeader() { return (React.createElement(React.Fragment, null, React.createElement("div", null, strings('Git Branch')), React.createElement("div", null, React.createElement("strong", null, this.state.text)), React.createElement("div", { className: "sub-text even-smaller-text" }, this.changeBranch()))); } /** @return the body for the Popover component */ popoverBody() { const statusModel = this.statusModel(); return (React.createElement("div", { className: "top-pad bottom-pad" }, this.summary(statusModel), this.changes(statusModel))); } /** @return a model of `git status -s` */ statusModel() { return !this.state.status ? [] : this.state.status .split(/\n/) .map(line => line.match(/(.+)\s+(.+)/)) .filter(Boolean) .map(match => ({ M: match[1], file: match[2] })); } /** @return UI that summarizes the `statusModel` changes */ summary(statusModel) { return (React.createElement("span", { className: "sub-text" }, statusModel.length > 0 ? strings('You have made the following changes to this branch.') : strings('You have made no changes to this branch.'))); } /** @return UI for changes represented by `statusModel` */ changes(statusModel) { return (React.createElement("div", { className: "small-top-pad monospace even-smaller-text pre-wrap" }, statusModel.map(({ M, file }) => (React.createElement("div", { key: `${M}-${file}`, className: "tiny-top-pad" }, [...M].map((m, idx) => (React.createElement("strong", { key: `${m}-${idx}`, className: /M/.test(m) ? 'red-text' : /D/.test(m) ? 'red-text' : /A/.test(m) ? 'cyan-text' : '' }, m))), React.createElement("span", { title: file, className: "small-left-pad clickable", onClick: () => pexecInCurrentTab(`git diff ${encodeComponent(file)}`) }, join(basename(dirname(file)), basename(file)))))))); } /** @return desired Popover model */ popover() { return { bodyContent: this.popoverBody(), headerContent: this.popoverHeader() }; } /** @return UI for changing branches */ changeBranch() { return (React.createElement("a", { href: "#", onClick: () => pexecInCurrentTab('git branch') }, strings2('Switch branch'))); } render() { return (React.createElement(TextWithIconWidget, { className: this.props.className, text: this.state.text, viewLevel: this.state.viewLevel, id: "kui--plugin-git--current-git-branch", title: strings2('Your current git branch'), popover: this.popover() }, React.createElement(Icons, { icon: "CodeBranch" }))); } } //# sourceMappingURL=CurrentGitBranch.js.map