diff --git a/src/components/choice/Choice.tsx b/src/components/choice/Choice.tsx index e1cc591..0f9b3fa 100644 --- a/src/components/choice/Choice.tsx +++ b/src/components/choice/Choice.tsx @@ -11,8 +11,8 @@ type ChoiceProps = { const Choice = ({ choice, onSelect }: ChoiceProps) => { return ( <> -

{choice["choice-name"]}

-
+

{choice["choice-name"]}

+
{choice.choices.map((subChoice) => ( + )} + {currentFile && ( + <> +

+ + {currentFile.name} +

+ + )} + + + + + + + )} + {(state === InstallerState.DOWNLOADING || + state === InstallerState.CHECKING_SIGNATURES) && ( + +

Downloading

+

+ Downloading package... +

+ + {log} + +
+ )} + + {state === InstallerState.ENTER_FLASH_MODE && ( + + + + {log} + + + )} + + {state === InstallerState.FLASHING && ( + + + + {log} + + + )} + {state === InstallerState.RESTARTING && ( + +

Restarting

+

+ Waiting for controller restart... +

+ + {log} + +
+ )} + {state === InstallerState.UPLOADING_FILES && ( + +

Uploading files

+

+ Uploading files... +

+ + {log} + +
+ )} + {state === InstallerState.DONE && ( + <> + +

Done

+

+ The controller has been successfully installed and + is ready to be used. +

+ + {log} + +
+ + + + + )} + {state === InstallerState.ERROR && ( + <> + +

Error!

+
+ {" "} + {errorMessage} +
+ + {log} + +
+ + + + + )} + + ); +}; + +export default UploadCustomImageModal; diff --git a/src/panels/firmware/Firmware.scss b/src/panels/firmware/Firmware.scss index 55aca06..fdd7f87 100644 --- a/src/panels/firmware/Firmware.scss +++ b/src/panels/firmware/Firmware.scss @@ -1,11 +1,9 @@ .firmware-component { - .button { - margin-right: 20px; - } + .card { - margin-bottom: 30px; - margin-top: 30px; + margin-bottom: 25px; + margin-top: 25px; background-color: #eee !important; } diff --git a/src/panels/firmware/Firmware.tsx b/src/panels/firmware/Firmware.tsx index 7c34aab..316fc80 100644 --- a/src/panels/firmware/Firmware.tsx +++ b/src/panels/firmware/Firmware.tsx @@ -12,8 +12,19 @@ import Choice from "../../components/choice"; import { Markdown } from "../../components/markdown/Markdown"; import PageTitle from "../../components/pagetitle/PageTitle"; import FirmwareBreadCrumbList from "./FirmwareBreadcrumbList"; -import { Col, FormCheck } from "react-bootstrap"; +import { + Col, + FormCheck, + Row, + Form, + DropdownButton, + Dropdown +} from "react-bootstrap"; import { useLocalStorage } from "../../hooks/useLocalStorage"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { IconDefinition } from "@fortawesome/fontawesome-svg-core"; +import { faFileArrowUp, faSliders } from "@fortawesome/free-solid-svg-icons"; +import UploadCustomImageModal from "../../components/installermodal/UploadCustomImageModal"; type Props = { onInstall: ( @@ -28,6 +39,7 @@ const Firmware = ({ onInstall }: Props) => { [] ); const [releases, setReleases] = useState([]); + const [uploadCustomImage, setUploadCustomImage] = useState(false); const [selectedRelease, setSelectedRelease] = useState(); const [errorMessage, setErrorMessage] = useState(); const [releaseManifest, setReleaseManifest] = useState< @@ -97,6 +109,13 @@ const Firmware = ({ onInstall }: Props) => { {errorMessage && (
{errorMessage}
)} + + {uploadCustomImage && ( + setUploadCustomImage(false)} + /> + )} + {!errorMessage && ( <> Install @@ -105,23 +124,59 @@ const Firmware = ({ onInstall }: Props) => { controller.

- - setShowPrerelease((value) => !value)} - /> + + + + chooseFirmware(event.target.value) + } + > + {!releases?.length && ( + + )} + {releases.map((release) => ( + + ))} + + + + + } + > + + {" "} + + setShowPrerelease( + (!showPrerelease).toString() + ) + } + /> + + + setUploadCustomImage(true)} + > + + Upload custom image... + + + + )} @@ -132,19 +187,28 @@ const Firmware = ({ onInstall }: Props) => { )} {!isLoading && selectedRelease && ( <> - {choice && releaseManifest && !choice.images && ( - <> - - - - - - )} + + + {choice && releaseManifest && !choice.images && ( + + + + + )} + - {selectedRelease.body} + + + {selectedRelease.body} + + + )}
diff --git a/src/services/GitHubService.ts b/src/services/GitHubService.ts index 03486c0..c5939b5 100644 --- a/src/services/GitHubService.ts +++ b/src/services/GitHubService.ts @@ -3,7 +3,7 @@ export type GithubReleaseAsset = { name: string; }; -const RESOURCES_BASE_URL = +export const RESOURCES_BASE_URL = "https://raw.githubusercontent.com/bdring/fluidnc-releases/main/releases"; export const CONFIG_BASE_URL = diff --git a/src/services/InstallService.ts b/src/services/InstallService.ts index e716761..a758ccb 100644 --- a/src/services/InstallService.ts +++ b/src/services/InstallService.ts @@ -56,6 +56,52 @@ const convertImagesToFlashFiles = ( }; export const InstallService = { + installImage: async ( + serialPort: SerialPort, + fileData: Uint8Array, + onProgress: (FlashProgress) => void, + onState: (state: InstallerState) => void, + onLogData: (data: string) => void, + baud: number = 921600 + ): Promise => { + try { + const flashFiles: FlashFile[] = [ + { + fileName: "firmware.bin", + data: fileData, + address: 0x10000 + } + ]; + + await flashDevice( + serialPort.getNativeSerialPort(), + flashFiles, + false, + baud, + onProgress, + onState, + onLogData + ); + + logEvent(analytics, "install", { + version: "custom-image", + success: true + }); + } catch (error) { + logEvent(analytics, "install", { + version: "custom-image", + success: false, + error: error + }); + + console.error(error); + onState(InstallerState.ERROR); + throw "Was not able to flash device: " + error; + } + + return Promise.resolve(); + }, + installChoice: async ( release: GithubRelease, serialPort: SerialPort,