Skip to content

Commit

Permalink
Add url setting type (#2327)
Browse files Browse the repository at this point in the history
  • Loading branch information
huchenlei authored Jan 23, 2025
1 parent 95ff01a commit 0ab1d97
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/components/common/FormItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import CustomFormValue from '@/components/common/CustomFormValue.vue'
import FormColorPicker from '@/components/common/FormColorPicker.vue'
import FormImageUpload from '@/components/common/FormImageUpload.vue'
import InputSlider from '@/components/common/InputSlider.vue'
import UrlInput from '@/components/common/UrlInput.vue'
import { FormItem } from '@/types/settingTypes'

const formValue = defineModel<any>('formValue')
Expand Down Expand Up @@ -91,6 +92,8 @@ function getFormComponent(item: FormItem): Component {
return FormImageUpload
case 'color':
return FormColorPicker
case 'url':
return UrlInput
default:
return InputText
}
Expand Down
83 changes: 83 additions & 0 deletions src/components/common/UrlInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<template>
<IconField class="w-full">
<InputText
:model-value="modelValue"
class="w-full"
:placeholder="placeholder"
:invalid="validationState === UrlValidationState.INVALID"
@update:model-value="handleInput"
@blur="validateUrl"
/>
<InputIcon
:class="{
'pi pi-spin pi-spinner text-neutral-400':
validationState === UrlValidationState.LOADING,
'pi pi-check text-green-500':
validationState === UrlValidationState.VALID,
'pi pi-times text-red-500':
validationState === UrlValidationState.INVALID
}"
/>
</IconField>
</template>

<script setup lang="ts">
import IconField from 'primevue/iconfield'
import InputIcon from 'primevue/inputicon'
import InputText from 'primevue/inputtext'
import { ref } from 'vue'
import { isValidUrl } from '@/utils/formatUtil'
import { checkUrlReachable } from '@/utils/networkUtil'
const props = defineProps<{
modelValue: string
placeholder?: string
}>()
const emit = defineEmits<{
'update:modelValue': [value: string]
}>()
enum UrlValidationState {
IDLE = 'IDLE',
LOADING = 'LOADING',
VALID = 'VALID',
INVALID = 'INVALID'
}
const validationState = ref<UrlValidationState>(UrlValidationState.IDLE)
const handleInput = (value: string) => {
emit('update:modelValue', value)
// Reset validation state when user types
validationState.value = UrlValidationState.IDLE
}
const validateUrl = async () => {
const url = props.modelValue.trim()
// Reset state
validationState.value = UrlValidationState.IDLE
// Skip validation if empty
if (!url) return
// First check if it's a valid URL format
if (!isValidUrl(url)) {
validationState.value = UrlValidationState.INVALID
return
}
// Then check if URL is reachable
validationState.value = UrlValidationState.LOADING
try {
const reachable = await checkUrlReachable(url)
validationState.value = reachable
? UrlValidationState.VALID
: UrlValidationState.INVALID
} catch {
validationState.value = UrlValidationState.INVALID
}
}
</script>
1 change: 1 addition & 0 deletions src/types/settingTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type SettingInputType =
| 'text'
| 'image'
| 'color'
| 'url'
| 'hidden'

export type SettingCustomRenderer = (
Expand Down
9 changes: 9 additions & 0 deletions src/utils/formatUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,12 @@ export function processDynamicPrompt(input: string): string {

return result.replace(/\\([{}|])/g, '$1')
}

export function isValidUrl(url: string): boolean {
try {
new URL(url)
return true
} catch {
return false
}
}
12 changes: 12 additions & 0 deletions src/utils/networkUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import axios from 'axios'

const VALID_STATUS_CODES = [200, 201, 301, 302, 307, 308]
export const checkUrlReachable = async (url: string): Promise<boolean> => {
try {
const response = await axios.head(url)
// Additional check for successful response
return VALID_STATUS_CODES.includes(response.status)
} catch {
return false
}
}

0 comments on commit 0ab1d97

Please sign in to comment.