Allow passing hostname, fastd-key and MAC as query-parameters when creating new node
This commit is contained in:
parent
fb5bf934ff
commit
1de5bc0604
3 changed files with 110 additions and 53 deletions
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useConfigStore } from "@/stores/config";
|
||||
import { useNodeStore } from "@/stores/node";
|
||||
import { computed, nextTick, ref } from "vue";
|
||||
import { computed, nextTick, onMounted, ref } from "vue";
|
||||
import CONSTRAINTS from "@/shared/validation/constraints";
|
||||
import ActionButton from "@/components/form/ActionButton.vue";
|
||||
import type {
|
||||
|
@ -30,6 +30,14 @@ import { ApiError } from "@/utils/Api";
|
|||
const configStore = useConfigStore();
|
||||
const nodeStore = useNodeStore();
|
||||
|
||||
interface Props {
|
||||
hostname?: Hostname;
|
||||
fastdKey?: FastdKey;
|
||||
mac?: MAC;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "create", node: StoredNode): void;
|
||||
}>();
|
||||
|
@ -44,13 +52,25 @@ const CONFLICT_MESSAGES: Record<string, string> = {
|
|||
|
||||
const conflictErrorMessage = ref<string | undefined>(undefined);
|
||||
|
||||
const hostname = ref("" as Hostname);
|
||||
const fastdKey = ref("" as FastdKey);
|
||||
const mac = ref("" as MAC);
|
||||
const coords = ref("" as Coordinates);
|
||||
const nickname = ref("" as Nickname);
|
||||
const email = ref("" as EmailAddress);
|
||||
const monitoring = ref(false);
|
||||
const hostnameModel = ref("" as Hostname);
|
||||
const fastdKeyModel = ref("" as FastdKey);
|
||||
const macModel = ref("" as MAC);
|
||||
const coordsModel = ref("" as Coordinates);
|
||||
const nicknameModel = ref("" as Nickname);
|
||||
const emailModel = ref("" as EmailAddress);
|
||||
const monitoringModel = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
if (props.hostname) {
|
||||
hostnameModel.value = props.hostname;
|
||||
}
|
||||
if (props.fastdKey) {
|
||||
fastdKeyModel.value = props.fastdKey;
|
||||
}
|
||||
if (props.mac) {
|
||||
macModel.value = props.mac;
|
||||
}
|
||||
});
|
||||
|
||||
async function onSubmit() {
|
||||
generalError.value = false;
|
||||
|
@ -61,13 +81,13 @@ async function onSubmit() {
|
|||
|
||||
try {
|
||||
const node = await nodeStore.create({
|
||||
hostname: hostname.value,
|
||||
key: fastdKey.value || undefined,
|
||||
mac: mac.value,
|
||||
coords: coords.value || undefined,
|
||||
nickname: nickname.value,
|
||||
email: email.value,
|
||||
monitoring: monitoring.value,
|
||||
hostname: hostnameModel.value,
|
||||
key: fastdKeyModel.value || undefined,
|
||||
mac: macModel.value,
|
||||
coords: coordsModel.value || undefined,
|
||||
nickname: nicknameModel.value,
|
||||
email: emailModel.value,
|
||||
monitoring: monitoringModel.value,
|
||||
});
|
||||
emit("create", node);
|
||||
} catch (error) {
|
||||
|
@ -114,7 +134,7 @@ async function onSubmit() {
|
|||
Beim Anlegen des Knotens ist ein Fehler aufgetreten. Bitte
|
||||
probiere es später nochmal. Sollte dieses Problem weiter
|
||||
bestehen, so wende dich bitte per E-Mail an
|
||||
<a :href="`mailto:${email}`">{{ email }}</a
|
||||
<a :href="`mailto:${emailModel}`">{{ emailModel }}</a
|
||||
>.
|
||||
</ErrorCard>
|
||||
|
||||
|
@ -122,7 +142,7 @@ async function onSubmit() {
|
|||
<h3>Knotendaten</h3>
|
||||
|
||||
<ValidationFormInput
|
||||
v-model="hostname"
|
||||
v-model="hostnameModel"
|
||||
label="Knotenname"
|
||||
placeholder="z. B. Lisas-Freifunk"
|
||||
:constraint="CONSTRAINTS.node.hostname"
|
||||
|
@ -130,7 +150,7 @@ async function onSubmit() {
|
|||
validation-error="Knotennamen dürfen maximal 32 Zeichen lang sein und nur Klein- und Großbuchstaben, sowie Ziffern, - und _ enthalten."
|
||||
/>
|
||||
<ValidationFormInput
|
||||
v-model="fastdKey"
|
||||
v-model="fastdKeyModel"
|
||||
label="VPN-Schlüssel (bitte nur weglassen, wenn Du weisst, was Du tust)"
|
||||
placeholder="Dein 64-stelliger VPN-Schlüssel"
|
||||
:constraint="CONSTRAINTS.node.key"
|
||||
|
@ -138,7 +158,7 @@ async function onSubmit() {
|
|||
validation-error="Knotennamen dürfen maximal 32 Zeichen lang sein und nur Klein- und Großbuchstaben, sowie Ziffern, - und _ enthalten."
|
||||
/>
|
||||
<ValidationFormInput
|
||||
v-model="mac"
|
||||
v-model="macModel"
|
||||
label="MAC-Adresse"
|
||||
placeholder="z. B. 12:34:56:78:9a:bc oder 123456789abc"
|
||||
:constraint="CONSTRAINTS.node.mac"
|
||||
|
@ -165,14 +185,14 @@ async function onSubmit() {
|
|||
</p>
|
||||
|
||||
<ValidationFormInput
|
||||
v-model="nickname"
|
||||
v-model="nicknameModel"
|
||||
label="Nickname / Name"
|
||||
placeholder="z. B. Lisa"
|
||||
:constraint="CONSTRAINTS.node.nickname"
|
||||
validation-error="Nicknames dürfen maximal 64 Zeichen lang sein und nur Klein- und Großbuchstaben, sowie Ziffern, - und _ enthalten. Umlaute sind erlaubt."
|
||||
/>
|
||||
<ValidationFormInput
|
||||
v-model="email"
|
||||
v-model="emailModel"
|
||||
type="email"
|
||||
label="E-Mail-Adresse"
|
||||
:placeholder="`z. B. lisa@${configStore.getConfig.community.domain}`"
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
createRouter,
|
||||
createWebHistory,
|
||||
type LocationQueryRaw,
|
||||
type RouteLocationNormalized,
|
||||
} from "vue-router";
|
||||
import AdminDashboardView from "@/views/AdminDashboardView.vue";
|
||||
import AdminNodesView from "@/views/AdminNodesView.vue";
|
||||
|
@ -9,10 +10,18 @@ import HomeView from "@/views/HomeView.vue";
|
|||
import NodeCreateView from "@/views/NodeCreateView.vue";
|
||||
import NodeDeleteView from "@/views/NodeDeleteView.vue";
|
||||
import {
|
||||
hasOwnProperty,
|
||||
isFastdKey,
|
||||
isHostname,
|
||||
isMAC,
|
||||
isNodesFilter,
|
||||
isNodeSortField,
|
||||
isSearchTerm,
|
||||
isSortDirection,
|
||||
type SearchTerm,
|
||||
isString,
|
||||
type JSONValue,
|
||||
parseJSON,
|
||||
type TypeGuard,
|
||||
} from "@/types";
|
||||
|
||||
export interface Route {
|
||||
|
@ -35,6 +44,39 @@ export function route(name: RouteName, query?: LocationQueryRaw): Route {
|
|||
};
|
||||
}
|
||||
|
||||
function getQueryField<T>(
|
||||
route: RouteLocationNormalized,
|
||||
field: string,
|
||||
isT: TypeGuard<T>
|
||||
): T | undefined {
|
||||
if (!hasOwnProperty(route.query, field)) {
|
||||
return undefined;
|
||||
}
|
||||
const value = route.query[field];
|
||||
return isT(value) ? value : undefined;
|
||||
}
|
||||
|
||||
function getJSONQueryField<T>(
|
||||
route: RouteLocationNormalized,
|
||||
field: string,
|
||||
isT: TypeGuard<T>
|
||||
): T | undefined {
|
||||
const value = getQueryField(route, field, isString);
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let json: JSONValue;
|
||||
try {
|
||||
json = parseJSON(value);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return isT(json) ? json : undefined;
|
||||
}
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
|
@ -47,6 +89,11 @@ const router = createRouter({
|
|||
path: "/node/create",
|
||||
name: RouteName.NODE_CREATE,
|
||||
component: NodeCreateView,
|
||||
props: (route) => ({
|
||||
hostname: getQueryField(route, "hostname", isHostname),
|
||||
fastdKey: getQueryField(route, "key", isFastdKey),
|
||||
mac: getQueryField(route, "mac", isMAC),
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: "/node/delete",
|
||||
|
@ -62,35 +109,12 @@ const router = createRouter({
|
|||
path: "/admin/nodes",
|
||||
name: RouteName.ADMIN_NODES,
|
||||
component: AdminNodesView,
|
||||
props: (route) => {
|
||||
let filter: unknown;
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(route.query, "filter")
|
||||
) {
|
||||
try {
|
||||
filter = JSON.parse(route.query.filter as string);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
filter = {};
|
||||
}
|
||||
} else {
|
||||
filter = {};
|
||||
}
|
||||
|
||||
const searchTerm = route.query.q
|
||||
? (route.query.q as SearchTerm)
|
||||
: undefined;
|
||||
return {
|
||||
filter: isNodesFilter(filter) ? filter : {},
|
||||
searchTerm,
|
||||
sortDirection: isSortDirection(route.query.sortDir)
|
||||
? route.query.sortDir
|
||||
: undefined,
|
||||
sortField: isNodeSortField(route.query.sortField)
|
||||
? route.query.sortField
|
||||
: undefined,
|
||||
};
|
||||
},
|
||||
props: (route) => ({
|
||||
filter: getJSONQueryField(route, "filter", isNodesFilter) || {},
|
||||
searchTerm: getQueryField(route, "q", isSearchTerm),
|
||||
sortDirection: getQueryField(route, "sortDir", isSortDirection),
|
||||
sortField: getQueryField(route, "sortField", isNodeSortField),
|
||||
}),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
|
|
@ -3,8 +3,15 @@ import PageContainer from "@/components/page/PageContainer.vue";
|
|||
import NodeCreateForm from "@/components/nodes/NodeCreateForm.vue";
|
||||
import NodeCreatedPanel from "@/components/nodes/NodeCreatedPanel.vue";
|
||||
import { ref } from "vue";
|
||||
import type { StoredNode, Token } from "@/types";
|
||||
import type { FastdKey, Hostname, MAC, StoredNode } from "@/types";
|
||||
|
||||
interface Props {
|
||||
hostname?: Hostname;
|
||||
fastdKey?: FastdKey;
|
||||
mac?: MAC;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const createdNode = ref<StoredNode | undefined>(undefined);
|
||||
|
||||
async function onCreate(node: StoredNode) {
|
||||
|
@ -14,7 +21,13 @@ async function onCreate(node: StoredNode) {
|
|||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<NodeCreateForm v-if="!createdNode" @create="onCreate" />
|
||||
<NodeCreateForm
|
||||
v-if="!createdNode"
|
||||
@create="onCreate"
|
||||
:hostname="props.hostname"
|
||||
:fastdKey="props.fastdKey"
|
||||
:mac="props.mac"
|
||||
/>
|
||||
<NodeCreatedPanel v-if="createdNode" :node="createdNode" />
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
|
Loading…
Reference in a new issue