Skip to content

Commit

Permalink
Swap annotation and object properties panel (#554)
Browse files Browse the repository at this point in the history
* Update left panel

* Update right panel

* Remove suggestion panel

* Fix UI test

* Fix test

* Update Playwright Snapshots

* Update Playwright Snapshots

* Remove commented code

* Update python/jupytercad_lab/src/index.ts

Co-authored-by: Arjun Verma <[email protected]>

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Arjun Verma <[email protected]>
  • Loading branch information
3 people authored Oct 31, 2024
1 parent 4fd3c31 commit 2d78f0b
Show file tree
Hide file tree
Showing 21 changed files with 418 additions and 124 deletions.
2 changes: 1 addition & 1 deletion packages/base/src/panelview/formbuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export class ObjectPropertiesForm extends React.Component<IProps, IStates> {
className="jpcad-property-panel"
data-path={this.props.filePath ?? ''}
>
<div className="jpcad-property-outer">
<div className="jpcad-property-outer jp-scrollbar-tiny">
<LuminoSchemaForm>{formSchema}</LuminoSchemaForm>
</div>
<div className="jpcad-property-buttons">
Expand Down
23 changes: 12 additions & 11 deletions packages/base/src/panelview/leftpanel.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import {
IAnnotationModel,
JupyterCadDoc,
IJupyterCadTracker
IJupyterCadTracker,
IJCadFormSchemaRegistry
} from '@jupytercad/schema';
import { SidePanel } from '@jupyterlab/ui-components';

import { IControlPanelModel } from '../types';
import { Annotations } from './annotations';
import { ControlPanelHeader } from './header';
import { ObjectTree } from './objecttree';
import { ObjectProperties } from './objectproperties';
import { AccordionPanel } from '@lumino/widgets';

export class LeftPanelWidget extends SidePanel {
constructor(options: LeftPanelWidget.IOptions) {
Expand All @@ -17,41 +18,41 @@ export class LeftPanelWidget extends SidePanel {
this.addClass('data-jcad-keybinding');
this.node.tabIndex = 0;
this._model = options.model;
this._annotationModel = options.annotationModel;
const header = new ControlPanelHeader();
this.header.addWidget(header);

const tree = new ObjectTree({ controlPanelModel: this._model });
this.addWidget(tree);

const annotations = new Annotations({ model: this._annotationModel });
this.addWidget(annotations);
const properties = new ObjectProperties({
controlPanelModel: this._model,
formSchemaRegistry: options.formSchemaRegistry,
tracker: options.tracker
});
this.addWidget(properties);

options.tracker.currentChanged.connect((_, changed) => {
if (changed) {
header.title.label = changed.context.localPath;
this._annotationModel.context =
options.tracker.currentWidget?.context || undefined;
} else {
header.title.label = '-';
this._annotationModel.context = undefined;
}
});
(this.content as AccordionPanel).setRelativeSizes([4, 6]);
}

dispose(): void {
super.dispose();
}

private _model: IControlPanelModel;
private _annotationModel: IAnnotationModel;
}

export namespace LeftPanelWidget {
export interface IOptions {
model: IControlPanelModel;
annotationModel: IAnnotationModel;
tracker: IJupyterCadTracker;
formSchemaRegistry: IJCadFormSchemaRegistry;
}

export interface IProps {
Expand Down
70 changes: 66 additions & 4 deletions packages/base/src/panelview/objectproperties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
IJupyterCadClientState,
IJupyterCadDoc,
IJupyterCadModel,
IJupyterCadTracker
IJupyterCadTracker,
ISelection
} from '@jupytercad/schema';
import { ReactWidget, showErrorMessage } from '@jupyterlab/apputils';
import { PanelWithToolbar } from '@jupyterlab/ui-components';
Expand All @@ -26,16 +27,77 @@ import { JupyterCadWidget } from '../widget';
export class ObjectProperties extends PanelWithToolbar {
constructor(params: ObjectProperties.IOptions) {
super(params);
const { controlPanelModel, formSchemaRegistry, tracker } = params;
this.title.label = 'Objects Properties';
const body = ReactWidget.create(
<ObjectPropertiesReact
cpModel={params.controlPanelModel}
tracker={params.tracker}
formSchemaRegistry={params.formSchemaRegistry}
cpModel={controlPanelModel}
tracker={tracker}
formSchemaRegistry={formSchemaRegistry}
/>
);
this.addWidget(body);
this.addClass('jpcad-sidebar-propertiespanel');

const updateTitle = (
sender: IJupyterCadModel,
clients: Map<number, IJupyterCadClientState>
) => {
const localState = sender.localState;
if (!localState) {
return;
}

let selection: { [key: string]: ISelection } = {};
if (localState.remoteUser) {
// We are in following mode.
// Sync selections from a remote user
const remoteState = clients.get(localState.remoteUser);

if (remoteState?.selected?.value) {
selection = remoteState?.selected?.value;
}
} else if (localState.selected?.value) {
selection = localState.selected.value;
}
const selectionNames = Object.keys(selection);
if (selectionNames.length === 1) {
const selected = selectionNames[0];
if (selected.startsWith('edge-') && selection[selected].parent) {
this.title.label = selection[selected].parent;
} else {
this.title.label = selected;
}
} else {
this.title.label = 'No selection';
}
};

let currentModel: IJupyterCadModel | undefined = undefined;
controlPanelModel.documentChanged.connect((_, changed) => {
if (changed) {
if (currentModel) {
currentModel.clientStateChanged.disconnect(updateTitle);
}

if (changed.context.model.sharedModel.editable) {
currentModel = changed.context.model;
const clients = currentModel.sharedModel.awareness.getStates() as Map<
number,
IJupyterCadClientState
>;
updateTitle(currentModel, clients);
currentModel.clientStateChanged.connect(updateTitle);

body.show();
} else {
this.title.label = 'Read Only File';
body.hide();
}
} else {
this.title.label = '-';
}
});
}
}

Expand Down
8 changes: 5 additions & 3 deletions packages/base/src/panelview/objecttree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const visibilityOffIcon = new LabIcon({
svgstr: visibilityOffSvg
});

const TREE_THEMES: ThemeSettings = {
export const TREE_THEMES: ThemeSettings = {
labTheme: {
text: {
fontSize: '14px',
Expand Down Expand Up @@ -345,7 +345,7 @@ class ObjectTreeReact extends React.Component<IProps, IStates> {
}

return (
<div className="jpcad-treeview-wrapper" tabIndex={0}>
<div className="jpcad-treeview-wrapper jp-scrollbar-tiny" tabIndex={0}>
<ReactTree
multiSelect={true}
nodes={data}
Expand Down Expand Up @@ -393,7 +393,9 @@ class ObjectTreeReact extends React.Component<IProps, IStates> {

return (
<div
className={`jpcad-control-panel-tree ${opts.selected ? 'selected' : ''}`}
className={`jpcad-control-panel-tree ${
opts.selected ? 'selected' : ''
}`}
onClick={() => this.handleNodeClick(opts.node.id as string)}
>
<div
Expand Down
82 changes: 17 additions & 65 deletions packages/base/src/panelview/rightpanel.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import {
IJCadFormSchemaRegistry,
IJupyterCadClientState,
IJupyterCadModel,
IAnnotationModel,
IJupyterCadTracker,
ISelection,
JupyterCadDoc
} from '@jupytercad/schema';
import { SidePanel } from '@jupyterlab/ui-components';

import { IControlPanelModel } from '../types';
import { Annotations } from './annotations';
import { ControlPanelHeader } from './header';
import { ObjectProperties } from './objectproperties';

export class RightPanelWidget extends SidePanel {
constructor(options: RightPanelWidget.IOptions) {
Expand All @@ -19,87 +16,42 @@ export class RightPanelWidget extends SidePanel {
this.addClass('data-jcad-keybinding');
this.node.tabIndex = 0;
this._model = options.model;
this._annotationModel = options.annotationModel;

const header = new ControlPanelHeader();
this.header.addWidget(header);
const properties = new ObjectProperties({
controlPanelModel: this._model,
formSchemaRegistry: options.formSchemaRegistry,
tracker: options.tracker
});

const updateTitle = (
sender: IJupyterCadModel,
clients: Map<number, IJupyterCadClientState>
) => {
const localState = sender.localState;
if (!localState) {
return;
}

let selection: { [key: string]: ISelection } = {};
if (localState.remoteUser) {
// We are in following mode.
// Sync selections from a remote user
const remoteState = clients.get(localState.remoteUser);

if (remoteState?.selected?.value) {
selection = remoteState?.selected?.value;
}
} else if (localState.selected?.value) {
selection = localState.selected.value;
}
const selectionNames = Object.keys(selection);
if (selectionNames.length === 1) {
const selected = selectionNames[0];
if (selected.startsWith('edge-') && selection[selected].parent) {
header.title.label = selection[selected].parent;
} else {
header.title.label = selected;
}
} else {
header.title.label = 'No selection';
}
};
const annotations = new Annotations({ model: this._annotationModel });
this.addWidget(annotations);

let currentModel: IJupyterCadModel | undefined = undefined;
this.addWidget(properties);
this._model.documentChanged.connect((_, changed) => {
options.tracker.currentChanged.connect((_, changed) => {
if (changed) {
if (currentModel) {
currentModel.clientStateChanged.disconnect(updateTitle);
}

if (changed.context.model.sharedModel.editable) {
currentModel = changed.context.model;
const clients = currentModel.sharedModel.awareness.getStates() as Map<
number,
IJupyterCadClientState
>;
updateTitle(currentModel, clients);
currentModel.clientStateChanged.connect(updateTitle);

properties.show();
} else {
header.title.label = `${changed.context.localPath} - Read Only`;
properties.hide();
}
header.title.label = changed.context.localPath;
this._annotationModel.context =
options.tracker.currentWidget?.context || undefined;
} else {
header.title.label = '-';
this._annotationModel.context = undefined;
}
});
}

get model(): IControlPanelModel {
return this._model;
}

dispose(): void {
super.dispose();
}
private _model: IControlPanelModel;
private _annotationModel: IAnnotationModel;
}

export namespace RightPanelWidget {
export interface IOptions {
model: IControlPanelModel;
tracker: IJupyterCadTracker;
formSchemaRegistry: IJCadFormSchemaRegistry;
annotationModel: IAnnotationModel;
}
export interface IProps {
filePath?: string;
Expand Down
Loading

0 comments on commit 2d78f0b

Please sign in to comment.