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