mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-29 01:25:37 -05:00
Introduce tabs for notebook views (#19526)
* Introduce tabs for notebook views Cards have been restructured to contain tabs instead of cells directly. Tabs then contain the cards that are displayed. Cards may contain one or more cards. The panel component has been reused to implement the cells. There is still some cleanup left to do of unused functions, but I want to reduce the size of the PR as much as possible.
This commit is contained in:
@@ -39,7 +39,9 @@ import { NotebookViewsCardComponent } from 'sql/workbench/contrib/notebook/brows
|
||||
import { NotebookViewsGridComponent } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsGrid.component';
|
||||
import { TextCellComponent } from 'sql/workbench/contrib/notebook/browser/cellViews/textCell.component';
|
||||
import { NotebookViewsModalComponent } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsModal.component';
|
||||
|
||||
import { TabComponent } from 'sql/base/browser/ui/panel/tab.component';
|
||||
import { PanelComponent } from 'sql/base/browser/ui/panel/panel.component';
|
||||
import { TabHeaderComponent } from 'sql/base/browser/ui/panel/tabHeader.component';
|
||||
const outputComponentRegistry = Registry.as<ICellComponentRegistry>(OutputComponentExtensions.CellComponentContributions);
|
||||
|
||||
export const NotebookModule = (params, selector: string, instantiationService: IInstantiationService): any => {
|
||||
@@ -66,6 +68,9 @@ export const NotebookModule = (params, selector: string, instantiationService: I
|
||||
NotebookViewsGridComponent,
|
||||
NotebookViewsCodeCellComponent,
|
||||
NotebookViewsModalComponent,
|
||||
TabComponent,
|
||||
TabHeaderComponent,
|
||||
PanelComponent,
|
||||
ComponentHostDirective,
|
||||
OutputAreaComponent,
|
||||
OutputComponent,
|
||||
|
||||
@@ -6,28 +6,39 @@
|
||||
-->
|
||||
<ng-template #templateRef>
|
||||
<div
|
||||
*ngIf="visible"
|
||||
class="grid-stack-item"
|
||||
attr.data-cell-id="{{cell.cellGuid}}"
|
||||
attr.data-card-guid="{{guid}}"
|
||||
attr.gs-w="{{width}}"
|
||||
attr.gs-h="{{height}}"
|
||||
attr.gs-x="{{x}}"
|
||||
attr.gs-y="{{y}}"
|
||||
(click)="selectCell(cell, $event)"
|
||||
>
|
||||
<div
|
||||
#item
|
||||
class="grid-stack-item-content notebook-cell"
|
||||
[class.active]="cell.active"
|
||||
>
|
||||
<div #actionbar [style.display]="showActionBar ? 'block' : 'none'" class="actionbar"></div>
|
||||
<div class="grid-stack-content-wrapper">
|
||||
<div class="grid-stack-header" ></div>
|
||||
<div class="grid-stack-content-wrapper-inner">
|
||||
<views-code-cell-component *ngIf="cell.cellType === 'code'" [cellModel]="cell" [model]="model" [activeCellId]="activeCellId" [visible]="visible">
|
||||
</views-code-cell-component>
|
||||
<text-cell-component *ngIf="cell.cellType === 'markdown'" [cellModel]="cell" [model]="model" [activeCellId]="activeCellId">
|
||||
</text-cell-component>
|
||||
<!--<div #actionbar [style.display]="showActionBar ? 'block' : 'none'" class="actionbar"></div>-->
|
||||
<panel (onTabChange)="handleTabChange($event)" (onTabClose)="handleTabClose($event)">
|
||||
<tab [visibilityType]="'visibility'" *ngFor="let tab of tabs" [title]="tab.title" class="fullsize" [identifier]="tab.id" [type]="'tab'" [canClose]="true">
|
||||
<ng-template>
|
||||
<ng-container>
|
||||
<div #container class="card-container">
|
||||
<div *ngIf="tab.cellModel !== undefined">
|
||||
<views-code-cell-component *ngIf="tab.cellModel.cellType === 'code'" [cellModel]="tab.cellModel" [model]="model" [activeCellId]="tab.cellModel.id" [visible]="visible">
|
||||
</views-code-cell-component>
|
||||
<text-cell-component *ngIf="tab.cellModel.cellType === 'markdown'" [cellModel]="tab.cellModel" [model]="model" [activeCellId]="tab.cellModel.id">
|
||||
</text-cell-component>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</tab>
|
||||
</panel>
|
||||
</div>
|
||||
<div class="grid-stack-footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./cellToolbar';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { Component, OnInit, Input, ViewChild, TemplateRef, ElementRef, Inject, Output, EventEmitter, ChangeDetectorRef, forwardRef, SimpleChanges } from '@angular/core';
|
||||
import { Component, OnInit, Input, ViewChild, TemplateRef, ElementRef, Inject, Output, EventEmitter, ChangeDetectorRef, forwardRef, SimpleChange } from '@angular/core';
|
||||
import { CellExecutionState, ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||
import { DEFAULT_VIEW_CARD_HEIGHT, DEFAULT_VIEW_CARD_WIDTH } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewModel';
|
||||
import { CellChangeEventType, INotebookView, INotebookViewCell } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
import { DEFAULT_VIEW_CARD_HEIGHT, DEFAULT_VIEW_CARD_WIDTH, ViewsTab } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewModel';
|
||||
import { CellChangeEventType, INotebookView, INotebookViewCard } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
import { ITaskbarContent, Taskbar } from 'sql/base/browser/ui/taskbar/taskbar';
|
||||
import { CellContext } from 'sql/workbench/contrib/notebook/browser/cellViews/codeActions';
|
||||
import { RunCellAction, HideCellAction, ViewCellToggleMoreActions } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsActions';
|
||||
@@ -17,22 +17,27 @@ import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
||||
import { IColorTheme, ICssStyleCollector, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
|
||||
import { cellBorder, notebookToolbarSelectBackground } from 'sql/platform/theme/common/colorRegistry';
|
||||
import { TabComponent } from 'sql/base/browser/ui/panel/tab.component';
|
||||
import { EDITOR_GROUP_HEADER_TABS_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_BORDER, TAB_INACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
@Component({
|
||||
selector: 'view-card-component',
|
||||
templateUrl: decodeURI(require.toUrl('./notebookViewsCard.component.html'))
|
||||
})
|
||||
export class NotebookViewsCardComponent extends AngularDisposable implements OnInit {
|
||||
cell: ICellModel;
|
||||
|
||||
private _actionbar: Taskbar;
|
||||
private _metadata: INotebookViewCell;
|
||||
private _executionState: CellExecutionState;
|
||||
private _pendingReinitialize: boolean = false;
|
||||
|
||||
public _cellToggleMoreActions: ViewCellToggleMoreActions;
|
||||
|
||||
@Input() cell: ICellModel;
|
||||
@Input() card: INotebookViewCard;
|
||||
@Input() cells: ICellModel[];
|
||||
@Input() model: NotebookModel;
|
||||
@Input() activeView: INotebookView;
|
||||
@Input() activeTab: ViewsTab;
|
||||
@Input() meta: boolean;
|
||||
@Input() ready: boolean;
|
||||
@Output() onChange: EventEmitter<any> = new EventEmitter();
|
||||
@@ -52,19 +57,11 @@ export class NotebookViewsCardComponent extends AngularDisposable implements OnI
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (this.activeView && changes['activeView'] && changes['activeView'].currentValue?.guid !== changes['activeView'].previousValue?.guid) {
|
||||
this._metadata = this.activeView.getCellMetadata(this.cell);
|
||||
this._pendingReinitialize = true;
|
||||
}
|
||||
ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
|
||||
this.detectChanges();
|
||||
}
|
||||
|
||||
ngAfterContentInit() {
|
||||
if (this.activeView) {
|
||||
this._metadata = this.activeView.getCellMetadata(this.cell);
|
||||
this._pendingReinitialize = true;
|
||||
}
|
||||
ngAfterViewInit() {
|
||||
this.detectChanges();
|
||||
}
|
||||
|
||||
@@ -75,6 +72,27 @@ export class NotebookViewsCardComponent extends AngularDisposable implements OnI
|
||||
}
|
||||
}
|
||||
|
||||
handleTabChange(selectedTab: TabComponent) {
|
||||
const tab = this.tabs.find(t => t.id === selectedTab.identifier);
|
||||
if (tab && this.cell?.cellGuid !== tab.cell?.guid) {
|
||||
this.cell = this.cells.find(c => c.cellGuid === tab.cell.guid);
|
||||
this.model.updateActiveCell(this.cell);
|
||||
this.changed('active');
|
||||
|
||||
this.initActionBar();
|
||||
}
|
||||
}
|
||||
|
||||
handleTabClose(selectedTab: TabComponent) {
|
||||
const tab = this.tabs.find(t => t.id === selectedTab.identifier);
|
||||
if (tab) {
|
||||
const cell = this.cells.find(c => c.cellGuid === tab.cell.guid);
|
||||
if (cell) {
|
||||
this.activeView.hideCell(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override ngOnDestroy() {
|
||||
if (this._actionbar) {
|
||||
this._actionbar.dispose();
|
||||
@@ -83,9 +101,17 @@ export class NotebookViewsCardComponent extends AngularDisposable implements OnI
|
||||
|
||||
public initialize(): void {
|
||||
this.initActionBar();
|
||||
if (this.card.activeTab !== undefined) {
|
||||
this.cell = this.cells.find(c => c.cellGuid === this.card.activeTab.cell.guid);
|
||||
}
|
||||
|
||||
this.detectChanges();
|
||||
}
|
||||
|
||||
public get tabs(): ViewsTab[] {
|
||||
return this.card?.tabs ?? [];
|
||||
}
|
||||
|
||||
initActionBar() {
|
||||
if (this._actionbarRef) {
|
||||
let taskbarContent: ITaskbarContent[] = [];
|
||||
@@ -119,10 +145,12 @@ export class NotebookViewsCardComponent extends AngularDisposable implements OnI
|
||||
return this._item;
|
||||
}
|
||||
|
||||
|
||||
changed(event: CellChangeEventType) {
|
||||
this.onChange.emit({ cell: this.cell, event: event });
|
||||
}
|
||||
|
||||
|
||||
get displayInputModal(): boolean {
|
||||
return this.awaitingInput;
|
||||
}
|
||||
@@ -154,8 +182,13 @@ export class NotebookViewsCardComponent extends AngularDisposable implements OnI
|
||||
this.changed('hide');
|
||||
}
|
||||
|
||||
public get metadata(): INotebookViewCell {
|
||||
return this._metadata;
|
||||
|
||||
public get metadata(): INotebookViewCard {
|
||||
return this.card;
|
||||
}
|
||||
|
||||
public get guid(): string {
|
||||
return this.metadata.guid;
|
||||
}
|
||||
|
||||
public get width(): number {
|
||||
@@ -182,7 +215,7 @@ export class NotebookViewsCardComponent extends AngularDisposable implements OnI
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this._metadata) { //Means not initialized
|
||||
if (!this.cell) { //Means not initialized
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -204,8 +237,8 @@ export class NotebookViewsCardComponent extends AngularDisposable implements OnI
|
||||
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
|
||||
const cellBorderColor = theme.getColor(cellBorder);
|
||||
if (cellBorderColor) {
|
||||
collector.addRule(`.notebookEditor .nb-grid-stack .notebook-cell.active .actionbar { border-color: ${cellBorderColor};}`);
|
||||
collector.addRule(`.notebookEditor .nb-grid-stack .notebook-cell.active .actionbar .codicon:before { background-color: ${cellBorderColor};}`);
|
||||
collector.addRule(`.notebookEditor .nb-grid-stack .actionbar { border-color: ${cellBorderColor};}`);
|
||||
collector.addRule(`.notebookEditor .nb-grid-stack .actionbar .codicon:before { background-color: ${cellBorderColor};}`);
|
||||
}
|
||||
|
||||
// Cell toolbar background
|
||||
@@ -213,4 +246,51 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
|
||||
if (notebookToolbarSelectBackgroundColor) {
|
||||
collector.addRule(`.notebookEditor .nb-grid-stack .notebook-cell.active .actionbar { background-color: ${notebookToolbarSelectBackgroundColor};}`);
|
||||
}
|
||||
|
||||
|
||||
const tabBorder = theme.getColor(TAB_BORDER);
|
||||
const tabBackground = theme.getColor(TAB_INACTIVE_BACKGROUND);
|
||||
const tabActiveBackground = theme.getColor(TAB_ACTIVE_BACKGROUND);
|
||||
|
||||
const headerBackground = theme.getColor(EDITOR_GROUP_HEADER_TABS_BACKGROUND);
|
||||
if (headerBackground) {
|
||||
collector.addRule(`
|
||||
.notebook-cell .grid-stack-header {
|
||||
background-color: ${headerBackground.toString()};
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
if (tabBackground && tabBorder) {
|
||||
collector.addRule(`
|
||||
.notebook-cell .tabbedPanel.horizontal > .title .tabList {
|
||||
border-color: ${tabBorder.toString()};
|
||||
background-color: ${tabBackground.toString()};
|
||||
}
|
||||
|
||||
.notebook-cell .tabbedPanel.horizontal > .title .tabList .tab-header {
|
||||
border-right: 1px solid ${tabBorder.toString()};
|
||||
background-color: ${tabBackground.toString()};
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.notebook-cell .tabbedPanel.horizontal > .title .tabList a.action-label.codicon.close {
|
||||
background-size: 9px 9px !important;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.notebook-cell .tabbedPanel.horizontal > .title .tabList .actions-container {
|
||||
margin-right: 0px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
`);
|
||||
}
|
||||
|
||||
if (tabActiveBackground) {
|
||||
collector.addRule(`
|
||||
.notebook-cell .tabbedPanel.horizontal > .title .tabList .tab-header.active {
|
||||
background-color: ${tabActiveBackground.toString()};
|
||||
}
|
||||
`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div class="nb-grid-stack grid-stack">
|
||||
<ng-container *ngFor="let cell of cells">
|
||||
<view-card-component #wrapper [ready]="loaded" [activeView]="activeView" [meta]="cell.metadata" [cell]="cell" [model]="model" (onChange)="onCellChanged($event)"></view-card-component>
|
||||
<ng-container #divContainer *ngFor="let card of cards; trackBy: trackByCardId">
|
||||
<view-card-component #wrapper [activeView]="activeView" [card]="card" [model]="model" [cells]="cells"></view-card-component>
|
||||
<ng-content *ngTemplateOutlet='wrapper.templateRef'></ng-content>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -4,16 +4,15 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./notebookViewsGrid';
|
||||
import { Component, OnInit, ViewChildren, QueryList, Input, Inject, forwardRef, ChangeDetectorRef, ViewEncapsulation, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, OnInit, ViewChildren, QueryList, Input, Inject, forwardRef, ChangeDetectorRef, ViewEncapsulation, ChangeDetectionStrategy, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';
|
||||
import { NotebookViewsCardComponent } from 'sql/workbench/contrib/notebook/browser/notebookViews/notebookViewsCard.component';
|
||||
import { ICellModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
|
||||
import { NotebookModel } from 'sql/workbench/services/notebook/browser/models/notebookModel';
|
||||
import { GridItemHTMLElement, GridStack, GridStackEvent, GridStackNode } from 'gridstack';
|
||||
import { localize } from 'vs/nls';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
import { CellChangeEvent, INotebookView, INotebookViewCell } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
import { CellChangeEvent, INotebookView, INotebookViewCard } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
import { AngularDisposable } from 'sql/base/browser/lifecycle';
|
||||
import { generateLayout } from 'sql/workbench/services/notebook/browser/notebookViews/autodash';
|
||||
|
||||
export interface INotebookViewsGridOptions {
|
||||
cellHeight?: number;
|
||||
@@ -31,6 +30,7 @@ export class NotebookViewsGridComponent extends AngularDisposable implements OnI
|
||||
@Input() activeView: INotebookView;
|
||||
@Input() views: NotebookViewsExtension;
|
||||
|
||||
@ViewChild('divContainer', { read: ViewContainerRef }) _containerRef: ViewContainerRef;
|
||||
@ViewChildren(NotebookViewsCardComponent) private _items: QueryList<NotebookViewsCardComponent>;
|
||||
|
||||
protected _grid: GridStack;
|
||||
@@ -45,13 +45,18 @@ export class NotebookViewsGridComponent extends AngularDisposable implements OnI
|
||||
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(forwardRef(() => ComponentFactoryResolver)) private _componentFactoryResolver: ComponentFactoryResolver
|
||||
) {
|
||||
super();
|
||||
this._loaded = false;
|
||||
}
|
||||
|
||||
public get cards(): INotebookViewCard[] {
|
||||
return this.activeView ? this.activeView.cards : [];
|
||||
}
|
||||
|
||||
public get empty(): boolean {
|
||||
return !this._items || !this._items.find(item => item.visible);
|
||||
return !this._items?.length;
|
||||
}
|
||||
|
||||
public get hiddenItems(): NotebookViewsCardComponent[] {
|
||||
@@ -89,11 +94,6 @@ export class NotebookViewsGridComponent extends AngularDisposable implements OnI
|
||||
this._grid = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.model?.activeCell?.id !== this._activeCell?.id) {
|
||||
this._activeCell = this.model.activeCell;
|
||||
this.detectChanges();
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
@@ -135,11 +135,12 @@ export class NotebookViewsGridComponent extends AngularDisposable implements OnI
|
||||
}
|
||||
|
||||
this._grid = GridStack.init({
|
||||
alwaysShowResizeHandle: false,
|
||||
alwaysShowResizeHandle: true,
|
||||
styleInHead: true,
|
||||
margin: 2,
|
||||
margin: 5,
|
||||
cellHeight: this._options.cellHeight,
|
||||
staticGrid: false,
|
||||
handleClass: 'grid-stack-header'
|
||||
});
|
||||
|
||||
|
||||
@@ -157,41 +158,48 @@ export class NotebookViewsGridComponent extends AngularDisposable implements OnI
|
||||
}
|
||||
|
||||
this._grid.batchUpdate();
|
||||
this.activeView.cells.forEach(cell => {
|
||||
const el = this._grid.getGridItems().find(x => x.getAttribute('data-cell-id') === cell.cellGuid);
|
||||
this.activeView.cards.forEach(card => {
|
||||
const el = this._grid.getGridItems().find(x => x.getAttribute('data-card-guid') === card.guid);
|
||||
if (el) {
|
||||
const cellData = this.activeView.getCellMetadata(cell);
|
||||
this._grid.update(el, { x: cellData.x, y: cellData.y, w: cellData.width, h: cellData.height });
|
||||
|
||||
if (cellData?.hidden) {
|
||||
this._grid.removeWidget(el, false); // Do not trigger event for batch update
|
||||
}
|
||||
this._grid.update(el, { x: card.x, y: card.y, w: card.width, h: card.height });
|
||||
}
|
||||
});
|
||||
this._grid.commit();
|
||||
}
|
||||
|
||||
private resizeCells(): void {
|
||||
private resizeCards(): void {
|
||||
this._items.forEach((i: NotebookViewsCardComponent) => {
|
||||
if (i.elementRef) {
|
||||
const cellHeight = this._options.cellHeight;
|
||||
let maxTabHeight = 30;
|
||||
|
||||
const naturalHeight = i.elementRef.nativeElement.clientHeight;
|
||||
const heightInCells = Math.ceil(naturalHeight / cellHeight);
|
||||
const cardContainers: HTMLCollection = i.elementRef.nativeElement.getElementsByClassName('card-container');
|
||||
if (cardContainers) {
|
||||
maxTabHeight = Array.from(cardContainers).reduce((accum, cardContainer) => {
|
||||
return Math.max(cardContainer.children[0]?.clientHeight ?? 0, accum);
|
||||
}, maxTabHeight);
|
||||
}
|
||||
|
||||
const update: INotebookViewCell = {
|
||||
const cardNaturalHeight = i.elementRef.nativeElement.clientHeight + maxTabHeight;
|
||||
const heightInCells = Math.ceil(cardNaturalHeight / cellHeight);
|
||||
|
||||
const update: INotebookViewCard = {
|
||||
height: heightInCells
|
||||
};
|
||||
|
||||
this.views.updateCell(i.cell, this.activeView, update);
|
||||
this.views.updateCard(i, update, this.activeView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private runAutoLayout(view: INotebookView): void {
|
||||
//Resize the cells before regenerating layout so that we know the natural height of the cells
|
||||
this.resizeCells();
|
||||
generateLayout(view);
|
||||
this.resizeCards();
|
||||
//generateLayout(view);
|
||||
}
|
||||
|
||||
trackByCardId(index, item) {
|
||||
return item ? item.guid : undefined;
|
||||
}
|
||||
|
||||
private detectChanges(): void {
|
||||
@@ -208,20 +216,29 @@ export class NotebookViewsGridComponent extends AngularDisposable implements OnI
|
||||
this.activeView.hideCell(e.cell);
|
||||
}
|
||||
|
||||
if (e.cell && e.event === 'insert') {
|
||||
const component = this._items.find(x => x.cell.cellGuid === e.cell.cellGuid);
|
||||
|
||||
this.activeView.insertCell(e.cell);
|
||||
if (e.cell && e.event === 'insert') {
|
||||
const card = this.activeView.insertCell(e.cell);
|
||||
|
||||
let cardComponentFactory = this._componentFactoryResolver.resolveComponentFactory(NotebookViewsCardComponent);
|
||||
let cardComponent = this._containerRef.createComponent(cardComponentFactory);
|
||||
|
||||
cardComponent.instance.ready = true;
|
||||
cardComponent.instance.activeView = this.activeView;
|
||||
cardComponent.instance.card = card;
|
||||
cardComponent.instance.model = this.model;
|
||||
cardComponent.instance.cells = this.cells;
|
||||
|
||||
cardComponent.instance.initialize();
|
||||
|
||||
this.detectChanges();
|
||||
|
||||
const el = this._grid.getGridItems().find(x => x.getAttribute('data-cell-id') === e.cell.cellGuid);
|
||||
this._grid.makeWidget(el);
|
||||
const el = this._grid.getGridItems().find(x => x.getAttribute('data-card-guid') === card.guid);
|
||||
|
||||
this._grid.addWidget(el);
|
||||
this._grid.update(el, { x: 0, y: 0 });
|
||||
this._grid.resizable(el, true);
|
||||
this._grid.movable(el, true);
|
||||
|
||||
component.initialize();
|
||||
}
|
||||
|
||||
if (e.cell && e.event === 'update') {
|
||||
@@ -243,25 +260,19 @@ export class NotebookViewsGridComponent extends AngularDisposable implements OnI
|
||||
*/
|
||||
persist(action: GridStackEvent, changedItems: GridStackNode[] = [], grid: GridStack, items: QueryList<NotebookViewsCardComponent>): void {
|
||||
changedItems.forEach((changedItem) => {
|
||||
const cellId = changedItem.el.getAttribute('data-cell-id');
|
||||
const item = items.toArray().find(item => item.cell.cellGuid === cellId);
|
||||
const cellId = changedItem.el.getAttribute('data-card-guid');
|
||||
const item = items.toArray().find(item => item.metadata.guid === cellId);
|
||||
|
||||
if (item && this.activeView) {
|
||||
const update: INotebookViewCell = {
|
||||
guid: this.activeView.guid,
|
||||
const update: INotebookViewCard = {
|
||||
guid: item.guid,
|
||||
x: changedItem.x,
|
||||
y: changedItem.y,
|
||||
width: changedItem.w,
|
||||
height: changedItem.h
|
||||
};
|
||||
|
||||
if (action === 'added') {
|
||||
update.hidden = false;
|
||||
} else if (action === 'removed') {
|
||||
update.hidden = true;
|
||||
}
|
||||
|
||||
this.views.updateCell(item.cell, this.activeView, update);
|
||||
this.views.updateCard(item.metadata, update, this.activeView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
.nb-grid-stack > .grid-stack-item > .grid-stack-item-content {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
overflow-x: hidden;
|
||||
@@ -310,6 +311,14 @@
|
||||
.nb-grid-stack > .grid-stack-item {
|
||||
margin: 0;
|
||||
}
|
||||
.nb-grid-stack > .grid-stack-item .grid-stack-header {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
}
|
||||
.nb-grid-stack > .grid-stack-item .grid-stack-footer {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
}
|
||||
.nb-grid-stack > .grid-stack-item .grid-stack-item-content {
|
||||
display: flex;
|
||||
cursor: move;
|
||||
@@ -325,9 +334,13 @@
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.nb-grid-stack > .grid-stack-item .grid-stack-item-content .grid-stack-content-wrapper-inner {
|
||||
height: calc(100% - 25px);
|
||||
}
|
||||
.nb-grid-stack > .grid-stack-item .grid-stack-item-content .grid-stack-content-wrapper-inner .card-container {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
cursor: auto;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.nb-grid-stack > .grid-stack-item .grid-stack-item-content ::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
|
||||
Reference in New Issue
Block a user