diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71377d24..cd73ce31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,9 @@ name: CI -on: push +on: + push: + branches: + - master permissions: contents: write @@ -21,42 +24,3 @@ jobs: - name: Build Package run: pnpm build - - - name: Package Output - run: pnpm package - - - name: Upload Artifact - uses: "marvinpinto/action-automatic-releases@latest" - with: - repo_token: "${{ secrets.GITHUB_TOKEN }}" - automatic_release_tag: "latest" - prerelease: false - files: | - ./dist/build.tar - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Buildah Build - id: build-container - uses: redhat-actions/buildah-build@v2 - with: - containerfiles: | - ./Containerfile - image: ${{github.event.repository.full_name}} - tags: latest ${{ github.sha }} - oci: true - platforms: linux/amd64, linux/arm64 - - - name: Push To Registry - id: push-to-registry - uses: redhat-actions/push-to-registry@v2 - with: - image: ${{ steps.build-container.outputs.image }} - tags: ${{ steps.build-container.outputs.tags }} - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Print image url - run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}" diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 9828a7ff..870ca6fe 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -19,3 +19,12 @@ jobs: - name: Build Package run: pnpm build + + - name: Compress build + run: pnpm package + + - name: Archive compressed build + uses: actions/upload-artifact@v4 + with: + name: build + path: dist/build.tar diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..2ac7ae19 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,55 @@ +name: 'Release' + +on: + release: + types: [released] + +permissions: + contents: write + packages: write + +jobs: + build-and-package: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Install Dependencies + run: pnpm install + + - name: Build Package + run: pnpm build + + - name: Package Output + run: pnpm package + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Buildah Build + id: build-container + uses: redhat-actions/buildah-build@v2 + with: + containerfiles: | + ./Containerfile + image: ${{github.event.repository.full_name}} + tags: latest ${{ github.sha }} + oci: true + platforms: linux/amd64, linux/arm64 + + - name: Push To Registry + id: push-to-registry + uses: redhat-actions/push-to-registry@v2 + with: + image: ${{ steps.build-container.outputs.image }} + tags: ${{ steps.build-container.outputs.tags }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Print image url + run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}" diff --git a/src/App.tsx b/src/App.tsx index 1a014eb5..48a806f4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { DeviceSelector } from "@components/DeviceSelector.js"; import { DialogManager } from "@components/Dialog/DialogManager.js"; import { NewDeviceDialog } from "@components/Dialog/NewDeviceDialog.js"; import { Toaster } from "@components/Toaster.js"; +import Footer from "@components/UI/Footer.js"; import { ThemeController } from "@components/generic/ThemeController.js"; import { useAppStore } from "@core/stores/appStore.js"; import { useDeviceStore } from "@core/stores/deviceStore.js"; @@ -40,7 +41,11 @@ export const App = (): JSX.Element => { ) : ( - + <> + +
+
+ )}
diff --git a/src/components/PageComponents/Messages/ChannelChat.tsx b/src/components/PageComponents/Messages/ChannelChat.tsx index 81ed007f..7507de97 100644 --- a/src/components/PageComponents/Messages/ChannelChat.tsx +++ b/src/components/PageComponents/Messages/ChannelChat.tsx @@ -68,7 +68,7 @@ export const ChannelChat = ({ )} -
+
diff --git a/src/components/PageComponents/ModuleConfig/Telemetry.tsx b/src/components/PageComponents/ModuleConfig/Telemetry.tsx index 6fb5ed4d..5af2f2b5 100644 --- a/src/components/PageComponents/ModuleConfig/Telemetry.tsx +++ b/src/components/PageComponents/ModuleConfig/Telemetry.tsx @@ -87,7 +87,7 @@ export const Telemetry = (): JSX.Element => { description: "How often to send Power data over the mesh", }, { - type: "text", + type: "toggle", name: "powerScreenEnabled", label: "Power Screen Enabled", description: "Enable the Power Telemetry Screen", diff --git a/src/components/PageLayout.tsx b/src/components/PageLayout.tsx index 274eef05..1a2e4dd7 100644 --- a/src/components/PageLayout.tsx +++ b/src/components/PageLayout.tsx @@ -1,5 +1,6 @@ import { cn } from "@app/core/utils/cn.js"; import { AlignLeftIcon, type LucideIcon } from "lucide-react"; +import Footer from "./UI/Footer"; export interface PageLayoutProps { label: string; @@ -18,40 +19,43 @@ export const PageLayout = ({ children, }: PageLayoutProps): JSX.Element => { return ( -
-
- -
-
- {label} -
- {actions?.map((action, index) => ( - - ))} + <> +
+
+ +
+
+ {label} +
+ {actions?.map((action, index) => ( + + ))} +
+
+ {children} +
+
-
- {children} -
-
+ ); }; diff --git a/src/components/UI/Footer.tsx b/src/components/UI/Footer.tsx new file mode 100644 index 00000000..d0e082e7 --- /dev/null +++ b/src/components/UI/Footer.tsx @@ -0,0 +1,37 @@ +import React from "react"; + +export interface FooterProps extends React.HTMLAttributes {} + +const Footer = React.forwardRef( + ({ className, ...props }, ref) => { + return ( + + ); + }, +); + +export default Footer; diff --git a/src/components/UI/Tabs.tsx b/src/components/UI/Tabs.tsx index 2d9b3e69..f8c83e6d 100644 --- a/src/components/UI/Tabs.tsx +++ b/src/components/UI/Tabs.tsx @@ -12,7 +12,7 @@ const TabsList = React.forwardRef< { const devices = useMemo(() => getDevices(), [getDevices]); return ( -
-
-
-

Connected Devices

- Manage, connect and disconnect devices + <> +
+
+
+

Connected Devices

+ Manage, connect and disconnect devices +
-
- + -
- {devices.length ? ( -
    - {devices.map((device) => { - return ( -
  • -
    -
    -

    - {device.nodes.get(device.hardware.myNodeNum)?.user - ?.longName ?? "UNK"} -

    -
    - {device.connection?.connType === "ble" && ( - <> - - BLE - - )} - {device.connection?.connType === "serial" && ( - <> - - Serial - - )} - {device.connection?.connType === "http" && ( - <> - - Network - - )} +
    + {devices.length ? ( +
      + {devices.map((device) => { + return ( +
    • +
      +
      +

      + {device.nodes.get(device.hardware.myNodeNum)?.user + ?.longName ?? "UNK"} +

      +
      + {device.connection?.connType === "ble" && ( + <> + + BLE + + )} + {device.connection?.connType === "serial" && ( + <> + + Serial + + )} + {device.connection?.connType === "http" && ( + <> + + Network + + )} +
      -
      -
      -
      -
      -
      -
    • - ); - })} -
    - ) : ( -
    - -

    No Devices

    - Connect atleast one device to get started - -
    - )} +
  • + ); + })} +
+ ) : ( +
+ +

No Devices

+ Connect atleast one device to get started + +
+ )} +
-
+ ); }; diff --git a/src/pages/Messages.tsx b/src/pages/Messages.tsx index 4afe1e62..c25f24a7 100644 --- a/src/pages/Messages.tsx +++ b/src/pages/Messages.tsx @@ -67,60 +67,62 @@ export const MessagesPage = (): JSX.Element => { ))} - +
+ + toast({ + title: "Traceroute sent.", + }), + ); + }, }, - }, - ] - : [] - } - > - {allChannels.map( - (channel) => - activeChat === channel.index && ( - - ), - )} - {filteredNodes.map( - (node) => - activeChat === node.num && ( - - ), - )} - + ] + : [] + } + > + {allChannels.map( + (channel) => + activeChat === channel.index && ( + + ), + )} + {filteredNodes.map( + (node) => + activeChat === node.num && ( + + ), + )} + +
); }; diff --git a/src/pages/Nodes.tsx b/src/pages/Nodes.tsx index 73ba6e46..c7682f59 100644 --- a/src/pages/Nodes.tsx +++ b/src/pages/Nodes.tsx @@ -1,3 +1,4 @@ +import Footer from "@app/components/UI/Footer"; import { useAppStore } from "@app/core/stores/appStore"; import { Sidebar } from "@components/Sidebar.js"; import { Button } from "@components/UI/Button.js"; @@ -27,73 +28,76 @@ export const NodesPage = (): JSX.Element => { return ( <> -
- [ - , -

- {node.user?.longName ?? - (node.user?.macaddr - ? `Meshtastic ${base16 - .stringify(node.user?.macaddr.subarray(4, 6) ?? []) - .toLowerCase()}` - : `UNK: ${node.num}`)} -

, +
+
+
[ + , +

+ {node.user?.longName ?? + (node.user?.macaddr + ? `Meshtastic ${base16 + .stringify(node.user?.macaddr.subarray(4, 6) ?? []) + .toLowerCase()}` + : `UNK: ${node.num}`)} +

, - - {Protobuf.Mesh.HardwareModel[node.user?.hwModel ?? 0]} - , - - {base16 - .stringify(node.user?.macaddr ?? []) - .match(/.{1,2}/g) - ?.join(":") ?? "UNK"} - , - - {node.lastHeard === 0 ? ( -

Never

- ) : ( - - )} -
, - - {node.snr}db/ - {Math.min(Math.max((node.snr + 10) * 5, 0), 100)}%/ - {(node.snr + 10) * 5}raw - , - - {node.lastHeard !== 0 - ? node.viaMqtt === false && node.hopsAway === 0 - ? "Direct" - : `${node.hopsAway.toString()} ${ - node.hopsAway > 1 ? "hops" : "hop" - } away` - : "-"} - {node.viaMqtt === true ? ", via MQTT" : ""} - , - , - ])} - /> + + {Protobuf.Mesh.HardwareModel[node.user?.hwModel ?? 0]} + , + + {base16 + .stringify(node.user?.macaddr ?? []) + .match(/.{1,2}/g) + ?.join(":") ?? "UNK"} + , + + {node.lastHeard === 0 ? ( +

Never

+ ) : ( + + )} +
, + + {node.snr}db/ + {Math.min(Math.max((node.snr + 10) * 5, 0), 100)}%/ + {(node.snr + 10) * 5}raw + , + + {node.lastHeard !== 0 + ? node.viaMqtt === false && node.hopsAway === 0 + ? "Direct" + : `${node.hopsAway.toString()} ${ + node.hopsAway > 1 ? "hops" : "hop" + } away` + : "-"} + {node.viaMqtt === true ? ", via MQTT" : ""} + , + , + ])} + /> + +
);