Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: add upgrade modal for model upload when private models disabled
Add separate upgrade modal that displays when users without private models
try to upload models, prompting them to upgrade their subscription.

- Add upgrade modal with body, header, and footer components
- Conditionally show upgrade or upload modal based on privateModelsEnabled flag
- Integrate with subscription system via showSubscriptionDialog()
- Add localization keys for upgrade messaging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
  • Loading branch information
luke-mino-altherr and claude committed Dec 4, 2025
commit 62bd595a99a2df216c014e952eda9fd8aeecd43f
9 changes: 8 additions & 1 deletion src/composables/useFeatureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ 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_UPDATE_OPTIONS_ENABLED = 'asset_update_options_enabled'
ASSET_UPDATE_OPTIONS_ENABLED = 'asset_update_options_enabled',
PRIVATE_MODELS_ENABLED = 'private_models_enabled'
}

/**
Expand Down Expand Up @@ -47,6 +48,12 @@ export function useFeatureFlags() {
false
)
)
},
get privateModelsEnabled() {
return api.getServerFeature(
ServerFeatureFlag.PRIVATE_MODELS_ENABLED,
false
)
}
})

Expand Down
2 changes: 2 additions & 0 deletions src/locales/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -2121,6 +2121,8 @@
"modelUploaded": "Model imported! 🎉",
"findInLibrary": "Find it in the {type} section of the models library.",
"finish": "Finish",
"upgradeToUnlockFeature": "Upgrade to unlock this feature",
"upgradeFeatureDescription": "This feature is only available with Creator or Pro plans.",
"allModels": "All Models",
"allCategory": "All {category}",
"unknown": "Unknown",
Expand Down
47 changes: 47 additions & 0 deletions src/platform/assets/components/UploadModelUpgradeModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<div
class="upload-model-upgrade-modal flex flex-col justify-between gap-6 p-4 pt-6 border-t-[1px] border-border-default"
>
<!-- Upgrade Content -->
<UploadModelUpgradeModalBody />

<!-- Footer -->
<UploadModelUpgradeModalFooter
@close="handleClose"
@subscribe="handleSubscribe"
/>
</div>
</template>

<script setup lang="ts">
import UploadModelUpgradeModalBody from '@/platform/assets/components/UploadModelUpgradeModalBody.vue'
import UploadModelUpgradeModalFooter from '@/platform/assets/components/UploadModelUpgradeModalFooter.vue'
import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'
import { useDialogStore } from '@/stores/dialogStore'

const dialogStore = useDialogStore()
const { showSubscriptionDialog } = useSubscription()

function handleClose() {
dialogStore.closeDialog({ key: 'upload-model-upgrade' })
}

function handleSubscribe() {
showSubscriptionDialog()
}
</script>

<style scoped>
.upload-model-upgrade-modal {
width: 90vw;
max-width: 500px;
min-height: 200px;
}

@media (min-width: 640px) {
.upload-model-upgrade-modal {
width: auto;
min-width: 450px;
}
}
</style>
11 changes: 11 additions & 0 deletions src/platform/assets/components/UploadModelUpgradeModalBody.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<div
class="flex flex-1 flex-col items-center justify-center gap-6 text-base text-muted-foreground"
>
<p class="m-0 max-w-md">
{{ $t('assetBrowser.upgradeFeatureDescription') }}
</p>
</div>
</template>

<script setup lang="ts"></script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>
<div class="flex justify-end gap-2 w-full">
<span
class="text-muted-foreground mr-auto underline flex items-center gap-2"
>
<i class="icon-[lucide--circle-question-mark]" />
<a
href="https://blog.comfy.org/p/comfy-cloud-new-features-and-pricing"
target="_blank"
class="text-muted-foreground"
>{{ $t('Learn more') }}</a
>
</span>
<TextButton
:label="$t('g.close')"
type="transparent"
size="md"
@click="emit('close')"
/>
<TextButton
:label="$t('Subscribe')"
type="secondary"
size="md"
@click="emit('subscribe')"
/>
</div>
</template>

<script setup lang="ts">
import TextButton from '@/components/button/TextButton.vue'

const emit = defineEmits<{
(e: 'close'): void
(e: 'subscribe'): void
}>()
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div class="flex items-center gap-2 p-4 font-bold">
<span>{{ $t('assetBrowser.upgradeToUnlockFeature') }}</span>
</div>
</template>
46 changes: 32 additions & 14 deletions src/platform/assets/composables/useModelUpload.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
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 type { AssetItem } from '@/platform/assets/schemas/assetSchema'
import { useDialogStore } from '@/stores/dialogStore'
import type { UseAsyncStateReturn } from '@vueuse/core'
Expand All @@ -14,22 +16,38 @@ export function useModelUpload(
const isUploadButtonEnabled = computed(() => flags.modelUploadButtonEnabled)

function showUploadDialog() {
dialogStore.showDialog({
key: 'upload-model',
headerComponent: UploadModelDialogHeader,
component: UploadModelDialog,
props: {
onUploadSuccess: async () => {
await execute?.()
if (!flags.privateModelsEnabled) {
// Show upgrade modal if private models are disabled
dialogStore.showDialog({
key: 'upload-model-upgrade',
headerComponent: UploadModelUpgradeModalHeader,
component: UploadModelUpgradeModal,
dialogComponentProps: {
pt: {
header: 'py-0! pl-0!',
content: 'p-0!'
}
}
},
dialogComponentProps: {
pt: {
header: 'py-0! pl-0!',
content: 'p-0!'
})
} else {
// Show regular upload modal
dialogStore.showDialog({
key: 'upload-model',
headerComponent: UploadModelDialogHeader,
component: UploadModelDialog,
props: {
onUploadSuccess: async () => {
await execute?.()
}
},
dialogComponentProps: {
pt: {
header: 'py-0! pl-0!',
content: 'p-0!'
}
}
}
})
})
}
}
return { isUploadButtonEnabled, showUploadDialog }
}