Skip to content

Commit 2d78f0b

Browse files
trungleducgithub-actions[bot]arjxn-py
authored
Swap annotation and object properties panel (#554)
* 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]>
1 parent 4fd3c31 commit 2d78f0b

File tree

21 files changed

+418
-124
lines changed

21 files changed

+418
-124
lines changed

packages/base/src/panelview/formbuilder.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export class ObjectPropertiesForm extends React.Component<IProps, IStates> {
183183
className="jpcad-property-panel"
184184
data-path={this.props.filePath ?? ''}
185185
>
186-
<div className="jpcad-property-outer">
186+
<div className="jpcad-property-outer jp-scrollbar-tiny">
187187
<LuminoSchemaForm>{formSchema}</LuminoSchemaForm>
188188
</div>
189189
<div className="jpcad-property-buttons">

packages/base/src/panelview/leftpanel.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import {
2-
IAnnotationModel,
32
JupyterCadDoc,
4-
IJupyterCadTracker
3+
IJupyterCadTracker,
4+
IJCadFormSchemaRegistry
55
} from '@jupytercad/schema';
66
import { SidePanel } from '@jupyterlab/ui-components';
77

88
import { IControlPanelModel } from '../types';
9-
import { Annotations } from './annotations';
109
import { ControlPanelHeader } from './header';
1110
import { ObjectTree } from './objecttree';
11+
import { ObjectProperties } from './objectproperties';
12+
import { AccordionPanel } from '@lumino/widgets';
1213

1314
export class LeftPanelWidget extends SidePanel {
1415
constructor(options: LeftPanelWidget.IOptions) {
@@ -17,41 +18,41 @@ export class LeftPanelWidget extends SidePanel {
1718
this.addClass('data-jcad-keybinding');
1819
this.node.tabIndex = 0;
1920
this._model = options.model;
20-
this._annotationModel = options.annotationModel;
2121
const header = new ControlPanelHeader();
2222
this.header.addWidget(header);
2323

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

27-
const annotations = new Annotations({ model: this._annotationModel });
28-
this.addWidget(annotations);
27+
const properties = new ObjectProperties({
28+
controlPanelModel: this._model,
29+
formSchemaRegistry: options.formSchemaRegistry,
30+
tracker: options.tracker
31+
});
32+
this.addWidget(properties);
2933

3034
options.tracker.currentChanged.connect((_, changed) => {
3135
if (changed) {
3236
header.title.label = changed.context.localPath;
33-
this._annotationModel.context =
34-
options.tracker.currentWidget?.context || undefined;
3537
} else {
3638
header.title.label = '-';
37-
this._annotationModel.context = undefined;
3839
}
3940
});
41+
(this.content as AccordionPanel).setRelativeSizes([4, 6]);
4042
}
4143

4244
dispose(): void {
4345
super.dispose();
4446
}
4547

4648
private _model: IControlPanelModel;
47-
private _annotationModel: IAnnotationModel;
4849
}
4950

5051
export namespace LeftPanelWidget {
5152
export interface IOptions {
5253
model: IControlPanelModel;
53-
annotationModel: IAnnotationModel;
5454
tracker: IJupyterCadTracker;
55+
formSchemaRegistry: IJCadFormSchemaRegistry;
5556
}
5657

5758
export interface IProps {

packages/base/src/panelview/objectproperties.tsx

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
IJupyterCadClientState,
77
IJupyterCadDoc,
88
IJupyterCadModel,
9-
IJupyterCadTracker
9+
IJupyterCadTracker,
10+
ISelection
1011
} from '@jupytercad/schema';
1112
import { ReactWidget, showErrorMessage } from '@jupyterlab/apputils';
1213
import { PanelWithToolbar } from '@jupyterlab/ui-components';
@@ -26,16 +27,77 @@ import { JupyterCadWidget } from '../widget';
2627
export class ObjectProperties extends PanelWithToolbar {
2728
constructor(params: ObjectProperties.IOptions) {
2829
super(params);
30+
const { controlPanelModel, formSchemaRegistry, tracker } = params;
2931
this.title.label = 'Objects Properties';
3032
const body = ReactWidget.create(
3133
<ObjectPropertiesReact
32-
cpModel={params.controlPanelModel}
33-
tracker={params.tracker}
34-
formSchemaRegistry={params.formSchemaRegistry}
34+
cpModel={controlPanelModel}
35+
tracker={tracker}
36+
formSchemaRegistry={formSchemaRegistry}
3537
/>
3638
);
3739
this.addWidget(body);
3840
this.addClass('jpcad-sidebar-propertiespanel');
41+
42+
const updateTitle = (
43+
sender: IJupyterCadModel,
44+
clients: Map<number, IJupyterCadClientState>
45+
) => {
46+
const localState = sender.localState;
47+
if (!localState) {
48+
return;
49+
}
50+
51+
let selection: { [key: string]: ISelection } = {};
52+
if (localState.remoteUser) {
53+
// We are in following mode.
54+
// Sync selections from a remote user
55+
const remoteState = clients.get(localState.remoteUser);
56+
57+
if (remoteState?.selected?.value) {
58+
selection = remoteState?.selected?.value;
59+
}
60+
} else if (localState.selected?.value) {
61+
selection = localState.selected.value;
62+
}
63+
const selectionNames = Object.keys(selection);
64+
if (selectionNames.length === 1) {
65+
const selected = selectionNames[0];
66+
if (selected.startsWith('edge-') && selection[selected].parent) {
67+
this.title.label = selection[selected].parent;
68+
} else {
69+
this.title.label = selected;
70+
}
71+
} else {
72+
this.title.label = 'No selection';
73+
}
74+
};
75+
76+
let currentModel: IJupyterCadModel | undefined = undefined;
77+
controlPanelModel.documentChanged.connect((_, changed) => {
78+
if (changed) {
79+
if (currentModel) {
80+
currentModel.clientStateChanged.disconnect(updateTitle);
81+
}
82+
83+
if (changed.context.model.sharedModel.editable) {
84+
currentModel = changed.context.model;
85+
const clients = currentModel.sharedModel.awareness.getStates() as Map<
86+
number,
87+
IJupyterCadClientState
88+
>;
89+
updateTitle(currentModel, clients);
90+
currentModel.clientStateChanged.connect(updateTitle);
91+
92+
body.show();
93+
} else {
94+
this.title.label = 'Read Only File';
95+
body.hide();
96+
}
97+
} else {
98+
this.title.label = '-';
99+
}
100+
});
39101
}
40102
}
41103

packages/base/src/panelview/objecttree.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ const visibilityOffIcon = new LabIcon({
4040
svgstr: visibilityOffSvg
4141
});
4242

43-
const TREE_THEMES: ThemeSettings = {
43+
export const TREE_THEMES: ThemeSettings = {
4444
labTheme: {
4545
text: {
4646
fontSize: '14px',
@@ -345,7 +345,7 @@ class ObjectTreeReact extends React.Component<IProps, IStates> {
345345
}
346346

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

394394
return (
395395
<div
396-
className={`jpcad-control-panel-tree ${opts.selected ? 'selected' : ''}`}
396+
className={`jpcad-control-panel-tree ${
397+
opts.selected ? 'selected' : ''
398+
}`}
397399
onClick={() => this.handleNodeClick(opts.node.id as string)}
398400
>
399401
<div

packages/base/src/panelview/rightpanel.tsx

Lines changed: 17 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import {
2-
IJCadFormSchemaRegistry,
3-
IJupyterCadClientState,
4-
IJupyterCadModel,
2+
IAnnotationModel,
53
IJupyterCadTracker,
6-
ISelection,
74
JupyterCadDoc
85
} from '@jupytercad/schema';
96
import { SidePanel } from '@jupyterlab/ui-components';
107

118
import { IControlPanelModel } from '../types';
9+
import { Annotations } from './annotations';
1210
import { ControlPanelHeader } from './header';
13-
import { ObjectProperties } from './objectproperties';
1411

1512
export class RightPanelWidget extends SidePanel {
1613
constructor(options: RightPanelWidget.IOptions) {
@@ -19,87 +16,42 @@ export class RightPanelWidget extends SidePanel {
1916
this.addClass('data-jcad-keybinding');
2017
this.node.tabIndex = 0;
2118
this._model = options.model;
19+
this._annotationModel = options.annotationModel;
20+
2221
const header = new ControlPanelHeader();
2322
this.header.addWidget(header);
24-
const properties = new ObjectProperties({
25-
controlPanelModel: this._model,
26-
formSchemaRegistry: options.formSchemaRegistry,
27-
tracker: options.tracker
28-
});
29-
30-
const updateTitle = (
31-
sender: IJupyterCadModel,
32-
clients: Map<number, IJupyterCadClientState>
33-
) => {
34-
const localState = sender.localState;
35-
if (!localState) {
36-
return;
37-
}
38-
39-
let selection: { [key: string]: ISelection } = {};
40-
if (localState.remoteUser) {
41-
// We are in following mode.
42-
// Sync selections from a remote user
43-
const remoteState = clients.get(localState.remoteUser);
4423

45-
if (remoteState?.selected?.value) {
46-
selection = remoteState?.selected?.value;
47-
}
48-
} else if (localState.selected?.value) {
49-
selection = localState.selected.value;
50-
}
51-
const selectionNames = Object.keys(selection);
52-
if (selectionNames.length === 1) {
53-
const selected = selectionNames[0];
54-
if (selected.startsWith('edge-') && selection[selected].parent) {
55-
header.title.label = selection[selected].parent;
56-
} else {
57-
header.title.label = selected;
58-
}
59-
} else {
60-
header.title.label = 'No selection';
61-
}
62-
};
24+
const annotations = new Annotations({ model: this._annotationModel });
25+
this.addWidget(annotations);
6326

64-
let currentModel: IJupyterCadModel | undefined = undefined;
65-
this.addWidget(properties);
66-
this._model.documentChanged.connect((_, changed) => {
27+
options.tracker.currentChanged.connect((_, changed) => {
6728
if (changed) {
68-
if (currentModel) {
69-
currentModel.clientStateChanged.disconnect(updateTitle);
70-
}
71-
72-
if (changed.context.model.sharedModel.editable) {
73-
currentModel = changed.context.model;
74-
const clients = currentModel.sharedModel.awareness.getStates() as Map<
75-
number,
76-
IJupyterCadClientState
77-
>;
78-
updateTitle(currentModel, clients);
79-
currentModel.clientStateChanged.connect(updateTitle);
80-
81-
properties.show();
82-
} else {
83-
header.title.label = `${changed.context.localPath} - Read Only`;
84-
properties.hide();
85-
}
29+
header.title.label = changed.context.localPath;
30+
this._annotationModel.context =
31+
options.tracker.currentWidget?.context || undefined;
8632
} else {
8733
header.title.label = '-';
34+
this._annotationModel.context = undefined;
8835
}
8936
});
9037
}
9138

39+
get model(): IControlPanelModel {
40+
return this._model;
41+
}
42+
9243
dispose(): void {
9344
super.dispose();
9445
}
9546
private _model: IControlPanelModel;
47+
private _annotationModel: IAnnotationModel;
9648
}
9749

9850
export namespace RightPanelWidget {
9951
export interface IOptions {
10052
model: IControlPanelModel;
10153
tracker: IJupyterCadTracker;
102-
formSchemaRegistry: IJCadFormSchemaRegistry;
54+
annotationModel: IAnnotationModel;
10355
}
10456
export interface IProps {
10557
filePath?: string;

0 commit comments

Comments
 (0)