diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 427bc9ad..90c6cafb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,13 +1,9 @@ name: Build -on: - push: - tags: - - "v*" - workflow_dispatch: +on: [push] jobs: - CI: + build: name: 🔨🚀 Build and deploy runs-on: ubuntu-latest steps: @@ -25,10 +21,10 @@ jobs: uses: pnpm/action-setup@v4 with: version: 8 - - name: 🐉 Use Node.js 18.16.x + - name: 🐉 Use Node.js 22.4.x uses: actions/setup-node@v3 with: - node-version: 18.16.x + node-version: 22.4.x cache: "pnpm" - name: ⏬ Install Node dependencies run: pnpm install @@ -38,17 +34,17 @@ jobs: - name: 🔨 Build site run: pnpm build - - name: 📦 Upload build artifacts - uses: actions/upload-artifact@v3.1.2 - with: - name: build - path: build - - name: Disable jekyll - run: touch build/.nojekyll - - name: Custom domain - run: echo 'manager.charachorder.com' > build/CNAME - - run: git config user.name github-actions - - run: git config user.email github-actions@github.com - - run: git --work-tree build add --all - - run: git commit -m "Automatic Deploy action run by github-actions" - - run: git push origin HEAD:gh-pages --force + - name: Setup SSH + run: | + install -m 600 -D /dev/null ~/.ssh/id_rsa + echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_rsa + echo "${{ secrets.DEPLOY_KNOWN_HOSTS }}" > ~/.ssh/known_hosts + + - name: Publish Stable + if: ${{ github.ref == 'refs/heads/v*' }} + run: rsync -rav --mkpath --delete build/ deploy@charachorder.io:/home/deploy/www/ + + - name: Publish Branch + run: rsync -rav --mkpath --delete build/ deploy@charachorder.io:/home/deploy/ref/${GITHUB_REF##*/} + - name: Publish Commit + run: rsync -rav --mkpath --delete build/ deploy@charachorder.io:/home/deploy/ref/${{ github.sha }} diff --git a/icons.config.js b/icons.config.js index af1a3e2f..b4d2411c 100644 --- a/icons.config.js +++ b/icons.config.js @@ -18,6 +18,8 @@ const config = { "update", "offline_pin", "warning", + "dangerous", + "check", "cable", "person", "sync", diff --git a/src/env.d.ts b/src/env.d.ts index 6c3602f6..94d5f056 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -15,6 +15,7 @@ interface ImportMetaEnv { readonly VITE_LATEST_FIRMWARE: string; readonly VITE_STORE_URL: string; readonly VITE_MATRIX_URL: string; + readonly VITE_FIRMWARE_URL: string; } interface ImportMeta { diff --git a/src/routes/(app)/ota-update/+layout.svelte b/src/routes/(app)/ota-update/+layout.svelte new file mode 100644 index 00000000..edc4d10f --- /dev/null +++ b/src/routes/(app)/ota-update/+layout.svelte @@ -0,0 +1,16 @@ + + +

Firmware Update

+ +{@render children()} + + diff --git a/src/routes/(app)/ota-update/+layout.ts b/src/routes/(app)/ota-update/+layout.ts new file mode 100644 index 00000000..ae88a275 --- /dev/null +++ b/src/routes/(app)/ota-update/+layout.ts @@ -0,0 +1,2 @@ +export const prerender = false; +export const ssr = false; diff --git a/src/routes/(app)/ota-update/+page.svelte b/src/routes/(app)/ota-update/+page.svelte index 29f70707..92c7ee36 100644 --- a/src/routes/(app)/ota-update/+page.svelte +++ b/src/routes/(app)/ota-update/+page.svelte @@ -1,15 +1,91 @@ + + +{#if !currentDevice} + +{/if} + + + diff --git a/src/routes/(app)/ota-update/+page.ts b/src/routes/(app)/ota-update/+page.ts new file mode 100644 index 00000000..66aa787c --- /dev/null +++ b/src/routes/(app)/ota-update/+page.ts @@ -0,0 +1,9 @@ +import type { PageLoad } from "./$types"; +import type { DirectoryListing } from "./listing"; + +export const load = (async ({ fetch }) => { + const result = await fetch(import.meta.env.VITE_FIRMWARE_URL); + const data = await result.json(); + + return { devices: data as DirectoryListing[] }; +}) satisfies PageLoad; diff --git a/src/routes/(app)/ota-update/[device]/+page.svelte b/src/routes/(app)/ota-update/[device]/+page.svelte new file mode 100644 index 00000000..25291894 --- /dev/null +++ b/src/routes/(app)/ota-update/[device]/+page.svelte @@ -0,0 +1,85 @@ + + +
+

Versions available for {data.device}

+ +
+ +{#if data.versions} + +{:else} +

The device {data.device} does not exist.

+{/if} + + diff --git a/src/routes/(app)/ota-update/[device]/+page.ts b/src/routes/(app)/ota-update/[device]/+page.ts new file mode 100644 index 00000000..0c1c1575 --- /dev/null +++ b/src/routes/(app)/ota-update/[device]/+page.ts @@ -0,0 +1,16 @@ +import type { PageLoad } from "./$types"; +import type { DirectoryListing } from "../listing"; + +export const load = (async ({ fetch, params }) => { + const result = await fetch( + `${import.meta.env.VITE_FIRMWARE_URL}/${params.device}/`, + ); + const data = await result.json(); + + return { + versions: (data as DirectoryListing[]).sort((a, b) => + b.name.localeCompare(a.name), + ), + device: params.device, + }; +}) satisfies PageLoad; diff --git a/src/routes/(app)/ota-update/[device]/[version]/+page.svelte b/src/routes/(app)/ota-update/[device]/[version]/+page.svelte new file mode 100644 index 00000000..dde33acd --- /dev/null +++ b/src/routes/(app)/ota-update/[device]/[version]/+page.svelte @@ -0,0 +1,163 @@ + + +
+

+ Update {data.device} + to {data.version} +

+ + + + {#if isCorrectDevice === false} +
+ These files are incompatible with your device +
+ {/if} + +
+

OTA Upate

+ {#if data.ota} +

OTA update

+ {:else} + There are no OTA files for this device. + {/if} +
+ +
+ +

Other options

+ +
+

Via UF2

+
    +
  1. Backup your device
  2. +
  3. Reboot to bootloader
  4. +
  5. Save CURRENT.UF2 to the new drive
  6. +
  7. Restore
  8. +
+
+
+

Via Serial

+

WIP

+
+
+ + diff --git a/src/routes/(app)/ota-update/[device]/[version]/+page.ts b/src/routes/(app)/ota-update/[device]/[version]/+page.ts new file mode 100644 index 00000000..7c5075de --- /dev/null +++ b/src/routes/(app)/ota-update/[device]/[version]/+page.ts @@ -0,0 +1,20 @@ +import type { PageLoad } from "./$types"; +import type { FileListing, Listing } from "../../listing"; + +export const load = (async ({ fetch, params }) => { + const result = await fetch( + `${import.meta.env.VITE_FIRMWARE_URL}/${params.device}/${params.version}/`, + ); + const data: Listing[] = await result.json(); + + return { + uf2: data.find( + (entry) => entry.type === "file" && entry.name === "CURRENT.UF2", + ) as FileListing, + ota: data.find( + (entry) => entry.type === "file" && entry.name === "firmware.bin", + ), + version: params.version, + device: params.device, + }; +}) satisfies PageLoad; diff --git a/src/routes/(app)/ota-update/listing.ts b/src/routes/(app)/ota-update/listing.ts new file mode 100644 index 00000000..17a61bf8 --- /dev/null +++ b/src/routes/(app)/ota-update/listing.ts @@ -0,0 +1,14 @@ +export type Listing = FileListing | DirectoryListing; + +export interface DirectoryListing { + name: string; + type: "directory"; + mtime: string; +} + +export interface FileListing { + name: string; + type: "file"; + mtime: string; + size: number; +} diff --git a/vite.config.ts b/vite.config.ts index 536bdc47..97072a81 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -23,6 +23,7 @@ process.env["VITE_LEARN_URL"] = "https://www.iq-eq.io/"; process.env["VITE_LATEST_FIRMWARE"] = "1.1.4"; process.env["VITE_STORE_URL"] = "https://www.charachorder.com/"; process.env["VITE_MATRIX_URL"] = "https://charachorder.io/"; +process.env["VITE_FIRMWARE_URL"] = "https://charachorder.io/firmware/"; export default defineConfig({ build: { @@ -54,10 +55,11 @@ export default defineConfig({ workbox: { // https://vite-pwa-org.netlify.app/frameworks/sveltekit.html#globpatterns globPatterns: [ - "client/**/*.{js,map,css,ico,woff2,csv,png,webp,svg,webmanifest}", + "client/**/*.{js,css,ico,woff2,csv,png,webp,svg,webmanifest}", "prerendered/**/*.html", ], ignoreURLParametersMatching: [/^import|redirectUrl|loginToken$/], + maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, }, manifest: { name: "CharaChorder Device Manager",