proper sidebar handling & host deletion
This commit is contained in:
parent
5a0ceb945a
commit
1da76da1a0
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
<data-source source="LOCAL" name="trifid@localhost" uuid="39c81b89-3fc4-493f-b203-7a00527cffe6">
|
<data-source source="LOCAL" name="trifidapi@localhost" uuid="39c81b89-3fc4-493f-b203-7a00527cffe6">
|
||||||
<driver-ref>postgresql</driver-ref>
|
<driver-ref>postgresql</driver-ref>
|
||||||
<synchronize>true</synchronize>
|
<synchronize>true</synchronize>
|
||||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||||
|
|
|
@ -1,53 +1,17 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {t} from "svelte-i18n";
|
import {t} from "svelte-i18n";
|
||||||
|
import Sidebar from "$components/Sidebar.svelte";
|
||||||
|
|
||||||
export let selected;
|
export let selected;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class=" container h-100 w-100">
|
<div class="container-fluid g-0">
|
||||||
<div class="d-flex flex-column flex-shrink-0 p-3 h-100 bg-dark col position-absolute" style="width: 300px; left: 0; top: 0;">
|
<div class="row">
|
||||||
<p class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none ml-5 fs-4">
|
<div class="col-sm-3 col-md-3 col-lg-3 col-xl-2">
|
||||||
<i class="fas fa-satellite fa-fw bi me-2"></i>
|
<Sidebar bind:selected={selected} />
|
||||||
Trifid
|
|
||||||
</p>
|
|
||||||
<hr>
|
|
||||||
<ul class="nav nav-pills flex-column mb-auto">
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link py-2 px-4" class:active={selected === 'hosts'} href="/hosts">
|
|
||||||
<i class="bi me-2 fas fa-computer fa-fw"></i>
|
|
||||||
{$t("common.page.hosts")}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link py-2 px-4" class:active={selected === 'lighthouses'} href="/lighthouses">
|
|
||||||
<i class="bi me-2 fas fa-server fa-fw"></i>
|
|
||||||
{$t("common.page.lighthouses")}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link py-2 px-4" class:active={selected === 'relays'} href="/relays">
|
|
||||||
<i class="bi me-2 fas fa-network-wired fa=fw"></i>
|
|
||||||
{$t("common.page.relays")}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link py-2 px-4" class:active={selected === 'roles'} href="/roles">
|
|
||||||
<i class="bi me-2 fas fa-address-book fa-fw"></i>
|
|
||||||
{$t("common.page.roles")}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<div class="nav-item">
|
|
||||||
<button class="nav-link py-2 px-4" on:click={() => {window.localStorage.setItem("mfa", "")}}>
|
|
||||||
<i class="me-2 fas fa-right-from-bracket fa-fw"></i>
|
|
||||||
{$t("common.logout")}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col me-3 mt-2">
|
||||||
</div>
|
|
||||||
<div class="col p-3">
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {t} from "svelte-i18n";
|
||||||
|
|
||||||
|
export let selected;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="sticky-top d-flex flex-column flex-shrink-0 p-3 vh-100 bg-dark">
|
||||||
|
<p class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none ml-5 fs-4">
|
||||||
|
<i class="fas fa-satellite fa-fw bi me-2"></i>
|
||||||
|
Trifid
|
||||||
|
</p>
|
||||||
|
<hr>
|
||||||
|
<ul class="nav nav-pills flex-column mb-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link py-2 px-4" class:active={selected === 'hosts'} href="/hosts">
|
||||||
|
<i class="bi me-2 fas fa-computer fa-fw"></i>
|
||||||
|
{$t("common.page.hosts")}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link py-2 px-4" class:active={selected === 'lighthouses'} href="/lighthouses">
|
||||||
|
<i class="bi me-2 fas fa-server fa-fw"></i>
|
||||||
|
{$t("common.page.lighthouses")}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link py-2 px-4" class:active={selected === 'relays'} href="/relays">
|
||||||
|
<i class="bi me-2 fas fa-network-wired fa=fw"></i>
|
||||||
|
{$t("common.page.relays")}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link py-2 px-4" class:active={selected === 'roles'} href="/roles">
|
||||||
|
<i class="bi me-2 fas fa-address-book fa-fw"></i>
|
||||||
|
{$t("common.page.roles")}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<div class="nav-item">
|
||||||
|
<button class="nav-link py-2 px-4" on:click={() => {window.localStorage.setItem("mfa", "")}}>
|
||||||
|
<i class="me-2 fas fa-right-from-bracket fa-fw"></i>
|
||||||
|
{$t("common.logout")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
|
@ -91,7 +91,7 @@
|
||||||
"ipaddr": "IP Address",
|
"ipaddr": "IP Address",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"enroll": "Enroll",
|
"enroll": "Enroll",
|
||||||
"delete": "Delete",
|
"deletehost": "Delete",
|
||||||
"config": "Configuration",
|
"config": "Configuration",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"create": {
|
"create": {
|
||||||
|
@ -105,6 +105,15 @@
|
||||||
"needsrole": "Role is required.",
|
"needsrole": "Role is required.",
|
||||||
"invalidip": "Invalid IP address"
|
"invalidip": "Invalid IP address"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"title": "Are you sure you want to delete the host {host}?",
|
||||||
|
"explainer": "This action cannot be undone. This host will still be able to connect to the network unless you block it first.",
|
||||||
|
"confirm": "I'm sure",
|
||||||
|
"cancel": "Nevermind",
|
||||||
|
"error": {
|
||||||
|
"ERR_DB_ERROR": "Removal failed"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"roles": {
|
"roles": {
|
||||||
|
|
|
@ -124,7 +124,7 @@
|
||||||
<a href="/hosts/{host.id}/enroll" title="{$t('hosts.enroll')}" class="btn btn-success"><i class="fas fa-arrows-rotate fa-fw"></i></a>
|
<a href="/hosts/{host.id}/enroll" title="{$t('hosts.enroll')}" class="btn btn-success"><i class="fas fa-arrows-rotate fa-fw"></i></a>
|
||||||
<a href="/hosts/{host.id}/edit" title="{$t('hosts.edit')}" class="btn btn-primary"><i class="fas fa-pencil fa-fw"></i></a>
|
<a href="/hosts/{host.id}/edit" title="{$t('hosts.edit')}" class="btn btn-primary"><i class="fas fa-pencil fa-fw"></i></a>
|
||||||
<a href="/hosts/{host.id}/edit/config" title="{$t('hosts.config')}" class="btn btn-info"><i class="fas fa-gear fa-fw"></i></a>
|
<a href="/hosts/{host.id}/edit/config" title="{$t('hosts.config')}" class="btn btn-info"><i class="fas fa-gear fa-fw"></i></a>
|
||||||
<a href="/hosts/{host.id}/delete" title="{$t('hosts.delete')}" class="btn btn-danger"><i class="fas fa-trash fa-fw"></i></a>
|
<a href="/hosts/{host.id}/delete" title="{$t('hosts.deletehost')}" class="btn btn-danger"><i class="fas fa-trash fa-fw"></i></a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {isLoading, t} from "svelte-i18n";
|
||||||
|
import LoadingWrapper from "$components/LoadingWrapper.svelte";
|
||||||
|
import {onMount} from "svelte";
|
||||||
|
import {APIResult, isAuthedMFA, isAuthedSession} from "$lib/auth.ts";
|
||||||
|
import {Logger, logSetup} from "$lib/logger";
|
||||||
|
import type {APIError} from "$lib/auth.ts";
|
||||||
|
import {PUBLIC_BASE_URL} from "$env/static/public";
|
||||||
|
import {Configuration, NetworksApi, HostsApi, FirewallRuleProtocolEnum, ResponseError} from "$lib/api";
|
||||||
|
import type {FirewallRule} from "$lib/api";
|
||||||
|
import AdminBar from "$components/AdminLayout.svelte";
|
||||||
|
import {page} from "$app/stores";
|
||||||
|
import AdminLayout from "$components/AdminLayout.svelte";
|
||||||
|
import {load} from "../../../+layout";
|
||||||
|
import type {HostGet200Response} from "$lib/api";
|
||||||
|
|
||||||
|
let loading = true;
|
||||||
|
let fullPageLoading = true;
|
||||||
|
let isError = false;
|
||||||
|
let error = '';
|
||||||
|
$: currentlyLoading = $isLoading || fullPageLoading;
|
||||||
|
|
||||||
|
logSetup();
|
||||||
|
let logger = new Logger("hosts/edit/+page.svelte");
|
||||||
|
|
||||||
|
let hosts;
|
||||||
|
let host: HostGet200Response = {
|
||||||
|
data: {
|
||||||
|
name: 'Loading'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let formErr = '';
|
||||||
|
let hasFormErr = false;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
let session_load_info = await isAuthedSession();
|
||||||
|
if (session_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = session_load_info[1] as APIError;
|
||||||
|
logger.error(`session load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/login';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mfa_load_info = await isAuthedMFA();
|
||||||
|
if (mfa_load_info[0] == APIResult.Failed) {
|
||||||
|
let err = mfa_load_info[1] as APIError;
|
||||||
|
logger.error(`mfa load failed: ${err.code} ${err.message}`);
|
||||||
|
window.location.href = '/2fa';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pull networks
|
||||||
|
const configuration = new Configuration({
|
||||||
|
basePath: PUBLIC_BASE_URL,
|
||||||
|
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
|
||||||
|
});
|
||||||
|
|
||||||
|
const networksApi = new NetworksApi(configuration);
|
||||||
|
let networks;
|
||||||
|
try {
|
||||||
|
networks = await networksApi.networksList();
|
||||||
|
} catch (e) {
|
||||||
|
let resp_json = await e.response.json();
|
||||||
|
if (resp_json.errors[0].code == "ERR_NO_ORG") {
|
||||||
|
window.location.href = "/networkcreate";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
isError = true;
|
||||||
|
error = $t("networkcreate.error.generic", {values:{err:resp_json.errors[0].code}});
|
||||||
|
loading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(networks);
|
||||||
|
|
||||||
|
if (networks.data?.length == 0) {
|
||||||
|
window.location.href = '/networkcreate';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostsApi = new HostsApi(configuration);
|
||||||
|
hosts = await hostsApi.hostsList();
|
||||||
|
|
||||||
|
// pull our role
|
||||||
|
host = await hostsApi.hostGet({
|
||||||
|
hostID: $page.params.host_id
|
||||||
|
});
|
||||||
|
|
||||||
|
fullPageLoading = false;
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function deleteRole() {
|
||||||
|
loading = true;
|
||||||
|
const configuration = new Configuration({
|
||||||
|
basePath: PUBLIC_BASE_URL,
|
||||||
|
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
|
||||||
|
});
|
||||||
|
const hostsApi = new HostsApi(configuration);
|
||||||
|
try {
|
||||||
|
await hostsApi.hostDelete({hostID: $page.params.host_id});
|
||||||
|
} catch (e) {
|
||||||
|
let body = await (<ResponseError>e).response.json();
|
||||||
|
|
||||||
|
console.log(body);
|
||||||
|
|
||||||
|
formErr = $t("hosts.delete.error." + body.errors[0].code);
|
||||||
|
hasFormErr = true;
|
||||||
|
loading = false;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.location.href = "/hosts";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{$t("common.title", {values: {title: $t("common.page.hosts")}})}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
|
||||||
|
<AdminLayout selected="hosts">
|
||||||
|
<h3>{$t("hosts.delete.title", {values: {host: host.data.name}})}</h3>
|
||||||
|
<p>{$t("hosts.delete.explainer")}</p>
|
||||||
|
{#if loading}
|
||||||
|
<button disabled class="btn btn-danger"><i class="fas fa-gear fa-spin"></i></button>
|
||||||
|
{:else}
|
||||||
|
<button on:click={deleteRole} class="btn btn-danger">{$t("hosts.delete.confirm")}</button>
|
||||||
|
{/if}
|
||||||
|
<button on:click={() => {window.location.href = "/hosts"}} class="btn btn-outline-info">{$t("hosts.delete.cancel")}</button>
|
||||||
|
{#if hasFormErr}
|
||||||
|
<p class="text-danger">{formErr}</p>
|
||||||
|
{/if}
|
||||||
|
</AdminLayout>
|
||||||
|
</LoadingWrapper>
|
Loading…
Reference in New Issue