role add, edit, main page

This commit is contained in:
core 2023-09-26 00:13:00 -04:00
parent 918a3ad1ea
commit 80c1250ec7
Signed by: core
GPG Key ID: FDBF740DADDCEECF
9 changed files with 336 additions and 168 deletions

View File

@ -1,12 +0,0 @@
<script lang="ts">
import {t} from "svelte-i18n";
export let selected;
</script>
<div>
<button disabled="{selected === 'hosts'}" on:click={() => {window.location.href="/hosts"}}>{$t("common.page.hosts")}</button>
<button disabled="{selected === 'lighthouses'}" on:click={() => {window.location.href="/lighthouses"}}>{$t("common.page.lighthouses")}</button>
<button disabled="{selected === 'relays'}" on:click={() => {window.location.href="/relays"}}>{$t("common.page.relays")}</button>
<button disabled="{selected === 'roles'}" on:click={() => {window.location.href="/roles"}}>{$t("common.page.roles")}</button>
</div>

View File

@ -0,0 +1,53 @@
<script lang="ts">
import {t} from "svelte-i18n";
export let selected;
</script>
<div class=" container h-100 w-100">
<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;">
<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>
<div class="col p-3">
<slot></slot>
</div>
</div>

View File

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import {logDeltaReset, Logger, logSetup} from "$lib/logger"; import {logDeltaReset, Logger, logSetup} from "$lib/logger";
import {t} from "svelte-i18n";
export let isLoading; export let isLoading;
export let isError; export let isError;
@ -19,10 +20,22 @@
</script> </script>
{#if isLoading} {#if isLoading}
<h1>its loading</h1> <div class="h-100 d-flex align-items-center justify-content-center">
<div class="card">
<div class="card-body text-center">
<h4 class="card-title mb-0">{$t("common.loading")} <i class="fas fa-gear fa-spin"></i></h4>
</div>
</div>
</div>
{:else} {:else}
{#if isError} {#if isError}
<h1>error: {error}</h1> <div class="h-100 d-flex align-items-center justify-content-center">
<div class="card w-25">
<div class="card-body text-center">
<h4 class="card-title mb-0 text-danger">{error}</h4>
</div>
</div>
</div>
{:else} {:else}
<slot></slot> <slot></slot>
{/if} {/if}

View File

@ -91,9 +91,8 @@
"rules": "Rule count", "rules": "Rule count",
"description": "Description", "description": "Description",
"actions": "Actions", "actions": "Actions",
"editbtn": "Edit",
"delete": "Delete",
"add": { "add": {
"title": "Create Role",
"any": "Any", "any": "Any",
"name": "Role name", "name": "Role name",
"desc": "Role description", "desc": "Role description",
@ -105,10 +104,9 @@
"description": "Description", "description": "Description",
"protocol": "Protocol", "protocol": "Protocol",
"portrange": "Port range", "portrange": "Port range",
"allowedrole": "Allowed role" "allowedrole": "Allowed role",
"actions": "Actions"
}, },
"ruleremove": "Remove rule",
"ruleedit": "Edit rule",
"rulesadd": "Add rule", "rulesadd": "Add rule",
"editrule": { "editrule": {
"protocol": "Protocol", "protocol": "Protocol",
@ -118,9 +116,13 @@
"add": "Add rule", "add": "Add rule",
"edit": "Save edit", "edit": "Save edit",
"cancel": "Cancel" "cancel": "Cancel"
},
"error": {
"needsname": "Role Name is required"
} }
}, },
"edit": { "edit": {
"title": "Editing rule {rule}",
"any": "Any", "any": "Any",
"name": "Role name", "name": "Role name",
"desc": "Role description", "desc": "Role description",
@ -162,6 +164,8 @@
"roles": "Roles", "roles": "Roles",
"lighthouses": "Lighthouses", "lighthouses": "Lighthouses",
"relays": "Relays" "relays": "Relays"
} },
"logout": "Log out",
"loading": "Dashboard is loading"
} }
} }

View File

@ -2,10 +2,14 @@
import "bootswatch/dist/darkly/bootstrap.css"; import "bootswatch/dist/darkly/bootstrap.css";
import "@fortawesome/fontawesome-free/css/all.css"; import "@fortawesome/fontawesome-free/css/all.css";
import "@fortawesome/fontawesome-free/js/all.js"; import "@fortawesome/fontawesome-free/js/all.js";
import "@popperjs/core";
import {onMount} from "svelte"; import {onMount} from "svelte";
onMount(async () => { onMount(async () => {
await import("bootstrap/dist/js/bootstrap.js"); const bootstrap = await import("bootstrap/dist/js/bootstrap.js");
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
}) })
</script> </script>

View File

@ -7,7 +7,7 @@
import type {APIError} from "$lib/auth.ts"; import type {APIError} from "$lib/auth.ts";
import {PUBLIC_BASE_URL} from "$env/static/public"; import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi} from "$lib/api"; import {Configuration, NetworksApi} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte"; import AdminLayout from "$components/AdminLayout.svelte";
let loading = true; let loading = true;
let isError = false; let isError = false;
@ -72,6 +72,7 @@
</svelte:head> </svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}> <LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="hosts" /> <AdminLayout selected="hosts">
<h1>its not loading anymore</h1> <h3>{$t("common.page.hosts")}</h3>
</AdminLayout>
</LoadingWrapper> </LoadingWrapper>

View File

@ -7,7 +7,7 @@
import type {APIError} from "$lib/auth.ts"; import type {APIError} from "$lib/auth.ts";
import {PUBLIC_BASE_URL} from "$env/static/public"; import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi, RolesApi} from "$lib/api"; import {Configuration, NetworksApi, RolesApi} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte"; import AdminLayout from "$components/AdminLayout.svelte";
let loading = true; let loading = true;
let isError = false; let isError = false;
@ -100,23 +100,26 @@
</svelte:head> </svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}> <LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="roles" /> <AdminLayout selected="roles">
<div class="block">
<h1>{$t("common.page.roles")}</h1> <h3 class="inline">{$t("common.page.roles")} <button class="inline float-end btn btn-primary" on:click={roleAdd}>{$t("roles.create")} <i class="bi ms-1 fas fa-add"></i></button></h3>
<button on:click={roleAdd}>{$t("roles.create")}</button> </div>
<p>{$t("roles.explain")}</p> <p>{$t("roles.explain")}</p>
{#if (roles.data.length === 0)} {#if (roles.data.length === 0)}
<p>{$t("roles.noroles")}</p> <p>{$t("roles.noroles")}</p>
{:else} {:else}
<table> <table class="table table-dark table-hover">
<thead>
<tr> <tr>
<th>{$t("roles.name")}</th> <th scope="col">{$t("roles.name")}</th>
<th>{$t("roles.rules")}</th> <th scope="col">{$t("roles.rules")}</th>
<th>{$t("roles.description")}</th> <th scope="col">{$t("roles.description")}</th>
<th>{$t("roles.actions")}</th> <th scope="col">{$t("roles.actions")}</th>
</tr> </tr>
</thead>
<tbody>
{#each roles.data as role} {#each roles.data as role}
<tr> <tr>
<td> <td>
@ -127,11 +130,16 @@
<td>{role.firewallRules.length}</td> <td>{role.firewallRules.length}</td>
<td>{role.description}</td> <td>{role.description}</td>
<td> <td>
<button on:click={() => {window.location.href = `/roles/${role.id}/edit`}}>{$t("roles.editbtn")}</button> <div class="btn-group">
<button on:click={() => {roleDelete(role.id)}}>{$t("roles.delete")}</button> <button class="btn btn-primary" on:click={() => {window.location.href = `/roles/${role.id}/edit`}}><i class="fas fa-pencil fa-fw"></i></button>
<button class="btn btn-danger" on:click={() => {roleDelete(role.id)}}><i class="fas fa-trash fa-fw"></i></button>
</div>
</td> </td>
</tr> </tr>
{/each} {/each}
</tbody>
</table> </table>
{/if} {/if}
</AdminLayout>
</LoadingWrapper> </LoadingWrapper>

View File

@ -8,8 +8,9 @@
import {PUBLIC_BASE_URL} from "$env/static/public"; import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi, RolesApi, FirewallRuleProtocolEnum} from "$lib/api"; import {Configuration, NetworksApi, RolesApi, FirewallRuleProtocolEnum} from "$lib/api";
import type {FirewallRule} from "$lib/api"; import type {FirewallRule} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte"; import AdminBar from "$components/AdminLayout.svelte";
import {page} from "$app/stores"; import {page} from "$app/stores";
import AdminLayout from "$components/AdminLayout.svelte";
let loading = true; let loading = true;
let isError = false; let isError = false;
@ -24,6 +25,8 @@
let roleName = ''; let roleName = '';
let roleDescription = ''; let roleDescription = '';
let formErr = '';
let hasFormErr = false;
enum RuleProtocol { enum RuleProtocol {
ANY = 0, ANY = 0,
@ -211,6 +214,7 @@
} }
async function roleEdit() { async function roleEdit() {
loading = true;
const configuration = new Configuration({ const configuration = new Configuration({
basePath: PUBLIC_BASE_URL, basePath: PUBLIC_BASE_URL,
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa") accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
@ -346,66 +350,106 @@
</svelte:head> </svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}> <LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="roles" /> <AdminLayout selected="roles">
<h3>{$t("roles.edit.title", {values: {rule: roleName}})}</h3>
<form on:submit|preventDefault={roleEdit}> <form>
<label for="roleName">{$t("roles.edit.name")}</label> <label class="mt-2 form-label" for="roleDesc">{$t("roles.edit.desc")}</label>
<input disabled bind:value={roleName} type="text" id="roleName" /> <input class="form-control" bind:value={roleDescription} type="text" id="roleDesc" />
<label for="roleDesc">{$t("roles.edit.desc")}</label> <hr>
<input bind:value={roleDescription} type="text" id="roleDesc" /> <h5>{$t("roles.edit.rules")}</h5>
<h3>{$t("roles.edit.rules")}</h3>
<p>{$t("roles.edit.rulesexplainer")}</p> <p>{$t("roles.edit.rulesexplainer")}</p>
<!-- firewall rules --> <!-- firewall rules -->
<table> <table class="table table-dark rounded-2 table-hover">
<thead>
<tr> <tr>
<th>{$t("roles.edit.rulescols.description")}</th> <th scope="col">{$t("roles.edit.rulescols.description")}</th>
<th>{$t("roles.edit.rulescols.protocol")}</th> <th scope="col">{$t("roles.edit.rulescols.protocol")}</th>
<th>{$t("roles.edit.rulescols.portrange")}</th> <th scope="col">{$t("roles.edit.rulescols.portrange")}</th>
<th>{$t("roles.edit.rulescols.allowedrole")}</th> <th scope="col">{$t("roles.edit.rulescols.allowedrole")}</th>
<th scope="col">{$t("roles.edit.rulescols.actions")}</th>
</tr> </tr>
</thead>
<tbody>
{#each rules as rule} {#each rules as rule}
<tr> <tr>
<td>{rule.description}</td> <td>{rule.description}</td>
<td>{protoToStringName(rule.protocol)}</td> <td>{protoToStringName(rule.protocol)}</td>
<td>{prettyPortRange(rule.portRange)}</td> <td>{prettyPortRange(rule.portRange)}</td>
<td>{findRole(rule.allowedRole)}</td> <td>{findRole(rule.allowedRole)}</td>
<button disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}>{$t("roles.edit.ruleedit")}</button> <td>
<button disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}>{$t("roles.edit.ruleremove")}</button> <div class="btn-group" role="group" aria-label="Actions">
<button type="button" class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}><i class="fas fa-pencil fa-fw"></i></button>
<button type="button" class="btn btn-danger" disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}><i class="fas fa-trash fa-fw"></i></button>
</div>
</td>
</tr> </tr>
{/each} {/each}
</table> </tbody>
<button disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.edit.rulesadd")}</button> </table>
{#if isEditingRule} {#if isEditingRule}
<form on:submit|preventDefault> <form on:submit|preventDefault>
<label for="ruleProtocol">{$t("roles.edit.editrule.protocol")}</label> <div class="container">
<select id="ruleProtocol" bind:value="{editingRuleProtocol}"> <div class="row">
<option value="{RuleProtocol.ANY}">{$t("roles.edit.any")}</option> <div class="col">
<label class="form-label" for="ruleProtocol">{$t("roles.edit.editrule.protocol")}</label>
<select class="form-select" id="ruleProtocol" bind:value="{editingRuleProtocol}">
<option selected value="{RuleProtocol.ANY}">{$t("roles.edit.any")}</option>
<option value="{RuleProtocol.TCP}">TCP</option> <option value="{RuleProtocol.TCP}">TCP</option>
<option value="{RuleProtocol.UDP}">UDP</option> <option value="{RuleProtocol.UDP}">UDP</option>
<option value="{RuleProtocol.ICMP}">ICMP</option> <option value="{RuleProtocol.ICMP}">ICMP</option>
</select> </select>
<label for="rulePortRange">{$t("roles.edit.editrule.range")}</label> </div>
<input type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/> <div class="col">
<label for="ruleAllowedRole">{$t("roles.edit.editrule.role")}</label> <label class="form-label" for="rulePortRange">{$t("roles.edit.editrule.range")}</label>
<select id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}"> <input class="form-control" type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/>
<option value="any">{$t("roles.edit.any")}</option> </div>
</div>
<div class="row">
<div class="col">
<label class="mt-2 form-label" for="ruleAllowedRole">{$t("roles.edit.editrule.role")}</label>
<select class="form-select" id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}">
<option selected value="any">{$t("roles.edit.any")}</option>
{#each roles.data as role} {#each roles.data as role}
<option value="{role.id}">{role.name}</option> <option value="{role.id}">{role.name}</option>
{/each} {/each}
</select> </select>
<label for="ruleDescription">{$t("roles.edit.editrule.desc")}</label> </div>
<input type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/> </div>
<button on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.edit.editrule.edit") : $t("roles.edit.editrule.add")}</button> <div class="row">
<button on:click|preventDefault={cancelEdit}>{$t("roles.edit.editrule.cancel")}</button> <div class="col">
<label class="mt-2 form-label" for="ruleDescription">{$t("roles.edit.editrule.desc")}</label>
<input class="form-control" type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/>
</div>
</div>
<div class="row">
<div class="col">
<button class="mt-3 mr-2 btn btn-primary" on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.edit.editrule.edit") : $t("roles.edit.editrule.add")}</button>
<button class="mt-3 ml-2 btn btn-outline-info" on:click|preventDefault={cancelEdit}>{$t("roles.edit.editrule.cancel")}</button>
</div>
</div>
</div>
</form> </form>
{/if} {/if}
<br/> <hr>
<button disabled="{allowClickingOtherStuff}">{$t("roles.edit.button")}</button> <button class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.edit.rulesadd")} <i class="bi ms-1 fas fa-add"></i></button>
<button disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.edit.cancel")}</button>
<hr>
{#if loading}
<button disabled class="btn btn-primary" on:click={roleEdit}><i class="fas fa-gear fa-spin"></i></button>
{:else}
<button class="btn btn-primary" on:click={roleEdit} disabled="{allowClickingOtherStuff}">{$t("roles.edit.button")}</button>
{/if}
<button class="btn btn-outline-info" disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.edit.cancel")}</button>
{#if hasFormErr}
<p class="text-danger">{formErr}</p>
{/if}
</form> </form>
</AdminLayout>
</LoadingWrapper> </LoadingWrapper>

View File

@ -8,18 +8,22 @@
import {PUBLIC_BASE_URL} from "$env/static/public"; import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi, RolesApi, FirewallRuleProtocolEnum} from "$lib/api"; import {Configuration, NetworksApi, RolesApi, FirewallRuleProtocolEnum} from "$lib/api";
import type {FirewallRule} from "$lib/api"; import type {FirewallRule} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte"; import AdminBar from "$components/AdminLayout.svelte";
import AdminLayout from "$components/AdminLayout.svelte";
let loading = true; let loading = true;
let isError = false; let isError = false;
let error = ''; let error = '';
$: currentlyLoading = $isLoading || loading; $: currentlyLoading = $isLoading;
logSetup(); logSetup();
let logger = new Logger("roles/add/+page.svelte"); let logger = new Logger("roles/add/+page.svelte");
let roles; let roles;
let formErr = '';
let hasFormErr = false;
onMount(async () => { onMount(async () => {
let session_load_info = await isAuthedSession(); let session_load_info = await isAuthedSession();
if (session_load_info[0] == APIResult.Failed) { if (session_load_info[0] == APIResult.Failed) {
@ -267,6 +271,13 @@
} }
async function roleAdd() { async function roleAdd() {
hasFormErr = false;
loading = true;
if (roleName == undefined || roleName == "" || roleName == " ") {
hasFormErr = true;
formErr = $t("roles.add.error.needsname");
}
const configuration = new Configuration({ const configuration = new Configuration({
basePath: PUBLIC_BASE_URL, basePath: PUBLIC_BASE_URL,
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa") accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
@ -299,66 +310,108 @@
</svelte:head> </svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}> <LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="roles" /> <AdminLayout selected="roles">
<h3>{$t("roles.add.title")}</h3>
<form> <form>
<label for="roleName">{$t("roles.add.name")}</label> <label class="form-label" for="roleName">{$t("roles.add.name")}</label>
<input bind:value={roleName} type="text" id="roleName" /> <input class="form-control" bind:value={roleName} type="text" id="roleName" />
<label for="roleDesc">{$t("roles.add.desc")}</label> <label class="mt-2 form-label" for="roleDesc">{$t("roles.add.desc")}</label>
<input bind:value={roleDescription} type="text" id="roleDesc" /> <input class="form-control" bind:value={roleDescription} type="text" id="roleDesc" />
<h3>{$t("roles.add.rules")}</h3> <hr>
<h5>{$t("roles.add.rules")}</h5>
<p>{$t("roles.add.rulesexplainer")}</p> <p>{$t("roles.add.rulesexplainer")}</p>
<!-- firewall rules --> <!-- firewall rules -->
<table> <table class="table table-dark rounded-2 table-hover">
<thead>
<tr> <tr>
<th>{$t("roles.add.rulescols.description")}</th> <th scope="col">{$t("roles.add.rulescols.description")}</th>
<th>{$t("roles.add.rulescols.protocol")}</th> <th scope="col">{$t("roles.add.rulescols.protocol")}</th>
<th>{$t("roles.add.rulescols.portrange")}</th> <th scope="col">{$t("roles.add.rulescols.portrange")}</th>
<th>{$t("roles.add.rulescols.allowedrole")}</th> <th scope="col">{$t("roles.add.rulescols.allowedrole")}</th>
<th scope="col">{$t("roles.add.rulescols.actions")}</th>
</tr> </tr>
</thead>
<tbody>
{#each rules as rule} {#each rules as rule}
<tr> <tr>
<td>{rule.description}</td> <td>{rule.description}</td>
<td>{protoToStringName(rule.protocol)}</td> <td>{protoToStringName(rule.protocol)}</td>
<td>{prettyPortRange(rule.portRange)}</td> <td>{prettyPortRange(rule.portRange)}</td>
<td>{findRole(rule.allowedRole)}</td> <td>{findRole(rule.allowedRole)}</td>
<button disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}>{$t("roles.add.ruleedit")}</button> <td>
<button disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}>{$t("roles.add.ruleremove")}</button> <div class="btn-group" role="group" aria-label="Actions">
<button type="button" class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}><i class="fas fa-pencil fa-fw"></i></button>
<button type="button" class="btn btn-danger" disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}><i class="fas fa-trash fa-fw"></i></button>
</div>
</td>
</tr> </tr>
{/each} {/each}
</table> </tbody>
<button disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.add.rulesadd")}</button> </table>
{#if isEditingRule} {#if isEditingRule}
<form on:submit|preventDefault> <form on:submit|preventDefault>
<label for="ruleProtocol">{$t("roles.add.editrule.protocol")}</label> <div class="container">
<select id="ruleProtocol" bind:value="{editingRuleProtocol}"> <div class="row">
<option value="{RuleProtocol.ANY}">{$t("roles.add.any")}</option> <div class="col">
<label class="form-label" for="ruleProtocol">{$t("roles.add.editrule.protocol")}</label>
<select class="form-select" id="ruleProtocol" bind:value="{editingRuleProtocol}">
<option selected value="{RuleProtocol.ANY}">{$t("roles.add.any")}</option>
<option value="{RuleProtocol.TCP}">TCP</option> <option value="{RuleProtocol.TCP}">TCP</option>
<option value="{RuleProtocol.UDP}">UDP</option> <option value="{RuleProtocol.UDP}">UDP</option>
<option value="{RuleProtocol.ICMP}">ICMP</option> <option value="{RuleProtocol.ICMP}">ICMP</option>
</select> </select>
<label for="rulePortRange">{$t("roles.add.editrule.range")}</label> </div>
<input type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/> <div class="col">
<label for="ruleAllowedRole">{$t("roles.add.editrule.role")}</label> <label class="form-label" for="rulePortRange">{$t("roles.add.editrule.range")}</label>
<select id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}"> <input class="form-control" type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/>
<option value="any">{$t("roles.add.any")}</option> </div>
</div>
<div class="row">
<div class="col">
<label class="mt-2 form-label" for="ruleAllowedRole">{$t("roles.add.editrule.role")}</label>
<select class="form-select" id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}">
<option selected value="any">{$t("roles.add.any")}</option>
{#each roles.data as role} {#each roles.data as role}
<option value="{role.id}">{role.name}</option> <option value="{role.id}">{role.name}</option>
{/each} {/each}
</select> </select>
<label for="ruleDescription">{$t("roles.add.editrule.desc")}</label> </div>
<input type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/> </div>
<button on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.add.editrule.edit") : $t("roles.add.editrule.add")}</button> <div class="row">
<button on:click|preventDefault={cancelEdit}>{$t("roles.add.editrule.cancel")}</button> <div class="col">
<label class="mt-2 form-label" for="ruleDescription">{$t("roles.add.editrule.desc")}</label>
<input class="form-control" type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/>
</div>
</div>
<div class="row">
<div class="col">
<button class="mt-3 mr-2 btn btn-primary" on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.add.editrule.edit") : $t("roles.add.editrule.add")}</button>
<button class="mt-3 ml-2 btn btn-outline-info" on:click|preventDefault={cancelEdit}>{$t("roles.add.editrule.cancel")}</button>
</div>
</div>
</div>
</form> </form>
{/if} {/if}
<br/> <hr>
<button on:click={roleAdd} disabled="{allowClickingOtherStuff}">{$t("roles.add.button")}</button> <button class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.add.rulesadd")} <i class="bi ms-1 fas fa-add"></i></button>
<button disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.add.cancel")}</button>
<hr>
{#if loading}
<button disabled class="btn btn-primary" on:click={roleAdd}><i class="fas fa-gear fa-spin"></i></button>
{:else}
<button class="btn btn-primary" on:click={roleAdd} disabled="{allowClickingOtherStuff}">{$t("roles.add.button")}</button>
{/if}
<button class="btn btn-outline-info" disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.add.cancel")}</button>
{#if hasFormErr}
<p class="text-danger">{formErr}</p>
{/if}
</form> </form>
</AdminLayout>
</LoadingWrapper> </LoadingWrapper>