[backport cloud/1.38] feat: remove obsolete model asset feature flags (#8568)

Backport of #8566 to `cloud/1.38`

Automatically created by backport workflow.

Co-authored-by: Luke Mino-Altherr <luke@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Comfy Org PR Bot
2026-02-03 12:12:25 +09:00
committed by GitHub
parent cb86a1c94e
commit aca98890b2
10 changed files with 25 additions and 244 deletions

View File

@@ -15,13 +15,10 @@ export enum ServerFeatureFlag {
MAX_UPLOAD_SIZE = 'max_upload_size',
MANAGER_SUPPORTS_V4 = 'extension.manager.supports_v4',
MODEL_UPLOAD_BUTTON_ENABLED = 'model_upload_button_enabled',
ASSET_DELETION_ENABLED = 'asset_deletion_enabled',
ASSET_RENAME_ENABLED = 'asset_rename_enabled',
PRIVATE_MODELS_ENABLED = 'private_models_enabled',
ONBOARDING_SURVEY_ENABLED = 'onboarding_survey_enabled',
HUGGINGFACE_MODEL_IMPORT_ENABLED = 'huggingface_model_import_enabled',
LINEAR_TOGGLE_ENABLED = 'linear_toggle_enabled',
ASYNC_MODEL_UPLOAD_ENABLED = 'async_model_upload_enabled',
TEAM_WORKSPACES_ENABLED = 'team_workspaces_enabled',
USER_SECRETS_ENABLED = 'user_secrets_enabled'
}
@@ -41,7 +38,6 @@ export function useFeatureFlags() {
return api.getServerFeature(ServerFeatureFlag.MANAGER_SUPPORTS_V4)
},
get modelUploadButtonEnabled() {
// Check remote config first (from /api/features), fall back to websocket feature flags
return (
remoteConfig.value.model_upload_button_enabled ??
api.getServerFeature(
@@ -50,12 +46,6 @@ export function useFeatureFlags() {
)
)
},
get assetDeletionEnabled() {
return (
remoteConfig.value.asset_deletion_enabled ??
api.getServerFeature(ServerFeatureFlag.ASSET_DELETION_ENABLED, false)
)
},
get assetRenameEnabled() {
return (
remoteConfig.value.asset_rename_enabled ??
@@ -63,7 +53,6 @@ export function useFeatureFlags() {
)
},
get privateModelsEnabled() {
// Check remote config first (from /api/features), fall back to websocket feature flags
return (
remoteConfig.value.private_models_enabled ??
api.getServerFeature(ServerFeatureFlag.PRIVATE_MODELS_ENABLED, false)
@@ -75,30 +64,12 @@ export function useFeatureFlags() {
api.getServerFeature(ServerFeatureFlag.ONBOARDING_SURVEY_ENABLED, true)
)
},
get huggingfaceModelImportEnabled() {
return (
remoteConfig.value.huggingface_model_import_enabled ??
api.getServerFeature(
ServerFeatureFlag.HUGGINGFACE_MODEL_IMPORT_ENABLED,
false
)
)
},
get linearToggleEnabled() {
return (
remoteConfig.value.linear_toggle_enabled ??
api.getServerFeature(ServerFeatureFlag.LINEAR_TOGGLE_ENABLED, false)
)
},
get asyncModelUploadEnabled() {
return (
remoteConfig.value.async_model_upload_enabled ??
api.getServerFeature(
ServerFeatureFlag.ASYNC_MODEL_UPLOAD_ENABLED,
false
)
)
},
/**
* Whether team workspaces feature is enabled.
* IMPORTANT: Returns false until authenticated remote config is loaded.

View File

@@ -54,7 +54,6 @@
>
<template #default>
<Button
v-if="flags.assetDeletionEnabled"
variant="secondary"
size="md"
class="justify-start"
@@ -141,7 +140,6 @@ import MoreButton from '@/components/button/MoreButton.vue'
import StatusBadge from '@/components/common/StatusBadge.vue'
import { showConfirmDialog } from '@/components/dialog/confirm/confirmDialog'
import Button from '@/components/ui/button/Button.vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import AssetBadgeGroup from '@/platform/assets/components/AssetBadgeGroup.vue'
import type { AssetDisplayItem } from '@/platform/assets/composables/useAssetBrowser'
import { assetService } from '@/platform/assets/services/assetService'
@@ -167,7 +165,6 @@ const emit = defineEmits<{
const { t } = useI18n()
const settingStore = useSettingStore()
const { closeDialog } = useDialogStore()
const { flags } = useFeatureFlags()
const { isDownloadedThisSession, acknowledgeAsset } = useAssetDownloadStore()
const dropdownMenuButton = useTemplateRef<InstanceType<typeof MoreButton>>(
@@ -181,11 +178,7 @@ const displayName = computed(() => getAssetDisplayName(asset))
const isNewlyImported = computed(() => isDownloadedThisSession(asset.id))
const showAssetOptions = computed(
() =>
(flags.assetDeletionEnabled || flags.assetRenameEnabled) &&
!(asset.is_immutable ?? true)
)
const showAssetOptions = computed(() => !(asset.is_immutable ?? true))
const tooltipDelay = computed<number>(() =>
settingStore.get('LiteGraph.Node.TooltipDelay')

View File

@@ -6,12 +6,7 @@
<div class="min-h-0 flex-auto basis-0 overflow-y-auto">
<!-- Step 1: Enter URL -->
<UploadModelUrlInput
v-if="currentStep === 1 && flags.huggingfaceModelImportEnabled"
v-model="wizardData.url"
:error="uploadError"
/>
<UploadModelUrlInputCivitai
v-else-if="currentStep === 1"
v-if="currentStep === 1"
v-model="wizardData.url"
:error="uploadError"
/>
@@ -56,17 +51,14 @@
<script setup lang="ts">
import { onMounted } from 'vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import UploadModelConfirmation from '@/platform/assets/components/UploadModelConfirmation.vue'
import UploadModelFooter from '@/platform/assets/components/UploadModelFooter.vue'
import UploadModelProgress from '@/platform/assets/components/UploadModelProgress.vue'
import UploadModelUrlInput from '@/platform/assets/components/UploadModelUrlInput.vue'
import UploadModelUrlInputCivitai from '@/platform/assets/components/UploadModelUrlInputCivitai.vue'
import { useModelTypes } from '@/platform/assets/composables/useModelTypes'
import { useUploadModelWizard } from '@/platform/assets/composables/useUploadModelWizard'
import { useDialogStore } from '@/stores/dialogStore'
const { flags } = useFeatureFlags()
const dialogStore = useDialogStore()
const { modelTypes, fetchModelTypes } = useModelTypes()

View File

@@ -1,11 +1,6 @@
<template>
<div class="flex items-center gap-2 p-4 font-bold">
<img
v-if="!flags.huggingfaceModelImportEnabled"
src="/assets/images/civitai.svg"
class="size-4"
/>
<span>{{ $t(titleKey) }}</span>
<span>{{ $t('assetBrowser.uploadModelGeneric') }}</span>
<span
class="rounded-full bg-white px-1.5 py-0 text-xxs font-inter font-semibold uppercase text-black"
>
@@ -13,17 +8,3 @@
</span>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
const { flags } = useFeatureFlags()
const titleKey = computed(() => {
return flags.huggingfaceModelImportEnabled
? 'assetBrowser.uploadModelGeneric'
: 'assetBrowser.uploadModelFromCivitai'
})
</script>

View File

@@ -1,9 +1,6 @@
<template>
<div class="flex justify-end gap-2 w-full">
<div
v-if="currentStep === 1 && flags.huggingfaceModelImportEnabled"
class="mr-auto flex items-center gap-2"
>
<div v-if="currentStep === 1" class="mr-auto flex items-center gap-2">
<i class="icon-[lucide--circle-question-mark] text-muted-foreground" />
<Button
variant="muted-textonly"
@@ -22,17 +19,6 @@
{{ $t('assetBrowser.providerHuggingFace') }}
</Button>
</div>
<Button
v-else-if="currentStep === 1"
variant="muted-textonly"
size="lg"
class="mr-auto underline"
data-attr="upload-model-step1-help-link"
@click="showCivitaiHelp = true"
>
<i class="icon-[lucide--circle-question-mark]" />
<span>{{ $t('assetBrowser.uploadModelHowDoIFindThis') }}</span>
</Button>
<Button
v-if="currentStep === 1"
variant="muted-textonly"
@@ -124,11 +110,8 @@
import { ref } from 'vue'
import Button from '@/components/ui/button/Button.vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import VideoHelpDialog from '@/platform/assets/components/VideoHelpDialog.vue'
const { flags } = useFeatureFlags()
const showCivitaiHelp = ref(false)
const showHuggingFaceHelp = ref(false)

View File

@@ -55,15 +55,6 @@
<p v-if="error" class="text-sm text-error">
{{ error }}
</p>
<p v-else-if="!flags.asyncModelUploadEnabled" class="text-foreground">
<i18n-t keypath="assetBrowser.maxFileSize" tag="span">
<template #size>
<span class="font-bold italic">{{
$t('assetBrowser.maxFileSizeValue')
}}</span>
</template>
</i18n-t>
</p>
</div>
</div>

View File

@@ -1,111 +0,0 @@
<template>
<div class="flex flex-col gap-6 text-sm text-muted-foreground">
<div class="flex flex-col gap-2">
<p class="m-0">
{{ $t('assetBrowser.uploadModelDescription1') }}
</p>
<ul class="list-disc space-y-1 pl-5 mt-0">
<li>
<i18n-t keypath="assetBrowser.uploadModelDescription2" tag="span">
<template #link>
<a
href="https://civitai.com/models"
target="_blank"
class="text-muted-foreground underline"
>
{{ $t('assetBrowser.uploadModelDescription2Link') }}
</a>
</template>
</i18n-t>
</li>
<li v-if="!flags.asyncModelUploadEnabled">
<i18n-t keypath="assetBrowser.uploadModelDescription3" tag="span">
<template #size>
<span class="font-bold italic">{{
$t('assetBrowser.maxFileSizeValue')
}}</span>
</template>
</i18n-t>
</li>
</ul>
</div>
<div class="flex flex-col gap-2">
<i18n-t keypath="assetBrowser.civitaiLinkLabel" tag="label" class="mb-0">
<template #download>
<span class="font-bold italic">{{
$t('assetBrowser.civitaiLinkLabelDownload')
}}</span>
</template>
</i18n-t>
<InputText
v-model="url"
autofocus
:placeholder="$t('assetBrowser.civitaiLinkPlaceholder')"
class="w-full border-0 bg-secondary-background p-4"
data-attr="upload-model-step1-url-input"
/>
<p v-if="error" class="text-sm text-error">
{{ error }}
</p>
<i18n-t
v-else
keypath="assetBrowser.civitaiLinkExample"
tag="p"
class="text-sm"
>
<template #example>
<strong>{{ $t('assetBrowser.civitaiLinkExampleStrong') }}</strong>
</template>
<template #link>
<a
href="https://civitai.com/models/10706/luisap-z-image-and-qwen-pixel-art-refiner?modelVersionId=2225295"
target="_blank"
class="text-muted-foreground underline"
>
{{ $t('assetBrowser.civitaiLinkExampleUrl') }}
</a>
</template>
</i18n-t>
<div v-if="showSecretsHint" class="text-sm text-muted">
<i18n-t keypath="assetBrowser.apiKeyHint" tag="span">
<template #link>
<Button
variant="textonly"
size="unset"
class="text-muted underline p-0"
@click="openSecretsSettings"
>
{{ $t('assetBrowser.apiKeyHintLink') }}
</Button>
</template>
</i18n-t>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import InputText from 'primevue/inputtext'
import { computed } from 'vue'
import Button from '@/components/ui/button/Button.vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import { useDialogService } from '@/services/dialogService'
const { flags } = useFeatureFlags()
const dialogService = useDialogService()
const showSecretsHint = computed(() => flags.userSecretsEnabled)
function openSecretsSettings() {
dialogService.showSettingsDialog('secrets')
}
defineProps<{
error?: string
}>()
const url = defineModel<string>({ required: true })
</script>

View File

@@ -1,10 +1,11 @@
import { computed } from 'vue'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import UploadModelDialog from '@/platform/assets/components/UploadModelDialog.vue'
import UploadModelDialogHeader from '@/platform/assets/components/UploadModelDialogHeader.vue'
import UploadModelUpgradeModal from '@/platform/assets/components/UploadModelUpgradeModal.vue'
import UploadModelUpgradeModalHeader from '@/platform/assets/components/UploadModelUpgradeModalHeader.vue'
import { useDialogStore } from '@/stores/dialogStore'
import { computed } from 'vue'
export function useModelUpload(
onUploadSuccess?: () => Promise<unknown> | void
@@ -15,7 +16,6 @@ export function useModelUpload(
function showUploadDialog() {
if (!flags.privateModelsEnabled) {
// Show upgrade modal if private models are disabled
dialogStore.showDialog({
key: 'upload-model-upgrade',
headerComponent: UploadModelUpgradeModalHeader,
@@ -28,7 +28,6 @@ export function useModelUpload(
}
})
} else {
// Show regular upload modal
dialogStore.showDialog({
key: 'upload-model',
headerComponent: UploadModelDialogHeader,

View File

@@ -2,7 +2,6 @@ import type { Ref } from 'vue'
import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useFeatureFlags } from '@/composables/useFeatureFlags'
import { st } from '@/i18n'
import { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'
import { huggingfaceImportSource } from '@/platform/assets/importSources/huggingfaceImportSource'
@@ -32,7 +31,6 @@ export function useUploadModelWizard(modelTypes: Ref<ModelTypeOption[]>) {
const assetsStore = useAssetsStore()
const assetDownloadStore = useAssetDownloadStore()
const modelToNodeStore = useModelToNodeStore()
const { flags } = useFeatureFlags()
const currentStep = ref(1)
const isFetchingMetadata = ref(false)
const isUploading = ref(false)
@@ -47,10 +45,10 @@ export function useUploadModelWizard(modelTypes: Ref<ModelTypeOption[]>) {
const selectedModelType = ref<string>()
// Available import sources
const importSources: ImportSource[] = flags.huggingfaceModelImportEnabled
? [civitaiImportSource, huggingfaceImportSource]
: [civitaiImportSource]
const importSources: ImportSource[] = [
civitaiImportSource,
huggingfaceImportSource
]
// Detected import source based on URL
const detectedSource = computed(() => {
@@ -233,40 +231,27 @@ export function useUploadModelWizard(modelTypes: Ref<ModelTypeOption[]>) {
model_type: selectedModelType.value
}
if (flags.asyncModelUploadEnabled) {
const result = await assetService.uploadAssetAsync({
source_url: wizardData.value.url,
tags,
user_metadata: userMetadata,
preview_id: previewId
})
const result = await assetService.uploadAssetAsync({
source_url: wizardData.value.url,
tags,
user_metadata: userMetadata,
preview_id: previewId
})
if (result.type === 'async' && result.task.status !== 'completed') {
if (selectedModelType.value) {
assetDownloadStore.trackDownload(
result.task.task_id,
selectedModelType.value,
filename
)
}
uploadStatus.value = 'processing'
} else {
uploadStatus.value = 'success'
await refreshModelCaches()
if (result.type === 'async' && result.task.status !== 'completed') {
if (selectedModelType.value) {
assetDownloadStore.trackDownload(
result.task.task_id,
selectedModelType.value,
filename
)
}
currentStep.value = 3
uploadStatus.value = 'processing'
} else {
await assetService.uploadAssetFromUrl({
url: wizardData.value.url,
name: filename,
tags,
user_metadata: userMetadata,
preview_id: previewId
})
uploadStatus.value = 'success'
await refreshModelCaches()
currentStep.value = 3
}
currentStep.value = 3
} catch (error) {
console.error('Failed to upload asset:', error)
uploadStatus.value = 'error'

View File

@@ -35,13 +35,10 @@ export type RemoteConfig = {
firebase_config?: FirebaseRuntimeConfig
telemetry_disabled_events?: TelemetryEventName[]
model_upload_button_enabled?: boolean
asset_deletion_enabled?: boolean
asset_rename_enabled?: boolean
private_models_enabled?: boolean
onboarding_survey_enabled?: boolean
huggingface_model_import_enabled?: boolean
linear_toggle_enabled?: boolean
async_model_upload_enabled?: boolean
team_workspaces_enabled?: boolean
user_secrets_enabled?: boolean
}