Skip to content

Commit dabfb28

Browse files
Improve deletion behavior (#369)
* Improve deletion behavior * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Handle updating objects parameters * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update ui-tests * Try fixing UI-tests * Trung's comment * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 71e093c commit dabfb28

File tree

5 files changed

+133
-20
lines changed

5 files changed

+133
-20
lines changed

packages/base/src/commands.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ const OPERATORS = {
246246
shape: 'Part::Cut',
247247
parameters,
248248
visible: true,
249-
name: Name
249+
name: Name,
250+
dependencies: [parameters['Base'], parameters['Tool']]
250251
};
251252

252253
return executeOperator(
@@ -287,7 +288,8 @@ const OPERATORS = {
287288
shape: 'Part::Extrusion',
288289
parameters,
289290
visible: true,
290-
name: Name
291+
name: Name,
292+
dependencies: [parameters['Base']]
291293
};
292294

293295
return executeOperator(
@@ -325,7 +327,8 @@ const OPERATORS = {
325327
shape: 'Part::MultiFuse',
326328
parameters,
327329
visible: true,
328-
name: Name
330+
name: Name,
331+
dependencies: parameters['Shapes']
329332
};
330333

331334
return executeOperator(
@@ -365,7 +368,8 @@ const OPERATORS = {
365368
shape: 'Part::MultiCommon',
366369
parameters,
367370
visible: true,
368-
name: Name
371+
name: Name,
372+
dependencies: parameters['Shapes']
369373
};
370374

371375
return executeOperator(
@@ -404,7 +408,8 @@ const OPERATORS = {
404408
shape: 'Part::Chamfer',
405409
parameters,
406410
visible: true,
407-
name: Name
411+
name: Name,
412+
dependencies: [parameters['Base']]
408413
};
409414

410415
return executeOperator(
@@ -441,7 +446,8 @@ const OPERATORS = {
441446
shape: 'Part::Fillet',
442447
parameters,
443448
visible: true,
444-
name: Name
449+
name: Name,
450+
dependencies: [parameters['Base']]
445451
};
446452

447453
return executeOperator(

packages/base/src/panelview/objecttree.tsx

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
IJupyterCadModel,
99
ISelection
1010
} from '@jupytercad/schema';
11-
import { ReactWidget } from '@jupyterlab/apputils';
11+
import { Dialog, ReactWidget, showDialog } from '@jupyterlab/apputils';
1212
import {
1313
closeIcon,
1414
LabIcon,
@@ -394,9 +394,44 @@ class ObjectTreeReact extends React.Component<IProps, IStates> {
394394
className={'jp-ToolbarButtonComponent'}
395395
onClick={() => {
396396
const objectId = opts.node.parentId as string;
397-
this.props.cpModel.jcadModel?.sharedModel.removeObjectByName(
398-
objectId
399-
);
397+
const sharedModel =
398+
this.props.cpModel.jcadModel?.sharedModel;
399+
if (!sharedModel) {
400+
return;
401+
}
402+
403+
const dependants =
404+
sharedModel.getDependants(objectId);
405+
406+
let body: React.JSX.Element;
407+
if (dependants.length) {
408+
body = (
409+
<div>
410+
{
411+
'Removing this object will also result in removing:'
412+
}
413+
<ul>
414+
{dependants.map(dependant => (
415+
<li>{dependant}</li>
416+
))}
417+
</ul>
418+
</div>
419+
);
420+
} else {
421+
body = <div>Are you sure?</div>;
422+
}
423+
424+
showDialog({
425+
title: `Removing ${objectId}`,
426+
body,
427+
buttons: [Dialog.okButton(), Dialog.cancelButton()]
428+
}).then(({ button: { accept } }) => {
429+
if (accept) {
430+
const toRemove = dependants.concat([objectId]);
431+
sharedModel.removeObjects(toRemove);
432+
}
433+
});
434+
400435
this.props.cpModel.jcadModel?.syncSelected({});
401436
}}
402437
icon={closeIcon}

packages/schema/src/doc.ts

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,48 @@ export class JupyterCadDoc
8181
return undefined;
8282
}
8383

84+
getDependants(name: string): string[] {
85+
const dependants: string[] = [];
86+
const dependantMap = new Map<string, Set<string>>();
87+
88+
for (const obj of this._objects) {
89+
const deps: string[] = obj.get('dependencies') || [];
90+
const objName = obj.get('name');
91+
deps.forEach(dep => {
92+
const currentSet = dependantMap.get(dep);
93+
if (currentSet) {
94+
currentSet.add(objName);
95+
} else {
96+
dependantMap.set(dep, new Set([objName]));
97+
}
98+
});
99+
}
100+
const selectedDeps = dependantMap.get(name);
101+
if (!selectedDeps) {
102+
return [];
103+
}
104+
while (selectedDeps.size) {
105+
const depsList = [...selectedDeps];
106+
depsList.forEach(it => {
107+
dependants.push(it);
108+
selectedDeps.delete(it);
109+
dependantMap.get(it)?.forEach(newIt => selectedDeps.add(newIt));
110+
});
111+
}
112+
113+
return dependants;
114+
}
115+
116+
removeObjects(names: string[]): void {
117+
this.transact(() => {
118+
for (const name of names) {
119+
this.removeObjectByName(name);
120+
}
121+
});
122+
}
123+
84124
removeObjectByName(name: string): void {
125+
// Get object index
85126
let index = 0;
86127
for (const obj of this._objects) {
87128
if (obj.get('name') === name) {
@@ -91,15 +132,13 @@ export class JupyterCadDoc
91132
}
92133

93134
if (this._objects.length > index) {
94-
this.transact(() => {
95-
this._objects.delete(index);
96-
const guidata = this.getOption('guidata');
97-
if (guidata) {
98-
delete guidata[name];
99-
this.setOption('guidata', guidata);
100-
}
101-
this.removeOutput(name);
102-
});
135+
this._objects.delete(index);
136+
const guidata = this.getOption('guidata');
137+
if (guidata) {
138+
delete guidata[name];
139+
this.setOption('guidata', guidata);
140+
}
141+
this.removeOutput(name);
103142
}
104143
}
105144

@@ -124,7 +163,34 @@ export class JupyterCadDoc
124163
if (!obj) {
125164
return;
126165
}
127-
this.transact(() => obj.set(key, value));
166+
167+
this.transact(() => {
168+
// Special case for changing parameters, we may need to update dependencies
169+
console.log('update ', key);
170+
if (key === 'parameters') {
171+
switch (obj.get('shape')) {
172+
case 'Part::Cut': {
173+
obj.set('dependencies', [value['Base'], value['Tool']]);
174+
break;
175+
}
176+
case 'Part::Extrusion':
177+
case 'Part::Fillet':
178+
case 'Part::Chamfer': {
179+
obj.set('dependencies', [value['Base']]);
180+
break;
181+
}
182+
case 'Part::MultiCommon':
183+
case 'Part::MultiFuse': {
184+
obj.set('dependencies', value['Shapes']);
185+
break;
186+
}
187+
default:
188+
break;
189+
}
190+
}
191+
192+
obj.set(key, value);
193+
});
128194
}
129195

130196
getOption(key: keyof IJCadOptions): IDict | undefined {

packages/schema/src/interfaces.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,12 @@ export interface IJupyterCadDoc extends YDocument<IJupyterCadDocChange> {
9191

9292
objectExists(name: string): boolean;
9393
getObjectByName(name: string): IJCadObject | undefined;
94+
removeObjects(names: string[]): void;
9495
removeObjectByName(name: string): void;
9596
addObject(value: IJCadObject): void;
9697
addObjects(value: Array<IJCadObject>): void;
9798
updateObjectByName(name: string, key: string, value: any): void;
99+
getDependants(name: string): string[];
98100

99101
getOption(key: keyof IJCadOptions): IDict | undefined;
100102
setOption(key: keyof IJCadOptions, value: IDict): void;

ui-tests/tests/ui.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ test.describe('UI Test', () => {
163163
.nth(1)
164164
.click();
165165

166+
if (await page.getByRole('button', { name: 'Ok' }).isVisible()) {
167+
await page.getByRole('button', { name: 'Ok' }).click();
168+
}
169+
166170
await page
167171
.getByRole('tablist', { name: 'main sidebar' })
168172
.getByRole('tab', { name: 'JupyterCad Control Panel' })

0 commit comments

Comments
 (0)