Compare commits
4 commits
e7ada4b47d
...
0e60183372
Author | SHA1 | Date | |
---|---|---|---|
0e60183372 | |||
ed948d642a | |||
c923c2dbf4 | |||
b0650a5bf4 |
6 changed files with 982 additions and 57 deletions
|
@ -19,7 +19,7 @@
|
||||||
"openapi-fetch": "^0.14.0",
|
"openapi-fetch": "^0.14.0",
|
||||||
"roboto-fontface": "*",
|
"roboto-fontface": "*",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vuetify": "^3.8.1"
|
"vuetify": "^3.9.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.24.0",
|
"@eslint/js": "^9.24.0",
|
||||||
|
@ -42,6 +42,7 @@
|
||||||
"unplugin-vue-components": "^28.5.0",
|
"unplugin-vue-components": "^28.5.0",
|
||||||
"unplugin-vue-router": "^0.12.0",
|
"unplugin-vue-router": "^0.12.0",
|
||||||
"vite": "^6.2.6",
|
"vite": "^6.2.6",
|
||||||
|
"vite-plugin-vue-devtools": "^7.7.7",
|
||||||
"vite-plugin-vuetify": "^2.1.1",
|
"vite-plugin-vuetify": "^2.1.1",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
"vue-tsc": "^2.2.8"
|
"vue-tsc": "^2.2.8"
|
||||||
|
|
950
frontend/pnpm-lock.yaml
generated
950
frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, useId, useTemplateRef } from "vue";
|
import { computed, ref, useId, useTemplateRef } from "vue";
|
||||||
import CountryListItem from "./CountryListItem.vue";
|
import CountryListItem from "./CountryListItem.vue";
|
||||||
import { Country, getAvailableCountries } from "../utils/countries";
|
import { type Country, getAvailableCountries, userCountry } from "../utils/countries.ts";
|
||||||
|
|
||||||
const formModel = ref(false);
|
const formModel = ref(false);
|
||||||
const formRef = useTemplateRef("form");
|
const formRef = useTemplateRef("form");
|
||||||
|
@ -16,16 +16,13 @@ const commonName = ref("");
|
||||||
const emailAddress = ref("");
|
const emailAddress = ref("");
|
||||||
const organization = ref("");
|
const organization = ref("");
|
||||||
const organizationalUnit = ref("");
|
const organizationalUnit = ref("");
|
||||||
const country = ref("");
|
const country = ref(userCountry?.alpha2);
|
||||||
const countryName = ref("");
|
const countryName = ref("");
|
||||||
const state = ref("");
|
const state = ref("");
|
||||||
const locality = ref("");
|
const locality = ref("");
|
||||||
|
|
||||||
// Countries data for autocomplete
|
// Countries data for autocomplete
|
||||||
const countries = ref<(Country | { divider: boolean; header: string })[]>([]);
|
const countries = ref(getAvailableCountries());
|
||||||
|
|
||||||
// Initialize countries list
|
|
||||||
countries.value = getAvailableCountries();
|
|
||||||
|
|
||||||
// Certificate settings
|
// Certificate settings
|
||||||
const keyLength = ref(4096);
|
const keyLength = ref(4096);
|
||||||
|
@ -35,20 +32,20 @@ const noExpiry = ref(false);
|
||||||
// Validation rules
|
// Validation rules
|
||||||
const domainRules = [
|
const domainRules = [
|
||||||
(value: string) => !!value || "A value must be provided to add the domain.",
|
(value: string) => !!value || "A value must be provided to add the domain.",
|
||||||
(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.)",
|
(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.)"
|
||||||
]
|
];
|
||||||
|
|
||||||
const emailRules = [
|
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 = [
|
const keyLengthRules = [
|
||||||
(value: number) => value >= 3000 || "Key length must be at least 3000 bits.",
|
(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 = [
|
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."
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,6 +64,7 @@ function addDomain() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSubmitting = ref(false);
|
const isSubmitting = ref(false);
|
||||||
|
|
||||||
async function submitNewCertificate() {
|
async function submitNewCertificate() {
|
||||||
if (!formRef.value?.validate()) {
|
if (!formRef.value?.validate()) {
|
||||||
return;
|
return;
|
||||||
|
@ -75,7 +73,7 @@ async function submitNewCertificate() {
|
||||||
isSubmitting.value = true;
|
isSubmitting.value = true;
|
||||||
try {
|
try {
|
||||||
// Extract country code if country is an object
|
// 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 as Country).alpha2
|
||||||
: country.value;
|
: country.value;
|
||||||
|
|
||||||
|
@ -91,10 +89,10 @@ async function submitNewCertificate() {
|
||||||
organizationalUnit: organizationalUnit.value,
|
organizationalUnit: organizationalUnit.value,
|
||||||
country: countryCode,
|
country: countryCode,
|
||||||
state: state.value,
|
state: state.value,
|
||||||
locality: locality.value,
|
locality: locality.value
|
||||||
},
|
},
|
||||||
extension: {
|
extension: {
|
||||||
alternativeDnsNames: domains.value,
|
alternativeDnsNames: domains.value
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -147,8 +145,11 @@ async function submitNewCertificate() {
|
||||||
hint="Search and select your country"
|
hint="Search and select your country"
|
||||||
class="mb-2"
|
class="mb-2"
|
||||||
>
|
>
|
||||||
<template #item="slotProps">
|
<template #item="{ props, item }">
|
||||||
<CountryListItem :item="slotProps.item" :props="slotProps.props" />
|
<CountryListItem
|
||||||
|
:item="item"
|
||||||
|
:item-props="props"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</v-autocomplete>
|
</v-autocomplete>
|
||||||
|
|
||||||
|
|
|
@ -1,45 +1,44 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// Define props with proper TypeScript typing
|
// Define props with proper TypeScript typing
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
|
import type { CountryListItemType } from "@/utils/countries.ts";
|
||||||
|
|
||||||
interface Country {
|
type ListItem<T> = {
|
||||||
country: string;
|
raw: T;
|
||||||
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
|
// Define props with proper TypeScript typing
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
item: { raw: CountryListItemType };
|
item: ListItem<CountryListItemType>;
|
||||||
props?: Record<string, unknown>;
|
itemProps?: Record<string, unknown>;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// Helper functions to check the type of the item
|
// Helper functions to check the type of the item
|
||||||
const isDivider = computed(() => {
|
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(() => {
|
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(() => {
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-divider v-if="isDivider" class="my-2" />
|
<v-divider
|
||||||
<v-list-subheader v-if="headerText">{{ headerText }}</v-list-subheader>
|
v-if="isDivider"
|
||||||
<v-list-item v-if="countryItem" v-bind="props" :title="countryItem.country" :value="countryItem.alpha2" />
|
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"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
"include": ["env.d.ts", "src/**/*", "src/**/*.ts", "src/**/*.vue"],
|
||||||
"exclude": ["src/**/__tests__/*"],
|
"exclude": ["src/**/__tests__/*"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import Components from 'unplugin-vue-components/vite'
|
||||||
import Vue from '@vitejs/plugin-vue'
|
import Vue from '@vitejs/plugin-vue'
|
||||||
import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
|
import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
|
||||||
import ViteFonts from 'unplugin-fonts/vite'
|
import ViteFonts from 'unplugin-fonts/vite'
|
||||||
|
import VueDevTools from 'vite-plugin-vue-devtools';
|
||||||
|
|
||||||
import VueRouter from 'unplugin-vue-router/vite'
|
import VueRouter from 'unplugin-vue-router/vite'
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
|
@ -32,6 +33,9 @@ export default defineConfig({
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
VueDevTools({
|
||||||
|
launchEditor: process.env.DEVTOOLS_LAUNCH_EDITOR ?? 'idea',
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
define: { 'process.env': {} },
|
define: { 'process.env': {} },
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue