diff --git a/web/src/App.tsx b/web/src/App.tsx index b3fe50f0..49288226 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -105,16 +105,19 @@ function Navigation() { items: [ { type: "link", + external: true, text: "Files in /srv/www", href: `/srv`, }, { type: "link", + external: true, text: "LXA IOBus Server", href: `http://${window.location.hostname}:8080/`, }, { type: "link", + external: true, text: "LXA TAC Manual", href: "https://www.linux-automation.com/lxatac-M02/index.html", }, diff --git a/web/src/Setup.tsx b/web/src/Setup.tsx index 0df3d3e6..5a7ba76f 100644 --- a/web/src/Setup.tsx +++ b/web/src/Setup.tsx @@ -18,410 +18,234 @@ import { useState } from "react"; import Box from "@cloudscape-design/components/box"; -import Button from "@cloudscape-design/components/button"; -import Cards from "@cloudscape-design/components/cards"; import Container from "@cloudscape-design/components/container"; +import Icon from "@cloudscape-design/components/icon"; import Header from "@cloudscape-design/components/header"; -import Form from "@cloudscape-design/components/form"; +import Link from "@cloudscape-design/components/link"; import SpaceBetween from "@cloudscape-design/components/space-between"; import Spinner from "@cloudscape-design/components/spinner"; import Wizard from "@cloudscape-design/components/wizard"; -import { SlotStatus } from "./TacComponents"; import { LabgridService, LabgridConfig } from "./SettingsLabgrid"; import { ConfigEditor } from "./ConfigEditor"; -import { useMqttState, useMqttAction } from "./mqtt"; +import { useMqttState } from "./mqtt"; const SSH_AUTH_KEYS_EXAMPLE = "# Paste one (or multiple) of your ssh public keys here.\n" + "# Use 'cat ~/.ssh/id_*.pub' to get a list of your ssh public\n" + "# keys or ssh-keygen if you don't have any yet.\n" + "# They will look something like this:\n" + - "# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBlPtT5dnGcZn0Z6FyD6VGqt3Jx0s+BHhMahxR0KlJ8G tux@igloo\n"; + "#\n" + + "# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBlPtT5dnGcZn0Z6FyD6VGqt3Jx0s+BHhMahxR0KlJ8G tux@igloo"; -enum WizardChoice { - Undecided, - Ssh, - CustomBundle, -} - -enum LeaveAction { - None, - HelpScreen, - Reboot, -} +export default function Setup() { + const [setupModeSettled, setupMode, setSetupMode] = + useMqttState("/v1/tac/setup_mode"); + const [activeStepIndex, setActiveStepIndex] = useState(0); -interface WizardProps { - setWizard: (w: WizardChoice) => void; - setSetupMode: (m: boolean) => void; - setLeaveAction: (m: LeaveAction) => void; -} + if (setupMode === undefined || !setupModeSettled) { + return ( +
+
+
+ +
+
+
+ ); + } -function WizardSelector(props: WizardProps) { - const [selection, setSelection] = useState(); - const [canContinue, setCanContinue] = useState(false); + if (!setupMode) { + window.location.replace("/#/"); + } return ( - - Setup Wizard - - } - > - - - Welcome to your LXA TAC! - - - The following wizard will guide you through the first time setup of - your TAC. Begin the setup process by choosing whether to keep using - the software that is already installed on your TAC or by installing a - pre-configured RAUC bundle you have prepared. - -
props.setWizard(selection[0].kind)} - > - Continue - +
+
+ + LXA TAC Setup Wizard + } > - { - setCanContinue(true); - setSelection(detail.selectedItems); + `Step ${stepNumber}`, + collapsedStepsLabel: (stepNumber, stepsCount: number) => + `Step ${stepNumber} of ${stepsCount}`, + skipToButtonLabel: (step, stepNumber) => `Skip to ${step.title}`, + navigationAriaLabel: "Steps", + cancelButton: "Cancel", + previousButton: "Back", + nextButton: "Next", + submitButton: "Done", + optional: "optional", }} - selectedItems={selection} - cardDefinition={{ - header: (e) => e.name, - sections: [ - { - id: "benefits", - header: "Benefits:", - content: (e) => e.benefits, - }, - { - id: "drawbacks", - header: "Drawbacks:", - content: (e) => e.drawbacks, - }, - ], - }} - cardsPerRow={[{ cards: 2 }]} - items={[ + onSubmit={() => setSetupMode(false)} + onNavigate={({ detail }) => + setActiveStepIndex(detail.requestedStepIndex) + } + activeStepIndex={activeStepIndex} + allowSkipTo + steps={[ { - name: "Setup via SSH keys", - kind: WizardChoice.Ssh, - benefits: ( -
    -
  • Get started immediately
  • -
  • Always get the newest software for your LXA TAC
  • -
  • Easier to set up
  • -
+ title: "Welcome", + description: "Welcome to your TAC and its setup mode", + content: ( + + Hey there, + + thank you for buying this TAC. We hope you'll like it! + + + Before you can get started using your TAC we need to set + up a few things so they match your preferences. Some of + these preferences can only be set via the web interface in + this special setup mode, because they affect the security + and inner workings of your TAC. To configure them once the + setup mode is done you either need ssh access to your TAC + or physical access to re-enable the setup mode via the + buttons on the TAC. + + + Ready to get started? Then maybe have a quick look at the{" "} + + online manual + {" "} + first and then click "Next" to continue the setup. + +
+ + + + Greetings, +
+ the Linux Automation GmbH team +
+
+
), - drawbacks: ( -
    -
  • Can get tedious in larger fleets
  • -
+ }, + { + title: "Add SSH keys", + description: + "Deploy SSH keys onto your LXA TAC so you can log into it", + content: ( + + + + For many actions on the LXA TAC you need access to it + via ssh. Permissions to ssh into the TAC are managed via + a list of ssh public keys, that allow logging in as the + root user. +
+ Paste a list of ssh public keys into the text box below, + to allow them to access the TAC, and click "Save". + Afterwards you should be able to log into your TAC like + this: + + $ ssh root@{window.location.hostname} + + Make sure to check if logging in works before leaving + the setup mode. +
+ +
+
), }, { - name: "Setup via custom RAUC bundle", - kind: WizardChoice.CustomBundle, - benefits: ( -
    -
  • - Quickly integrate new LXA TACs into an existing fleet -
  • -
  • Deploy a custom selection of software
  • -
  • Deploy custom config
  • -
+ title: "Configure Labgrid", + description: "Configure your labgrid Exporter", + isOptional: true, + content: ( + + + + The LXA TAC comes with a mostly pre-configured labgrid + exporter, that exports a lot of resources that are built + into the TAC or can be connected to it via USB. +
+ You may however want to configure the labgrid + coordinator IP address/hostname on the "Environment" tab + or export additional resources in the "User Config" tab. +
+ Once you have made the required changes click "Save" and + test your configuration by clicking "Next". +
+ +
+
), - drawbacks: ( -
    -
  • - Requires up-front work to configure and build bundles -
  • -
  • - You have to manually re-build bundles to get software - updates -
  • -
+ }, + { + title: "Test Labgrid", + description: + "Make sure your labgrid Exporter Service looks healthy", + isOptional: true, + content: ( + + + + In this step you can check if the labgrid exporter + starts as expected and the correct resources are + exported. Use the "Start", "Stop" and "Restart" buttons + to control the labgrid exporter systemd service and + observe the systemd journal output in the text window + above them. +
+ Go back to the exporter configuration step to make + changes and click "Next" once you are satisfied. +
+ +
+
+ ), + }, + { + title: "Complete Setup", + description: "Make sure everything is working alright", + content: ( + + + You are about to complete the setup wizard. + + + You will not be able to re-enter the setup wizard via the + web interface. You can however re-enable the setup wizard + using the buttons and the screen on the device. If you do + not have physical access to the TAC you should make sure + that you can log in now using: + + $ ssh root@{window.location.hostname} + + before pressing "Done". + + ), }, ]} - selectionType="single" - trackBy="name" /> - - -
- ); -} - -function SshWizard(props: WizardProps) { - const [activeStepIndex, setActiveStepIndex] = useState(0); - - return ( - - SSH key based Wizard - - } - > - `Step ${stepNumber}`, - collapsedStepsLabel: (stepNumber, stepsCount: number) => - `Step ${stepNumber} of ${stepsCount}`, - skipToButtonLabel: (step, stepNumber) => `Skip to ${step.title}`, - navigationAriaLabel: "Steps", - cancelButton: "Cancel", - previousButton: "Back", - nextButton: "Next", - submitButton: "Done", - optional: "optional", - }} - onCancel={() => props.setWizard(WizardChoice.Undecided)} - onSubmit={() => { - props.setLeaveAction(LeaveAction.HelpScreen); - props.setSetupMode(false); - }} - onNavigate={({ detail }) => - setActiveStepIndex(detail.requestedStepIndex) - } - activeStepIndex={activeStepIndex} - allowSkipTo - steps={[ - { - title: "Add SSH keys", - description: - "Deploy SSH keys on your LXA TAC so you can log into it", - content: ( - - - - ), - }, - { - title: "Configure Labgrid", - description: "Configure your labgrid Exporter", - isOptional: true, - content: ( - - - - ), - }, - { - title: "Test Labgrid", - description: "Make sure your labgrid Exporter Service looks healty", - isOptional: true, - content: ( - - - - ), - }, - { - title: "Complete Setup", - description: "Make sure everything is working alright", - content: ( - - You are about to complete the setup wizard. - - You will not be able to re-enter the setup wizard to deploy - new SSH keys via the web interface. You can however re-enable - the setup wizard using the buttons and the screen on the - device. If you do not have physical access the TAC you should - make sure that you can log in to the device via the SSH keys - you have deployed before pressing "Done". - - - ), - }, - ]} - /> - - ); -} - -function CustomBundleWizard(props: WizardProps) { - const [activeStepIndex, setActiveStepIndex] = useState(0); - - return ( - - RAUC based Wizard - - } - > - `Step ${stepNumber}`, - collapsedStepsLabel: (stepNumber, stepsCount: number) => - `Step ${stepNumber} of ${stepsCount}`, - skipToButtonLabel: (step, stepNumber) => `Skip to ${step.title}`, - navigationAriaLabel: "Steps", - cancelButton: "Cancel", - previousButton: "Back", - nextButton: "Next", - submitButton: "Reboot", - optional: "optional", - }} - onCancel={() => props.setWizard(WizardChoice.Undecided)} - onSubmit={() => { - props.setLeaveAction(LeaveAction.Reboot); - props.setSetupMode(false); - }} - onNavigate={({ detail }) => - setActiveStepIndex(detail.requestedStepIndex) - } - activeStepIndex={activeStepIndex} - allowSkipTo - steps={[ - { - title: "Add Signing Key", - description: - "Add a public key that matches the key your bundles are signed with", - content: ( - - Sorry, this is not yet implemented - - ), - }, - { - title: "Check Slot Status", - description: "Make sure everything look correct", - isOptional: true, - content: , - }, - { - title: "Complete Setup", - description: "Make sure everything look correct", - content: ( - - You are about to complete the setup wizard. - Lorem Ipsum Dolor Sit Amet - - ), - }, - ]} - /> - - ); -} - -function SetupComplete() { - return ( - - Setup Complete - - } - > -
- Start Exploring! - - } - > - - - It looks like your LXA TAC is fully set up and you are ready to - explore its features 🎉! - - - You can always go back to the setup mode by going to the system - screen on the on-device LCD and selecting the setup mode. - - -
-
- ); -} - -export default function Setup() { - const [setupModeSettled, setupMode, setSetupMode] = - useMqttState("/v1/tac/setup_mode"); - const setReboot = useMqttAction("/v1/tac/reboot"); - const setScreen = useMqttAction("/v1/tac/display/screen"); - const [wizard, setWizard] = useState(WizardChoice.Undecided); - const [leaveAction, setLeaveAction] = useState(LeaveAction.None); - - let content = undefined; - - if (setupMode === undefined || !setupModeSettled) { - content = ( -
- +
- ); - } else if (setupMode) { - switch (wizard) { - case WizardChoice.Ssh: { - content = ( - - ); - break; - } - case WizardChoice.CustomBundle: { - content = ( - - ); - break; - } - default: { - content = ( - - ); - break; - } - } - } else { - if (leaveAction === LeaveAction.Reboot) { - setReboot(true); - setLeaveAction(LeaveAction.None); - } - - if (leaveAction === LeaveAction.HelpScreen) { - setScreen("Help"); - setLeaveAction(LeaveAction.None); - } - - content = ; - } - - return ( -
-
{content}
); } diff --git a/web/src/TacComponents.tsx b/web/src/TacComponents.tsx index e9418e84..111fca16 100644 --- a/web/src/TacComponents.tsx +++ b/web/src/TacComponents.tsx @@ -265,6 +265,7 @@ export function UpdateChannels() { { id: "description", header: "Description", + maxWidth: "50em", cell: (e) => ( {e.description.split("\n").map((p) => (