diff --git a/modules/lstream/intercept.js b/modules/lstream/intercept.js new file mode 100644 index 00000000..5f14c930 --- /dev/null +++ b/modules/lstream/intercept.js @@ -0,0 +1,14 @@ +export function intercept(stream, interceptor) { + + stream._realNext = stream.next; + + stream.next = function(value) { + + const next = (value) => { + this._realNext(value); + }; + + interceptor(value, stream, next); + }; + return stream; +} \ No newline at end of file diff --git a/modules/ui/components/Dialog.tsx b/modules/ui/components/Dialog.tsx index 80dd19a1..df7b9464 100644 --- a/modules/ui/components/Dialog.tsx +++ b/modules/ui/components/Dialog.tsx @@ -4,15 +4,17 @@ import cx from 'classnames'; import ButtonGroup from "ui/components/controls/ButtonGroup"; import Button from "ui/components/controls/Button"; -export function Dialog({children, className, onOK, ...props}: WindowProps & { - onOK: () => void +export function Dialog({children, className, okText, cancelText, onOK, ...props}: WindowProps & { + cancelText?: string, + okText?: string, + onOK?: () => void }) { return - - + + {onOK && } } {...props} > diff --git a/modules/ui/components/Tree.tsx b/modules/ui/components/Tree.tsx index 33cbca5e..a1d56188 100644 --- a/modules/ui/components/Tree.tsx +++ b/modules/ui/components/Tree.tsx @@ -21,12 +21,12 @@ export function Tree({children, icon, label, initCollapsed = false, className} : }) : } - ${icon} - ${label} + {icon} + {label} } {children &&
{children}
} -` + ; } diff --git a/modules/ui/styles/global/form.less b/modules/ui/styles/global/form.less index 1e7f66db..f3a8b133 100644 --- a/modules/ui/styles/global/form.less +++ b/modules/ui/styles/global/form.less @@ -23,6 +23,9 @@ button { margin: -4px 4px -4px -2px; } } + &.compact { + padding: 1px 3px; + } } button.neutral { diff --git a/modules/ui/styles/global/links.less b/modules/ui/styles/global/links.less index 2dc807a2..b625974c 100644 --- a/modules/ui/styles/global/links.less +++ b/modules/ui/styles/global/links.less @@ -2,6 +2,6 @@ a { color: @font-color; text-decoration: underline; &:hover { - color: @color-text-highlight + color: @on-color-highlight } } \ No newline at end of file diff --git a/modules/ui/styles/global/tree.less b/modules/ui/styles/global/tree.less index be5341e7..ede54048 100644 --- a/modules/ui/styles/global/tree.less +++ b/modules/ui/styles/global/tree.less @@ -1,4 +1,5 @@ .tree { + line-height: 1.9; } @@ -10,7 +11,7 @@ cursor: pointer; &:hover { - color: @color-text-highlight; + color: @on-color-highlight; } } @@ -22,7 +23,7 @@ } .tree-icon { - + padding: 0 5px 0 2px; } .tree-label { diff --git a/modules/ui/styles/theme.less b/modules/ui/styles/theme.less index e6a06744..11236af4 100644 --- a/modules/ui/styles/theme.less +++ b/modules/ui/styles/theme.less @@ -13,6 +13,7 @@ @bg-color-8: hsl(@hue-prim, @saturation, 48%); @bg-color-9: hsl(@hue-prim, @saturation, 53%); + @bg-base-color: @bg-color-1; @font-color-empph: #fff; @@ -41,5 +42,9 @@ @color-btn-selected: hsl(@hue-prim, 55%, 46%); -@color-text-highlight: hsl(@hue-prim, 85%, 85%); - +@on-color-highlight: lightskyblue; +@on-color-highlight-variant-yellow: bisque; +@on-color-highlight-variant-pink: hotpink; +@on-color-highlight-variant-red: tomato; +@on-color-highlight-variant-green: springgreen; +@on-color-highlight-variant-blue: aquamarine; diff --git a/modules/ui/styles/theme.ts b/modules/ui/styles/theme.ts new file mode 100644 index 00000000..0915965f --- /dev/null +++ b/modules/ui/styles/theme.ts @@ -0,0 +1,56 @@ +import theme from "!!less-vars-loader?camelCase&resolveVariables!./theme.less"; + +interface Theme { + + huePrim: string; + saturation: string; + + bgColor0: string; + bgColor1: string; + bgColor2: string; + bgColor3: string; + bgColor4: string; + bgColor5: string; + bgColor6: string; + bgColor7: string; + bgColor8: string; + bgColor9: string; + + bgBaseColor: string; + + fontColorEmpph: string; + fontColor: string; + fontColorMinor: string; + fontColorSuppressed: string; + fontColorDisabled: string; + + borderColor: string; + + controlColorNumber: string; + controlColorText: string; + controlBg: string; + + workAreaColor: string; + + workAreaControlBarBgColor: string; + workAreaControlBarBgColorActive: string; + workAreaControlBarFontColor: string; + + colorDanger: string; + colorAccent: string; + + colorNeutral: string; + colorHighlight: string; + + colorBtnSelected: string; + + onColorHighlight: string; + onColorHighlightVariantYellow: string; + onColorHighlightVariantPink: string; + onColorHighlightVariantRed: string; + onColorHighlightVariantGreen: string; + onColorHighlightVariantBlue: string; + +} + +export default (theme as unknown); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9d4ea0af..b591f7f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3897,6 +3897,12 @@ } } }, + "cypress-wait-until": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-1.7.1.tgz", + "integrity": "sha512-8DL5IsBTbAxBjfYgCzdbohPq/bY+IKc63fxtso1C8RWhLnQkZbVESyaclNr76jyxfId6uyzX8+Xnt0ZwaXNtkA==", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -7445,6 +7451,67 @@ "pify": "^4.0.1" } }, + "less-vars-loader": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/less-vars-loader/-/less-vars-loader-1.1.0.tgz", + "integrity": "sha1-LyJF2QQCJb/fVT+l4N3Y5HvKlbg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "less-vars-to-js": "^1.1.2", + "loader-utils": "^0.2.16", + "object.entries": "^1.0.3" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "less-vars-to-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/less-vars-to-js/-/less-vars-to-js-1.3.0.tgz", + "integrity": "sha512-xeiLLn/IMCGtdyCkYQnW8UuzoW2oYMCKg9boZRaGI58fLz5r90bNJDlqGzmVt/1Uqk75/DxIVtQSNCMkE5fRZQ==", + "dev": true, + "requires": { + "strip-json-comments": "^2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + } + } + }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", diff --git a/package.json b/package.json index 4e8f744f..464f245c 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "babel-polyfill": "^6.26.0", "css-loader": "^3.4.2", "cypress": "^4.2.0", + "cypress-wait-until": "^1.7.1", "eslint": "^6.8.0", "eslint-plugin-babel": "^5.3.0", "eslint-plugin-import": "^2.20.1", @@ -51,6 +52,7 @@ "grunt": "^1.1.0", "grunt-contrib-copy": "1.0.0", "less-loader": "^5.0.0", + "less-vars-loader": "^1.1.0", "raw-loader": "^4.0.0", "style-loader": "^1.1.3", "ts-loader": "^7.0.2", diff --git a/test/coreTests/defineCypress.js b/test/coreTests/defineCypress.js index d4732c64..96d913ff 100644 --- a/test/coreTests/defineCypress.js +++ b/test/coreTests/defineCypress.js @@ -22,6 +22,10 @@ export function defineCypressTests(groupName, module) { }; }); + if (!hasOnly) { + hasOnly = !!module.only; + } + (hasOnly ? describe.only : describe)(groupName, () => { @@ -53,7 +57,9 @@ export function defineCypressTests(groupName, module) { test.loadStream(win).attach(ready => { if (ready) { - test.func(testEnv, subject); + test.func(testEnv, subject).then(() => { + onDone(); + }); } }); }); diff --git a/test/coreTests/subjects/modellerTPI.js b/test/coreTests/subjects/modellerTPI.js index 18410206..9a9c97d3 100644 --- a/test/coreTests/subjects/modellerTPI.js +++ b/test/coreTests/subjects/modellerTPI.js @@ -6,14 +6,38 @@ import { } from '../../../web/app/cad/scene/controls/pickControlPlugin'; import {Vector3} from "three"; +function waitFor(checkFn) { + return new Promise((resolve, reject) => { + const tick = () => { + const res = checkFn(); + if (res) { + resolve(res) + } else { + setTimeout(tick, 100); + } + }; + tick(); + }); +} + + export default ctx => { function openWizard(operationId) { ctx.services.action.run(operationId); } - function wizardOK() { + async function wizardOK() { + const handles = Cypress.$('.x-HistoryTimeline-handle'); + const handle = Cypress.$('.x-HistoryTimeline-active .x-HistoryTimeline-handle')[0]; + const index = handles.index(handle); ctx.services.wizard.applyWorkingRequest(); + return waitFor(() => { + const handles = Cypress.$('.x-HistoryTimeline-handle'); + const handle = Cypress.$('.x-HistoryTimeline-active .x-HistoryTimeline-handle')[0]; + const newIndex = handles.index(handle); + return newIndex !== index; + }); } function sceneMouseEvent(type, x, y) { diff --git a/test/coreTests/testCases/craftBoolean.js b/test/coreTests/testCases/craftBoolean.js index dc434c78..c4e0e217 100644 --- a/test/coreTests/testCases/craftBoolean.js +++ b/test/coreTests/testCases/craftBoolean.js @@ -3,54 +3,52 @@ import {assertEquals, assertTrue} from '../utils/asserts'; export const TEST_MODE = 'modellerUI'; - -export function testBooleanUnion(env, ui) { +export async function testBooleanUnion(env, ui) { ui.openWizard('BOX'); - ui.wizardOK(); + await ui.wizardOK(); ui.openWizard('DATUM_CREATE'); ui.wizardContext.updateParam('x', 0); ui.wizardContext.updateParam('y', 500); ui.wizardContext.updateParam('z', 500); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('SPHERE'); - ui.wizardOK(); + await ui.wizardOK(); ui.openWizard('UNION'); ui.select([-10, 250, 250], [10, 250, 250]); ui.select([-260, 500, 500], [-240, 500, 500]); - ui.wizardOK(); + await ui.wizardOK(); assertEquals(1, ui.context.services.cadRegistry.models.length); let [m1] = ui.rayCast([-10, 250, 250], [10, 250, 250]); let [m2] = ui.rayCast([-260, 500, 500], [-240, 500, 500]); assertEquals(m1.shell, m2.shell); - env.done(); } -export function testBooleanIntersect(env, ui) { +export async function testBooleanIntersect(env, ui) { ui.openWizard('BOX'); - ui.wizardOK(); + await ui.wizardOK(); ui.openWizard('DATUM_CREATE'); ui.wizardContext.updateParam('x', 0); ui.wizardContext.updateParam('y', 500); ui.wizardContext.updateParam('z', 500); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('SPHERE'); - ui.wizardOK(); + await ui.wizardOK(); ui.openWizard('INTERSECTION'); ui.select([-10, 250, 250], [10, 250, 250]); ui.select([-260, 500, 500], [-240, 500, 500]); - ui.wizardOK(); + await ui.wizardOK(); assertEquals(1, ui.context.services.cadRegistry.models.length); let [m1] = ui.rayCast([-10, 250, 250], [10, 250, 250]); @@ -59,34 +57,32 @@ export function testBooleanIntersect(env, ui) { assertTrue(m2 === undefined); ui.select([-10, 450, 450], [10, 450, 450]); assertTrue(ui.context.services.selection.face.single !== undefined); - - env.done(); } -export function testBooleanSubtract(env, ui) { +export async function testBooleanSubtract(env, ui) { ui.openWizard('BOX'); - ui.wizardOK(); + await ui.wizardOK(); ui.openWizard('DATUM_CREATE'); ui.wizardContext.updateParam('x', 0); ui.wizardContext.updateParam('y', 500); ui.wizardContext.updateParam('z', 500); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('SPHERE'); - ui.wizardOK(); + await ui.wizardOK(); ui.openWizard('SUBTRACT'); ui.select([-10, 250, 250], [10, 250, 250]); ui.select([-260, 500, 500], [-240, 500, 500]); - ui.wizardOK(); + await ui.wizardOK(); assertEquals(1, ui.context.services.cadRegistry.models.length); let [m1] = ui.rayCast([-10, 250, 250], [10, 250, 250]); let [m2] = ui.rayCast([-260, 500, 500], [-240, 500, 500]); assertTrue(m1 !== undefined); assertTrue(m2 === undefined); - env.done(); -} \ No newline at end of file +} + diff --git a/test/coreTests/testCases/craftCut.js b/test/coreTests/testCases/craftCut.js index 4e7e3000..e76fafc4 100644 --- a/test/coreTests/testCases/craftCut.js +++ b/test/coreTests/testCases/craftCut.js @@ -2,8 +2,8 @@ import {extrudeCube} from '../utils/scripts'; export const TEST_MODE = 'modellerUI'; -export function testCutMid(env, ui) { - extrudeCube(ui); +export async function testCutMid(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -12,13 +12,13 @@ export function testCutMid(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI1Faces(env, ui) { - extrudeCube(ui); +export async function testCutCOI1Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -27,13 +27,13 @@ export function testCutCOI1Faces(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI2Faces(env, ui) { - extrudeCube(ui); +export async function testCutCOI2Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -42,13 +42,13 @@ export function testCutCOI2Faces(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI3Faces(env, ui) { - extrudeCube(ui); +export async function testCutCOI3Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -57,13 +57,13 @@ export function testCutCOI3Faces(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI4Faces(env, ui) { - extrudeCube(ui); +export async function testCutCOI4Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -72,15 +72,15 @@ export function testCutCOI4Faces(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } // all the way cuts -export function testCutMidAllWay(env, ui) { - extrudeCube(ui); +export async function testCutMidAllWay(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -89,13 +89,13 @@ export function testCutMidAllWay(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI1FacesAllWay(env, ui) { - extrudeCube(ui); +export async function testCutCOI1FacesAllWay(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -104,13 +104,13 @@ export function testCutCOI1FacesAllWay(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI2FacesAllWay(env, ui) { - extrudeCube(ui); +export async function testCutCOI2FacesAllWay(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -119,13 +119,13 @@ export function testCutCOI2FacesAllWay(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI3FacesAllWay(env, ui) { - extrudeCube(ui); +export async function testCutCOI3FacesAllWay(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -134,13 +134,13 @@ export function testCutCOI3FacesAllWay(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testCutCOI4FacesAllWay(env, ui) { - extrudeCube(ui); +export async function testCutCOI4FacesAllWay(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -149,8 +149,8 @@ export function testCutCOI4FacesAllWay(env, ui) { ui.openWizard('CUT'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } diff --git a/test/coreTests/testCases/craftDatum.js b/test/coreTests/testCases/craftDatum.js index 0bdc26a4..fc8af4bd 100644 --- a/test/coreTests/testCases/craftDatum.js +++ b/test/coreTests/testCases/craftDatum.js @@ -3,36 +3,36 @@ import {DATUM} from '../../../web/app/cad/scene/entites'; export const TEST_MODE = 'modellerUI'; -export function testCreateDatumOrigin(env, ui) { +export async function testCreateDatumOrigin(env, ui) { ui.openWizard('DATUM_CREATE'); - ui.wizardOK(); + await ui.wizardOK(); let datum = ui.context.services.cadRegistry.models[0]; ui.context.services.pickControl.pick(datum); ui.openWizard('PLANE_FROM_DATUM'); assertEquals(datum.id, ui.wizardContext.workingRequest$.value.params.datum); - ui.wizardOK(); + await ui.wizardOK(); let [placeFace] = ui.rayCastFaces([10, 10, -10], [10, 10, 10]); assertTrue(placeFace !== undefined); - env.done(); + } -export function testCreateMovedDatum(env, ui) { +export async function testCreateMovedDatum(env, ui) { ui.openWizard('DATUM_CREATE'); ui.wizardContext.updateParam("x", 100); ui.wizardContext.updateParam("y", 100); ui.wizardContext.updateParam("z", 100); - ui.wizardOK(); + await ui.wizardOK(); let datum = ui.context.services.cadRegistry.models[0]; ui.context.services.pickControl.pick(datum); ui.openWizard('PLANE_FROM_DATUM'); assertEquals(datum.id, ui.wizardContext.workingRequest$.value.params.datum); - ui.wizardOK(); + await ui.wizardOK(); ui.select([10, 10, -10], [10, 10, 10]); assertTrue(ui.context.services.selection.face.single === undefined); @@ -40,21 +40,21 @@ export function testCreateMovedDatum(env, ui) { ui.select([110, 110, 90], [110, 110, 110]); assertTrue(ui.context.services.selection.face.single !== undefined); - env.done(); + } -export function testCreateDatumOffFace(env, ui) { +export async function testCreateDatumOffFace(env, ui) { ui.openWizard('DATUM_CREATE'); ui.wizardContext.updateParam("x", 100); ui.wizardContext.updateParam("y", 100); ui.wizardContext.updateParam("z", 100); - ui.wizardOK(); + await ui.wizardOK(); let datum = ui.context.services.cadRegistry.models[0]; ui.context.services.pickControl.pick(datum); ui.openWizard('PLANE_FROM_DATUM'); - ui.wizardOK(); + await ui.wizardOK(); ui.select([110, 110, 90], [110, 110, 110]); @@ -62,59 +62,59 @@ export function testCreateDatumOffFace(env, ui) { ui.wizardContext.updateParam("x", 100); ui.wizardContext.updateParam("y", 100); ui.wizardContext.updateParam("z", 100); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('PLANE_FROM_DATUM'); - ui.wizardOK(); + await ui.wizardOK(); ui.select([210, 210, 190], [210, 210, 210]); assertTrue(ui.context.services.selection.face.single !== undefined); - env.done(); + } -export function testRotateDatum(env, ui) { +export async function testRotateDatum(env, ui) { ui.openWizard('DATUM_CREATE'); ui.wizardContext.updateParam("x", 100); ui.wizardContext.updateParam("y", 100); ui.wizardContext.updateParam("z", 100); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('DATUM_ROTATE'); ui.wizardContext.updateParam('axis', 'Z'); ui.wizardContext.updateParam('angle', 180); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('PLANE_FROM_DATUM'); - ui.wizardOK(); + await ui.wizardOK(); ui.select([90, 90, 90], [90, 90, 110]); assertTrue(ui.context.services.selection.face.single !== undefined); - env.done(); + } -export function testMoveDatum(env, ui) { +export async function testMoveDatum(env, ui) { ui.openWizard('DATUM_CREATE'); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('DATUM_MOVE'); ui.wizardContext.updateParam("x", 100); ui.wizardContext.updateParam("y", 100); ui.wizardContext.updateParam("z", 100); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFirst(DATUM); ui.openWizard('PLANE_FROM_DATUM'); - ui.wizardOK(); + await ui.wizardOK(); ui.select([110, 110, 90], [110, 110, 110]); assertTrue(ui.context.services.selection.face.single !== undefined); - env.done(); + } \ No newline at end of file diff --git a/test/coreTests/testCases/craftExtrude.js b/test/coreTests/testCases/craftExtrude.js index 831cbe55..6d1f5bce 100644 --- a/test/coreTests/testCases/craftExtrude.js +++ b/test/coreTests/testCases/craftExtrude.js @@ -2,8 +2,8 @@ import {extrudeCube} from '../utils/scripts'; export const TEST_MODE = 'modellerUI'; -export function testExtrudeMid(env, ui) { - extrudeCube(ui); +export async function testExtrudeMid(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -12,13 +12,13 @@ export function testExtrudeMid(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testExtrudeCOI1Faces(env, ui) { - extrudeCube(ui); +export async function testExtrudeCOI1Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -27,13 +27,13 @@ export function testExtrudeCOI1Faces(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testExtrudeCOI2Faces(env, ui) { - extrudeCube(ui); +export async function testExtrudeCOI2Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -42,13 +42,13 @@ export function testExtrudeCOI2Faces(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testExtrudeCOI3Faces(env, ui) { - extrudeCube(ui); +export async function testExtrudeCOI3Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -57,13 +57,13 @@ export function testExtrudeCOI3Faces(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } -export function testExtrudeCOI4Faces(env, ui) { - extrudeCube(ui); +export async function testExtrudeCOI4Faces(env, ui) { + await extrudeCube(ui); ui.selectFaces([0, 0, 210], [0, 0, 190]); let sui = ui.openSketcher(); @@ -72,7 +72,7 @@ export function testExtrudeCOI4Faces(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 50); - ui.wizardOK(); + await ui.wizardOK(); - env.done(); + } diff --git a/test/coreTests/testCases/craftExtrudeBasicShapes.js b/test/coreTests/testCases/craftExtrudeBasicShapes.js index e373b293..26c451d8 100644 --- a/test/coreTests/testCases/craftExtrudeBasicShapes.js +++ b/test/coreTests/testCases/craftExtrudeBasicShapes.js @@ -3,8 +3,8 @@ import {createPlaneAndOpenSketcher} from '../utils/scripts'; export const TEST_MODE = 'modellerUI'; -export function testExtrudeFromSketch(env, ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function testExtrudeFromSketch(env, ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); let sketchedFace = ui.context.services.selection.face.single; let seg1 = sketcherUI.addSegment(-100, -100, 100, -100); let seg2 = sketcherUI.addSegment(100, -100, 100, 100); @@ -18,7 +18,7 @@ export function testExtrudeFromSketch(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); let [leftFace] = ui.rayCastFaces([-110, 0, 100], [-90, 0, 100]); let [rightFace] = ui.rayCastFaces([110, 0, 100], [90, 0, 100]); @@ -44,11 +44,11 @@ export function testExtrudeFromSketch(env, ui) { assertFaceOrigination(topFace, sketchId, seg3.id); assertFaceOrigination(leftFace, sketchId, seg4.id); - env.done(); + } -export function testExtrudeArc(env, ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function testExtrudeArc(env, ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); let sketchedFace = ui.context.services.selection.face.single; let arc = sketcherUI.addArc(0, 0, 100, 0, -100, 0); let segment = sketcherUI.addSegment(100, 0, -100, 0); @@ -64,7 +64,7 @@ export function testExtrudeArc(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); let [curvedFace] = ui.rayCastFaces([0, 110, 100], [0, 90, 100]); let [flatFace] = ui.rayCastFaces([0, -10, 100], [0, 10, 100]); @@ -82,11 +82,11 @@ export function testExtrudeArc(env, ui) { assertFaceOrigination(curvedFace, sketchId, arc.id); assertFaceOrigination(flatFace, sketchId, segment.id); - env.done(); + } -export function testExtrudeCircle(env, ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function testExtrudeCircle(env, ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); let sketchedFace = ui.context.services.selection.face.single; let circle = sketcherUI.addCircle(100, 100, 100); @@ -97,7 +97,7 @@ export function testExtrudeCircle(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); let [curvedFace] = ui.rayCastFaces([100, -10, 100], [100, 10, 100]); let [topFace] = ui.rayCastFaces([100, 100, 210], [100, 100, 190]); @@ -112,11 +112,11 @@ export function testExtrudeCircle(env, ui) { assertFaceOrigination(curvedFace, sketchId, circle.id); - env.done(); + } -export function testExtrudeEllipse(env, ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function testExtrudeEllipse(env, ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); let sketchedFace = ui.context.services.selection.face.single; let ellipse = sketcherUI.addEllipse(-100, 100, 100, 100, 0, 150); @@ -127,7 +127,7 @@ export function testExtrudeEllipse(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); let [curvedFace] = ui.rayCastFaces([0, 151, 100], [0, 149, 100]); let [topFace] = ui.rayCastFaces([0, 100, 201],[0, 100, 199]); @@ -142,11 +142,11 @@ export function testExtrudeEllipse(env, ui) { assertFaceOrigination(curvedFace, sketchId, ellipse.id); - env.done(); + } -export function testExtrudeEllipticalArc(env, ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function testExtrudeEllipticalArc(env, ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); let sketchedFace = ui.context.services.selection.face.single; let eArc = sketcherUI.addEllipticalArc(-100, 100, 100, 100, 0, 150); sketcherUI.move(100, 100, -50, 170); @@ -159,7 +159,7 @@ export function testExtrudeEllipticalArc(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); let [curvedFace] = ui.rayCastFaces([-110, 100, 100], [-90, 100, 100]); let [topFace] = ui.rayCastFaces([0, 100, 201],[0, 100, 199]); @@ -174,11 +174,11 @@ export function testExtrudeEllipticalArc(env, ui) { assertFaceOrigination(curvedFace, sketchId, eArc.id); - env.done(); + } -export function testExtrudeBezier(env, ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function testExtrudeBezier(env, ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); let sketchedFace = ui.context.services.selection.face.single; let bezier = sketcherUI.addBezier(-100, 100, 100, 100, 0, 150); sketcherUI.move(bezier.cp2.x, bezier.cp2.y, bezier.cp2.x, bezier.cp1.y); @@ -193,7 +193,7 @@ export function testExtrudeBezier(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); let [curvedFace] = ui.rayCastFaces([0, 178, 50], [0, 170, 50]); let [topFace] = ui.rayCastFaces([0, 100, 201],[0, 100, 199]); @@ -208,5 +208,5 @@ export function testExtrudeBezier(env, ui) { assertFaceOrigination(curvedFace, sketchId, bezier.id); - env.done(); + } diff --git a/test/coreTests/testCases/craftExtrudeOptions.js b/test/coreTests/testCases/craftExtrudeOptions.js index 1fdcd4c1..0924bd41 100644 --- a/test/coreTests/testCases/craftExtrudeOptions.js +++ b/test/coreTests/testCases/craftExtrudeOptions.js @@ -3,8 +3,8 @@ import {createPlaneAndOpenSketcher} from '../utils/scripts'; export const TEST_MODE = 'modellerUI'; -export function testExtrudePrism(env, ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function testExtrudePrism(env, ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); let sketchedFace = ui.context.services.selection.face.single; let [S1, S2, S3, S4] = sketcherUI.addRectangle(-100, -100, 100, 100); @@ -19,7 +19,7 @@ export function testExtrudePrism(env, ui) { ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 2000); ui.wizardContext.updateParam('prism', 0.1); - ui.wizardOK(); + await ui.wizardOK(); env.fail(); - env.done(); + } diff --git a/test/coreTests/testCases/craftFillet.js b/test/coreTests/testCases/craftFillet.js index bf8582d4..2639e75f 100644 --- a/test/coreTests/testCases/craftFillet.js +++ b/test/coreTests/testCases/craftFillet.js @@ -2,31 +2,31 @@ import {createPlaneAndOpenSketcher, extrudeCube} from '../utils/scripts'; export const TEST_MODE = 'modellerUI'; -export function test1Fillet(env, ui) { - extrudeCube(ui); +export async function test1Fillet(env, ui) { + await extrudeCube(ui); ui.openWizard('FILLET'); ui.select([0, 110, 210], [0, 90, 190]); - ui.wizardOK(); - env.done(); + await ui.wizardOK(); + } -export function test2Fillet(env, ui) { - extrudeCube(ui); +export async function test2Fillet(env, ui) { + await extrudeCube(ui); ui.openWizard('FILLET'); ui.select([0, 110, 210], [0, 90, 190]); ui.select([-110, 110, 100], [-90, 90, 100]); - ui.wizardOK(); - env.done(); + await ui.wizardOK(); + } -export function test3Fillet(env, ui) { - extrudeCube(ui); +export async function test3Fillet(env, ui) { + await extrudeCube(ui); ui.openWizard('FILLET'); ui.select([0, 110, 210], [0, 90, 190]); ui.select([-110, 110, 100], [-90, 90, 100]); ui.select([-110, 0, 210], [-90, 0, 190]); - ui.wizardOK(); - env.done(); + await ui.wizardOK(); + } diff --git a/test/coreTests/testCases/craftLoft.js b/test/coreTests/testCases/craftLoft.js index 046bd0ff..07338c02 100644 --- a/test/coreTests/testCases/craftLoft.js +++ b/test/coreTests/testCases/craftLoft.js @@ -2,14 +2,14 @@ import {createPlaneAndOpenSketcher, extrudeCube} from '../utils/scripts'; export const TEST_MODE = 'modellerUI'; -export function testLoftOver2Sections(env, ui) { - let sui = createPlaneAndOpenSketcher(ui); +export async function testLoftOver2Sections(env, ui) { + let sui = await createPlaneAndOpenSketcher(ui); sui.addRectangle(-100, -100, 100, 100); ui.commitSketch(); ui.openWizard('PLANE'); ui.wizardContext.updateParam('depth', 300); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFaces([0, 0, 290], [0, 0, 310]); sui = ui.openSketcher(); sui.addPolygon([0, -100], [100, 100], [-100, 100]); @@ -18,18 +18,18 @@ export function testLoftOver2Sections(env, ui) { ui.openWizard('LOFT'); ui.select([0, 0, 310], [0, 0, 290]); ui.select([0, 0, -10], [0, 0, 10]); - ui.wizardOK(); - env.done(); + await ui.wizardOK(); + } -export function testLoftOver3Sections(env, ui) { - let sui = createPlaneAndOpenSketcher(ui); +export async function testLoftOver3Sections(env, ui) { + let sui = await createPlaneAndOpenSketcher(ui); sui.addRectangle(-100, -100, 100, 100); ui.commitSketch(); ui.openWizard('PLANE'); ui.wizardContext.updateParam('depth', 300); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFaces([0, 0, 290], [0, 0, 310]); sui = ui.openSketcher(); sui.addPolygon([0, -100], [100, 100], [-100, 100]); @@ -38,7 +38,7 @@ export function testLoftOver3Sections(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('depth', 600); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFaces([0, 0, 590], [0, 0, 610]); sui = ui.openSketcher(); sui.addPolygon([0, 100], [100, -100], [-100, -100]); @@ -49,19 +49,19 @@ export function testLoftOver3Sections(env, ui) { ui.select([0, 0, 610], [0, 0, 590]); ui.select([0, 0, 310], [0, 0, 290]); ui.select([0, 0, -10], [0, 0, 10]); - ui.wizardOK(); - env.done(); + await ui.wizardOK(); + } -export function testLoftCircleSections(env, ui) { - let sui = createPlaneAndOpenSketcher(ui); +export async function testLoftCircleSections(env, ui) { + let sui = await createPlaneAndOpenSketcher(ui); sui.addRectangle(-100, -100, 100, 100); ui.commitSketch(); ui.openWizard('PLANE'); ui.wizardContext.updateParam('depth', 300); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFaces([0, 0, 290], [0, 0, 310]); sui = ui.openSketcher(); sui.addCircle(0, 0, 100); @@ -70,8 +70,8 @@ export function testLoftCircleSections(env, ui) { ui.openWizard('LOFT'); ui.select([0, 0, 310], [0, 0, 290]); ui.select([0, 0, -10], [0, 0, 10]); - ui.wizardOK(); - env.done(); + await ui.wizardOK(); + } diff --git a/test/coreTests/testCases/craftPlane.js b/test/coreTests/testCases/craftPlane.js index 1d83a577..0fe4fd71 100644 --- a/test/coreTests/testCases/craftPlane.js +++ b/test/coreTests/testCases/craftPlane.js @@ -2,63 +2,57 @@ import {assertEmpty, assertEquals, assertFaceIsPlane, assertTrue} from '../utils export const TEST_MODE = 'modellerUI'; -export function testCreatePlaneAtOriginDefaultXY(env, ui) { +export async function testCreatePlaneAtOriginDefaultXY(env, ui) { ui.openWizard('PLANE'); - ui.wizardOK(); + await ui.wizardOK(); assertFaceIsPlane(ui.rayCastFaces([0, 0, -10], [0, 0, 10])[0]); - env.done(); } -export function testCreatePlaneAtOriginXZ(env, ui) { +export async function testCreatePlaneAtOriginXZ(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('orientation', 'XZ'); - ui.wizardOK(); + await ui.wizardOK(); assertFaceIsPlane(ui.rayCastFaces([0, -10, 0], [0, 10, 0])[0]); - env.done(); } -export function testCreatePlaneAtZY(env, ui) { +export async function testCreatePlaneAtZY(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('orientation', 'ZY'); - ui.wizardOK(); + await ui.wizardOK(); assertFaceIsPlane(ui.rayCastFaces([-10, 0, 0], [10, 0, 0])[0]); - env.done(); } -export function testCreatePlaneAtOriginXYOffset(env, ui) { +export async function testCreatePlaneAtOriginXYOffset(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('depth', 100); - ui.wizardOK(); + await ui.wizardOK(); assertEmpty(ui.rayCastFaces([0, 0, -10], [0, 0, 10])); assertFaceIsPlane(ui.rayCastFaces([0, 0, 90], [0, 0, 110])[0]); - env.done(); } -export function testCreatePlaneAtOriginXZOffset(env, ui) { +export async function testCreatePlaneAtOriginXZOffset(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('orientation', 'XZ'); ui.wizardContext.updateParam('depth', 100); - ui.wizardOK(); + await ui.wizardOK(); assertEmpty(ui.rayCastFaces([0, -10, 0], [0, 10, 0])); assertFaceIsPlane(ui.rayCastFaces([0, 90, 0], [0, 110, 0])[0]); - env.done(); } -export function testCreatePlaneAtOriginZYOffset(env, ui) { +export async function testCreatePlaneAtOriginZYOffset(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('orientation', 'ZY'); ui.wizardContext.updateParam('depth', 100); - ui.wizardOK(); + await ui.wizardOK(); assertEmpty(ui.rayCastFaces([-10, 0, 0], [10, 0, 0])); assertFaceIsPlane(ui.rayCastFaces([90, 0, 0], [110, 0, 0])[0]); - env.done(); } -export function testCreatePlaneParallelToOther(env, ui) { +export async function testCreatePlaneParallelToOther(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('orientation', 'ZY'); ui.wizardContext.updateParam('depth', 100); - ui.wizardOK(); + await ui.wizardOK(); assertEmpty(ui.rayCastFaces([-10, 0, 0], [10, 0, 0])); let captured = ui.rayCastFaces([90, 0, 0], [210, 0, 0]); @@ -69,13 +63,11 @@ export function testCreatePlaneParallelToOther(env, ui) { ui.openWizard('PLANE'); ui.wizardContext.updateParam('parallelTo', baseFace.id); ui.wizardContext.updateParam('depth', 100); - ui.wizardOK(); + await ui.wizardOK(); captured = ui.rayCastFaces([90, 0, 0], [210, 0, 0]); assertTrue(captured.length === 2); assertTrue(captured[0].id === baseFace.id); assertTrue(captured[1].id !== baseFace.id); - - env.done(); } diff --git a/test/coreTests/testCases/craftRevolve.js b/test/coreTests/testCases/craftRevolve.js index 804f7471..a20dd443 100644 --- a/test/coreTests/testCases/craftRevolve.js +++ b/test/coreTests/testCases/craftRevolve.js @@ -2,8 +2,8 @@ import {createPlaneAndOpenSketcher, extrudeCube} from '../utils/scripts'; export const TEST_MODE = 'modellerUI'; -export function testRevolveHalfWay(env, ui) { - createPlaneAndOpenSketcher(ui); +export async function testRevolveHalfWay(env, ui) { + await createPlaneAndOpenSketcher(ui); let sui = ui.openSketcher(); sui.addRectangle(20, -50, 50, 50); sui.changeToConstructionLayer(); @@ -13,13 +13,13 @@ export function testRevolveHalfWay(env, ui) { ui.openWizard('REVOLVE'); ui.wizardContext.updateParam('angle', 180); ui.select([0, 0, 10], [0, 0, -10]); - ui.wizardOK(); + await ui.wizardOK(); + - env.done(); } -export function testRevolveAllWay(env, ui) { - createPlaneAndOpenSketcher(ui); +export async function testRevolveAllWay(env, ui) { + await createPlaneAndOpenSketcher(ui); let sui = ui.openSketcher(); sui.addRectangle(20, -50, 50, 50); sui.changeToConstructionLayer(); @@ -29,8 +29,8 @@ export function testRevolveAllWay(env, ui) { ui.openWizard('REVOLVE'); ui.wizardContext.updateParam('angle', 360); ui.select([0, 0, 10], [0, 0, -10]); - ui.wizardOK(); + await ui.wizardOK(); + - env.done(); } diff --git a/test/coreTests/testCases/offset.js b/test/coreTests/testCases/offset.js index a0fdbfee..c838affb 100644 --- a/test/coreTests/testCases/offset.js +++ b/test/coreTests/testCases/offset.js @@ -7,7 +7,7 @@ export default { testRefreshHappensOnce: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, @@ -16,7 +16,7 @@ export default { win.prompt = function() { setTimeout(() => { env.assertEquals('OFFSET0 = 30', app.viewer.params.constantDefinition); - env.done(); + }); return 30; }; @@ -34,7 +34,7 @@ export default { win.prompt = function() { setTimeout(() => { env.assertEquals('OFFSET0 = 100\nOFFSET1 = 30', app.viewer.params.constantDefinition); - env.done(); + }); return 30; }; @@ -49,49 +49,49 @@ export default { testConstantsInwardArc: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testCWAndCCWSame: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testNonConvex: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testStart: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testTwoArcs: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testThreeArcs: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testCircle: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, @@ -108,7 +108,7 @@ export default { app.actions['offsetTool'].action(); app.viewer.toolManager.tool.mousemove(new TestMouseEvent(302, 106)); env.assertEquals(0, findMarked(app).length); - env.done(); + })); }, @@ -116,49 +116,49 @@ export default { test.emptySketch(env.test((win, app) => { win.prompt = function() { }; - env.done(); + })); }, testPentagon: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testHexagon: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testAfterRectangleTool: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testRectWithFillet: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testAgainstBoundary: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); }, testDegradingGeom: function (env) { test.emptySketch(env.test((win, app) => { env.fail('implement me'); - env.done(); + })); } } diff --git a/test/coreTests/testCases/segment.js b/test/coreTests/testCases/segment.js index 88eba762..f9619d68 100644 --- a/test/coreTests/testCases/segment.js +++ b/test/coreTests/testCases/segment.js @@ -4,7 +4,7 @@ import {createSketcherTPI} from "../subjects/sketcherTPI"; export const TEST_MODE = 'sketcherUI'; -export function testSegmentWizard(env, tpi) { +export async function testSegmentWizard(env, tpi) { assertEquals(0, tpi.viewer.activeLayer.objects.length); tpi.addSegment(10, 10, 100, 100); @@ -15,16 +15,16 @@ export function testSegmentWizard(env, tpi) { const [bsx, bsy] = tpi.toScreen(100, 100); assertPoint2DEquals(tpi.toModel(asx, asy), segment.a); assertPoint2DEquals(tpi.toModel(bsx, bsy), segment.b); - env.done(); + } -export function testSaveLoad(env, tpi) { +export async function testSaveLoad(env, tpi) { assertEquals(0, tpi.viewer.activeLayer.objects.length); tpi.addSegment(10, 10, 100, 100); tpi.runAction('Save'); cy.visit('http://localhost:3000'); cy.window().then(win => { - env.done(); + }); // env.navigate('http://google.com').then(win => { // const tpi = createSketcherTPI(win.__CAD_APP); @@ -43,7 +43,7 @@ testSaveLoad.only = true; // env.assertEquals(0, app.viewer.selected.length); // sketcher_utils.clickXY(app, 50, 50); // env.assertEquals(1, app.viewer.selected.length); -// env.done(); +// // })); // }, // @@ -55,7 +55,7 @@ testSaveLoad.only = true; // sketcher_utils.clickXY(app, 55, 50); // env.assertEquals(1, app.viewer.selected.length); // env.assertEquals('TCAD.TWO.Segment', app.viewer.selected[0]._class); -// env.done(); +// // })); // }, // @@ -67,7 +67,7 @@ testSaveLoad.only = true; // const keyboardEvent = keyboard.keyCode('keydown', 8); // win.dispatchEvent(keyboardEvent); // env.assertEquals(0, app.viewer.activeLayer.objects.length); -// env.done(); +// // })); // }, // @@ -82,7 +82,7 @@ testSaveLoad.only = true; // env.assertEquals(1, s2.a.linked.length); // env.assertEquals(s1.b.linked[0], s2.a); // env.assertEquals(s2.a.linked[0], s1.b); -// env.done(); +// // })); // }, // @@ -97,7 +97,7 @@ testSaveLoad.only = true; // env.assertEquals(1, s2.b.linked.length); // env.assertEquals(s1.b.linked[0], s2.b); // env.assertEquals(s2.b.linked[0], s1.b); -// env.done(); +// // })); // }, // @@ -109,7 +109,7 @@ testSaveLoad.only = true; // env.assertPoint2DEquals(sketcher_utils.toModel(app, 10, 10), segment.a); // //should be moved // env.assertPoint2DEquals(sketcher_utils.toModel(app, 200, 150), segment.b); -// env.done(); +// // })); // }, // @@ -124,7 +124,7 @@ testSaveLoad.only = true; // env.assertPoint2DEquals(sketcher_utils.toModelP(app, initA.plus(moveDelta)), segment.a); // env.assertPoint2DEquals(sketcher_utils.toModelP(app, initB.plus(moveDelta)), segment.b); // env.assertEquals('TCAD.TWO.Segment', app.viewer.selected[0]._class); -// env.done(); +// // })); // } diff --git a/test/coreTests/testCases/solveSystems.js b/test/coreTests/testCases/solveSystems.js index 43377ce2..881d5a04 100644 --- a/test/coreTests/testCases/solveSystems.js +++ b/test/coreTests/testCases/solveSystems.js @@ -3,7 +3,7 @@ import {NOOP} from '../../../modules/gems/func'; export const TEST_MODE = 'sketcherUI'; -export function testEqualConstraints(env, ui) { +export async function testEqualConstraints(env, ui) { ui.addRectangle(10, 10, 100, 100); @@ -11,10 +11,10 @@ export function testEqualConstraints(env, ui) { assertEquals(4, ui.viewer.parametricManager.system.constraints.length); assertEquals(1, ui.viewer.parametricManager.system.subSystems[0].constraints.length); - env.done(); + } -export function testBuildGraphBasics(env, ui) { +export async function testBuildGraphBasics(env, ui) { const seg1 = ui.addSegment(10, 10, 10, 100); const seg2 = ui.addSegment(200, 10, 200, 100); @@ -36,10 +36,10 @@ export function testBuildGraphBasics(env, ui) { assertEquals(1, ui.viewer.parametricManager.system.subSystems[0].constraints.length); assertEquals(1, ui.viewer.parametricManager.system.subSystems[1].constraints.length); - env.done(); + } -export function testThreeConnectedConstraints(env, ui) { +export async function testThreeConnectedConstraints(env, ui) { const seg1 = ui.addSegment(10, 10, 10, 100); const seg2 = ui.addSegment(200, 10, 200, 100); @@ -68,10 +68,10 @@ export function testThreeConnectedConstraints(env, ui) { assertEquals(3, ui.viewer.parametricManager.system.constraints.length); assertEquals(3, ui.viewer.parametricManager.system.subSystems[0].constraints.length); - env.done(); + } -export function testIgnoreBoundaries(env, ui) { +export async function testIgnoreBoundaries(env, ui) { const boundary = ui.addSegment(500, 10, 500, 100); boundary.aux = true; @@ -90,10 +90,10 @@ export function testIgnoreBoundaries(env, ui) { assertEquals(2, ui.viewer.parametricManager.system.constraints.length); assertEquals(2, ui.viewer.parametricManager.system.subSystems[0].constraints.length); - env.done(); + } -export function testMirroring(env, ui) { +export async function testMirroring(env, ui) { const seg1 = ui.addSegment(10, 10, 10, 100); const seg2 = ui.addSegment(200, 10, 200, 100); @@ -112,10 +112,10 @@ export function testMirroring(env, ui) { const subSystem1 = system.constraintToSubSystem.get(system.constraints[1]); assertTrue( subSystem1.dependencies[0] === subSystem0, "Second subsystem depends on first one"); - env.done(); + } -export function testCircularDependencies(env, ui) { +export async function testCircularDependencies(env, ui) { const seg1 = ui.addSegment(10, 10, 10, 100); const seg2 = ui.addSegment(200, 10, 200, 100); @@ -138,11 +138,11 @@ export function testCircularDependencies(env, ui) { assertEquals(2, ui.viewer.parametricManager.system.subSystems.length); assertTrue(isCircular, "System should contain circular depending subsystems"); - env.done(); + } -export function testSimpleRemove(env, ui) { +export async function testSimpleRemove(env, ui) { const seg1 = ui.addSegment(10, 10, 10, 100); const seg2 = ui.addSegment(200, 10, 200, 100); @@ -168,10 +168,10 @@ export function testSimpleRemove(env, ui) { assertEquals(1, ui.viewer.parametricManager.system.subSystems.length); assertEquals(2, ui.viewer.parametricManager.system.constraints.length); - env.done(); + } -export function testMirroringRemove(env, ui) { +export async function testMirroringRemove(env, ui) { const seg1 = ui.addSegment(10, 10, 10, 100); const seg2 = ui.addSegment(200, 10, 200, 100); @@ -187,10 +187,10 @@ export function testMirroringRemove(env, ui) { ui.viewer.remove(seg1); assertEquals(0, ui.viewer.parametricManager.system.subSystems.length); - env.done(); + } -export function testDoubleAngle(env, ui) { +export async function testDoubleAngle(env, ui) { const seg1 = ui.addSegment(100, 100, 100, 200); const seg2 = ui.addSegment(100, 200, 200, 200); @@ -212,5 +212,5 @@ export function testDoubleAngle(env, ui) { assertFalse(isCircular, "shouldn't be circular"); - env.done(); + } diff --git a/test/coreTests/utils/scripts.js b/test/coreTests/utils/scripts.js index 045ca16d..1d487d45 100644 --- a/test/coreTests/utils/scripts.js +++ b/test/coreTests/utils/scripts.js @@ -1,18 +1,18 @@ -export function createPlaneAndOpenSketcher(ui) { +export async function createPlaneAndOpenSketcher(ui) { ui.openWizard('PLANE'); - ui.wizardOK(); + await ui.wizardOK(); ui.selectFaces([0, 0, -10], [0, 0, 10]); return ui.openSketcher(); } -export function extrudeCube(ui) { - let sketcherUI = createPlaneAndOpenSketcher(ui); +export async function extrudeCube(ui) { + let sketcherUI = await createPlaneAndOpenSketcher(ui); sketcherUI.addRectangle(-100, -100, 100, 100); ui.commitSketch(); ui.selectFaces([0, 0, -10], [0, 0, 10]); ui.openWizard('EXTRUDE'); ui.wizardContext.updateParam('value', 200); - ui.wizardOK(); + await ui.wizardOK(); } diff --git a/test/cypress/integration/part3d/partImport.spec.ts b/test/cypress/integration/part3d/partImport.spec.ts new file mode 100644 index 00000000..e64a2f15 --- /dev/null +++ b/test/cypress/integration/part3d/partImport.spec.ts @@ -0,0 +1,13 @@ + +describe("Part Import", () => { + + beforeEach(() => { + cy.openModeller(); + }); + + it("import from web-cad.org smoke test", () => { + cy.getActionButton('IMPORT_PART').click(); + cy.get('.wizard').should('have.attr', 'data-operation-id', 'IMPORT_PART'); + + }); +}); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index 61554e19..6d533da4 100644 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -1,3 +1,4 @@ +import 'cypress-wait-until'; import modellerUISubject from "../../coreTests/subjects/modellerTPI"; diff --git a/test/cypress/support/index.d.ts b/test/cypress/support/index.d.ts new file mode 100644 index 00000000..cb6f17ac --- /dev/null +++ b/test/cypress/support/index.d.ts @@ -0,0 +1,27 @@ +declare namespace Cypress { + interface Chainable { + + openModeller(): Chainable; + getActionButton(actionId: string): Chainable; + getMenu(menuId: string): Chainable; + getActiveWizardField(fieldName: string): Chainable; + selectRaycasting(from :vec3, to: vec3): Chainable; + simulateClickByRayCast(from :vec3, to: vec3): Chainable; + openSketcher(): Chainable; + commitSketch(): Chainable; + getModellerTPI(): Chainable; + + } + export interface ModellerTPI { + + } + + export interface SketcherTPI { + addRectangle(x1: number, y1: number, x2: number, y2: number); + + } + + type vec3 = [number, number, number]; +} + + diff --git a/test/cypress/tsconfig.json b/test/cypress/tsconfig.json new file mode 100644 index 00000000..b4ae7934 --- /dev/null +++ b/test/cypress/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "strict": true, + "baseUrl": "../node_modules", + "target": "es5", + "lib": ["es5", "dom"], + "types": ["cypress"] + }, + "include": [ + "**/*.ts" + ] +} \ No newline at end of file diff --git a/web/app/api/model/modelObject.js b/web/app/api/model/modelObject.js deleted file mode 100644 index 91bbcde5..00000000 --- a/web/app/api/model/modelObject.js +++ /dev/null @@ -1,10 +0,0 @@ - -interface IMObject { - - - -} - -IMFace - -IMVertex \ No newline at end of file diff --git a/web/app/cad/craft/cadRegistryPlugin.js b/web/app/cad/craft/cadRegistryPlugin.ts similarity index 76% rename from web/app/cad/craft/cadRegistryPlugin.js rename to web/app/cad/craft/cadRegistryPlugin.ts index 65317a48..7d48890c 100644 --- a/web/app/cad/craft/cadRegistryPlugin.js +++ b/web/app/cad/craft/cadRegistryPlugin.ts @@ -1,8 +1,13 @@ import {DATUM, DATUM_AXIS, EDGE, FACE, LOOP, SHELL, SKETCH_OBJECT} from '../scene/entites'; import {MShell} from '../model/mshell'; +import {Emitter} from "lstream"; +import {ShowDialogRequest} from "ui/showDialogRequest"; +import {CatalogCategory, CatalogPart, PartsCatalog} from "../partImport/partImportPlugin"; +import {MObject} from "../model/mobject"; -export function activate({streams, services}) { +export function activate(ctx) { + const {streams, services} = ctx; streams.cadRegistry = { shells: streams.craft.models.map(models => models.filter(m => m instanceof MShell)).remember(), @@ -108,7 +113,32 @@ export function activate({streams, services}) { get shells() { return getAllShells(); } - } + }; + ctx.cadRegistry = services.cadRegistry; } +export interface CadRegistry { + + getAllShells(): MObject[]; + findShell(id: string): MObject; + findFace(id: string): MObject; + findEdge(id: string): MObject; + findSketchObject(id: string): MObject; + findEntity(id: string): MObject; + findEntity(id: string): MObject; + findDatum(id: string): MObject; + findDatumAxis(id: string): MObject; + findLoop(id: string): MObject; + modelIndex: Map; + models: MObject[]; + shells: MObject[]; + +} + +declare module 'context' { + interface ApplicationContext { + + cadRegistry: CadRegistry; + } +} diff --git a/web/app/cad/craft/craftPlugin.js b/web/app/cad/craft/craftPlugin.js index 674595fa..8775c198 100644 --- a/web/app/cad/craft/craftPlugin.js +++ b/web/app/cad/craft/craftPlugin.js @@ -1,47 +1,45 @@ import {addModification, stepOverriding} from './craftHistoryUtils'; import {state, stream} from 'lstream'; -import {MShell} from '../model/mshell'; -import {MDatum} from '../model/mdatum'; import materializeParams from './materializeParams'; import CadError from '../../utils/errors'; import {MObjectIdGenerator} from '../model/mobject'; +import {intercept} from "../../../../modules/lstream/intercept"; -export function activate({streams, services}) { - +export function activate(ctx) { + const {streams, services} = ctx; streams.craft = { + modifications: state({ history: [], pointer: -1 }), + models: state([]), update: stream() }; let preRun = null; - function modifyWithPreRun(request, modificationsUpdater, onAccepted) { - preRun = { - request - }; - try { - preRun.result = runRequest(request); - if (onAccepted) { - onAccepted(); - } + function modifyWithPreRun(request, modificationsUpdater, onAccepted, onError) { + + runRequest(request).then(result => { + onAccepted(); + preRun = { + request, + result + }; modificationsUpdater(request); - } finally { - preRun = null; - } + }).catch(onError); } - function modify(request, onAccepted) { + function modify(request, onAccepted, onError) { modifyWithPreRun(request, - request => streams.craft.modifications.update(modifications => addModification(modifications, request)), onAccepted); + request => streams.craft.modifications.update(modifications => addModification(modifications, request)), onAccepted, onError); } - function modifyInHistoryAndStep(request, onAccepted) { + function modifyInHistoryAndStep(request, onAccepted, onError) { modifyWithPreRun(request, - request => streams.craft.modifications.update(modifications => stepOverriding(modifications, request)), onAccepted); + request => streams.craft.modifications.update(modifications => stepOverriding(modifications, request)), onAccepted, onError); } function reset(modifications) { @@ -60,25 +58,28 @@ export function activate({streams, services}) { function runRequest(request) { let op = services.operation.get(request.type); if (!op) { - throw(`unknown operation ${request.type}`); + return Promise.reject(new Error(`unknown operation ${request.type}`)); } let params = {}; let errors = []; materializeParams(services, request.params, op.schema, params, errors); if (errors.length) { - throw new CadError({ + return Promise.reject(new CadError({ kind: CadError.KIND.INVALID_PARAMS, userMessage: errors.map(err => `${err.path.join('.')}: ${err.message}`).join('\n') - }); + })); } - - return op.run(params, services); + + const result = op.run(params, ctx); + return result.then ? result : Promise.resolve(result); } function runOrGetPreRunResults(request) { if (preRun !== null && preRun.request === request) { - return preRun.result; + const result = preRun.result; + preRun = null; + return Promise.resolve(result); } else { return runRequest(request); } @@ -89,7 +90,13 @@ export function activate({streams, services}) { historyTravel: historyTravel(streams.craft.modifications) }; - streams.craft.modifications.pairwise().attach(([prev, curr]) => { + let locked = false; + intercept(streams.craft.modifications, (curr, stream, next) => { + const prev = stream.value; + if (locked) { + console.error('concurrent modification'); + } + locked = true; let models; let beginIndex; if (isAdditiveChange(prev, curr)) { @@ -102,23 +109,34 @@ export function activate({streams, services}) { models = new Set(streams.craft.models.value); let {history, pointer} = curr; - for (let i = beginIndex; i <= pointer; i++) { + + function runPromise(i) { + if (i > pointer) { + locked = false; + next(curr); + return; + } + let request = history[i]; - try { - let {consumed, created} = runOrGetPreRunResults(request); + const promise = runOrGetPreRunResults(request) + promise.then(({consumed, created}) => { + consumed.forEach(m => models.delete(m)); created.forEach(m => models.add(m)); streams.craft.models.next(Array.from(models).sort(m => m.id)); - } catch(e) { + + runPromise(i + 1); + }).catch(e => { + locked = false; console.error(e); //TODO: need to find a way to propagate the error to the wizard. - setTimeout(() => streams.craft.modifications.next({ + next({ ...curr, pointer: i-1 - })); - break; - } + }); + }) } + runPromise(beginIndex); }) } diff --git a/web/app/cad/craft/cutExtrude/cutExtrude.js b/web/app/cad/craft/cutExtrude/cutExtrude.js index 250ed2c7..49804ff3 100644 --- a/web/app/cad/craft/cutExtrude/cutExtrude.js +++ b/web/app/cad/craft/cutExtrude/cutExtrude.js @@ -4,19 +4,19 @@ import {enclose} from '../../../brep/brep-enclose' import {BooleanOperation, combineShells} from '../booleanOperation' -export function Extrude(params, sketcher) { - return doOperation(params, sketcher, false); +export function Extrude(params, ctx) { + return doOperation(params, ctx, false); } -export function Cut(params, sketcher) { - return doOperation(params, sketcher, true); +export function Cut(params, ctx) { + return doOperation(params, ctx, true); } -export function doOperation(params, {cadRegistry, sketcher}, cut) { +export function doOperation(params, {cadRegistry, sketcherService}, cut) { const face = cadRegistry.findFace(params.face); const solid = face.solid; - let sketch = sketcher.readSketch(face.id); + let sketch = sketcherService.readSketch(face.id); if (!sketch) throw 'illegal state'; let vector = resolveExtrudeVector(cadRegistry, face, params, !cut); diff --git a/web/app/cad/craft/e0/craftMethods.js b/web/app/cad/craft/e0/craftMethods.js index cb25dcc8..bdd4abe5 100644 --- a/web/app/cad/craft/e0/craftMethods.js +++ b/web/app/cad/craft/e0/craftMethods.js @@ -91,9 +91,9 @@ function booleanBasedOperation(engineParams, params, impl) { function cutExtrude(isCut, request) { - function createExtrudeCommand(request, {cadRegistry, sketcher}, invert) { + function createExtrudeCommand(request, {cadRegistry, sketcherService}, invert) { const face = cadRegistry.findFace(request.face); - const paths = readSketch(face, request, sketcher); + const paths = readSketch(face, request, sketcherService); return { face, diff --git a/web/app/cad/craft/e0/e0Plugin.js b/web/app/cad/craft/e0/e0Plugin.js index 91fe00a2..5b3ddcf4 100644 --- a/web/app/cad/craft/e0/e0Plugin.js +++ b/web/app/cad/craft/e0/e0Plugin.js @@ -11,7 +11,8 @@ export function activate(ctx) { ctx.services.operation.handlers.push(operationHandler); ctx.services.craftEngine = { ...craftMethods - } + }; + ctx.craftEngine = ctx.services.craftEngine; } function instantiateEngine(importObject, callback) { diff --git a/web/app/cad/craft/e0/operationHandler.js b/web/app/cad/craft/e0/operationHandler.js index c67d3ddc..a0f03822 100644 --- a/web/app/cad/craft/e0/operationHandler.js +++ b/web/app/cad/craft/e0/operationHandler.js @@ -41,9 +41,9 @@ export default function operationHandler(id, request, services) { } } -function createExtrudeCommand(request, {cadRegistry, sketcher}, invert) { +function createExtrudeCommand(request, {cadRegistry, sketcherService}, invert) { const face = cadRegistry.findFace(request.face); - const paths = readSketch(face, request, sketcher); + const paths = readSketch(face, request, sketcherService); return { face, @@ -56,9 +56,9 @@ function createExtrudeCommand(request, {cadRegistry, sketcher}, invert) { }; } -function createRevolveCommand(request, {cadRegistry, sketcher}) { +function createRevolveCommand(request, {cadRegistry, sketcherService}) { const face = cadRegistry.findFace(request.face); - const paths = readSketch(face, request, sketcher); + const paths = readSketch(face, request, sketcherService); let pivot = cadRegistry.findSketchObject(request.axis).sketchPrimitive; let tr = face.csys.outTransformation; diff --git a/web/app/cad/craft/operationPlugin.js b/web/app/cad/craft/operationPlugin.js deleted file mode 100644 index 537b123e..00000000 --- a/web/app/cad/craft/operationPlugin.js +++ /dev/null @@ -1,94 +0,0 @@ -import {state} from 'lstream'; -import {isEntityType} from './schemaUtils'; - -export function activate(context) { - let {services} = context; - - context.streams.operation = { - registry: state({}) - }; - - let registry$ = context.streams.operation.registry; - - function addOperation(descriptor, actions) { - let {id, label, info, icon, actionParams} = descriptor; - let appearance = { - label, - info, - icon32: icon + '32.png', - icon96: icon + '96.png', - }; - let opAction = { - id: id, - appearance, - invoke: () => services.wizard.open(id), - ...actionParams - }; - actions.push(opAction); - - let schemaIndex = createSchemaIndex(descriptor.schema); - - registry$.mutate(registry => registry[id] = Object.assign({appearance, schemaIndex}, descriptor, { - run: (request, services) => runOperation(request, descriptor, services) - })); - } - - function registerOperations(operations) { - let actions = []; - for (let op of operations) { - addOperation(op, actions); - } - services.action.registerActions(actions); - } - - function get(id) { - let op = registry$.value[id]; - if (!op) { - throw `operation ${id} is not registered`; - } - return op; - } - - let handlers = []; - - function runOperation(request, descriptor, services) { - for (let handler of handlers) { - let result = handler(descriptor.id, request, services); - if (result) { - return result; - } - } - return descriptor.run(request, services); - } - - services.operation = { - registerOperations, - get, - handlers - }; -} - -function createSchemaIndex(schema) { - const entitiesByType = {}; - const entitiesByParam = {}; - const entityParams = []; - for (let field of Object.keys(schema)) { - let md = schema[field]; - let entityType = md.type === 'array' ? md.itemType : md.type; - - if (isEntityType(entityType)) { - let byType = entitiesByType[entityType]; - if (!byType) { - byType = []; - entitiesByType[entityType] = byType; - } - byType.push(field); - entitiesByParam[field] = entityType; - entityParams.push(field); - } - } - return {entitiesByType, entitiesByParam, - entityParams: Object.keys(entitiesByParam), - params: Object.keys(schema) - }; -} \ No newline at end of file diff --git a/web/app/cad/craft/operationPlugin.ts b/web/app/cad/craft/operationPlugin.ts new file mode 100644 index 00000000..923b37d4 --- /dev/null +++ b/web/app/cad/craft/operationPlugin.ts @@ -0,0 +1,169 @@ +import React from 'react'; +import {state} from 'lstream'; +import {IconType} from "react-icons"; +import {isEntityType} from './schemaUtils'; +import {ActionAppearance} from "../actions/actionSystemPlugin"; +import {MObject} from "../model/mobject"; +import {ApplicationContext} from "context"; + +export function activate(context) { + let {services} = context; + + context.streams.operation = { + registry: state({}) + }; + + let registry$ = context.streams.operation.registry; + + function addOperation(descriptor, actions) { + let {id, label, info, icon, actionParams} = descriptor; + let appearance: ActionAppearance = { + label, + info + }; + if (typeof icon === 'string') { + appearance.icon32 = icon + '32.png'; + appearance.icon96 = icon + '96.png'; + } else { + appearance.icon = icon; + } + let opAction = { + id: id, + appearance, + invoke: () => services.wizard.open(id), + ...actionParams + }; + actions.push(opAction); + + let schemaIndex = createSchemaIndex(descriptor.schema); + + registry$.mutate(registry => registry[id] = Object.assign({appearance, schemaIndex}, descriptor, { + run: (request, opContext) => runOperation(request, descriptor, opContext) + })); + } + + function registerOperations(operations) { + let actions = []; + for (let op of operations) { + addOperation(op, actions); + } + services.action.registerActions(actions); + } + + function get(id) { + let op = registry$.value[id]; + if (!op) { + throw `operation ${id} is not registered`; + } + return op; + } + + let handlers = []; + + function runOperation(request, descriptor, opContext) { + for (let handler of handlers) { + let result = handler(descriptor.id, request, opContext); + if (result) { + return result; + } + } + return descriptor.run(request, opContext); + } + + services.operation = { + registerOperations, + get, + handlers + }; + + context.operationService = services.operation; +} + +export interface Operation extends OperationDescriptor{ + appearance: { + id: string; + label: string; + info: string; + icon32: string; + icon96: string; + icon: string|IconType; + }; + schemaIndex: { + entitiesByType: any; + entitiesByParam: any; + entityParams: any[]; + params: any[]; + }, +} + +function createSchemaIndex(schema) { + const entitiesByType = {}; + const entitiesByParam = {}; + const entityParams = []; + for (let field of Object.keys(schema)) { + let md = schema[field]; + let entityType = md.type === 'array' ? md.itemType : md.type; + + if (isEntityType(entityType)) { + let byType = entitiesByType[entityType]; + if (!byType) { + byType = []; + entitiesByType[entityType] = byType; + } + byType.push(field); + entitiesByParam[field] = entityType; + entityParams.push(field); + } + } + return {entitiesByType, entitiesByParam, + entityParams: Object.keys(entitiesByParam), + params: Object.keys(schema) + }; +} + + +export interface OperationDescriptor { + id: string; + label: string; + info: string; + icon: IconType | string; + actionParams?: any; + run: (request: R, opContext: OperationContext) => OperationResult; + paramsInfo: (params: R) => string, + previewGeomProvider: (params: R) => OperationGeometryProvider, + form: () => React.ReactNode, + schema: any +} + +export interface OperationService { + registerOperations(descriptior: OperationDescriptor[]); + get(operationId: string): Operation; + handlers: (( + id: string, + request: any, + opContext: OperationContext + ) => void)[] +} + +export interface OperationGeometryProvider { + +} + +export interface OperationResult { + + consumed: MObject[]; + created: MObject[]; + +} + +export interface OperationContext { + cadRegistry: any +} + +declare module 'context' { + interface ApplicationContext { + + operationService: OperationService; + } +} + diff --git a/web/app/cad/craft/wizard/components/Wizard.jsx b/web/app/cad/craft/wizard/components/Wizard.jsx index 87a39775..a3736984 100644 --- a/web/app/cad/craft/wizard/components/Wizard.jsx +++ b/web/app/cad/craft/wizard/components/Wizard.jsx @@ -15,12 +15,13 @@ import {IoMdHelp} from "react-icons/io"; @connect((streams, props) => combine(props.context.workingRequest$, props.context.state$) .map(([workingRequest, state]) => ({ ...workingRequest, - activeParam: state.activeParam + activeParam: state.activeParam, + error: state.error }))) export default class Wizard extends React.Component { state = { - hasError: false, + hasInternalError: false, }; updateParam = (name, value) => { @@ -54,15 +55,16 @@ export default class Wizard extends React.Component { let Form = operation.form; + const error = this.props.error; return + initLeft={left || 15} + title={title} + onClose={this.cancel} + onKeyDown={this.onKeyDown} + setFocus={this.focusFirstInput} + className='Wizard mid-typography' + data-operation-id={operation.id} + controlButtons={<> DocumentationTopic$.next({ topic: operation.id, x: e.pageX + 40, @@ -79,13 +81,13 @@ export default class Wizard extends React.Component { - {this.state.hasError &&
- {this.state.algorithmError && + {error &&
+ {CadError.ALGORITMTHM_ERROR_KINDS.includes(error.kind) && performing operation with current parameters leads to an invalid object (self-intersecting / zero-thickness / complete degeneration or unsupported cases) } - {this.state.code &&
{this.state.code}
} - {this.state.userMessage &&
{this.state.userMessage}
} + {error.code &&
{error.code}
} + {error.userMessage &&
{error.userMessage}
}
} ; @@ -118,34 +120,8 @@ export default class Wizard extends React.Component { }; onOK = () => { - try { - this.props.onOK(); - } catch (error) { - this.handleError(error); - } + this.props.onOK(); }; - - handleError(error) { - let stateUpdate = { - hasError: true - }; - let printError = true; - if (error.TYPE === CadError) { - let {code, userMessage, kind} = error; - printError = !code; - if (CadError.ALGORITMTHM_ERROR_KINDS.includes(kind)) { - stateUpdate.algorithmError = true; - } - if (code && kind === CadError.KIND.INTERNAL_ERROR) { - console.warn('Operation Error Code: ' + code); - } - Object.assign(stateUpdate, {code, userMessage}); - } - this.setState(stateUpdate); - if (printError) { - throw error; - } - } } diff --git a/web/app/cad/craft/wizard/wizardPlugin.js b/web/app/cad/craft/wizard/wizardPlugin.js index 05b836bc..0b853a38 100644 --- a/web/app/cad/craft/wizard/wizardPlugin.js +++ b/web/app/cad/craft/wizard/wizardPlugin.js @@ -131,10 +131,11 @@ export function activate(ctx) { applyWorkingRequest: () => { let {type, params} = streams.wizard.wizardContext.value.workingRequest$.value; let request = clone({type, params}); + const setError = error => streams.wizard.wizardContext.mutate(ctx => ctx.state$.mutate(state => state.error = error)); if (streams.wizard.insertOperation.value.type) { - ctx.services.craft.modify(request, () => streams.wizard.insertOperation.value = EMPTY_OBJECT); + ctx.services.craft.modify(request, () => streams.wizard.insertOperation.value = EMPTY_OBJECT, setError ); } else { - ctx.services.craft.modifyInHistoryAndStep(request, () => streams.wizard.effectiveOperation.value = EMPTY_OBJECT); + ctx.services.craft.modifyInHistoryAndStep(request, () => streams.wizard.effectiveOperation.value = EMPTY_OBJECT, setError); } }, diff --git a/web/app/cad/dom/menu/MenuHolder.jsx b/web/app/cad/dom/menu/MenuHolder.jsx index cfdc4100..b4f50c42 100644 --- a/web/app/cad/dom/menu/MenuHolder.jsx +++ b/web/app/cad/dom/menu/MenuHolder.jsx @@ -34,8 +34,8 @@ function ActionMenuItem({label, cssIcons, icon32, icon96, enabled, hotKey, visib backgroundImage: `url(${icon32 || icon96})`, backgroundRepeat: 'no-repeat', backgroundSize: `${size}px ${size}px`, - backgroundPositionY: 6, backgroundPositionX: 5, + backgroundPositionY: 4, }; if (!enabled) { style.filter = 'grayscale(90%)'; diff --git a/web/app/cad/model/mobject.js b/web/app/cad/model/mobject.ts similarity index 87% rename from web/app/cad/model/mobject.js rename to web/app/cad/model/mobject.ts index 14c83040..b309ae3f 100644 --- a/web/app/cad/model/mobject.js +++ b/web/app/cad/model/mobject.ts @@ -1,10 +1,10 @@ export class MObject { - TYPE; + TYPE: string; - id; - ext = {}; + id: string; + ext: any = {}; constructor(TYPE, id) { this.TYPE = TYPE; diff --git a/web/app/cad/partImport/importPartOperation/ImportPartForm.tsx b/web/app/cad/partImport/importPartOperation/ImportPartForm.tsx new file mode 100644 index 00000000..5a68c5fa --- /dev/null +++ b/web/app/cad/partImport/importPartOperation/ImportPartForm.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import {Group} from "../../craft/wizard/components/form/Form"; +import EntityList from "../../craft/wizard/components/form/EntityList"; +import {PartRefField} from "../ui/PartRefControl"; + +export function ImportPartForm() { + + return + + + ; +} \ No newline at end of file diff --git a/web/app/cad/partImport/importPartOperation/importPartOperation.ts b/web/app/cad/partImport/importPartOperation/importPartOperation.ts new file mode 100644 index 00000000..df60dcc3 --- /dev/null +++ b/web/app/cad/partImport/importPartOperation/importPartOperation.ts @@ -0,0 +1,53 @@ +import {GrCloudDownload} from "react-icons/gr"; +import {ImportPartForm} from "./ImportPartForm"; +import importPartSchema from "./importPartSchema"; +import {OperationDescriptor, OperationResult} from "../../craft/operationPlugin"; +import CSys from "../../../math/csys"; +import {MDatum} from "../../model/mdatum"; +import {ApplicationContext} from "context"; + +export interface ImportPartOperationParams { + partRef: string, + datum: string, + consumeDatum: boolean; +} + +export const ImportPartOperation: OperationDescriptor = { + + id: 'IMPORT_PART', + label: 'import part', + icon: GrCloudDownload, + info: 'opens a dialog to import parts from the catalog', + paramsInfo: ({partRef}) => partRef, + previewGeomProvider: null, + run: runImportOperation, + form: ImportPartForm, + schema: importPartSchema +}; + + +function runImportOperation(params: ImportPartOperationParams, ctx: ApplicationContext): OperationResult { + + + const {cadRegistry, partImportService} = ctx; + + let mDatum = params.datum && cadRegistry.findDatum(params.datum); + + + const res = { + consumed: [], + created: [] + }; + + // partImportService.resolvePartReference(params.); + + if (mDatum) { + + if (params.consumeDatum) { + res.consumed.push(mDatum); + } + + } + + return res; +} \ No newline at end of file diff --git a/web/app/cad/partImport/importPartOperation/importPartSchema.js b/web/app/cad/partImport/importPartOperation/importPartSchema.js new file mode 100644 index 00000000..0d977745 --- /dev/null +++ b/web/app/cad/partImport/importPartOperation/importPartSchema.js @@ -0,0 +1,14 @@ +export default { + partRef: { + type: 'string' + }, + datum: { + type: 'datum', + optional: true, + initializeBySelection: 0 + }, + consumeDatum: { + type: 'boolean', + defaultValue: false + }, +} diff --git a/web/app/cad/partImport/partCatalogConfig.ts b/web/app/cad/partImport/partCatalogConfig.ts index 3c11f815..0f08bb4c 100644 --- a/web/app/cad/partImport/partCatalogConfig.ts +++ b/web/app/cad/partImport/partCatalogConfig.ts @@ -1,13 +1,13 @@ -import {FaSitemap} from "react-icons/fa"; import {PartsCatalog} from "./partImportPlugin"; import {GitHubRepoRepository} from "../repository/GitHubRepoRepository"; +import {GrCubes} from "react-icons/gr"; export const WEB_CAD_ORG_COMMONS: PartsCatalog = Object.freeze({ id: 'web-cad.org', name: 'Commons Parts', description: 'Public parts repository by web-cad.org', - icon: FaSitemap, + icon: GrCubes, repo: new GitHubRepoRepository('xibyte/web-cad', 'master'), metadataPath: 'commons.catalog.json', partsPath: 'parts' diff --git a/web/app/cad/partImport/partImortActions.js b/web/app/cad/partImport/partImortActions.js deleted file mode 100644 index 147816da..00000000 --- a/web/app/cad/partImport/partImortActions.js +++ /dev/null @@ -1,17 +0,0 @@ -export const PartImportActions = [ - { - id: 'StartPartImportOperation', - appearance: { - info: 'import partt', - label: 'coincident', - icon32: 'img/coi.png', - }, - invoke: ctx => { - - - - let viewer = services.sketcher.inPlaceEditor.viewer; - viewer.parametricManager.coincident(viewer.selected); - } - }, -]; \ No newline at end of file diff --git a/web/app/cad/partImport/partImportPlugin.ts b/web/app/cad/partImport/partImportPlugin.ts index 58e62c1f..9adeff38 100644 --- a/web/app/cad/partImport/partImportPlugin.ts +++ b/web/app/cad/partImport/partImportPlugin.ts @@ -5,26 +5,13 @@ import {WEB_CAD_ORG_COMMONS} from "./partCatalogConfig"; import {Emitter, stream} from "lstream"; import {ShowDialogRequest} from "ui/showDialogRequest"; import {CatalogPartChooser} from "./ui/CatalogPartChooser"; -import {GrCloudDownload} from "react-icons/gr"; +import {ImportPartOperation} from "./importPartOperation/importPartOperation"; export function activate(ctx: ApplicationContext) { ctx.domService.contributeComponent(CatalogPartChooser); - ctx.actionService.registerAction({ - id: 'IMPORT_PART', - appearance: { - info: 'opens a dialog to import parts from the catalog', - label: 'import part', - icon: GrCloudDownload - }, - invoke: (ctx: ApplicationContext) => { - ctx.partImportService.choosePartRequest$.next({ - centerScreen: true, - onDone: () => {} - }) - }, - }); + ctx.operationService.registerOperations([ImportPartOperation]); function loadDefinedCatalogs(): Promise<[CatalogCategory, PartsCatalog][]> { diff --git a/web/app/cad/partImport/ui/CatalogPartChooser.tsx b/web/app/cad/partImport/ui/CatalogPartChooser.tsx index 0acc1998..67a31d57 100644 --- a/web/app/cad/partImport/ui/CatalogPartChooser.tsx +++ b/web/app/cad/partImport/ui/CatalogPartChooser.tsx @@ -5,7 +5,8 @@ import {AppContext} from "../../dom/components/AppContext"; import {Dialog} from "ui/components/Dialog"; import {useDataLoader} from "ui/useDataLoader"; import {WhenDataReady} from "ui/components/WhenDataReady"; -import {GiPuzzle} from "react-icons/gi"; +import {GrCubes} from "react-icons/gr"; +import theme from "ui/styles/theme"; export function CatalogPartChooser() { @@ -28,14 +29,15 @@ export function CatalogPartChooser() { title='PART CATALOG' enableResize={true} onClose={close} - onOK={() => { - setReq(null); - req.onDone(chosen); - }} + cancelText='Close' + > - {catalogs => catalogs.map(([partCatalog, descriptor]) => } />)} + {catalogs => catalogs.map(([partCatalog, descriptor]) => { + const Icon = descriptor.icon || GrCubes; + return } /> + })} diff --git a/web/app/cad/partImport/ui/PartCatalog.tsx b/web/app/cad/partImport/ui/PartCatalog.tsx index 3aaf91c5..7348abd7 100644 --- a/web/app/cad/partImport/ui/PartCatalog.tsx +++ b/web/app/cad/partImport/ui/PartCatalog.tsx @@ -1,7 +1,9 @@ import React, {ReactNode} from "react"; import {CatalogCategory, CatalogPart} from "../partImportPlugin"; import {Tree} from "ui/components/Tree"; -import {TiFolder, TiPuzzleOutline} from "react-icons/ti"; +import {FiBox} from "react-icons/fi"; +import {GrCubes} from "react-icons/gr"; +import theme from "ui/styles/theme"; export function PartCatalog({root, initCollapsed, name, icon} : { root: CatalogCategory, @@ -17,13 +19,13 @@ export function PartCatalog({root, initCollapsed, name, icon} : { const category = entry as CatalogCategory; - return }/> + return }/> } else if (entry.type === 'part') { const part = entry as CatalogPart; - return }/> + return }/> } })} diff --git a/web/app/cad/partImport/ui/PartRefControl.tsx b/web/app/cad/partImport/ui/PartRefControl.tsx new file mode 100644 index 00000000..451c191f --- /dev/null +++ b/web/app/cad/partImport/ui/PartRefControl.tsx @@ -0,0 +1,42 @@ +import React, {useContext, useEffect} from 'react'; +import {attachToForm, formField} from "../../craft/wizard/components/form/Form"; +import InputControl from "ui/components/controls/InputControl"; +import {AppContext} from "../../dom/components/AppContext"; + +export function PartRefControl(props) { + + let {onChange, initValue, onFocus, openIfEmpty} = props; + useEffect(() => { + + if (openIfEmpty && !initValue) { + openChooser(undefined); + } + + }, []); + + const ctx = useContext(AppContext); + + const openChooser = e => { + + ctx.partImportService.choosePartRequest$.next({ + centerScreen: true, + onDone: () => {} + }) + }; + + return
+ onChange(e.target.value)} + onFocus={onFocus} + style={{ + flex: 1 + }}/> + +
+ +} + +export const PartRefField = attachToForm(formField(PartRefControl)); diff --git a/web/app/cad/sketch/sketcherPlugin.js b/web/app/cad/sketch/sketcherPlugin.ts similarity index 95% rename from web/app/cad/sketch/sketcherPlugin.js rename to web/app/cad/sketch/sketcherPlugin.ts index f72343dc..f44989b7 100644 --- a/web/app/cad/sketch/sketcherPlugin.js +++ b/web/app/cad/sketch/sketcherPlugin.ts @@ -8,6 +8,8 @@ import sketcherStreams from '../../sketcher/sketcherStreams'; import {Viewer} from "../../sketcher/viewer2d"; import {IO} from "../../sketcher/io"; import {DelegatingPanTool} from "../../sketcher/tools/pan"; +import {CadRegistry} from "../craft/cadRegistryPlugin"; +import {MObject} from "../model/mobject"; export function defineStreams(ctx) { ctx.streams.sketcher = { @@ -188,6 +190,18 @@ export function activate(ctx) { services.sketcher = { sketchFace, sketchFace2D, updateAllSketches, getAllSketches, readSketch, hasSketch, inPlaceEditor, reassignSketch, reassignSketchMode: initReassignSketchMode(ctx) - } + }; + ctx.sketcherService = services.sketcher; } +export interface SketcherService { + +} + + +declare module 'context' { + interface ApplicationContext { + + sketcherService: SketcherService; + } +}