Compare commits

..

No commits in common. "0e60183372936e27b6b288713fdc5e50422bd1c0" and "e7ada4b47d1d2df592c84edb1d86629fbc6c6fff" have entirely different histories.

6 changed files with 57 additions and 982 deletions

View file

@ -19,7 +19,7 @@
"openapi-fetch": "^0.14.0",
"roboto-fontface": "*",
"vue": "^3.5.13",
"vuetify": "^3.9.0"
"vuetify": "^3.8.1"
},
"devDependencies": {
"@eslint/js": "^9.24.0",
@ -42,7 +42,6 @@
"unplugin-vue-components": "^28.5.0",
"unplugin-vue-router": "^0.12.0",
"vite": "^6.2.6",
"vite-plugin-vue-devtools": "^7.7.7",
"vite-plugin-vuetify": "^2.1.1",
"vue-router": "^4.5.0",
"vue-tsc": "^2.2.8"

950
frontend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
<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 { Country, getAvailableCountries } from "../utils/countries";
const formModel = ref(false);
const formRef = useTemplateRef("form");
@ -16,13 +16,16 @@ const commonName = ref("");
const emailAddress = ref("");
const organization = ref("");
const organizationalUnit = ref("");
const country = ref(userCountry?.alpha2);
const country = ref("");
const countryName = ref("");
const state = ref("");
const locality = ref("");
// Countries data for autocomplete
const countries = ref(getAvailableCountries());
const countries = ref<(Country | { divider: boolean; header: string })[]>([]);
// Initialize countries list
countries.value = getAvailableCountries();
// Certificate settings
const keyLength = ref(4096);
@ -32,20 +35,20 @@ const noExpiry = ref(false);
// Validation rules
const domainRules = [
(value: string) => !!value || "A value must be provided to add the domain.",
(value: string) => /^[a-z0-9][a-z0-9.\-_]+$|^xn--[a-z0-9.\-_]+$/i.test(value) || "Invalid domain characters provided. (To use some special characters, convert the domain to xn-domain format.)"
];
(value: string) => new RegExp("^[a-z0-9][a-z0-9.]+$").test(value) || "Invalid domain characters provided. (To use some characters, convert the domain to xn-domain format.)",
]
const emailRules = [
(value: string) => !value || /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value) || "Invalid email format."
(value: string) => !value || /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value) || "Invalid email format.",
];
const keyLengthRules = [
(value: number) => value >= 3000 || "Key length must be at least 3000 bits.",
(value: number) => value <= 6000 || "Key length must not exceed 6000 bits."
(value: number) => value <= 6000 || "Key length must not exceed 6000 bits.",
];
const validityDaysRules = [
(value: number) => !value || value > 0 || "Validity period (in days) must be a positive integer."
(value: number) => !value || value > 0 || "Validity period (in days) must be a positive integer.",
];
@ -64,7 +67,6 @@ function addDomain() {
}
const isSubmitting = ref(false);
async function submitNewCertificate() {
if (!formRef.value?.validate()) {
return;
@ -73,7 +75,7 @@ async function submitNewCertificate() {
isSubmitting.value = true;
try {
// Extract country code if country is an object
const countryCode = typeof country.value === "object" && country.value !== null
const countryCode = typeof country.value === 'object' && country.value !== null
? (country.value as Country).alpha2
: country.value;
@ -89,10 +91,10 @@ async function submitNewCertificate() {
organizationalUnit: organizationalUnit.value,
country: countryCode,
state: state.value,
locality: locality.value
locality: locality.value,
},
extension: {
alternativeDnsNames: domains.value
alternativeDnsNames: domains.value,
}
});
} finally {
@ -145,11 +147,8 @@ async function submitNewCertificate() {
hint="Search and select your country"
class="mb-2"
>
<template #item="{ props, item }">
<CountryListItem
:item="item"
:item-props="props"
/>
<template #item="slotProps">
<CountryListItem :item="slotProps.item" :props="slotProps.props" />
</template>
</v-autocomplete>

View file

@ -1,44 +1,45 @@
<script setup lang="ts">
// Define props with proper TypeScript typing
import { computed } from "vue";
import type { CountryListItemType } from "@/utils/countries.ts";
type ListItem<T> = {
raw: T;
interface Country {
country: string;
alpha2: string;
alpha3: string;
numeric: string;
}
interface Divider {
divider: boolean;
header: string;
}
// Define a type that can be either a Country or a Divider
type CountryListItemType = Country | Divider;
// Define props with proper TypeScript typing
const props = defineProps<{
item: ListItem<CountryListItemType>;
itemProps?: Record<string, unknown>;
item: { raw: CountryListItemType };
props?: Record<string, unknown>;
}>();
// Helper functions to check the type of the item
const isDivider = computed(() => {
return "divider" in props.item.raw && props.item.raw.divider;
return 'divider' in props.item.raw && props.item.raw.divider;
});
const headerText = computed(() => {
return "header" in props.item.raw ? props.item.raw.header : "";
return 'header' in props.item.raw ? props.item.raw.header : "";
});
const countryItem = computed(() => {
return !isDivider.value && !headerText.value && "country" in props.item.raw ? props.item.raw : undefined;
});
return !isDivider.value && !headerText.value && 'country' in props.item.raw ? props.item.raw: undefined;
})
</script>
<template>
<v-divider
v-if="isDivider"
class="my-2"
/>
<v-list-subheader v-if="headerText">
{{ headerText }}
</v-list-subheader>
<v-list-item
v-if="countryItem"
v-bind="itemProps"
:title="countryItem.country"
/>
<v-divider v-if="isDivider" class="my-2" />
<v-list-subheader v-if="headerText">{{ headerText }}</v-list-subheader>
<v-list-item v-if="countryItem" v-bind="props" :title="countryItem.country" :value="countryItem.alpha2" />
</template>

View file

@ -1,6 +1,6 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.ts", "src/**/*.vue"],
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,

View file

@ -2,7 +2,6 @@ import Components from 'unplugin-vue-components/vite'
import Vue from '@vitejs/plugin-vue'
import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
import ViteFonts from 'unplugin-fonts/vite'
import VueDevTools from 'vite-plugin-vue-devtools';
import VueRouter from 'unplugin-vue-router/vite'
import { defineConfig } from 'vite'
@ -33,9 +32,6 @@ export default defineConfig({
}],
},
}),
VueDevTools({
launchEditor: process.env.DEVTOOLS_LAUNCH_EDITOR ?? 'idea',
}),
],
define: { 'process.env': {} },
resolve: {