-
Notifications
You must be signed in to change notification settings - Fork 10
Feat: add app blockly version #573
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Changes from all commits
8334263
bc00e93
40e1541
bee4305
1981b6b
fde1aac
4a0b035
efc52c4
2c147b3
cbc0236
f1492c4
30f4e6f
b27c16f
c39a7a4
e1cd97d
9614d79
ef0af95
6509e01
3f4b165
a61bc68
e5af08d
7e6a865
232da2a
404da10
f0520d4
faabb0d
004f3c1
9dcdb38
fd4576f
5ab43ad
03fa3bb
6547752
ab9cf63
3f9abea
c555adc
1621724
093618e
9f6e632
e58cff3
9c2cd9b
d4950b7
a64b480
ec28f66
f729bd5
7738c43
0c0e571
a868990
729cd90
829a129
b0dd23f
1cca951
92da900
4ab1185
1cce55f
c091c4d
e5e42a4
e6fbfc3
5eeb792
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /// <reference types="cypress" /> | ||
|
|
||
| describe("Embedded Blockly Page Tests", () => { | ||
| it("[Embedded] visits the embedded page", () => { | ||
| cy.visit("/embedded"); | ||
| cy.url().should("include", "/embedded"); | ||
| }); | ||
|
|
||
| it("[Embedded] displays Blockly workspace", () => { | ||
| cy.visit("/embedded"); | ||
| cy.get(".blocklySvg", { timeout: 10000 }).should("exist"); | ||
| }); | ||
|
|
||
| it("[Embedded] displays iPad toolbar", () => { | ||
| cy.visit("/embedded"); | ||
| cy.get(".embedded-toolbar", { timeout: 10000 }).should("exist"); | ||
| // Share, Reset icons exist | ||
| cy.get(".embedded-toolbar svg.fa-share-nodes").should("exist"); | ||
| cy.get(".embedded-toolbar svg.fa-share").should("exist"); | ||
|
|
||
| // Select a board so Compile button becomes available | ||
| cy.get('img[alt="Sensebox ESP"]', { timeout: 10000 }).click(); | ||
| cy.get(".embedded-toolbar svg.fa-clipboard-check").should("exist"); | ||
| }); | ||
|
|
||
| it("[Embedded] displays workspace name component", () => { | ||
| cy.visit("/embedded"); | ||
| cy.get(".embedded-toolbar").find("div").should("exist"); | ||
| }); | ||
|
|
||
| it("[Embedded] displays device selection", () => { | ||
| cy.visit("/embedded"); | ||
| cy.get('img[alt="Sensebox ESP"]', { timeout: 10000 }).should("exist"); | ||
| cy.get('img[alt="Sensebox MCU"]').should("exist"); | ||
| cy.get('img[alt="Sensebox Mini"]').should("exist"); | ||
| }); | ||
|
|
||
| it("[Embedded] compiles code", () => { | ||
| cy.intercept({ method: "POST", pathname: "/compile" }).as("compile"); | ||
| cy.visit("/embedded"); | ||
| cy.get('img[alt="Sensebox ESP"]', { timeout: 8000 }).click(); | ||
| cy.get(".embedded-toolbar svg.fa-clipboard-check").parents("button").click(); | ||
| cy.wait("@compile", { responseTimeout: 30000, requestTimeout: 30000 }) | ||
| .its("response.statusCode").should("eq", 200); | ||
| }); | ||
|
|
||
| it("[Embedded] opens reset dialog", () => { | ||
| cy.visit("/embedded"); | ||
| cy.get('img[alt="Sensebox ESP"]', { timeout: 8000 }).click(); | ||
| cy.get(".embedded-toolbar svg.fa-share").parents("button").click(); | ||
| cy.get('[role="dialog"]', { timeout: 5000 }).should("exist"); | ||
| }); | ||
|
|
||
| it("[Embedded] displays toolbox with search", () => { | ||
| cy.visit("/embedded"); | ||
| cy.get(".blocklyToolbox", { timeout: 10000 }).should("exist"); | ||
| cy.get('input[type="search"]').should("exist"); | ||
| }); | ||
|
|
||
| it("[Embedded] marks toolbox xml as embedded mode", () => { | ||
| cy.visit("/embedded"); | ||
| cy.get('xml#blockly').should("have.class", "embedded-mode"); | ||
| }); | ||
|
|
||
| it("[Embedded] uses tablet mode for compilation with embedded-specific text", () => { | ||
| cy.intercept({ method: "POST", pathname: "/compile" }).as("compile"); | ||
|
|
||
| cy.visit("/embedded"); | ||
| cy.get('img[alt="Sensebox ESP"]', { timeout: 10000 }).click(); | ||
| cy.get(".embedded-toolbar svg.fa-clipboard-check").parents("button").click(); | ||
|
|
||
| cy.wait("@compile", { responseTimeout: 30000, requestTimeout: 30000 }) | ||
| .its("response.statusCode").should("eq", 200); | ||
|
|
||
| cy.get('[role="dialog"]', { timeout: 10000 }).should("exist"); | ||
|
|
||
| // Verify embedded mode specific elements | ||
| cy.get('[role="dialog"]').should("contain.text", "Gehe zum Übertragungs-Tab"); | ||
| cy.get('[role="dialog"]').should("contain.text", "Over-The-Air Übertragung"); | ||
| cy.get('[role="dialog"]').should("contain.text", "Der Code wurde erfolgreich kompiliert"); | ||
| cy.get('[role="dialog"]').should("contain.text", "Klicke den unteren Button um zum Übertragungs-Tab zu gelangen"); | ||
|
|
||
| // Verify stepper configuration | ||
| cy.get('[role="dialog"]').within(() => { | ||
| cy.get('.MuiStep-root').should("have.length", 2); | ||
| cy.get('.MuiStep-root').first().should("contain.text", "Kompilieren"); | ||
| cy.get('.MuiStep-root').last().should("contain.text", "Übertragen"); | ||
| cy.get('.MuiStepLabel-label').should("not.contain.text", "Herunterladen"); | ||
| cy.get('a[href*="blocklyconnect-app://"]').should("exist"); | ||
| }); | ||
| }); | ||
|
|
||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import { | |
| STATISTICS, | ||
| PLATFORM, | ||
| COMPILER, | ||
| EMBEDDED_MODE, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: I don't want to create a separate copy of existing code for embedded use, rather make (minimal) changes to the existing code, if needed. This variable is to track, if user is on /embedded path. |
||
| } from "./types"; | ||
|
|
||
| export const visitPage = () => (dispatch) => { | ||
|
|
@@ -58,3 +59,10 @@ export const setCompiler = (compiler) => (dispatch) => { | |
| payload: compiler, | ||
| }); | ||
| }; | ||
|
|
||
| export const setEmbeddedMode = (isEmbedded) => (dispatch) => { | ||
| dispatch({ | ||
| type: EMBEDDED_MODE, | ||
| payload: isEmbedded, | ||
| }); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| import React, { useEffect, useRef, useState } from "react"; | ||
| import React, { useEffect, useMemo, useRef, useState } from "react"; | ||
| import PropTypes from "prop-types"; | ||
| import { useSelector } from "react-redux"; | ||
|
|
||
| import * as Blockly from "blockly/core"; | ||
| import "./blocks/index"; | ||
| import "@/components/Blockly/generator/index"; | ||
|
|
||
| import Toolbox from "./toolbox/Toolbox"; | ||
| import EmbeddedToolbox from "./toolbox/EmbeddedToolbox"; | ||
| import { reservedWords } from "./helpers/reservedWords"; | ||
| import Snackbar from "../Snackbar"; | ||
|
|
||
|
|
@@ -26,6 +28,7 @@ export function BlocklyComponent({ initialXml, style, ...rest }) { | |
| const blocklyDivRef = useRef(null); | ||
| const toolboxRef = useRef(null); | ||
| const [workspace, setWorkspace] = useState(undefined); | ||
| const isEmbedded = useSelector((state) => state.general.embeddedMode); | ||
|
|
||
| const [snackbar, setSnackbar] = useState({ | ||
| open: false, | ||
|
|
@@ -36,14 +39,24 @@ export function BlocklyComponent({ initialXml, style, ...rest }) { | |
|
|
||
| // Inject Blockly once on mount | ||
| useEffect(() => { | ||
| const ws = Blockly.inject(blocklyDivRef.current, { | ||
| const blocklyOptions = { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i could not find exactly where but I think the renderer for blockly got changed. Im guessing that this was not intentional. thats why the blocks look different. i think putting the renderer "Thrasos" in the blockly options makes the blocks look "normal" again. |
||
| toolbox: toolboxRef.current, | ||
| plugins: { | ||
| blockDragger: ScrollBlockDragger, | ||
| metricsManager: ScrollMetricsManager, | ||
| }, | ||
| ...rest, | ||
| }); | ||
| }; | ||
|
|
||
| // Only apply mobile layout options when in embedded mode | ||
| if (isEmbedded) { | ||
| blocklyOptions.horizontalLayout = true; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: This are settings to move toolbox to the bottom. |
||
| blocklyOptions.toolboxPosition = 'end'; | ||
| // Ensure toolbox icon sprites and other assets load correctly in embedded view | ||
| blocklyOptions.media = '/media/blockly/'; | ||
| } | ||
|
|
||
| const ws = Blockly.inject(blocklyDivRef.current, blocklyOptions); | ||
|
|
||
| setWorkspace(ws); | ||
|
|
||
|
|
@@ -93,12 +106,28 @@ export function BlocklyComponent({ initialXml, style, ...rest }) { | |
| ws?.dispose(); | ||
| }; | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, []); | ||
| }, [isEmbedded]); | ||
|
|
||
| const cardStyle = useMemo(() => { | ||
| return isEmbedded ?{ | ||
| height: "100%", | ||
| width: "100%", | ||
| } : {}; | ||
| }, [isEmbedded]); | ||
|
|
||
| return ( | ||
| <> | ||
| <Card ref={blocklyDivRef} id="blocklyDiv" style={style ? style : {}} /> | ||
| <Toolbox toolbox={toolboxRef} workspace={workspace} /> | ||
| <Card | ||
| ref={blocklyDivRef} | ||
| id="blocklyDiv" | ||
| style={style ? style : cardStyle} | ||
| className={isEmbedded ? "embedded-mode" : ""} | ||
| /> | ||
| {isEmbedded ? ( | ||
| <EmbeddedToolbox toolbox={toolboxRef} workspace={workspace} /> | ||
| ) : ( | ||
| <Toolbox toolbox={toolboxRef} workspace={workspace} /> | ||
| )} | ||
| <Snackbar | ||
| open={snackbar.open} | ||
| message={snackbar.message} | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: This is a route name I thought reflects the best it's purpose. But I am open for suggestions.