diff --git a/.github/workflows/publish-release.yaml b/.github/workflows/publish-release.yaml index b6c9bc2..eb1ad57 100644 --- a/.github/workflows/publish-release.yaml +++ b/.github/workflows/publish-release.yaml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Variable Gathering id: gathervars @@ -33,13 +33,13 @@ jobs: echo "NOT_PREVIOUSLY_PUBLISHED=$NOT_PREVIOUSLY_PUBLISHED" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }} with: registry: ghcr.io @@ -47,7 +47,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker Image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }} with: build-args: | @@ -60,7 +60,7 @@ jobs: push: true - name: Extract build out of docker image - uses: shrink/actions-docker-extract@v2 + uses: shrink/actions-docker-extract@v3 if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }} id: extract with: @@ -73,33 +73,14 @@ jobs: cd "${{ steps.extract.outputs.destination }}" 7z a headscale-ui.zip web - - name: Create Draft Release - id: create_release - uses: actions/create-release@v1 + - name: Create Release + uses: softprops/action-gh-release@v2 if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ env.VERSION }} - release_name: headscale-ui - draft: true - prerelease: false - - - name: upload asset to releases - uses: actions/upload-release-asset@v1.0.1 - if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ${{ steps.extract.outputs.destination }}/headscale-ui.zip - asset_name: headscale-ui.zip - asset_content_type: application/zip - - - name: publish release - uses: eregon/publish-release@v1 - if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - release_id: ${{ steps.create_release.outputs.id }} + name: headscale-ui + files: ${{ steps.extract.outputs.destination }}/headscale-ui.zip + generate_release_notes: true + make_latest: true \ No newline at end of file diff --git a/README.md b/README.md index 23c68e6..0d7e483 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ See [Other Configurations](/documentation/configuration.md) for further proxy ex The following versions correspond to the appropriate headscale version | Headscale Version | HS-UI Version | |-------------------|---------------| +| 26+ | 2025-05-22+ | | 25+ | 2025-03-14+ | | 24+ | 2025-01-20+ | | 23+ | 2024-10-01+ | diff --git a/docker/development/scripts/install-openvscode-server.sh b/docker/development/scripts/install-openvscode-server.sh index bae7aab..204cc4a 100644 --- a/docker/development/scripts/install-openvscode-server.sh +++ b/docker/development/scripts/install-openvscode-server.sh @@ -1,5 +1,5 @@ # script variables -OPENVSCODE_VERSION="1.98.0" +OPENVSCODE_VERSION="1.103.1" OPENVSCODE_URL="https://github.com/gitpod-io/openvscode-server/releases/download/openvscode-server-v$OPENVSCODE_VERSION/openvscode-server-v$OPENVSCODE_VERSION-linux-x64.tar.gz" OPENVSCODE_RELEASE="openvscode-server-v$OPENVSCODE_VERSION-linux-x64" diff --git a/package-lock.json b/package-lock.json index 5b830fa..8b14a9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "headscale-ui", - "version": "2025.03.14", + "version": "2025.07.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "headscale-ui", - "version": "2025.03.14", + "version": "2025.07.12", "devDependencies": { "@sveltejs/adapter-auto": "^4", "@sveltejs/adapter-static": "^3", diff --git a/package.json b/package.json index 0d8e9ae..600addf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "headscale-ui", - "version": "2025.03.21", + "version": "2025.08.23", "scripts": { "dev": "vite dev --port 8080 --host 0.0.0.0", "build": "vite build", @@ -33,4 +33,4 @@ "typescript": "^5" }, "type": "module" -} \ No newline at end of file +} diff --git a/src/lib/common/apiFunctions.svelte b/src/lib/common/apiFunctions.svelte index bbaa328..960b367 100644 --- a/src/lib/common/apiFunctions.svelte +++ b/src/lib/common/apiFunctions.svelte @@ -329,7 +329,7 @@ return apiKeys; } - export async function getPreauthKeys(userName: string): Promise { + export async function getPreauthKeys(userID: string): Promise { // variables in local storage let headscaleURL = localStorage.getItem('headscaleURL') || ''; let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || ''; @@ -341,7 +341,7 @@ let headscalePreAuthKey = [new PreAuthKey()]; let headscalePreAuthKeyResponse: Response = new Response(); - await fetch(headscaleURL + endpointURL + '?user=' + userName, { + await fetch(headscaleURL + endpointURL + '?user=' + userID, { method: 'GET', headers: { Accept: 'application/json', @@ -367,7 +367,7 @@ return headscalePreAuthKey; } - export async function newPreAuthKey(userName: string, expiry: string, reusable: boolean, ephemeral: boolean): Promise { + export async function newPreAuthKey(userID: string, expiry: string, reusable: boolean, ephemeral: boolean): Promise { // variables in local storage let headscaleURL = localStorage.getItem('headscaleURL') || ''; let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || ''; @@ -381,7 +381,7 @@ Authorization: `Bearer ${headscaleAPIKey}` }, body: JSON.stringify({ - user: userName, + user: userID, expiration: expiry, reusable: reusable, ephemeral: ephemeral @@ -401,7 +401,7 @@ }); } - export async function removePreAuthKey(userName: string, preAuthKey: string): Promise { + export async function removePreAuthKey(userID: string, preAuthKey: string): Promise { // variables in local storage let headscaleURL = localStorage.getItem('headscaleURL') || ''; let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || ''; @@ -416,7 +416,7 @@ Authorization: `Bearer ${headscaleAPIKey}` }, body: JSON.stringify({ - user: userName, + user: userID, key: preAuthKey }) }) @@ -464,7 +464,7 @@ }); } - export async function moveDevice(deviceID: string, user: string): Promise { + export async function moveDevice(deviceID: string, userID: string): Promise { // variables in local storage let headscaleURL = localStorage.getItem('headscaleURL') || ''; @@ -480,7 +480,7 @@ Authorization: `Bearer ${headscaleAPIKey}` }, body: JSON.stringify({ - user: user + user: parseInt(userID) }) }) .then((response) => { diff --git a/src/lib/common/classes.ts b/src/lib/common/classes.ts index e6b5dd0..d66c622 100644 --- a/src/lib/common/classes.ts +++ b/src/lib/common/classes.ts @@ -7,7 +7,10 @@ export class Device { public forcedTags: string[] = []; public validTags: string[] = []; public invalidTags: string[] = []; - public user: { name: string } = { name: '' }; + public approvedRoutes: string[] = []; + public availableRoutes: string[] = []; + public subnetRoutes: string[] = []; + public user: User = new User(); public online?: boolean; public constructor(init?: Partial) { @@ -18,19 +21,7 @@ export class Device { export class ACL { public groups: { [key: string]: [string] } = {}; - public constructor(init?: Partial) { - Object.assign(this, init); - } -} - -export class Route { - // current (hs 18+) method of handling a route - advertised: boolean = true; - prefix: string = ''; - enabled: boolean = false; - id: number = 0; - - public constructor(init?: Partial) { + public constructor(init?: Partial) { Object.assign(this, init); } } @@ -42,7 +33,7 @@ export class APIKey { createdAt: string = ''; lastSeen: string = ''; - public constructor(init?: Partial) { + public constructor(init?: Partial) { Object.assign(this, init); } } @@ -65,6 +56,7 @@ export class PreAuthKey { export class User { public id: string = ''; public name: string = ''; + public email: string = ''; public createdAt: string = ''; public constructor(init?: Partial) { Object.assign(this, init); diff --git a/src/lib/devices/CreateDevice.svelte b/src/lib/devices/CreateDevice.svelte index 7d32a7f..2b73888 100644 --- a/src/lib/devices/CreateDevice.svelte +++ b/src/lib/devices/CreateDevice.svelte @@ -65,7 +65,7 @@ diff --git a/src/lib/devices/DeviceCard/DeviceRoutes.svelte b/src/lib/devices/DeviceCard/DeviceRoutes.svelte index 59f606f..1e693c5 100644 --- a/src/lib/devices/DeviceCard/DeviceRoutes.svelte +++ b/src/lib/devices/DeviceCard/DeviceRoutes.svelte @@ -1,67 +1,18 @@ Device Routes
    - {#each routesList as route, index} + {#each device.availableRoutes as route}
  • - {route.prefix} - {#if route.enabled} - - {:else} - - {/if} +
  • {/each}
+ import { getDevices } from '$lib/common/apiFunctions.svelte'; + import { Device } from '$lib/common/classes'; + import { alertStore } from '$lib/common/stores'; + import { approveDeviceRoute } from './DeviceRouteAPI.svelte'; + + export let route = ''; + export let device = new Device(); + + let routeDisabled = false; + function approveRouteAction() { + approveDeviceRoute(device.id, [...device.approvedRoutes, route]) + .then(() => { + // refresh users after editing + getDevices(); + }) + .catch((error) => { + $alertStore = error; + }); + } + + function removeRouteAction() { + approveDeviceRoute(device.id, device.approvedRoutes.filter((r) => r !== route)) + .then(() => { + // refresh users after editing + getDevices(); + }) + .catch((error) => { + $alertStore = error; + }); + } + + +{route} +{#if device.approvedRoutes.includes(route)} + +{:else} + +{/if} +{#if device.subnetRoutes.includes(route)} + +{/if} diff --git a/src/lib/devices/DeviceCard/DeviceRoutes/DeviceRouteAPI.svelte b/src/lib/devices/DeviceCard/DeviceRoutes/DeviceRouteAPI.svelte new file mode 100644 index 0000000..1f28ecb --- /dev/null +++ b/src/lib/devices/DeviceCard/DeviceRoutes/DeviceRouteAPI.svelte @@ -0,0 +1,34 @@ + diff --git a/src/lib/devices/DeviceCard/DeviceRoutesAPI.svelte b/src/lib/devices/DeviceCard/DeviceRoutesAPI.svelte deleted file mode 100644 index 4ffff36..0000000 --- a/src/lib/devices/DeviceCard/DeviceRoutesAPI.svelte +++ /dev/null @@ -1,84 +0,0 @@ - diff --git a/src/lib/devices/DeviceCard/DeviceTags.svelte b/src/lib/devices/DeviceCard/DeviceTags.svelte index 2e3b9f2..6a7f5d8 100644 --- a/src/lib/devices/DeviceCard/DeviceTags.svelte +++ b/src/lib/devices/DeviceCard/DeviceTags.svelte @@ -34,9 +34,5 @@ > {/each} - - {#each device.validTags as tag} - {tag.replace("tag:","")} - {/each} diff --git a/src/lib/devices/DeviceCard/MoveDevice.svelte b/src/lib/devices/DeviceCard/MoveDevice.svelte index a8bc766..e44d5b4 100644 --- a/src/lib/devices/DeviceCard/MoveDevice.svelte +++ b/src/lib/devices/DeviceCard/MoveDevice.svelte @@ -6,7 +6,7 @@ export let device = new Device(); let deviceMoving = false; - let selectedUser = device.user.name; + let selectedUser = device.user.id; function moveDeviceAction() { moveDevice(device.id, selectedUser) @@ -39,7 +39,7 @@
diff --git a/src/lib/users/UserCard.svelte b/src/lib/users/UserCard.svelte index b7eac39..1aee04a 100644 --- a/src/lib/users/UserCard.svelte +++ b/src/lib/users/UserCard.svelte @@ -39,6 +39,10 @@
+ + + + diff --git a/src/lib/users/UserCard/PreAuthKeys.svelte b/src/lib/users/UserCard/PreAuthKeys.svelte index 7c5ea4c..599c298 100644 --- a/src/lib/users/UserCard/PreAuthKeys.svelte +++ b/src/lib/users/UserCard/PreAuthKeys.svelte @@ -22,7 +22,7 @@ } function getPreauthKeysAction() { - getPreauthKeys(user.name) + getPreauthKeys(user.id) .then((keys) => { keyList = keys; }) @@ -107,7 +107,7 @@ {#if new Date(key.expiration).getTime() > new Date().getTime() && (!key.used || key.reusable)} - { newPreAuthKeyShow = false; getPreauthKeysAction(); @@ -26,7 +26,7 @@ } function getPreauthKeysAction() { - getPreauthKeys(user.name) + getPreauthKeys(user.id) .then((keys) => { keyList = keys; }) diff --git a/src/lib/users/UserCard/RenameUser.svelte b/src/lib/users/UserCard/RenameUser.svelte index 7728ac8..efb84ee 100644 --- a/src/lib/users/UserCard/RenameUser.svelte +++ b/src/lib/users/UserCard/RenameUser.svelte @@ -32,7 +32,7 @@ {#if !cardEditing} - {user.id}: {user.name} + {user.id}: {user.name.length > 1 ? user.name : user.email}
Email{user.email}
User Creation Date {new Date(user.createdAt)}