11<template >
22 <div class =" upload-model-dialog flex flex-col justify-between gap-6 p-4 pt-6" >
33 <!-- Step 1: Enter URL -->
4- <UploadModelUrlInput v-if =" currentStep === 1" v-model =" wizardData.url" />
4+ <UploadModelUrlInput
5+ v-if =" currentStep === 1"
6+ v-model =" wizardData.url"
7+ :error =" uploadError"
8+ />
59
610 <!-- Step 2: Confirm Metadata -->
711 <UploadModelConfirmation
7377</template >
7478
7579<script setup lang="ts">
76- import { computed , onMounted , ref } from ' vue'
80+ import { computed , onMounted , ref , watch } from ' vue'
7781
7882import IconTextButton from ' @/components/button/IconTextButton.vue'
7983import TextButton from ' @/components/button/TextButton.vue'
@@ -120,6 +124,14 @@ const selectedModelType = ref<string>('loras')
120124
121125const { modelTypes, fetchModelTypes } = useModelTypes ()
122126
127+ // Clear error when URL changes
128+ watch (
129+ () => wizardData .value .url ,
130+ () => {
131+ uploadError .value = ' '
132+ }
133+ )
134+
123135// Validation
124136const canFetchMetadata = computed (() => {
125137 return wizardData .value .url .trim ().length > 0
@@ -132,6 +144,24 @@ const canUploadModel = computed(() => {
132144async function handleFetchMetadata() {
133145 if (! canFetchMetadata .value ) return
134146
147+ // Validate that URL is from Civitai domain
148+ const isCivitaiUrl = (url : string ): boolean => {
149+ try {
150+ const urlObj = new URL (url )
151+ return (
152+ urlObj .hostname === ' civitai.com' ||
153+ urlObj .hostname .endsWith (' .civitai.com' )
154+ )
155+ } catch {
156+ return false
157+ }
158+ }
159+
160+ if (! isCivitaiUrl (wizardData .value .url )) {
161+ uploadError .value = ' Only Civitai URLs are supported'
162+ return
163+ }
164+
135165 isFetchingMetadata .value = true
136166 try {
137167 const metadata = await assetService .getAssetMetadata (wizardData .value .url )
0 commit comments