@jupyterlab/git
Version:
A JupyterLab extension for version control using git
107 lines (106 loc) • 7.04 kB
JavaScript
import { caretDownIcon } from '@jupyterlab/ui-components';
import * as React from 'react';
import { changeStageButtonStyle, sectionAreaStyle, sectionFileContainerStyle, sectionHeaderSizeStyle } from '../style/GitStageStyle';
import { hiddenButtonStyle } from '../style/ActionButtonStyle';
import { ActionButton } from './ActionButton';
import { addIcon, trashIcon, discardIcon } from '../style/icons';
import { UseSignal } from '@jupyterlab/apputils';
import { FixedSizeList } from 'react-window';
import { listStyle, sectionButtonContainerStyle, stashFileStyle, stashEntryMessageStyle, stashContainerStyle } from '../style/GitStashStyle';
import { FilePath } from './FilePath';
import { stopPropagation, stopPropagationWrapper } from '../utils';
import { classes } from 'typestyle';
const HEADER_HEIGHT = 34;
const ITEM_HEIGHT = 25;
/**
* Dropdown for each entry in the stash
*/
const GitStashEntry = (props) => {
var _a;
const [showStashFiles, setShowStashFiles] = React.useState(false);
const nFiles = props.files.length;
const canToggle = ((_a = props.collapsible) !== null && _a !== void 0 ? _a : false) && nFiles > 0;
const onToggle = () => {
if (canToggle) {
setShowStashFiles(!showStashFiles);
}
};
const stashEntryLabel = props.trans.__('%1 (on %2)', props.message, props.branch);
return (React.createElement("div", { className: sectionFileContainerStyle },
React.createElement("div", { className: classes('jp-AccordionPanel-title', showStashFiles && nFiles > 0 ? 'lm-mod-expanded' : null, sectionAreaStyle), onClick: onToggle },
props.collapsible && (React.createElement("button", { type: "button", className: classes('lm-AccordionPanel-titleCollapser', changeStageButtonStyle), "aria-expanded": canToggle ? showStashFiles : undefined, "aria-label": stashEntryLabel, disabled: !canToggle },
React.createElement(caretDownIcon.react, { tag: "span" }))),
React.createElement("span", { className: "lm-AccordionPanel-titleLabel" },
React.createElement("span", { className: stashEntryMessageStyle }, stashEntryLabel)),
props.actions && (React.createElement("div", { className: classes('jp-AccordionPanel-toolbar', sectionButtonContainerStyle), onClick: stopPropagation }, props.actions))),
showStashFiles && (React.createElement(FixedSizeList, { className: listStyle, height: Math.max(Math.min(props.height - HEADER_HEIGHT, nFiles * ITEM_HEIGHT), ITEM_HEIGHT), itemCount: nFiles, innerElementType: "ul", itemData: props === null || props === void 0 ? void 0 : props.files, itemKey: (index, data) => data[index], itemSize: ITEM_HEIGHT, width: 'auto', style: { margin: 0, paddingLeft: 0 } }, ({ index }) => {
const file = props.files[index];
return (React.createElement("li", { className: stashFileStyle },
React.createElement(FilePath, { filepath: file })));
}))));
};
export const GitStash = (props) => {
var _a, _b, _c;
const [showStash, setShowStash] = React.useState(false);
const [stashIsLoading, setStashIsLoading] = React.useState(true);
const nStash = (_b = (_a = props.stash) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
const canToggle = ((_c = props.collapsible) !== null && _c !== void 0 ? _c : false) && nStash > 0;
const onToggle = () => {
if (canToggle) {
setShowStash(!showStash);
}
};
const stashLabel = props.trans.__('Stash');
const gitStashPop = React.useCallback(async (index) => {
try {
await props.model.popStash(index);
}
catch (err) {
console.error(err);
}
}, [props.model]);
const gitStashDrop = React.useCallback(async (index) => {
try {
await props.model.dropStash(index);
}
catch (err) {
console.error(err);
}
}, [props.model]);
const gitStashApply = React.useCallback(async (index) => {
try {
await props.model.applyStash(index);
}
catch (err) {
console.error(err);
}
}, [props.model]);
return (React.createElement("div", { className: classes(sectionFileContainerStyle, stashContainerStyle) },
React.createElement("div", { className: classes('jp-AccordionPanel-title', showStash && nStash > 0 ? 'lm-mod-expanded' : null, sectionAreaStyle), onClick: onToggle },
props.selectAllButton && (React.createElement("span", { style: { display: 'contents' }, onClick: stopPropagation }, props.selectAllButton)),
props.collapsible && (React.createElement("button", { type: "button", className: classes('lm-AccordionPanel-titleCollapser', changeStageButtonStyle), "aria-expanded": canToggle ? showStash : undefined, "aria-label": stashLabel, disabled: !canToggle },
React.createElement(caretDownIcon.react, { tag: "span" }))),
React.createElement("span", { className: "lm-AccordionPanel-titleLabel" }, stashLabel),
React.createElement("div", { className: classes('jp-AccordionPanel-toolbar', sectionButtonContainerStyle), onClick: stopPropagation },
props.actions,
React.createElement("span", { className: nStash > 0 ? sectionHeaderSizeStyle : undefined, "data-test-id": "num-stashes", "data-loading": stashIsLoading ? 'true' : 'false' }, nStash > 0 ? nStash : ''))),
React.createElement(UseSignal, { signal: props.model.stashChanged }, () => {
if (!props.stash || !Array.isArray(props.stash)) {
return null;
}
const nStash = props.stash.length;
setStashIsLoading(false);
return (props.model.stashChanged &&
showStash &&
nStash > 0 && (React.createElement(React.Fragment, null, props.stash.map(entry => (React.createElement(GitStashEntry, { key: entry.index, files: entry.files, model: props.model, index: entry.index, branch: entry.branch, trans: props.trans, message: entry.message, height: 100, collapsible: true, actions: React.createElement(React.Fragment, null,
React.createElement(ActionButton, { className: hiddenButtonStyle, icon: discardIcon, title: props.trans.__('Pop stash entry'), onClick: stopPropagationWrapper(() => {
gitStashPop(entry.index);
}) }),
React.createElement(ActionButton, { className: hiddenButtonStyle, icon: addIcon, title: props.trans.__('Apply stash entry'), onClick: stopPropagationWrapper(() => {
gitStashApply(entry.index);
}) }),
React.createElement(ActionButton, { className: hiddenButtonStyle, icon: trashIcon, title: props.trans.__('Drop stash entry'), onClick: stopPropagationWrapper(() => {
gitStashDrop(entry.index);
}) })) }))))));
})));
};