Compare commits

...

7 commits

Author SHA1 Message Date
routerino
a7f79824bf
Update install-openvscode-server.sh 2025-08-30 11:25:52 +10:00
routerino
3c22ed935d
Update version before release 2025-08-23 11:00:38 +10:00
routerino
c48c0a54fb
210 feature request show user names not just usernames (#211)
* fix: display email if username is too short

* feat: added email field to expanded cards
2025-08-23 10:59:46 +10:00
routerino
fbb8b2b968
test before release 2025-07-12 10:02:00 +10:00
routerino
baffa0024c
fix undocumented headscale ui change (#207) 2025-07-12 10:01:05 +10:00
Eloxt Wang
15c4dd9575
Add route removal functionality and fix code formatting (#206)
- Add removeRouteAction function to allow disabling active routes
- Update approveDeviceRoute to accept full routes array instead of single route
2025-07-11 09:00:47 +10:00
routerino
7dd92ab4ad
Fix: CICD Pipeline for release plugin (#201)
* testing-github-piprline

* fix pipeline

* bump version
2025-05-24 12:57:50 +10:00
12 changed files with 55 additions and 50 deletions

View file

@ -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

View file

@ -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"

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "headscale-ui",
"version": "2025.03.21",
"version": "2025.07.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "headscale-ui",
"version": "2025.03.21",
"version": "2025.07.12",
"devDependencies": {
"@sveltejs/adapter-auto": "^4",
"@sveltejs/adapter-static": "^3",

View file

@ -1,6 +1,6 @@
{
"name": "headscale-ui",
"version": "2025.05.22",
"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"
}
}

View file

@ -464,7 +464,7 @@
});
}
export async function moveDevice(deviceID: string, user: string): Promise<any> {
export async function moveDevice(deviceID: string, userID: string): Promise<any> {
// 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) => {

View file

@ -10,7 +10,7 @@ export class Device {
public approvedRoutes: string[] = [];
public availableRoutes: string[] = [];
public subnetRoutes: string[] = [];
public user: { name: string } = { name: '' };
public user: User = new User();
public online?: boolean;
public constructor(init?: Partial<Device>) {
@ -56,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<User>) {
Object.assign(this, init);

View file

@ -65,7 +65,7 @@
<label class="block text-secondary text-sm font-bold mb-2" for="select">Select User</label>
<select class="card-select mr-3" required bind:value={selectedUser}>
{#each $userStore as user}
<option>{user.name}</option>
<option>{user.name.length > 1 ? user.name : user.email}</option>
{/each}
</select>
</div>

View file

@ -1,15 +1,15 @@
<script>
import { getDevices } from '$lib/common/apiFunctions.svelte';
import { Device } from '$lib/common/classes';
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();
export let route = '';
export let device = new Device();
let routeDisabled = false;
function approveRouteAction() {
approveDeviceRoute(device.id, [route])
approveDeviceRoute(device.id, [...device.approvedRoutes, route])
.then(() => {
// refresh users after editing
getDevices();
@ -19,11 +19,29 @@
});
}
function removeRouteAction() {
approveDeviceRoute(device.id, device.approvedRoutes.filter((r) => r !== route))
.then(() => {
// refresh users after editing
getDevices();
})
.catch((error) => {
$alertStore = error;
});
}
</script>
{route}
{#if device.approvedRoutes.includes(route)}
<button type="button" class="btn btn-xs tooltip capitalize bg-success text-success-content mx-1">active</button>
<button
on:click={() => {
routeDisabled = true;
removeRouteAction();
routeDisabled = false;
}}
type="button"
class="btn btn-xs tooltip capitalize bg-success text-success-content mx-1">active</button
>
{:else}
<button
on:click={() => {
@ -32,7 +50,8 @@
routeDisabled = false;
}}
type="button"
class="btn btn-xs tooltip capitalize bg-secondary text-secondary-content mx-1" class:disabled={routeDisabled}
class="btn btn-xs tooltip capitalize bg-secondary text-secondary-content mx-1"
class:disabled={routeDisabled}
data-tip="click to enable route">pending</button
>
{/if}

View file

@ -1,6 +1,6 @@
<script context="module" lang="ts">
export async function approveDeviceRoute(deviceID: string, routes: [string]): Promise<any> {
export async function approveDeviceRoute(deviceID: string, routes: string[]): Promise<any> {
// variables in local storage
let headscaleURL = localStorage.getItem('headscaleURL') || '';
let headscaleAPIKey = localStorage.getItem('headscaleAPIKey') || '';

View file

@ -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 @@
<form on:submit|preventDefault={moveDeviceAction}>
<select class="card-select mr-3" required bind:value={selectedUser}>
{#each $userStore as user}
<option>{user.name}</option>
<option value={user.id}>{user.name.length > 1 ? user.name : user.email}</option>
{/each}
</select>
<!-- edit accept symbol -->

View file

@ -39,6 +39,10 @@
<div class="overflow-x-auto">
<table class="table table-compact w-full">
<tbody>
<tr>
<th>Email</th>
<td>{user.email}</td>
</tr>
<tr>
<th>User Creation Date</th>
<td>{new Date(user.createdAt)}</td>

View file

@ -32,7 +32,7 @@
</script>
{#if !cardEditing}
<span class="font-bold">{user.id}: {user.name}</span>
<span class="font-bold">{user.id}: {user.name.length > 1 ? user.name : user.email}</span>
<!-- edit symbol -->
<button type="button" on:click|stopPropagation={() => editingUser()} class="ml-2"
><svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 inline flex-shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">