Compare commits

...

3 commits

Author SHA1 Message Date
22eae92cba
wip: Start work on submitting the cert
Some checks failed
Build / build (pull_request) Successful in 54s
Check formatting / check-formatting (pull_request) Failing after 17s
2025-07-14 22:11:18 +02:00
651c205656
feat: Install tanstack query for Vue 2025-07-14 22:10:51 +02:00
13efdd06b9
wip: Prepare CertificateEditor for submitting a certificate 2025-07-14 21:51:11 +02:00
5 changed files with 107 additions and 31 deletions

View file

@ -14,6 +14,7 @@
},
"dependencies": {
"@mdi/font": "7.4.47",
"@tanstack/vue-query": "^5.83.0",
"core-js": "^3.41.0",
"iso-3166-1": "^2.1.1",
"openapi-fetch": "^0.14.0",

View file

@ -11,6 +11,9 @@ importers:
'@mdi/font':
specifier: 7.4.47
version: 7.4.47
'@tanstack/vue-query':
specifier: ^5.83.0
version: 5.83.0(vue@3.5.13(typescript@5.8.3))
core-js:
specifier: ^3.41.0
version: 3.41.0
@ -798,6 +801,22 @@ packages:
resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
engines: {node: '>=18'}
'@tanstack/match-sorter-utils@8.19.4':
resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==}
engines: {node: '>=12'}
'@tanstack/query-core@5.83.0':
resolution: {integrity: sha512-0M8dA+amXUkyz5cVUm/B+zSk3xkQAcuXuz5/Q/LveT4ots2rBpPTZOzd7yJa2Utsf8D2Upl5KyjhHRY+9lB/XA==}
'@tanstack/vue-query@5.83.0':
resolution: {integrity: sha512-sC3nnFEyAPOV4aGgt36ILrFIoR42UzRb+kqva96tiT3c80PCX99wDnVC5P01uxw6b3PaH7AD60HFFLBMFCKYow==}
peerDependencies:
'@vue/composition-api': ^1.1.2
vue: ^2.6.0 || ^3.3.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
'@tsconfig/node22@22.0.1':
resolution: {integrity: sha512-VkgOa3n6jvs1p+r3DiwBqeEwGAwEvnVCg/hIjiANl5IEcqP3G0u5m8cBJspe1t9qjZRlZ7WFgqq5bJrGdgAKMg==}
@ -1934,6 +1953,9 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
remove-accents@0.5.0:
resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==}
request-light@0.7.0:
resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==}
@ -2502,6 +2524,17 @@ packages:
vscode-uri@3.0.8:
resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
vue-demi@0.14.10:
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
engines: {node: '>=12'}
hasBin: true
peerDependencies:
'@vue/composition-api': ^1.0.0-rc.1
vue: ^3.0.0-0 || ^2.6.0
peerDependenciesMeta:
'@vue/composition-api':
optional: true
vue-eslint-parser@10.1.3:
resolution: {integrity: sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@ -3235,6 +3268,20 @@ snapshots:
'@sindresorhus/merge-streams@4.0.0': {}
'@tanstack/match-sorter-utils@8.19.4':
dependencies:
remove-accents: 0.5.0
'@tanstack/query-core@5.83.0': {}
'@tanstack/vue-query@5.83.0(vue@3.5.13(typescript@5.8.3))':
dependencies:
'@tanstack/match-sorter-utils': 8.19.4
'@tanstack/query-core': 5.83.0
'@vue/devtools-api': 6.6.4
vue: 3.5.13(typescript@5.8.3)
vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.3))
'@tsconfig/node22@22.0.1': {}
'@types/cookie@0.6.0': {}
@ -4486,6 +4533,8 @@ snapshots:
readdirp@4.1.2: {}
remove-accents@0.5.0: {}
request-light@0.7.0: {}
require-directory@2.1.1: {}
@ -5027,6 +5076,10 @@ snapshots:
vscode-uri@3.0.8: {}
vue-demi@0.14.10(vue@3.5.13(typescript@5.8.3)):
dependencies:
vue: 3.5.13(typescript@5.8.3)
vue-eslint-parser@10.1.3(eslint@9.24.0):
dependencies:
debug: 4.4.0(supports-color@10.0.0)

View file

@ -1,7 +1,12 @@
<script setup lang="ts">
import { computed, ref, useId, useTemplateRef } from "vue";
import { ref, useId, useTemplateRef } from "vue";
import CountryListItem from "./CountryListItem.vue";
import { type Country, getAvailableCountries, userCountry } from "../utils/countries.ts";
import { type Schemas } from "../plugins/client.ts";
const { isSubmitting } = defineProps({
isSubmitting: Boolean,
})
const formModel = ref(false);
const formRef = useTemplateRef("form");
@ -63,41 +68,40 @@ function addDomain() {
}
}
const isSubmitting = ref(false);
const emit = defineEmits(["submit"]);
async function submitNewCertificate() {
if (!formRef.value?.validate()) {
return;
}
isSubmitting.value = true;
try {
// Extract country code if country is an object
const countryCode = typeof country.value === "object" && country.value !== null
? (country.value as Country).alpha2
: country.value;
// Extract country code if country is an object
const countryCode = typeof country.value === "object" && country.value !== null
? (country.value as Country).alpha2
: country.value;
// TODO: Implement certificate request submission
console.log({
type: "STANDALONE_CERTIFICATE",
requestedKeyLength: keyLength.value,
requestedValidityDays: noExpiry.value ? null : validityDays.value,
subject: {
commonName: commonName.value,
emailAddress: emailAddress.value,
organization: organization.value,
organizationalUnit: organizationalUnit.value,
country: countryCode,
state: state.value,
locality: locality.value
},
extension: {
alternativeDnsNames: domains.value
}
});
} finally {
isSubmitting.value = false;
}
// Prepare certificate request data
const certificateRequest: Schemas["CertificateInfo"] = {
type: "STANDALONE_CERTIFICATE",
requestedKeyLength: keyLength.value,
requestedValidityDays: noExpiry.value ? undefined : validityDays.value,
subject: {
commonName: commonName.value,
emailAddress: emailAddress.value,
organization: organization.value,
organizationalUnit: organizationalUnit.value,
country: countryCode,
state: state.value,
locality: locality.value
},
extension: {
alternativeDnsNames: domains.value
}
};
emit("submit", {
certificateRequest
});
}
</script>

View file

@ -1,10 +1,26 @@
<script setup lang="ts">
import CertificateEditor from "@/components/CertificateEditor.vue";
import { useMutation } from "@tanstack/vue-query";
import { fetchClient } from "@/plugins/client.ts";
const submitNewCert = useMutation({
mutationKey: ["submit-new-certificate"],
mutationFn: async (certificate) => {
fetchClient.POST("/api/certificates", {
body: certificate,
})
},
})
function submitCertificate({ certificate }) {
submitNewCert.mutate(certificate);
}
</script>
<template>
<v-container>
<CertificateEditor />
<CertificateEditor @submit="submitCertificate" :is-submitting="submitNewCert.isPending" />
</v-container>
</template>

View file

@ -3,10 +3,12 @@ import router from "../router";
import client from "./client";
import type { App } from "vue";
import { VueQueryPlugin } from "@tanstack/vue-query";
export function registerPlugins(app: App) {
app
.use(vuetify)
.use(router)
.use(client);
.use(client)
.use(VueQueryPlugin);
}