[API Node] Show message tip about API-key-based login (#3851)

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Chenlei Hu <hcl@comfy.org>
This commit is contained in:
Christian Byrne
2025-05-13 10:03:13 -07:00
committed by GitHub
parent 58906fa821
commit a9bdc70e28
17 changed files with 61 additions and 36 deletions

View File

@@ -67,9 +67,9 @@ import Tabs from 'primevue/tabs'
import { computed, watch } from 'vue'
import SearchBox from '@/components/common/SearchBox.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useSettingSearch } from '@/composables/setting/useSettingSearch'
import { useSettingUI } from '@/composables/setting/useSettingUI'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
import { SettingTreeNode } from '@/stores/settingStore'
import { ISettingGroup, SettingParams } from '@/types/settingTypes'
import { flattenTree } from '@/utils/treeUtil'
@@ -107,7 +107,7 @@ const {
getSearchResults
} = useSettingSearch()
const authService = useFirebaseAuthService()
const authActions = useFirebaseAuthActions()
// Sort groups for a category
const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => {
@@ -140,7 +140,7 @@ watch(activeCategory, (_, oldValue) => {
activeCategory.value = oldValue
}
if (activeCategory.value?.key === 'credits') {
void authService.fetchBalance()
void authActions.fetchBalance()
}
})
</script>

View File

@@ -101,6 +101,15 @@
{{ t('auth.apiKey.generateKey') }}
</a>
</small>
<Message
v-if="authActions.accessError.value"
severity="info"
icon="pi pi-info-circle"
variant="outlined"
closable
>
{{ t('toastMessages.useApiKeyTip') }}
</Message>
</div>
<!-- Terms & Contact -->
@@ -134,12 +143,12 @@
import Button from 'primevue/button'
import Divider from 'primevue/divider'
import Message from 'primevue/message'
import { onMounted, ref } from 'vue'
import { onMounted, onUnmounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { COMFY_PLATFORM_BASE_URL } from '@/config/comfyApi'
import { SignInData, SignUpData } from '@/schemas/signInSchema'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
import { isInChina } from '@/utils/networkUtil'
import ApiKeyForm from './signin/ApiKeyForm.vue'
@@ -151,7 +160,7 @@ const { onSuccess } = defineProps<{
}>()
const { t } = useI18n()
const authService = useFirebaseAuthService()
const authActions = useFirebaseAuthActions()
const isSecureContext = window.isSecureContext
const isSignIn = ref(true)
const showApiKeyForm = ref(false)
@@ -162,25 +171,25 @@ const toggleState = () => {
}
const signInWithGoogle = async () => {
if (await authService.signInWithGoogle()) {
if (await authActions.signInWithGoogle()) {
onSuccess()
}
}
const signInWithGithub = async () => {
if (await authService.signInWithGithub()) {
if (await authActions.signInWithGithub()) {
onSuccess()
}
}
const signInWithEmail = async (values: SignInData) => {
if (await authService.signInWithEmail(values.email, values.password)) {
if (await authActions.signInWithEmail(values.email, values.password)) {
onSuccess()
}
}
const signUpWithEmail = async (values: SignUpData) => {
if (await authService.signUpWithEmail(values.email, values.password)) {
if (await authActions.signUpWithEmail(values.email, values.password)) {
onSuccess()
}
}
@@ -189,4 +198,8 @@ const userIsInChina = ref(false)
onMounted(async () => {
userIsInChina.value = await isInChina()
})
onUnmounted(() => {
authActions.accessError.value = false
})
</script>

View File

@@ -51,7 +51,7 @@
import Button from 'primevue/button'
import UserCredit from '@/components/common/UserCredit.vue'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import CreditTopUpOption from './credit/CreditTopUpOption.vue'
@@ -65,9 +65,9 @@ const {
preselectedAmountOption?: number
}>()
const authService = useFirebaseAuthService()
const authActions = useFirebaseAuthActions()
const handleSeeDetails = async () => {
await authService.accessBillingPortal()
await authActions.accessBillingPortal()
}
</script>

View File

@@ -23,10 +23,10 @@ import Button from 'primevue/button'
import { ref } from 'vue'
import PasswordFields from '@/components/dialog/content/signin/PasswordFields.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { updatePasswordSchema } from '@/schemas/signInSchema'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
const authService = useFirebaseAuthService()
const authActions = useFirebaseAuthActions()
const loading = ref(false)
const { onSuccess } = defineProps<{
@@ -37,7 +37,7 @@ const onSubmit = async (event: FormSubmitEvent) => {
if (event.valid) {
loading.value = true
try {
await authService.updatePassword(event.values.password)
await authActions.updatePassword(event.values.password)
onSuccess()
} finally {
loading.value = false

View File

@@ -41,9 +41,9 @@ import ProgressSpinner from 'primevue/progressspinner'
import Tag from 'primevue/tag'
import { onBeforeUnmount, ref } from 'vue'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
const authService = useFirebaseAuthService()
const authActions = useFirebaseAuthActions()
const {
amount,
@@ -61,7 +61,7 @@ const loading = ref(false)
const handleBuyNow = async () => {
loading.value = true
await authService.purchaseCredits(editable ? customAmount.value : amount)
await authActions.purchaseCredits(editable ? customAmount.value : amount)
loading.value = false
didClickBuyNow.value = true
}
@@ -69,7 +69,7 @@ const handleBuyNow = async () => {
onBeforeUnmount(() => {
if (didClickBuyNow.value) {
// If clicked buy now, then returned back to the dialog and closed, fetch the balance
void authService.fetchBalance()
void authActions.fetchBalance()
}
})
</script>

View File

@@ -36,7 +36,7 @@
text
size="small"
severity="secondary"
@click="() => authService.fetchBalance()"
@click="() => authActions.fetchBalance()"
/>
</div>
</div>
@@ -112,8 +112,8 @@ import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import UserCredit from '@/components/common/UserCredit.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { formatMetronomeCurrency } from '@/utils/formatUtil'
@@ -127,7 +127,7 @@ interface CreditHistoryItemData {
const { t } = useI18n()
const dialogService = useDialogService()
const authStore = useFirebaseAuthStore()
const authService = useFirebaseAuthService()
const authActions = useFirebaseAuthActions()
const loading = computed(() => authStore.loading)
const balanceLoading = computed(() => authStore.isFetchingBalance)
@@ -142,7 +142,7 @@ const handlePurchaseCreditsClick = () => {
}
const handleCreditsHistoryClick = async () => {
await authService.accessBillingPortal()
await authActions.accessBillingPortal()
}
const handleMessageSupport = () => {

View File

@@ -80,12 +80,12 @@ import ProgressSpinner from 'primevue/progressspinner'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { type SignInData, signInSchema } from '@/schemas/signInSchema'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
const authStore = useFirebaseAuthStore()
const firebaseAuthService = useFirebaseAuthService()
const firebaseAuthActions = useFirebaseAuthActions()
const loading = computed(() => authStore.loading)
const { t } = useI18n()
@@ -102,6 +102,6 @@ const onSubmit = (event: FormSubmitEvent) => {
const handleForgotPassword = async (email: string) => {
if (!email) return
await firebaseAuthService.sendPasswordReset(email)
await firebaseAuthActions.sendPasswordReset(email)
}
</script>

View File

@@ -69,11 +69,11 @@ import { onMounted } from 'vue'
import UserAvatar from '@/components/common/UserAvatar.vue'
import UserCredit from '@/components/common/UserCredit.vue'
import { useCurrentUser } from '@/composables/auth/useCurrentUser'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
const { userDisplayName, userEmail, userPhotoUrl } = useCurrentUser()
const authService = useFirebaseAuthService()
const authActions = useFirebaseAuthActions()
const dialogService = useDialogService()
const handleOpenUserSettings = () => {
@@ -89,6 +89,6 @@ const handleOpenApiPricing = () => {
}
onMounted(() => {
void authService.fetchBalance()
void authActions.fetchBalance()
})
</script>

View File

@@ -1,4 +1,5 @@
import { FirebaseError } from 'firebase/app'
import { ref } from 'vue'
import { useErrorHandling } from '@/composables/useErrorHandling'
import { t } from '@/i18n'
@@ -11,11 +12,13 @@ import { usdToMicros } from '@/utils/formatUtil'
* All actions are wrapped with error handling.
* @returns {Object} - Object containing all Firebase Auth actions
*/
export const useFirebaseAuthService = () => {
export const useFirebaseAuthActions = () => {
const authStore = useFirebaseAuthStore()
const toastStore = useToastStore()
const { wrapWithErrorHandlingAsync, toastErrorHandler } = useErrorHandling()
const accessError = ref(false)
const reportError = (error: unknown) => {
// Ref: https://firebase.google.com/docs/auth/admin/errors
if (
@@ -26,6 +29,7 @@ export const useFirebaseAuthService = () => {
'auth/unauthorized-continue-uri'
].includes(error.code)
) {
accessError.value = true
toastStore.add({
severity: 'error',
summary: t('g.error'),
@@ -141,6 +145,7 @@ export const useFirebaseAuthService = () => {
signInWithGithub,
signInWithEmail,
signUpWithEmail,
updatePassword
updatePassword,
accessError
}
}

View File

@@ -5,6 +5,7 @@ import {
LiteGraph
} from '@comfyorg/litegraph'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import {
DEFAULT_DARK_COLOR_PALETTE,
DEFAULT_LIGHT_COLOR_PALETTE
@@ -13,7 +14,6 @@ import { t } from '@/i18n'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthService } from '@/services/firebaseAuthService'
import { useLitegraphService } from '@/services/litegraphService'
import { useWorkflowService } from '@/services/workflowService'
import type { ComfyCommand } from '@/stores/commandStore'
@@ -32,7 +32,7 @@ export function useCoreCommands(): ComfyCommand[] {
const workflowStore = useWorkflowStore()
const dialogService = useDialogService()
const colorPaletteStore = useColorPaletteStore()
const firebaseAuthService = useFirebaseAuthService()
const firebaseAuthActions = useFirebaseAuthActions()
const toastStore = useToastStore()
const getTracker = () => workflowStore.activeWorkflow?.changeTracker
@@ -671,7 +671,7 @@ export function useCoreCommands(): ComfyCommand[] {
label: 'Sign Out',
versionAdded: '1.18.1',
function: async () => {
await firebaseAuthService.logout()
await firebaseAuthActions.logout()
}
}
]

View File

@@ -1259,7 +1259,8 @@
"failedToInitiateCreditPurchase": "Failed to initiate credit purchase: {error}",
"failedToAccessBillingPortal": "Failed to access billing portal: {error}",
"failedToPurchaseCredits": "Failed to purchase credits: {error}",
"unauthorizedDomain": "Your domain {domain} is not authorized to use this service. Please contact {email} to add your domain to the whitelist."
"unauthorizedDomain": "Your domain {domain} is not authorized to use this service. Please contact {email} to add your domain to the whitelist.",
"useApiKeyTip": "Tip: Can't access normal login? Use the Comfy API Key option."
},
"auth": {
"apiKey": {

View File

@@ -1362,6 +1362,7 @@
"unableToGetModelFilePath": "No se puede obtener la ruta del archivo del modelo",
"unauthorizedDomain": "Tu dominio {domain} no está autorizado para usar este servicio. Por favor, contacta a {email} para agregar tu dominio a la lista blanca.",
"updateRequested": "Actualización solicitada",
"useApiKeyTip": "Consejo: ¿No puedes acceder al inicio de sesión normal? Usa la opción de clave API de Comfy.",
"userNotAuthenticated": "Usuario no autenticado"
},
"userSelect": {

View File

@@ -1362,6 +1362,7 @@
"unableToGetModelFilePath": "Impossible d'obtenir le chemin du fichier modèle",
"unauthorizedDomain": "Votre domaine {domain} n'est pas autorisé à utiliser ce service. Veuillez contacter {email} pour ajouter votre domaine à la liste blanche.",
"updateRequested": "Mise à jour demandée",
"useApiKeyTip": "Astuce : Vous ne pouvez pas accéder à la connexion normale ? Utilisez loption Clé API Comfy.",
"userNotAuthenticated": "Utilisateur non authentifié"
},
"userSelect": {

View File

@@ -1362,6 +1362,7 @@
"unableToGetModelFilePath": "モデルファイルのパスを取得できません",
"unauthorizedDomain": "あなたのドメイン {domain} はこのサービスを利用する権限がありません。ご利用のドメインをホワイトリストに追加するには、{email} までご連絡ください。",
"updateRequested": "更新が要求されました",
"useApiKeyTip": "ヒント通常のログインにアクセスできませんかComfy APIキーオプションを使用してください。",
"userNotAuthenticated": "ユーザーが認証されていません"
},
"userSelect": {

View File

@@ -1362,6 +1362,7 @@
"unableToGetModelFilePath": "모델 파일 경로를 가져올 수 없습니다",
"unauthorizedDomain": "귀하의 도메인 {domain}은(는) 이 서비스를 사용할 수 있는 권한이 없습니다. 도메인을 허용 목록에 추가하려면 {email}로 문의해 주세요.",
"updateRequested": "업데이트 요청됨",
"useApiKeyTip": "팁: 일반 로그인을 사용할 수 없나요? Comfy API Key 옵션을 사용하세요.",
"userNotAuthenticated": "사용자가 인증되지 않았습니다"
},
"userSelect": {

View File

@@ -1362,6 +1362,7 @@
"unableToGetModelFilePath": "Не удалось получить путь к файлу модели",
"unauthorizedDomain": "Ваш домен {domain} не авторизован для использования этого сервиса. Пожалуйста, свяжитесь с {email}, чтобы добавить ваш домен в белый список.",
"updateRequested": "Запрошено обновление",
"useApiKeyTip": "Совет: Нет доступа к обычному входу? Используйте опцию Comfy API Key.",
"userNotAuthenticated": "Пользователь не аутентифицирован"
},
"userSelect": {

View File

@@ -1362,6 +1362,7 @@
"unableToGetModelFilePath": "无法获取模型文件路径",
"unauthorizedDomain": "您的域名 {domain} 未被授权使用此服务。请联系 {email} 将您的域名添加到白名单。",
"updateRequested": "已请求更新",
"useApiKeyTip": "提示:无法正常登录?请使用 Comfy API Key 选项。",
"userNotAuthenticated": "用户未认证"
},
"userSelect": {