diff --git a/package.json b/package.json index 5684dfae3b9..43f3e2dc6ba 100755 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "protocol-designer", "shared-data", "step-generation", - "webpack-config", "api-client", "react-api-client", "usb-bridge/node-client" diff --git a/protocol-designer/README.md b/protocol-designer/README.md index c7bf1b3983a..ae8b91e2e52 100644 --- a/protocol-designer/README.md +++ b/protocol-designer/README.md @@ -1,10 +1,10 @@ -# Opentrons Protocol Designer Beta +# Opentrons Protocol Designer ## Overview Protocol Designer is a tool for scientists and technicians to create protocols for their [OT-2 personal pipetting robot][ot-2] without having to write any code. It provides visual feedback including liquid tracking and tip tracking to allow users to see exactly what their protocol will do at each step. The protocols are saved to Opentrons JSON Protocol files, which can be uploaded to the Opentrons Desktop App to run on a robot. -Protocol Designer Beta is optimized for [Chrome][chrome] browser. Other browsers are not fully supported. +Protocol Designer is optimized for [Chrome][chrome] browser. Other browsers are not fully supported. ## Build setup for development diff --git a/protocol-designer/cypress.json b/protocol-designer/cypress.json index 44203bdc3da..fa95795bfd6 100644 --- a/protocol-designer/cypress.json +++ b/protocol-designer/cypress.json @@ -2,5 +2,6 @@ "baseUrl": "http://localhost:5173", "video": false, "viewportWidth": 1440, - "viewportHeight": 900 + "viewportHeight": 900, + "pluginsFile": false } diff --git a/protocol-designer/cypress/integration/batchEdit.spec.js b/protocol-designer/cypress/integration/batchEdit.spec.js index 55071aae50a..300983ad9b0 100644 --- a/protocol-designer/cypress/integration/batchEdit.spec.js +++ b/protocol-designer/cypress/integration/batchEdit.spec.js @@ -1,5 +1,3 @@ -import { beforeEach, describe, it } from 'vitest' - describe('Batch Edit Transform', () => { beforeEach(() => { cy.visit('/') diff --git a/protocol-designer/cypress/integration/home.spec.js b/protocol-designer/cypress/integration/home.spec.js index 99e554e0d8f..c2f2bda9f92 100644 --- a/protocol-designer/cypress/integration/home.spec.js +++ b/protocol-designer/cypress/integration/home.spec.js @@ -1,5 +1,3 @@ -import { beforeEach, describe, it } from 'vitest' - describe('The Home Page', () => { beforeEach(() => { cy.visit('/') @@ -7,7 +5,7 @@ describe('The Home Page', () => { }) it('successfully loads', () => { - cy.title().should('equal', 'Opentrons Protocol Designer BETA') + cy.title().should('equal', 'Opentrons Protocol Designer') }) it('has the right charset', () => { diff --git a/protocol-designer/cypress/integration/migrations.spec.js b/protocol-designer/cypress/integration/migrations.spec.js index 0fad10a0a10..6bc1036477a 100644 --- a/protocol-designer/cypress/integration/migrations.spec.js +++ b/protocol-designer/cypress/integration/migrations.spec.js @@ -1,4 +1,3 @@ -import { beforeEach, describe, it } from 'vitest' import 'cypress-file-upload' import cloneDeep from 'lodash/cloneDeep' import { expectDeepEqual } from '@opentrons/shared-data/js/cypressUtils' diff --git a/protocol-designer/cypress/integration/mixSettings.spec.js b/protocol-designer/cypress/integration/mixSettings.spec.js index 67960c5dd94..809c92237b3 100644 --- a/protocol-designer/cypress/integration/mixSettings.spec.js +++ b/protocol-designer/cypress/integration/mixSettings.spec.js @@ -1,4 +1,3 @@ -import { describe, it } from 'vitest' const isMacOSX = Cypress.platform === 'darwin' const invalidInput = 'abcdefghijklmnopqrstuvwxyz!@#$%^&*()<>?,-' const batchEditClickOptions = { [isMacOSX ? 'metaKey' : 'ctrlKey']: true } @@ -125,7 +124,7 @@ describe('Advanced Settings for Mix Form', () => { cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) cy.get('input[name="aspirate_flowRate"]').click({ force: true }) - cy.get('div[class*=FlowRateInput__description]').contains( + cy.contains( 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') @@ -144,7 +143,7 @@ describe('Advanced Settings for Mix Form', () => { it('verify functionality of flowrate in batch edit mix form', () => { // Batch editing the Flowrate value cy.get('input[name="aspirate_flowRate"]').click({ force: true }) - cy.get('div[class*=FlowRateInput__description]').contains( + cy.contains( 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') diff --git a/protocol-designer/cypress/integration/settings.spec.js b/protocol-designer/cypress/integration/settings.spec.js index 5e70c779ffd..3f248d79ab0 100644 --- a/protocol-designer/cypress/integration/settings.spec.js +++ b/protocol-designer/cypress/integration/settings.spec.js @@ -1,4 +1,3 @@ -import { describe, it, before } from 'vitest' describe('The Settings Page', () => { const exptlSettingText = 'Disable module placement restrictions' @@ -142,7 +141,7 @@ describe('The Settings Page', () => { cy.contains(exptlSettingText).next().click() cy.get('button').contains('Continue').click() // Leave the settings page - cy.get("button[class*='navbar__tab__']").contains('FILE').click() + cy.get("button[id='NavTab_file']").contains('FILE').click() // Go back to settings cy.openSettingsPage() // The toggle is still on @@ -160,7 +159,7 @@ describe('The Settings Page', () => { cy.contains(exptlSettingText).next().click() cy.get('button').contains('Continue').click() // Leave the settings page - cy.get("button[class*='navbar__tab__']").contains('FILE') + cy.get("button[id='NavTab_file']").contains('FILE') // Go back to settings cy.openSettingsPage() // The toggle is still off diff --git a/protocol-designer/cypress/integration/sidebar.spec.js b/protocol-designer/cypress/integration/sidebar.spec.js index e967c0c7b38..7b71fc67cc2 100644 --- a/protocol-designer/cypress/integration/sidebar.spec.js +++ b/protocol-designer/cypress/integration/sidebar.spec.js @@ -1,5 +1,3 @@ -import { describe, it, beforeEach } from 'vitest' - describe('Desktop Navigation', () => { beforeEach(() => { cy.visit('/') @@ -7,7 +5,7 @@ describe('Desktop Navigation', () => { }) it('contains a working file button', () => { - cy.get("button[class*='navbar__tab__']") + cy.get("button[id='NavTab_file']") .contains('FILE') .parent() .should('have.prop', 'disabled') @@ -15,21 +13,21 @@ describe('Desktop Navigation', () => { }) it('contains a disabled liquids button', () => { - cy.get("button[class*='navbar__tab__']") + cy.get("button[id='NavTab_liquids']") .contains('LIQUIDS') .parent() .should('have.prop', 'disabled') }) it('contains a disabled design button', () => { - cy.get("button[class*='navbar__tab__']") + cy.get("button[id='NavTab_design']") .contains('DESIGN') .parent() .should('have.prop', 'disabled') }) it('contains a help button with external link', () => { - cy.get("a[class*='navbar__tab__']") + cy.get('a') .contains('HELP') .parent() .should('have.prop', 'href') @@ -37,13 +35,11 @@ describe('Desktop Navigation', () => { }) it('contains a settings button', () => { - cy.get("button[class*='navbar__tab__']") - .contains('Settings') - .should('exist') + cy.get('button').contains('Settings').should('exist') }) it('returns to the file controls when the file button is clicked', () => { - cy.get("button[class*='navbar__tab__']").contains('FILE').click() + cy.get("button[id='NavTab_file']").contains('FILE').click() cy.contains('Protocol File') }) }) diff --git a/protocol-designer/cypress/integration/transferSettings.spec.js b/protocol-designer/cypress/integration/transferSettings.spec.js index 4cbb114a47b..a4c831fddd4 100644 --- a/protocol-designer/cypress/integration/transferSettings.spec.js +++ b/protocol-designer/cypress/integration/transferSettings.spec.js @@ -1,5 +1,3 @@ -import { describe, it, before } from 'vitest' - const isMacOSX = Cypress.platform === 'darwin' const batchEditClickOptions = { [isMacOSX ? 'metaKey' : 'ctrlKey']: true } @@ -134,7 +132,7 @@ describe('Advanced Settings for Transfer Form', () => { cy.get('[data-test="StepItem_2"]').click(batchEditClickOptions) cy.get('input[name="aspirate_flowRate"]').click({ force: true }) - cy.get('div[class*=FlowRateInput__description]').contains( + cy.contains( 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') @@ -153,7 +151,7 @@ describe('Advanced Settings for Transfer Form', () => { it('verify functionality of flowrate in batch edit transfer', () => { // Batch editing the Flowrate value cy.get('input[name="aspirate_flowRate"]').click({ force: true }) - cy.get('div[class*=FlowRateInput__description]').contains( + cy.contains( 'Our default aspirate speed is optimal for a P1000 Single-Channel GEN2 aspirating liquids with a viscosity similar to water' ) cy.get('input[name="aspirate_flowRate_customFlowRate"]').type('100') diff --git a/protocol-designer/cypress/support/commands.js b/protocol-designer/cypress/support/commands.js index 6de9b96aabc..09543c42330 100644 --- a/protocol-designer/cypress/support/commands.js +++ b/protocol-designer/cypress/support/commands.js @@ -34,14 +34,17 @@ Cypress.Commands.add('closeAnnouncementModal', () => { cy.get('[data-test="ComputingSpinner"]', { timeout: 30000 }).should( 'not.exist' ) - cy.get('button').contains('Got It!').should('be.visible').click() + cy.get('button') + .contains('Got It!') + .should('be.visible') + .click({ force: true }) }) // // File Page Actions // Cypress.Commands.add('openFilePage', () => { - cy.get('button[class*="navbar__tab__"]').contains('FILE').click() + cy.get('button[id="NavTab_file"]').contains('FILE').click() }) // @@ -87,7 +90,7 @@ Cypress.Commands.add( // Design Page Actions // Cypress.Commands.add('openDesignPage', () => { - cy.get('button[class*="navbar__tab__"]').contains('DESIGN').parent().click() + cy.get('button[id="NavTab_design"]').contains('DESIGN').parent().click() }) Cypress.Commands.add('addStep', stepName => { cy.get('button').contains('Add Step').click() @@ -98,7 +101,7 @@ Cypress.Commands.add('addStep', stepName => { // Settings Page Actions // Cypress.Commands.add('openSettingsPage', () => { - cy.get('button[class*="navbar__tab__"]').contains('Settings').click() + cy.get('button').contains('Settings').click() }) // Advance Settings for Transfer Steps diff --git a/protocol-designer/index.html b/protocol-designer/index.html index cfcafbedf22..9fbcfaf5875 100644 --- a/protocol-designer/index.html +++ b/protocol-designer/index.html @@ -7,7 +7,7 @@ - Protocol Designer + Opentrons Protocol Designer
diff --git a/protocol-designer/package.json b/protocol-designer/package.json index 7e8969f5885..564ebdb2fe1 100755 --- a/protocol-designer/package.json +++ b/protocol-designer/package.json @@ -8,8 +8,7 @@ "email": "engineering@opentrons.com" }, "name": "protocol-designer", - "type": "module", - "productName": "Opentrons Protocol Designer BETA", + "productName": "Opentrons Protocol Designer", "private": true, "version": "0.0.0-dev", "description": "Protocol designer app", diff --git a/protocol-designer/src/components/DeckSetup/LabwareOverlays/SlotControls.tsx b/protocol-designer/src/components/DeckSetup/LabwareOverlays/SlotControls.tsx index 14a27061cb3..be0b21f77fc 100644 --- a/protocol-designer/src/components/DeckSetup/LabwareOverlays/SlotControls.tsx +++ b/protocol-designer/src/components/DeckSetup/LabwareOverlays/SlotControls.tsx @@ -70,7 +70,10 @@ export const SlotControls = (props: SlotControlsProps): JSX.Element | null => { accept: DND_TYPES.LABWARE, canDrop: (item: DroppedItem) => { const draggedDef = item?.labwareOnDeck?.def - assert(draggedDef, 'no labware def of dragged item, expected it on drop') + console.assert( + draggedDef, + 'no labware def of dragged item, expected it on drop' + ) if (moduleType != null && draggedDef != null) { // this is a module slot, prevent drop if the dragged labware is not compatible diff --git a/protocol-designer/src/index.hbs b/protocol-designer/src/index.hbs deleted file mode 100644 index ab68be76554..00000000000 --- a/protocol-designer/src/index.hbs +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - {{htmlWebpackPlugin.options.title}} - - - - -
- - diff --git a/protocol-designer/src/localization/en/modal.json b/protocol-designer/src/localization/en/modal.json index 03562ba1bb3..edceb80718f 100644 --- a/protocol-designer/src/localization/en/modal.json +++ b/protocol-designer/src/localization/en/modal.json @@ -202,7 +202,7 @@ } }, "gate": { - "sign_up_below": "Sign Up For Opentrons Protocol Designer Beta", + "sign_up_below": "Sign Up For Opentrons Protocol Designer", "failed_verification": "Something Went Wrong", "sign_up_success": "Please confirm your email address to continue", "check_email": "We've sent a confirmation URL to your email that will take you to the Protocol Designer. Keep an eye out for a follow up email which contains links to resources such as our help documents." diff --git a/protocol-designer/vite.config.ts b/protocol-designer/vite.config.ts index 2db2bd80b1a..70d055a6fd8 100644 --- a/protocol-designer/vite.config.ts +++ b/protocol-designer/vite.config.ts @@ -1,11 +1,12 @@ import path from 'path' -import { defineConfig } from 'vite' +import { UserConfig, defineConfig } from 'vite' import react from '@vitejs/plugin-react' import postCssImport from 'postcss-import' import postCssApply from 'postcss-apply' import postColorModFunction from 'postcss-color-mod-function' import postCssPresetEnv from 'postcss-preset-env' import lostCss from 'lost' +import { versionForProject } from '../scripts/git-version' const testAliases: {} | { 'file-saver': string } = process.env.CYPRESS === '1' @@ -15,53 +16,59 @@ const testAliases: {} | { 'file-saver': string } = } : {} -export default defineConfig({ - // this makes imports relative rather than absolute - base: '', - build: { - // Relative to the root - outDir: 'dist', - }, - plugins: [ - react({ - include: '**/*.tsx', - babel: { - // Use babel.config.js files - configFile: true, +export default defineConfig( + async (): Promise => { + const OT_PD_VERSION = await versionForProject('protocol-designer') + const OT_PD_BUILD_DATE = new Date().toUTCString() + return { + // this makes imports relative rather than absolute + base: '', + build: { + // Relative to the root + outDir: 'dist', }, - }), - ], - optimizeDeps: { - esbuildOptions: { - target: 'es2020', - }, - }, - css: { - postcss: { plugins: [ - postCssImport({ root: 'src/' }), - postCssApply(), - postColorModFunction(), - postCssPresetEnv({ stage: 0 }), - lostCss(), + react({ + include: '**/*.tsx', + babel: { + // Use babel.config.js files + configFile: true, + }, + }), ], - }, - }, - define: { - 'process.env': process.env, - global: 'globalThis', - }, - resolve: { - alias: { - '@opentrons/components/styles': path.resolve( - '../components/src/index.module.css' - ), - '@opentrons/components': path.resolve('../components/src/index.ts'), - '@opentrons/shared-data': path.resolve('../shared-data/js/index.ts'), - '@opentrons/step-generation': path.resolve( - '../step-generation/src/index.ts' - ), - ...testAliases, - }, - }, -}) + optimizeDeps: { + esbuildOptions: { + target: 'es2020', + }, + }, + css: { + postcss: { + plugins: [ + postCssImport({ root: 'src/' }), + postCssApply(), + postColorModFunction(), + postCssPresetEnv({ stage: 0 }), + lostCss(), + ], + }, + }, + define: { + 'process.env': { ...process.env, OT_PD_VERSION, OT_PD_BUILD_DATE }, + global: 'globalThis', + }, + resolve: { + alias: { + '@opentrons/components/styles': path.resolve( + '../components/src/index.module.css' + ), + '@opentrons/components': path.resolve('../components/src/index.ts'), + '@opentrons/shared-data': path.resolve('../shared-data/js/index.ts'), + '@opentrons/step-generation': path.resolve( + '../step-generation/src/index.ts' + ), + ...testAliases, + }, + }, + } + } +) diff --git a/protocol-designer/webpack.config.js b/protocol-designer/webpack.config.js deleted file mode 100644 index d987a780b31..00000000000 --- a/protocol-designer/webpack.config.js +++ /dev/null @@ -1,87 +0,0 @@ -'use strict' - -const path = require('path') -const webpack = require('webpack') -const merge = require('webpack-merge') -const HtmlWebpackPlugin = require('html-webpack-plugin') -const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin') -const WorkerPlugin = require('worker-plugin') -const { versionForProject } = require('../scripts/git-version') - -const { DEV_MODE, baseConfig } = require('@opentrons/webpack-config') -const { productName: title, description, author } = require('./package.json') -const PROTOCOL_DESIGNER_ENV_VAR_PREFIX = 'OT_PD_' -const PASS_THROUGH_ENV_VARS = Object.keys(process.env) - .filter(v => v.startsWith(PROTOCOL_DESIGNER_ENV_VAR_PREFIX)) - .concat(['NODE_ENV', 'CYPRESS']) - -const OT_PD_BUILD_DATE = new Date().toUTCString() - -const JS_ENTRY = path.join(__dirname, 'src/index.tsx') -const HTML_ENTRY = path.join(__dirname, 'src/index.hbs') -const ERROR_HTML = path.join(__dirname, 'src/error.html') - -const OUTPUT_PATH = path.join(__dirname, 'dist') -const PUBLIC_PATH = DEV_MODE ? '' : './' - -const testAliases = - process.env.CYPRESS === '1' - ? { - 'file-saver': path.resolve(__dirname, 'cypress/mocks/file-saver.js'), - } - : {} - -module.exports = async () => { - const OT_PD_VERSION = await versionForProject('protocol-designer') - - const envVarsWithDefaults = { - OT_PD_VERSION, - OT_PD_BUILD_DATE, - } - - const envVars = PASS_THROUGH_ENV_VARS.reduce( - (acc, envVar) => ({ [envVar]: '', ...acc }), - { ...envVarsWithDefaults } - ) - console.log(`PD version: ${OT_PD_VERSION || 'UNKNOWN!'}`) - return merge(baseConfig, { - entry: [JS_ENTRY], - - output: Object.assign( - { - path: OUTPUT_PATH, - publicPath: PUBLIC_PATH, - }, - // workaround for worker-plugin HMR - // see https://github.com/GoogleChromeLabs/worker-plugin#globalobject-string--false - DEV_MODE ? { globalObject: 'this' } : {} - ), - - plugins: [ - new webpack.EnvironmentPlugin(envVars), - new WorkerPlugin({ - // disable warnings about HMR when we're in prod - globalObject: DEV_MODE ? 'self' : false, - // add required JS plugins to child compiler - plugins: ['EnvironmentPlugin'], - }), - new HtmlWebpackPlugin({ - title, - description, - author, - template: HTML_ENTRY, - favicon: './src/images/favicon.ico', - }), - new HtmlWebpackPlugin({ - filename: 'error.html', - inject: false, - template: ERROR_HTML, - }), - new ScriptExtHtmlWebpackPlugin({ defaultAttribute: 'defer' }), - ], - - resolve: { - alias: testAliases, - }, - }) -} diff --git a/step-generation/src/commandCreators/atomic/disengageMagnet.ts b/step-generation/src/commandCreators/atomic/disengageMagnet.ts index 567fb6d2c29..4a4b56f9587 100644 --- a/step-generation/src/commandCreators/atomic/disengageMagnet.ts +++ b/step-generation/src/commandCreators/atomic/disengageMagnet.ts @@ -13,7 +13,7 @@ export const disengageMagnet: CommandCreator = ( const { module: moduleId } = args const commandType = 'magneticModule/disengage' - if (module === null) { + if (moduleId === null) { return { errors: [errorCreators.missingModuleError()], } diff --git a/step-generation/src/commandCreators/atomic/engageMagnet.ts b/step-generation/src/commandCreators/atomic/engageMagnet.ts index 6d1a0070d14..da5f8af11b7 100644 --- a/step-generation/src/commandCreators/atomic/engageMagnet.ts +++ b/step-generation/src/commandCreators/atomic/engageMagnet.ts @@ -13,7 +13,7 @@ export const engageMagnet: CommandCreator = ( const { module: moduleId, engageHeight } = args const commandType = 'magneticModule/engage' - if (module === null) { + if (moduleId === null) { return { errors: [errorCreators.missingModuleError()], } diff --git a/step-generation/src/commandCreators/atomic/heaterShakerSetTargetShakeSpeed.ts b/step-generation/src/commandCreators/atomic/heaterShakerSetTargetShakeSpeed.ts index 58c9af666b0..24721a2967d 100644 --- a/step-generation/src/commandCreators/atomic/heaterShakerSetTargetShakeSpeed.ts +++ b/step-generation/src/commandCreators/atomic/heaterShakerSetTargetShakeSpeed.ts @@ -10,7 +10,7 @@ export const heaterShakerSetTargetShakeSpeed: CommandCreator ) => { const { moduleId, rpm } = args - if (module === null) { + if (moduleId === null) { return { errors: [errorCreators.missingModuleError()], }