mirror of
https://github.com/gurucomputing/headscale-ui.git
synced 2026-01-23 18:46:14 +00:00
Compare commits
No commits in common. "master" and "2025.05.22" have entirely different histories.
master
...
2025.05.22
12 changed files with 50 additions and 55 deletions
43
.github/workflows/publish-release.yaml
vendored
43
.github/workflows/publish-release.yaml
vendored
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- 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@v3
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v2
|
||||
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@v6
|
||||
uses: docker/build-push-action@v4
|
||||
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@v3
|
||||
uses: shrink/actions-docker-extract@v2
|
||||
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
|
||||
id: extract
|
||||
with:
|
||||
|
|
@ -73,14 +73,33 @@ jobs:
|
|||
cd "${{ steps.extract.outputs.destination }}"
|
||||
7z a headscale-ui.zip web
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
- name: Create Draft Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
if: ${{ env.NOT_PREVIOUSLY_PUBLISHED != 0 }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ env.VERSION }}
|
||||
name: headscale-ui
|
||||
files: ${{ steps.extract.outputs.destination }}/headscale-ui.zip
|
||||
generate_release_notes: true
|
||||
make_latest: true
|
||||
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 }}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# script variables
|
||||
OPENVSCODE_VERSION="1.103.1"
|
||||
OPENVSCODE_VERSION="1.98.0"
|
||||
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
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "headscale-ui",
|
||||
"version": "2025.07.12",
|
||||
"version": "2025.03.21",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "headscale-ui",
|
||||
"version": "2025.07.12",
|
||||
"version": "2025.03.21",
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^4",
|
||||
"@sveltejs/adapter-static": "^3",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "headscale-ui",
|
||||
"version": "2025.08.23",
|
||||
"version": "2025.05.22",
|
||||
"scripts": {
|
||||
"dev": "vite dev --port 8080 --host 0.0.0.0",
|
||||
"build": "vite build",
|
||||
|
|
@ -33,4 +33,4 @@
|
|||
"typescript": "^5"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
}
|
||||
|
|
@ -464,7 +464,7 @@
|
|||
});
|
||||
}
|
||||
|
||||
export async function moveDevice(deviceID: string, userID: string): Promise<any> {
|
||||
export async function moveDevice(deviceID: string, user: string): Promise<any> {
|
||||
|
||||
// variables in local storage
|
||||
let headscaleURL = localStorage.getItem('headscaleURL') || '';
|
||||
|
|
@ -480,7 +480,7 @@
|
|||
Authorization: `Bearer ${headscaleAPIKey}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user: parseInt(userID)
|
||||
user: user
|
||||
})
|
||||
})
|
||||
.then((response) => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export class Device {
|
|||
public approvedRoutes: string[] = [];
|
||||
public availableRoutes: string[] = [];
|
||||
public subnetRoutes: string[] = [];
|
||||
public user: User = new User();
|
||||
public user: { name: string } = { name: '' };
|
||||
public online?: boolean;
|
||||
|
||||
public constructor(init?: Partial<Device>) {
|
||||
|
|
@ -56,7 +56,6 @@ 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);
|
||||
|
|
|
|||
|
|
@ -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.length > 1 ? user.name : user.email}</option>
|
||||
<option>{user.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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, [...device.approvedRoutes, route])
|
||||
approveDeviceRoute(device.id, [route])
|
||||
.then(() => {
|
||||
// refresh users after editing
|
||||
getDevices();
|
||||
|
|
@ -19,29 +19,11 @@
|
|||
});
|
||||
}
|
||||
|
||||
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
|
||||
on:click={() => {
|
||||
routeDisabled = true;
|
||||
removeRouteAction();
|
||||
routeDisabled = false;
|
||||
}}
|
||||
type="button"
|
||||
class="btn btn-xs tooltip capitalize bg-success text-success-content mx-1">active</button
|
||||
>
|
||||
<button type="button" class="btn btn-xs tooltip capitalize bg-success text-success-content mx-1">active</button>
|
||||
{:else}
|
||||
<button
|
||||
on:click={() => {
|
||||
|
|
@ -50,8 +32,7 @@
|
|||
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}
|
||||
|
|
|
|||
|
|
@ -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') || '';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
export let device = new Device();
|
||||
let deviceMoving = false;
|
||||
let selectedUser = device.user.id;
|
||||
let selectedUser = device.user.name;
|
||||
|
||||
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 value={user.id}>{user.name.length > 1 ? user.name : user.email}</option>
|
||||
<option>{user.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<!-- edit accept symbol -->
|
||||
|
|
|
|||
|
|
@ -39,10 +39,6 @@
|
|||
<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>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
</script>
|
||||
|
||||
{#if !cardEditing}
|
||||
<span class="font-bold">{user.id}: {user.name.length > 1 ? user.name : user.email}</span>
|
||||
<span class="font-bold">{user.id}: {user.name}</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">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue