mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-28 18:22:40 +00:00
Compare commits
4 Commits
v1.39.9
...
enable-non
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8423f64ca | ||
|
|
2eb7b8c994 | ||
|
|
3eccf3ec61 | ||
|
|
1b73b5b31e |
50
CODEOWNERS
50
CODEOWNERS
@@ -2,57 +2,57 @@
|
||||
* @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Desktop/Electron
|
||||
/apps/desktop-ui/ @benceruleanlu
|
||||
/src/stores/electronDownloadStore.ts @benceruleanlu
|
||||
/src/extensions/core/electronAdapter.ts @benceruleanlu
|
||||
/vite.electron.config.mts @benceruleanlu
|
||||
/apps/desktop-ui/ @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
/src/stores/electronDownloadStore.ts @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
/src/extensions/core/electronAdapter.ts @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
/vite.electron.config.mts @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Common UI Components
|
||||
/src/components/chip/ @viva-jinyi
|
||||
/src/components/card/ @viva-jinyi
|
||||
/src/components/button/ @viva-jinyi
|
||||
/src/components/input/ @viva-jinyi
|
||||
/src/components/chip/ @viva-jinyi @Comfy-org/comfy_frontend_devs
|
||||
/src/components/card/ @viva-jinyi @Comfy-org/comfy_frontend_devs
|
||||
/src/components/button/ @viva-jinyi @Comfy-org/comfy_frontend_devs
|
||||
/src/components/input/ @viva-jinyi @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Topbar
|
||||
/src/components/topbar/ @pythongosssss
|
||||
/src/components/topbar/ @pythongosssss @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Thumbnail
|
||||
/src/renderer/core/thumbnail/ @pythongosssss
|
||||
/src/renderer/core/thumbnail/ @pythongosssss @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Legacy UI
|
||||
/scripts/ui/ @pythongosssss
|
||||
/scripts/ui/ @pythongosssss @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Link rendering
|
||||
/src/renderer/core/canvas/links/ @benceruleanlu
|
||||
/src/renderer/core/canvas/links/ @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Partner Nodes
|
||||
/src/composables/node/useNodePricing.ts @jojodecayz @bigcat88
|
||||
/src/composables/node/useNodePricing.ts @jojodecayz @bigcat88 @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Node help system
|
||||
/src/utils/nodeHelpUtil.ts @benceruleanlu
|
||||
/src/stores/workspace/nodeHelpStore.ts @benceruleanlu
|
||||
/src/services/nodeHelpService.ts @benceruleanlu
|
||||
/src/utils/nodeHelpUtil.ts @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
/src/stores/workspace/nodeHelpStore.ts @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
/src/services/nodeHelpService.ts @benceruleanlu @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Selection toolbox
|
||||
/src/components/graph/selectionToolbox/ @Myestery
|
||||
/src/components/graph/selectionToolbox/ @Myestery @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Minimap
|
||||
/src/renderer/extensions/minimap/ @jtydhr88 @Myestery
|
||||
/src/renderer/extensions/minimap/ @jtydhr88 @Myestery @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Workflow Templates
|
||||
/src/platform/workflow/templates/ @Myestery @christian-byrne @comfyui-wiki
|
||||
/src/components/templates/ @Myestery @christian-byrne @comfyui-wiki
|
||||
/src/platform/workflow/templates/ @Myestery @christian-byrne @comfyui-wiki @Comfy-org/comfy_frontend_devs
|
||||
/src/components/templates/ @Myestery @christian-byrne @comfyui-wiki @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Mask Editor
|
||||
/src/extensions/core/maskeditor.ts @trsommer @brucew4yn3rp
|
||||
/src/extensions/core/maskEditorLayerFilenames.ts @trsommer @brucew4yn3rp
|
||||
/src/extensions/core/maskeditor.ts @trsommer @brucew4yn3rp @Comfy-org/comfy_frontend_devs
|
||||
/src/extensions/core/maskEditorLayerFilenames.ts @trsommer @brucew4yn3rp @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# 3D
|
||||
/src/extensions/core/load3d.ts @jtydhr88
|
||||
/src/components/load3d/ @jtydhr88
|
||||
/src/extensions/core/load3d.ts @jtydhr88 @Comfy-org/comfy_frontend_devs
|
||||
/src/components/load3d/ @jtydhr88 @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Manager
|
||||
/src/workbench/extensions/manager/ @viva-jinyi @christian-byrne @ltdrdata
|
||||
/src/workbench/extensions/manager/ @viva-jinyi @christian-byrne @ltdrdata @Comfy-org/comfy_frontend_devs
|
||||
|
||||
# Translations
|
||||
/src/locales/ @Comfy-Org/comfy_maintainer @Comfy-org/comfy_frontend_devs
|
||||
|
||||
@@ -422,8 +422,9 @@ import { createGridStyle } from '@/utils/gridUtil'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const { onClose: originalOnClose } = defineProps<{
|
||||
const { onClose: originalOnClose, initialCategory = 'all' } = defineProps<{
|
||||
onClose: () => void
|
||||
initialCategory?: string
|
||||
}>()
|
||||
|
||||
// Track session time for telemetry
|
||||
@@ -547,7 +548,7 @@ const allTemplates = computed(() => {
|
||||
})
|
||||
|
||||
// Navigation
|
||||
const selectedNavItem = ref<string | null>('all')
|
||||
const selectedNavItem = ref<string | null>(initialCategory)
|
||||
|
||||
// Filter templates based on selected navigation item
|
||||
const navigationFilteredTemplates = computed(() => {
|
||||
|
||||
@@ -254,9 +254,6 @@ const isLoadingBalance = isLoading
|
||||
|
||||
const displayedCredits = computed(() => {
|
||||
if (initState.value !== 'ready') return ''
|
||||
// Wait for subscription to load
|
||||
if (subscription.value === null) return ''
|
||||
if (!isActiveSubscription.value) return '0'
|
||||
|
||||
// API field is named _micros but contains cents (naming inconsistency)
|
||||
const cents =
|
||||
@@ -343,9 +340,7 @@ const toggleWorkspaceSwitcher = (event: MouseEvent) => {
|
||||
}
|
||||
|
||||
const refreshBalance = () => {
|
||||
if (isActiveSubscription.value) {
|
||||
void fetchBalance()
|
||||
}
|
||||
void fetchBalance()
|
||||
}
|
||||
|
||||
defineExpose({ refreshBalance })
|
||||
|
||||
@@ -3,6 +3,14 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { useBillingContext } from './useBillingContext'
|
||||
|
||||
vi.mock('@/composables/useFeatureFlags', () => ({
|
||||
useFeatureFlags: () => ({
|
||||
flags: {
|
||||
teamWorkspacesEnabled: true
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/workspace/stores/teamWorkspaceStore', () => {
|
||||
const isInPersonalWorkspace = { value: true }
|
||||
const activeWorkspace = { value: { id: 'personal-123', type: 'personal' } }
|
||||
@@ -10,6 +18,7 @@ vi.mock('@/platform/workspace/stores/teamWorkspaceStore', () => {
|
||||
useTeamWorkspaceStore: () => ({
|
||||
isInPersonalWorkspace: isInPersonalWorkspace.value,
|
||||
activeWorkspace: activeWorkspace.value,
|
||||
updateActiveWorkspace: vi.fn(),
|
||||
_setPersonalWorkspace: (value: boolean) => {
|
||||
isInPersonalWorkspace.value = value
|
||||
activeWorkspace.value = value
|
||||
@@ -80,7 +89,10 @@ vi.mock('@/platform/workspace/api/workspaceApi', () => ({
|
||||
currency: 'usd'
|
||||
}),
|
||||
subscribe: vi.fn().mockResolvedValue({ status: 'subscribed' }),
|
||||
previewSubscribe: vi.fn().mockResolvedValue({ allowed: true })
|
||||
previewSubscribe: vi.fn().mockResolvedValue({ allowed: true }),
|
||||
getPaymentPortalUrl: vi
|
||||
.fn()
|
||||
.mockResolvedValue({ url: 'https://example.com/billing' })
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -90,35 +102,37 @@ describe('useBillingContext', () => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('returns legacy type for personal workspace', () => {
|
||||
it('returns workspace type for personal workspace when feature flag enabled', () => {
|
||||
const { type } = useBillingContext()
|
||||
expect(type.value).toBe('legacy')
|
||||
expect(type.value).toBe('workspace')
|
||||
})
|
||||
|
||||
it('provides subscription info from legacy billing', () => {
|
||||
const { subscription } = useBillingContext()
|
||||
it('provides subscription info from workspace billing', async () => {
|
||||
const { subscription, initialize } = useBillingContext()
|
||||
await initialize()
|
||||
|
||||
expect(subscription.value).toEqual({
|
||||
isActive: true,
|
||||
tier: 'PRO',
|
||||
duration: 'MONTHLY',
|
||||
planSlug: null,
|
||||
renewalDate: 'Jan 1, 2025',
|
||||
renewalDate: null,
|
||||
endDate: null,
|
||||
isCancelled: false,
|
||||
hasFunds: true
|
||||
})
|
||||
})
|
||||
|
||||
it('provides balance info from legacy billing', () => {
|
||||
const { balance } = useBillingContext()
|
||||
it('provides balance info from workspace billing', async () => {
|
||||
const { balance, initialize } = useBillingContext()
|
||||
await initialize()
|
||||
|
||||
expect(balance.value).toEqual({
|
||||
amountMicros: 5000000,
|
||||
amountMicros: 10000000,
|
||||
currency: 'usd',
|
||||
effectiveBalanceMicros: 5000000,
|
||||
prepaidBalanceMicros: 0,
|
||||
cloudCreditBalanceMicros: 0
|
||||
effectiveBalanceMicros: undefined,
|
||||
prepaidBalanceMicros: undefined,
|
||||
cloudCreditBalanceMicros: undefined
|
||||
})
|
||||
})
|
||||
|
||||
@@ -139,7 +153,7 @@ describe('useBillingContext', () => {
|
||||
|
||||
it('exposes subscribe action', async () => {
|
||||
const { subscribe } = useBillingContext()
|
||||
await expect(subscribe('pro-monthly')).resolves.toBeUndefined()
|
||||
await expect(subscribe('pro-monthly')).resolves.toBeDefined()
|
||||
})
|
||||
|
||||
it('exposes manageSubscription action', async () => {
|
||||
|
||||
@@ -83,13 +83,11 @@ function useBillingContextInternal(): BillingContext {
|
||||
/**
|
||||
* Determines which billing type to use:
|
||||
* - If team workspaces feature is disabled: always use legacy (/customers)
|
||||
* - If team workspaces feature is enabled:
|
||||
* - Personal workspace: use legacy (/customers)
|
||||
* - Team workspace: use workspace (/billing)
|
||||
* - If team workspaces feature is enabled: always use workspace (/billing)
|
||||
*/
|
||||
const type = computed<BillingType>(() => {
|
||||
if (!flags.teamWorkspacesEnabled) return 'legacy'
|
||||
return store.isInPersonalWorkspace ? 'legacy' : 'workspace'
|
||||
return 'workspace'
|
||||
})
|
||||
|
||||
const activeContext = computed(() =>
|
||||
@@ -121,7 +119,7 @@ function useBillingContextInternal(): BillingContext {
|
||||
watch(
|
||||
subscription,
|
||||
(sub) => {
|
||||
if (!sub || store.isInPersonalWorkspace) return
|
||||
if (!sub) return
|
||||
|
||||
store.updateActiveWorkspace({
|
||||
isSubscribed: sub.isActive && !sub.isCancelled,
|
||||
|
||||
132
src/composables/useWorkflowTemplateSelectorDialog.test.ts
Normal file
132
src/composables/useWorkflowTemplateSelectorDialog.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mockDialogService = vi.hoisted(() => ({
|
||||
showLayoutDialog: vi.fn()
|
||||
}))
|
||||
|
||||
const mockDialogStore = vi.hoisted(() => ({
|
||||
closeDialog: vi.fn()
|
||||
}))
|
||||
|
||||
const mockNewUserService = vi.hoisted(() => ({
|
||||
isNewUser: vi.fn()
|
||||
}))
|
||||
|
||||
const mockTelemetry = vi.hoisted(() => ({
|
||||
trackTemplateLibraryOpened: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/services/dialogService', () => ({
|
||||
useDialogService: () => mockDialogService
|
||||
}))
|
||||
|
||||
vi.mock('@/stores/dialogStore', () => ({
|
||||
useDialogStore: () => mockDialogStore
|
||||
}))
|
||||
|
||||
vi.mock('@/services/useNewUserService', () => ({
|
||||
useNewUserService: () => mockNewUserService
|
||||
}))
|
||||
|
||||
vi.mock('@/platform/telemetry', () => ({
|
||||
useTelemetry: () => mockTelemetry
|
||||
}))
|
||||
|
||||
vi.mock(
|
||||
'@/components/custom/widget/WorkflowTemplateSelectorDialog.vue',
|
||||
() => ({
|
||||
default: { name: 'MockWorkflowTemplateSelectorDialog' }
|
||||
})
|
||||
)
|
||||
|
||||
import { useWorkflowTemplateSelectorDialog } from './useWorkflowTemplateSelectorDialog'
|
||||
|
||||
describe('useWorkflowTemplateSelectorDialog', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('show', () => {
|
||||
it('defaults to "all" category for non-new users', () => {
|
||||
mockNewUserService.isNewUser.mockReturnValue(false)
|
||||
|
||||
const dialog = useWorkflowTemplateSelectorDialog()
|
||||
dialog.show()
|
||||
|
||||
expect(mockDialogService.showLayoutDialog).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
props: expect.objectContaining({
|
||||
initialCategory: 'all'
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('defaults to "basics-getting-started" category for new users', () => {
|
||||
mockNewUserService.isNewUser.mockReturnValue(true)
|
||||
|
||||
const dialog = useWorkflowTemplateSelectorDialog()
|
||||
dialog.show()
|
||||
|
||||
expect(mockDialogService.showLayoutDialog).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
props: expect.objectContaining({
|
||||
initialCategory: 'basics-getting-started'
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('defaults to "all" when new user status is undetermined', () => {
|
||||
mockNewUserService.isNewUser.mockReturnValue(null)
|
||||
|
||||
const dialog = useWorkflowTemplateSelectorDialog()
|
||||
dialog.show()
|
||||
|
||||
expect(mockDialogService.showLayoutDialog).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
props: expect.objectContaining({
|
||||
initialCategory: 'all'
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('uses explicit initialCategory when provided', () => {
|
||||
mockNewUserService.isNewUser.mockReturnValue(true)
|
||||
|
||||
const dialog = useWorkflowTemplateSelectorDialog()
|
||||
dialog.show('command', { initialCategory: 'custom-category' })
|
||||
|
||||
expect(mockDialogService.showLayoutDialog).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
props: expect.objectContaining({
|
||||
initialCategory: 'custom-category'
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('tracks telemetry with source', () => {
|
||||
mockNewUserService.isNewUser.mockReturnValue(false)
|
||||
|
||||
const dialog = useWorkflowTemplateSelectorDialog()
|
||||
dialog.show('sidebar')
|
||||
|
||||
expect(mockTelemetry.trackTemplateLibraryOpened).toHaveBeenCalledWith({
|
||||
source: 'sidebar'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('hide', () => {
|
||||
it('closes the dialog', () => {
|
||||
const dialog = useWorkflowTemplateSelectorDialog()
|
||||
dialog.hide()
|
||||
|
||||
expect(mockDialogStore.closeDialog).toHaveBeenCalledWith({
|
||||
key: 'global-workflow-template-selector'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,26 +1,37 @@
|
||||
import WorkflowTemplateSelectorDialog from '@/components/custom/widget/WorkflowTemplateSelectorDialog.vue'
|
||||
import { useTelemetry } from '@/platform/telemetry'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useNewUserService } from '@/services/useNewUserService'
|
||||
import { useDialogStore } from '@/stores/dialogStore'
|
||||
|
||||
const DIALOG_KEY = 'global-workflow-template-selector'
|
||||
const GETTING_STARTED_CATEGORY_ID = 'basics-getting-started'
|
||||
|
||||
export const useWorkflowTemplateSelectorDialog = () => {
|
||||
const dialogService = useDialogService()
|
||||
const dialogStore = useDialogStore()
|
||||
const newUserService = useNewUserService()
|
||||
|
||||
function hide() {
|
||||
dialogStore.closeDialog({ key: DIALOG_KEY })
|
||||
}
|
||||
|
||||
function show(source: 'sidebar' | 'menu' | 'command' = 'command') {
|
||||
function show(
|
||||
source: 'sidebar' | 'menu' | 'command' = 'command',
|
||||
options?: { initialCategory?: string }
|
||||
) {
|
||||
useTelemetry()?.trackTemplateLibraryOpened({ source })
|
||||
|
||||
const initialCategory =
|
||||
options?.initialCategory ??
|
||||
(newUserService.isNewUser() ? GETTING_STARTED_CATEGORY_ID : 'all')
|
||||
|
||||
dialogService.showLayoutDialog({
|
||||
key: DIALOG_KEY,
|
||||
component: WorkflowTemplateSelectorDialog,
|
||||
props: {
|
||||
onClose: hide
|
||||
onClose: hide,
|
||||
initialCategory
|
||||
},
|
||||
dialogComponentProps: {
|
||||
pt: {
|
||||
|
||||
@@ -23,11 +23,9 @@ export function getComfyApiBaseUrl(): string {
|
||||
return BUILD_TIME_API_BASE_URL
|
||||
}
|
||||
|
||||
return configValueOrDefault(
|
||||
remoteConfig.value,
|
||||
'comfy_api_base_url',
|
||||
BUILD_TIME_API_BASE_URL
|
||||
)
|
||||
// In cloud mode, proxy all comfy-api requests through the cloud server
|
||||
// instead of calling api.comfy.org directly
|
||||
return ''
|
||||
}
|
||||
|
||||
export function getComfyPlatformBaseUrl(): string {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { defineAsyncComponent } from 'vue'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useDialogStore } from '@/stores/dialogStore'
|
||||
import { useFeatureFlags } from '@/composables/useFeatureFlags'
|
||||
import { useTeamWorkspaceStore } from '@/platform/workspace/stores/teamWorkspaceStore'
|
||||
|
||||
const DIALOG_KEY = 'subscription-required'
|
||||
|
||||
@@ -10,15 +9,13 @@ export const useSubscriptionDialog = () => {
|
||||
const { flags } = useFeatureFlags()
|
||||
const dialogService = useDialogService()
|
||||
const dialogStore = useDialogStore()
|
||||
const workspaceStore = useTeamWorkspaceStore()
|
||||
|
||||
function hide() {
|
||||
dialogStore.closeDialog({ key: DIALOG_KEY })
|
||||
}
|
||||
|
||||
function show() {
|
||||
const useWorkspaceVariant =
|
||||
flags.teamWorkspacesEnabled && !workspaceStore.isInPersonalWorkspace
|
||||
const useWorkspaceVariant = flags.teamWorkspacesEnabled
|
||||
|
||||
const component = useWorkspaceVariant
|
||||
? defineAsyncComponent(
|
||||
|
||||
@@ -4,11 +4,10 @@ import { ref } from 'vue'
|
||||
|
||||
import type { components, operations } from '@/types/comfyRegistryTypes'
|
||||
import { isAbortError } from '@/utils/typeGuardUtil'
|
||||
|
||||
const API_BASE_URL = 'https://api.comfy.org'
|
||||
import { getComfyApiBaseUrl } from '@/config/comfyApi'
|
||||
|
||||
const registryApiClient = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
baseURL: getComfyApiBaseUrl(),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
|
||||
@@ -340,10 +340,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
email: string,
|
||||
password: string
|
||||
): Promise<UserCredential> => {
|
||||
const result = await executeAuthAction(
|
||||
(authInstance) =>
|
||||
signInWithEmailAndPassword(authInstance, email, password),
|
||||
{ createCustomer: true }
|
||||
const result = await executeAuthAction((authInstance) =>
|
||||
signInWithEmailAndPassword(authInstance, email, password)
|
||||
)
|
||||
|
||||
if (isCloud) {
|
||||
@@ -361,10 +359,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
email: string,
|
||||
password: string
|
||||
): Promise<UserCredential> => {
|
||||
const result = await executeAuthAction(
|
||||
(authInstance) =>
|
||||
createUserWithEmailAndPassword(authInstance, email, password),
|
||||
{ createCustomer: true }
|
||||
const result = await executeAuthAction((authInstance) =>
|
||||
createUserWithEmailAndPassword(authInstance, email, password)
|
||||
)
|
||||
|
||||
if (isCloud) {
|
||||
@@ -379,9 +375,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
}
|
||||
|
||||
const loginWithGoogle = async (): Promise<UserCredential> => {
|
||||
const result = await executeAuthAction(
|
||||
(authInstance) => signInWithPopup(authInstance, googleProvider),
|
||||
{ createCustomer: true }
|
||||
const result = await executeAuthAction((authInstance) =>
|
||||
signInWithPopup(authInstance, googleProvider)
|
||||
)
|
||||
|
||||
if (isCloud) {
|
||||
@@ -398,9 +393,8 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => {
|
||||
}
|
||||
|
||||
const loginWithGithub = async (): Promise<UserCredential> => {
|
||||
const result = await executeAuthAction(
|
||||
(authInstance) => signInWithPopup(authInstance, githubProvider),
|
||||
{ createCustomer: true }
|
||||
const result = await executeAuthAction((authInstance) =>
|
||||
signInWithPopup(authInstance, githubProvider)
|
||||
)
|
||||
|
||||
if (isCloud) {
|
||||
|
||||
Reference in New Issue
Block a user