UI: Fixed marker deletion bug, updated gather icons

This commit is contained in:
Andrew Head 2019-03-04 11:29:46 -08:00
Родитель 60cb46c4b5
Коммит b969a7fa0a
16 изменённых файлов: 195 добавлений и 176 удалений

Просмотреть файл

@ -9,6 +9,9 @@ Download the extension with one command:
jupyter labextension install gather
```
If you are seeing installation errors, make sure that npm
and Jupyter Lab are up-to-date.
Read the docs [here](https://microsoft.github.io/gather).
And read our academic paper on the design of the tool
[here](https://people.eecs.berkeley.edu/~andrewhead/pdf/notebooks.pdf).
@ -47,6 +50,10 @@ will continue to live after the tests finish running---it
will recompile and re-run the tests whenever the test code
changes. Type Ctrl+C to abort the command at any time.
Note that running tests with this command may interfere with
you opening Chrome browsers. If that happens, cancel the
command, open Chrome, and then restart the command.
To debug the tests, call:
```bash

Просмотреть файл

@ -436,7 +436,6 @@ class CallNamesListener implements ast.IWalkListener {
this._statement = statement;
}
// TODO: Include the level of each name...
onEnterNode(node: ast.ISyntaxNode, type: string, ancestors: ast.ISyntaxNode[]) {
if (type == ast.CALL) {
let callNode = node as ast.ICall;
@ -530,7 +529,6 @@ class TargetsDefListener implements ast.IWalkListener {
this._statement = statement;
}
// TODO: Include the level of each name...
onEnterNode(node: ast.ISyntaxNode, type: string, ancestors: ast.ISyntaxNode[]) {
if (type == ast.NAME) {
let level = ReferenceType.DEFINITION;

Просмотреть файл

@ -34,14 +34,10 @@ export class Clipboard {
return this._copied;
}
/**
* TODO(andrewhead): selected outputs should be passed as arguments to this function too.
*/
copy(slice: SlicedExecution) {
copy(slice: SlicedExecution, outputSelections?: OutputSelection[]) {
const JUPYTER_CELL_MIME = 'application/vnd.jupyter.cells';
if (slice) {
// let cellJson = sliceToCellJson(slice, this._gatherModel.selectedOutputs.concat());
let cellJson = getCellsJsonForSlice(slice, []);
let cellJson = getCellsJsonForSlice(slice, outputSelections);
const clipboard = JupyterClipboard.getInstance();
clipboard.clear();
clipboard.setData(JUPYTER_CELL_MIME, cellJson);
@ -75,9 +71,6 @@ export class ScriptOpener {
}
openScriptForSlice(slice: SlicedExecution) {
/*
* TODO(andrewhead): give the document a context-sensitive name, say the name of the result.
*/
this._documentManager.newUntitled({ ext: 'py' }).then(model => {
let kernelSpec = _createKernelSpecForCurrentWidget(this._notebooks);
let editor = this._documentManager.open(model.path, undefined, kernelSpec) as IDocumentWidget<FileEditor>;
@ -107,9 +100,6 @@ export class NotebookOpener {
}
openNotebookForSlice(slice: SlicedExecution, outputSelections?: OutputSelection[]) {
/*
* TODO(andrewhead): give the document a context-sensitive name, say the name of the result.
*/
this._documentManager.newUntitled({ ext: 'ipynb' }).then(model => {
let kernelSpec = _createKernelSpecForCurrentWidget(this._notebooks);
const widget = this._documentManager.open(model.path, undefined, kernelSpec) as NotebookPanel;

Просмотреть файл

@ -13,7 +13,7 @@ import { ExecutionLogSlicer } from '../analysis/slice/log-slicer';
import { GatherController, GatherModel, GatherState, SliceSelection } from '../model';
import { GatherModelRegistry, getGatherModelForActiveNotebook } from '../model/gather-registry';
import { NotifactionExtension as NotificationExtension } from '../overlay/notification';
import { ResultsHighlighter } from '../overlay/result-highlighter';
import { CellChangeListener } from '../overlay/cell-listener';
import { initToolbar } from '../overlay/toolbar';
import { MarkerManager } from '../overlay/variable-markers';
import { loadHistory as loadHistory } from '../persistence/load';
@ -21,6 +21,7 @@ import { storeHistory } from '../persistence/store';
import { initLogger, log } from '../util/log';
import { ExecutionLogger } from './execution-logger';
import { Clipboard } from './gather-actions';
import { RevisionBrowser } from '../overlay/revision-browser';
const extension: JupyterLabPlugin<void> = {
@ -37,8 +38,9 @@ const extension: JupyterLabPlugin<void> = {
*/
export class CodeGatheringExtension implements DocumentRegistry.IWidgetExtension<NotebookPanel, INotebookModel> {
constructor(documentManager: DocumentManager, notebooks: INotebookTracker,
constructor(app: JupyterLab, documentManager: DocumentManager, notebooks: INotebookTracker,
gatherModelRegistry: GatherModelRegistry) {
this._app = app;
this._documentManager = documentManager;
this._notebooks = notebooks;
this._gatherModelRegistry = gatherModelRegistry;
@ -59,10 +61,10 @@ export class CodeGatheringExtension implements DocumentRegistry.IWidgetExtension
* update the UI automatically as we populate the log.
*/
this._toolbarWidgets = initToolbar(notebook, gatherModel, this);
let markerManager = new MarkerManager(gatherModel, notebook);
new ResultsHighlighter(gatherModel, notebook, markerManager);
new MarkerManager(gatherModel, notebook);
new CellChangeListener(gatherModel, notebook);
new GatherController(gatherModel, this._documentManager, this._notebooks);
this._gatherModelRegistry.addGatherModel(notebookModel, gatherModel);
new ExecutionLogger(notebook, gatherModel);
saveHistoryOnNotebookSave(notebook, gatherModel);
@ -108,7 +110,15 @@ export class CodeGatheringExtension implements DocumentRegistry.IWidgetExtension
}
}
gatherRevisions() {
let gatherModel = getGatherModelForActiveNotebook(this._notebooks, this._gatherModelRegistry);
let revisionBrowser = new RevisionBrowser(gatherModel);
this._app.shell.addToMainArea(revisionBrowser);
this._app.shell.activateById(revisionBrowser.id);
}
private _toolbarWidgets: Widget[];
private _app: JupyterLab;
private _documentManager: DocumentManager;
private _notebooks: INotebookTracker;
private _gatherModelRegistry: GatherModelRegistry;
@ -130,11 +140,11 @@ function activateExtension(app: JupyterLab, palette: ICommandPalette, notebooks:
const notificationExtension = new NotificationExtension();
app.docRegistry.addWidgetExtension('Notebook', notificationExtension);
Clipboard.getInstance().copied.connect(() => {
notificationExtension.showMessage("Copied cells to clipboard.");
notificationExtension.showMessage("Copied cells to clipboard. Type 'V' to paste.");
});
let gatherModelRegistry = new GatherModelRegistry();
let codeGatheringExtension = new CodeGatheringExtension(documentManager, notebooks, gatherModelRegistry);
let codeGatheringExtension = new CodeGatheringExtension(app, documentManager, notebooks, gatherModelRegistry);
app.docRegistry.addWidgetExtension('Notebook', codeGatheringExtension);
function addCommand(command: string, label: string, execute: (options?: JSONObject) => void) {
@ -154,36 +164,12 @@ function activateExtension(app: JupyterLab, palette: ICommandPalette, notebooks:
codeGatheringExtension.gatherToScript();
});
// TODO: re-enable this as an optional feature.
/*
addCommand('gather:gatherFromHistory', 'Compare previous versions of this result', () => {
const panel = notebooks.currentWidget;
if (panel && panel.content && panel.content.activeCell.model.type === 'code') {
const activeCell = panel.content.activeCell;
let slicer = executionLogger.executionSlicer;
let cellModel = activeCell.model as ICodeCellModel;
let slicedExecutions = slicer.sliceAllExecutions(new LabCell(cellModel));
// TODO: Update this with a real gather-model and real output renderer.
let historyModel = buildHistoryModel<IOutputModel>(new GatherModel(), activeCell.model.id, slicedExecutions);
let widget = new HistoryViewer({
model: historyModel,
outputRenderer: { render: () => null }
});
if (!widget.isAttached) {
app.shell.addToMainArea(widget);
}
app.shell.activateById(widget.id);
}
codeGatheringExtension.gatherRevisions();
});
*/
// settingRegistry.set("gather:plugin", "gatheringConfig", { email: "andrewhead@berkeley.edu" });
initLogger(settingRegistry);
console.log('Code gathering tools have been activated.');
console.log('Gathering tools have been activated.');
}
export default extension;

Просмотреть файл

@ -35,7 +35,7 @@ export class GatherController implements IGatherObserver {
let mergedSlice = slices[0].merge(...slices.slice(1));
if (newState == GatherState.GATHER_TO_CLIPBOARD) {
log("Gathering to clipboard", { slice: mergedSlice });
this._cellClipboard.copy(mergedSlice);
this._cellClipboard.copy(mergedSlice, [...model.selectedOutputs]);
} else if (newState == GatherState.GATHER_TO_NOTEBOOK) {
log("Gathering to notebook", { slice: mergedSlice });
if (this._notebookOpener !== undefined) {

Просмотреть файл

@ -0,0 +1,49 @@
import { CodeCellModel, ICellModel } from "@jupyterlab/cells";
import { NotebookPanel } from "@jupyterlab/notebook";
import { IObservableList } from "@jupyterlab/observables";
import { GatherModel } from "../model";
import { LabCell } from "../model/cell";
/**
* Listens to cell executions and edits.
*/
export class CellChangeListener {
private _gatherModel: GatherModel;
constructor(gatherModel: GatherModel, panel: NotebookPanel) {
this._gatherModel = gatherModel;
for (let i = 0; i < panel.content.model.cells.length; i++) {
this.registerCell(panel.content.model.cells.get(i));
}
panel.content.model.cells.changed.connect((_, change) => this.registerAddedCells(change), this);
}
private registerCell(cell: ICellModel) {
if (cell.type !== 'code') { return; }
/**
* A cell will be considered edited whenever any of its contents changed, including
* execution count, metadata, outputs, text, etc.
*/
cell.contentChanged.connect((changedCell, _) => {
if (changedCell instanceof CodeCellModel) {
this._gatherModel.lastEditedCell = new LabCell(changedCell);
}
});
}
public registerAddedCells(cellListChange: IObservableList.IChangedArgs<ICellModel>): void {
if (cellListChange.type === 'add' || cellListChange.type === 'remove') {
const cellModel = cellListChange.newValues[0] as ICellModel;
if (cellListChange.type === 'add') {
this.registerCell(cellModel);
} else if (cellListChange.type === 'remove') {
if (cellModel instanceof CodeCellModel) {
this._gatherModel.lastDeletedCell = new LabCell(cellModel);
}
}
}
}
}

Просмотреть файл

@ -1,56 +0,0 @@
import { IClientSession } from "@jupyterlab/apputils";
import { CodeCellModel, ICellModel } from "@jupyterlab/cells";
import { Notebook, NotebookPanel } from "@jupyterlab/notebook";
import { IObservableList } from "@jupyterlab/observables";
import { MarkerManager } from "./variable-markers";
import { GatherModel } from "../model";
import { LabCell } from "../model/cell";
/**
* Highlights gatherable entities.
*/
export class ResultsHighlighter {
private _markerManager: MarkerManager;
private _gatherModel: GatherModel;
constructor(gatherModel: GatherModel, panel: NotebookPanel, markerManager: MarkerManager) {
this._markerManager = markerManager;
this._gatherModel = gatherModel;
panel.content.model.cells.changed.connect(
(cells, value) =>
this.onCellsChanged(panel.content, panel.session, cells, value),
this);
document.body.addEventListener("mouseup", (event: MouseEvent) => {
this._markerManager.handleClick(event);
});
}
public onCellsChanged(
notebook: Notebook,
_: IClientSession,
__: IObservableList<ICellModel>,
cellListChange: IObservableList.IChangedArgs<ICellModel>
): void {
if (cellListChange.type === 'add') {
const cellModel = cellListChange.newValues[0] as ICellModel;
if (cellModel.type !== 'code') { return; }
// When a cell is added, register for its state changes.
cellModel.contentChanged.connect((changedCell, args) => {
// TODO(andrewhead): check that this change is due to a user's text edit in the cell.
if (changedCell instanceof CodeCellModel) {
this._gatherModel.lastEditedCell = new LabCell(changedCell);
}
});
}
if (cellListChange.type === 'remove') {
const cellModel = cellListChange.newValues[0] as ICellModel;
if (cellModel instanceof CodeCellModel) {
this._gatherModel.lastDeletedCell = new LabCell(cellModel);
}
}
}
}

Просмотреть файл

@ -33,7 +33,7 @@ export function initToolbar(notebook: NotebookPanel, gatherModel: GatherModel,
let labelLayout = gatherLabelWidget.layout = new PanelLayout();
let gatherLabel = new Widget({ node: document.createElement("span") });
gatherLabel.addClass('jp-GatherLabel');
gatherLabel.node.textContent = "Gather to";
gatherLabel.node.textContent = "Gather to:";
labelLayout.addWidget(gatherLabel);
notebook.toolbar.insertItem(insertIndex, "gatherLabel", gatherLabelWidget);
return gatherLabelWidget;
@ -55,6 +55,11 @@ export function initToolbar(notebook: NotebookPanel, gatherModel: GatherModel,
let buttons = [
new GatherToClipboardButton(gatherModel, codeGatheringExtension.gatherToClipboard.bind(codeGatheringExtension)),
new GatherToNotebookButton(gatherModel, codeGatheringExtension.gatherToNotebook.bind(codeGatheringExtension)),
/*
* The following line adds a button for gathering code to a script.
*/
// new GatherToScriptButton(gatherModel, codeGatheringExtension.gatherToScript.bind(codeGatheringExtension)),
new GatherRevisionsButton(gatherModel, codeGatheringExtension.gatherRevisions.bind(codeGatheringExtension)),
new ClearButton(gatherModel)
];
for (let button of buttons) {
@ -124,9 +129,9 @@ export class GatherToClipboardButton extends GatherButton {
constructor(gatherModel: GatherModel, callback: () => void) {
super("gatherToClipboard", gatherModel, {
className: "jp-Toolbar-gathertoclipboardbutton",
iconClassName: "jp-CopyIcon jp-Icon jp-Icon-16",
tooltip: "Gather code to clipboard",
label: "Clipboard",
iconClassName: "jp-CellsIcon jp-Icon jp-Icon-16",
tooltip: "Gather cells code to clipboard",
label: "Cells",
onClick: () => { this.onClick() }
});
this._callback = callback;
@ -174,6 +179,77 @@ export class GatherToNotebookButton extends GatherButton {
private _callback: () => void;
}
/**
* A button to gather code to a new notebook.
*/
export class GatherToScriptButton extends GatherButton {
constructor(gatherModel: GatherModel, callback: () => void) {
super("gatherToScript", gatherModel, {
className: "jp-Toolbar-gathertoscriptbutton",
iconClassName: "jp-TextEditorIcon jp-Icon jp-Icon-16",
tooltip: "Gather code to new script",
label: "Script",
onClick: () => { this.onClick() }
});
this._callback = callback;
}
onClick() {
if (this._gatherModel.selectedSlices.length >= 1) {
log("Button: Clicked gather to script");
this._callback();
} else {
log("Button: Clicked gather to script without selections");
window.alert("Before you gather, click on one of the blue variable names, or one of the outputs with a blue border.");
}
}
private _callback: () => void;
}
/**
* A button to gather code to a new notebook.
*/
export class GatherRevisionsButton extends GatherButton {
constructor(gatherModel: GatherModel, callback: () => void) {
super("gatherRevisions", gatherModel, {
className: "jp-Toolbar-gatherrevisionsbutton",
iconClassName: "jp-HistoryIcon jp-Icon jp-Icon-16",
tooltip: "Gather revisions of this cell",
label: "Version Browser",
onClick: () => { this.onClick() }
});
this._callback = callback;
}
protected _updateDisabled() {
if (this._gatherModel.selectedSlices.length == 1) {
this.addClass(HIGHLIGHTED_BUTTON_CLASS);
this.removeClass(this.DISABLED_CLASS_NAME);
} else {
this.removeClass(HIGHLIGHTED_BUTTON_CLASS);
this.addClass(this.DISABLED_CLASS_NAME);
}
}
onClick() {
if (this._gatherModel.selectedSlices.length == 1) {
log("Button: Clicked gather to history with a selection");
this._callback();
} else if (this._gatherModel.selectedSlices.length == 0) {
log("Button: Clicked gather to history without any selections");
window.alert("Before bringing up a history, first click on one of the blue variables, or one of the outputs with a blue border.");
} else if (this._gatherModel.selectedSlices.length > 1) {
log("Button: Clicked gather to history with too many selections");
window.alert("You cannot bring up a history if more than one blue variable name or output has been selected. Make sure only one variable or output is selectedß");
}
}
private _callback: () => void;
}
/**
* A button to clear the gathering selections.
*/

Просмотреть файл

@ -24,8 +24,10 @@ export class DisplayData extends Widget {
let layout = (this.layout = new PanelLayout());
// Code borrowed from OutputArea extension.
// TODO(andrewhead): support other types of display data.
// TODO(andrewhead): change second argument (preferSafe) based on display data field.
/*
* TODO(andrewhead): support other types of display data.
* TODO(andrewhead): change second argument (preferSafe) based on display data field.
*/
if (nbformat.isExecuteResult(model) || nbformat.isDisplayData(model)) {
let mimeType = rendermime.preferredMimeType(model.data, "ensure");
let output = rendermime.createRenderer(mimeType);

Просмотреть файл

@ -43,10 +43,10 @@ export function buildHistoryModel(
let recentCellVersion = latestCellVersions[cell.persistentId];
let latestText: string = "";
if (recentCellVersion) {
latestText = recentCellVersion.textSlice;
latestText = recentCellVersion.textSliceLines;
}
let thisVersionText: string = cellSlice.textSlice;
let thisVersionText: string = cellSlice.textSliceLines;
let diff = computeTextDiff(latestText, thisVersionText);
let slicedCell: SlicedCellModel = new SlicedCellModel({

Просмотреть файл

@ -11,10 +11,6 @@ const HISTORY_VIEWER_ICON_CLASS = 'jp-HistoryViewerIcon';
const REFERENCE_VERSION_CLASS = 'jp-HistoryViewer-referenceversion';
const OLDER_VERSIONS_CLASS = 'jp-HistoryViewer-olderversions';
const OLDER_VERSIONS_CONTENTS_CLASS = 'jp-HistoryViewer-olderversions-revisions';
/**
* A widget for showing the history of a result and how it was produced.
*/
@ -33,40 +29,30 @@ export class HistoryViewer extends Widget {
this.title.closable = true;
this._model = options.model;
// let rendermime = (this.rendermime = options.rendermime);
// Add revisions from most recent to oldest.
let layout = (this.layout = new PanelLayout());
// Add pane for reference (most recent) version.
let referenceVersion = new Widget({ node: document.createElement("div") });
referenceVersion.addClass(REFERENCE_VERSION_CLASS);
referenceVersion.layout = new PanelLayout();
const now = new Date();
(referenceVersion.layout as PanelLayout).addWidget(new Revision({
let referenceVersion = new Revision({
model: this._model.revisions[this._model.revisions.length - 1],
outputRenderer: options.outputRenderer,
now: now
}));
});
referenceVersion.addClass(REFERENCE_VERSION_CLASS);
layout.addWidget(referenceVersion);
// Add pane for older versions.
if (this._model.revisions.length > 1) {
let olderVersions = new Widget({ node: document.createElement("div") });
olderVersions.addClass(OLDER_VERSIONS_CLASS);
let olderVersionsContents = new Widget({ node: document.createElement("div") });
olderVersionsContents.addClass(OLDER_VERSIONS_CONTENTS_CLASS);
olderVersions.node.appendChild(olderVersionsContents.node);
olderVersionsContents.layout = new PanelLayout();
for (let i = this._model.revisions.length - 2; i >= 0; i--) {
let revisionModel = this._model.revisions[i];
(olderVersionsContents.layout as PanelLayout).addWidget(new Revision({
layout.addWidget(new Revision({
model: revisionModel,
outputRenderer: options.outputRenderer,
now: now
}));
}
layout.addWidget(olderVersions);
}
}
@ -77,11 +63,6 @@ export class HistoryViewer extends Widget {
return this._model;
}
/**
* The rendermime instance used by the widget.
*/
// readonly rendermime: RenderMimeRegistry;
/**
* Dispose of the resources used by the widget.
*/

1
style/icons/cells.svg Normal file
Просмотреть файл

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><path d="M22,3.375c0,-0.747 -0.607,-1.354 -1.354,-1.354l-17.292,0c-0.747,0 -1.354,0.607 -1.354,1.354l0,0.921c0,0.748 0.607,1.354 1.354,1.354l17.292,0c0.747,0 1.354,-0.606 1.354,-1.354l0,-0.921Z" style="fill:none;stroke:#5a5a5a;stroke-width:2px;"/><path d="M22,10.354c0,-1.2 -0.975,-2.175 -2.176,-2.175l-15.648,0c-1.201,0 -2.176,0.975 -2.176,2.175l0,1.481c0,1.2 0.975,2.175 2.176,2.175l15.648,0c1.201,0 2.176,-0.975 2.176,-2.175l0,-1.481Z" style="fill:none;stroke:#5a5a5a;stroke-width:2px;"/><path d="M22,18.584c0,-1.129 -0.916,-2.045 -2.045,-2.045l-15.91,0c-1.129,0 -2.045,0.916 -2.045,2.045l0,1.392c0,1.128 0.916,2.045 2.045,2.045l15.91,0c1.129,0 2.045,-0.917 2.045,-2.045l0,-1.392Z" style="fill:none;stroke:#5a5a5a;stroke-width:2px;"/></svg>

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

10
style/icons/ellipses.svg Normal file
Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<svg fill="#616161" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
<g>
<circle cx="12" cy="12" r="2"/>
<g>
<circle cx="5" cy="12" r="2"/>
<circle cx="19" cy="12" r="2"/>
</g>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 320 B

1
style/icons/history.svg Normal file
Просмотреть файл

@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><rect x="11.62" y="4.913" width="0.873" height="8" style="fill:none;stroke:#5a5a5a;stroke-width:2px;"/><rect x="6.826" y="12.037" width="5" height="0.873" style="fill:none;stroke:#5a5a5a;stroke-width:2px;"/><path d="M12.057,21.664c-5.303,0 -9.608,-4.305 -9.608,-9.607c0,-5.303 4.305,-9.608 9.608,-9.608c5.302,0 9.607,4.305 9.607,9.608" style="fill:none;stroke:#5a5a5a;stroke-width:2px;"/><path d="M20.075,14.949l0,6.059l-6.059,0l0,-6.059m8.603,-2.544l-11.147,0l0,11.086l11.086,0l0.061,-11.086Z" style="fill:#ef6c00;fill-rule:nonzero;"/><path d="M18.966,19.899l-1.886,-1.502l-1.955,1.502l0,-3.841l3.841,0l0,3.841Z" style="fill:#ef6c00;fill-rule:nonzero;"/></svg>

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Двоичные данные
style/icons/icons.afdesign Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -53,14 +53,18 @@ span.jp-GatherLabel {
background-image: var(--jp-icon-book);
}
.jp-CopyIcon {
background-image: var(--jp-icon-copy);
.jp-CellsIcon {
background-image: url('icons/cells.svg');
}
.jp-CloseIcon {
background-image: var(--jp-icon-close);
}
.jp-HistoryIcon {
background-image: url('icons/history.svg');
}
/**
* Clues for gatherable text.
*/
@ -155,36 +159,26 @@ div.CodeMirror-linebackground.jp-InputArea-editor-dependencyline {
.jp-HistoryViewer {
width: 100%;
height: 100%;
overflow-x: scroll;
white-space: nowrap;
margin: auto;
}
.jp-HistoryViewer .jp-HistoryViewer-referenceversion,
.jp-HistoryViewer .jp-HistoryViewer-olderversions {
.jp-HistoryViewer .jp-Revision {
display: inline-block;
vertical-align: top;
}
.jp-HistoryViewer-referenceversion {
max-width: 500px;
height: 98%;
padding-right: 50px;
}
.jp-HistoryViewer-olderversions {
height: 99%;
width: 65%;
overflow-y: hidden;
}
.jp-HistoryViewer-olderversions-revisions {
height: 99%;
display: flex;
flex-flow: row;
white-space: nowrap;
overflow-x: auto;
max-width: 500px;
}
.jp-Revision {
display: inline-block;
height: 99%;
vertical-align: top;
background-color: #eee;
@ -206,15 +200,6 @@ div.CodeMirror-linebackground.jp-InputArea-editor-dependencyline {
flex-flow: column;
}
.jp-HistoryViewer-referenceversion .jp-Revision {
margin-left: 30px;
}
.jp-HistoryViewer-olderversions .jp-Revision {
max-width: 500px;
margin-right: 20px;
}
.jp-HistoryViewer-referenceversion .jp-Revision-header {
font-weight: bold;
}
@ -222,7 +207,6 @@ div.CodeMirror-linebackground.jp-InputArea-editor-dependencyline {
.jp-Revision-header {
flex: 0 0 auto;
background-color: white;
/* border: 1px solid black; */
font-size: medium;
padding-left: 1ex;
padding-right: 1ex;
@ -284,7 +268,6 @@ div.CodeMirror-linebackground.jp-InputArea-editor-dependencyline {
.jp-DiffedCell-editor-aftertext.jp-DiffedCell-editor-changedtext {
font-weight: bold;
/* background-color: #ffe189; */
}
.jp-DiffedCell-editor-beforebackground {
@ -292,7 +275,6 @@ div.CodeMirror-linebackground.jp-InputArea-editor-dependencyline {
}
.jp-DiffedCell-editor-beforetext {
/* background-color: #d8f7ff; */
font-style: italic;
color: #6d6d6d;
}
@ -304,6 +286,10 @@ div.CodeMirror-linebackground.jp-InputArea-editor-dependencyline {
}
/* Revision cell outputs */
.jp-Notebook-revisionbrowser {
background-color: #eee;
}
.jp-Notebook-revisionbrowser-output div.output_area {
max-height: 5000px;
overflow-y: auto;
@ -314,20 +300,8 @@ div.CodeMirror-linebackground.jp-InputArea-editor-dependencyline {
width: 100%;
max-width: 100%;
overflow-x: auto;
/* border-right: 1px solid black; */
/* border-left: 1px solid black; */
}
/*
.jp-Notebook-revisionbrowser-output div.output_area:last-child div.output_subarea {
border-bottom: 1px solid black;
}
.jp-Notebook-revisionbrowser-output div.output_area:first-child div.output_subarea {
border-top: 1px solid black;
}
*/
.jp-Notebook-revisionbrowser-output .output_area:first-child {
margin-left: 1em;
}