mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
## Summary Adds the [tailwind lint plugin](https://github.com/francoismassart/eslint-plugin-tailwindcss/?tab=readme-ov-file#eslint-plugin-tailwindcss) and fixes the currently fixable rules ([v4 is still in beta](https://github.com/francoismassart/eslint-plugin-tailwindcss/?tab=readme-ov-file#about-tailwind-css-4-support)). ## Changes - **What**: Enforces things like consistent class order, and eventually can prohibit extra classes that could be utilities instead - **Dependencies**: The plugin and its types ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5984-Lint-Add-tailwind-linter-2866d73d365081d89db0d998232533bb) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com>
149 lines
4.4 KiB
Vue
149 lines
4.4 KiB
Vue
<template>
|
|
<NoResultsPlaceholder
|
|
class="pb-0"
|
|
icon="pi pi-exclamation-circle"
|
|
:title="t('missingModelsDialog.missingModels')"
|
|
:message="t('missingModelsDialog.missingModelsMessage')"
|
|
/>
|
|
<div class="mb-4 flex gap-1">
|
|
<Checkbox v-model="doNotAskAgain" binary input-id="doNotAskAgain" />
|
|
<label for="doNotAskAgain">{{
|
|
t('missingModelsDialog.doNotAskAgain')
|
|
}}</label>
|
|
</div>
|
|
<ListBox :options="missingModels" class="comfy-missing-models">
|
|
<template #option="{ option }">
|
|
<Suspense v-if="isElectron()">
|
|
<ElectronFileDownload
|
|
:url="option.url"
|
|
:label="option.label"
|
|
:error="option.error"
|
|
/>
|
|
</Suspense>
|
|
<FileDownload
|
|
v-else
|
|
:url="option.url"
|
|
:label="option.label"
|
|
:error="option.error"
|
|
/>
|
|
</template>
|
|
</ListBox>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import Checkbox from 'primevue/checkbox'
|
|
import ListBox from 'primevue/listbox'
|
|
import { computed, onBeforeUnmount, ref } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import ElectronFileDownload from '@/components/common/ElectronFileDownload.vue'
|
|
import FileDownload from '@/components/common/FileDownload.vue'
|
|
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
|
|
import { useSettingStore } from '@/platform/settings/settingStore'
|
|
import { isElectron } from '@/utils/envUtil'
|
|
|
|
// TODO: Read this from server internal API rather than hardcoding here
|
|
// as some installations may wish to use custom sources
|
|
const allowedSources = [
|
|
'https://civitai.com/',
|
|
'https://huggingface.co/',
|
|
'http://localhost:' // Included for testing usage only
|
|
]
|
|
const allowedSuffixes = ['.safetensors', '.sft']
|
|
// Models that fail above conditions but are still allowed
|
|
const whiteListedUrls = new Set([
|
|
'https://huggingface.co/stabilityai/stable-zero123/resolve/main/stable_zero123.ckpt',
|
|
'https://huggingface.co/TencentARC/T2I-Adapter/resolve/main/models/t2iadapter_depth_sd14v1.pth?download=true',
|
|
'https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth'
|
|
])
|
|
|
|
interface ModelInfo {
|
|
name: string
|
|
directory: string
|
|
directory_invalid?: boolean
|
|
url: string
|
|
downloading?: boolean
|
|
completed?: boolean
|
|
progress?: number
|
|
error?: string
|
|
folder_path?: string
|
|
}
|
|
|
|
const props = defineProps<{
|
|
missingModels: ModelInfo[]
|
|
paths: Record<string, string[]>
|
|
}>()
|
|
|
|
const { t } = useI18n()
|
|
|
|
const doNotAskAgain = ref(false)
|
|
|
|
const modelDownloads = ref<Record<string, ModelInfo>>({})
|
|
const missingModels = computed(() => {
|
|
return props.missingModels.map((model) => {
|
|
const paths = props.paths[model.directory]
|
|
if (model.directory_invalid || !paths) {
|
|
return {
|
|
label: `${model.directory} / ${model.name}`,
|
|
url: model.url,
|
|
error: 'Invalid directory specified (does this require custom nodes?)'
|
|
}
|
|
}
|
|
const downloadInfo: ModelInfo = modelDownloads.value[model.name] ?? {
|
|
downloading: false,
|
|
completed: false,
|
|
progress: 0,
|
|
error: null,
|
|
name: model.name,
|
|
directory: model.directory,
|
|
url: model.url,
|
|
folder_path: paths[0]
|
|
}
|
|
modelDownloads.value[model.name] = downloadInfo
|
|
if (!whiteListedUrls.has(model.url)) {
|
|
if (!allowedSources.some((source) => model.url.startsWith(source))) {
|
|
return {
|
|
label: `${model.directory} / ${model.name}`,
|
|
url: model.url,
|
|
error: `Download not allowed from source '${model.url}', only allowed from '${allowedSources.join("', '")}'`
|
|
}
|
|
}
|
|
if (!allowedSuffixes.some((suffix) => model.name.endsWith(suffix))) {
|
|
return {
|
|
label: `${model.directory} / ${model.name}`,
|
|
url: model.url,
|
|
error: `Only allowed suffixes are: '${allowedSuffixes.join("', '")}'`
|
|
}
|
|
}
|
|
}
|
|
return {
|
|
url: model.url,
|
|
label: `${model.directory} / ${model.name}`,
|
|
downloading: downloadInfo.downloading,
|
|
completed: downloadInfo.completed,
|
|
progress: downloadInfo.progress,
|
|
error: downloadInfo.error,
|
|
name: model.name,
|
|
paths: paths,
|
|
folderPath: downloadInfo.folder_path
|
|
}
|
|
})
|
|
})
|
|
|
|
onBeforeUnmount(async () => {
|
|
if (doNotAskAgain.value) {
|
|
await useSettingStore().set(
|
|
'Comfy.Workflow.ShowMissingModelsWarning',
|
|
false
|
|
)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.comfy-missing-models {
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
</style>
|