mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
[API Nodes] Signin/Signup dialog (#3466)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -49,4 +49,6 @@ const additionalInstructions = `
|
||||
7. Implement proper error handling
|
||||
8. Follow Vue 3 style guide and naming conventions
|
||||
9. Use Vite for fast development and building
|
||||
10. Use vue-i18n in composition API for any string literals. Place new translation
|
||||
entries in src/locales/en/main.json.
|
||||
`;
|
||||
|
||||
118
src/components/dialog/content/SignInContent.vue
Normal file
118
src/components/dialog/content/SignInContent.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="w-96 p-2">
|
||||
<!-- Header -->
|
||||
<div class="flex flex-col gap-4 mb-8">
|
||||
<h1 class="text-2xl font-medium leading-normal my-0">
|
||||
{{ isSignIn ? t('auth.login.title') : t('auth.signup.title') }}
|
||||
</h1>
|
||||
<p class="text-base my-0">
|
||||
<span class="text-muted">{{
|
||||
isSignIn
|
||||
? t('auth.login.newUser')
|
||||
: t('auth.signup.alreadyHaveAccount')
|
||||
}}</span>
|
||||
<span class="ml-1 cursor-pointer text-blue-500" @click="toggleState">{{
|
||||
isSignIn ? t('auth.login.signUp') : t('auth.signup.signIn')
|
||||
}}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<SignInForm v-if="isSignIn" @submit="signInWithEmail" />
|
||||
<SignUpForm v-else @submit="signInWithEmail" />
|
||||
|
||||
<!-- Divider -->
|
||||
<Divider align="center" layout="horizontal" class="my-8">
|
||||
<span class="text-muted">{{ t('auth.login.orContinueWith') }}</span>
|
||||
</Divider>
|
||||
|
||||
<!-- Social Login Buttons -->
|
||||
<div class="flex flex-col gap-6">
|
||||
<Button
|
||||
type="button"
|
||||
class="h-10"
|
||||
severity="secondary"
|
||||
outlined
|
||||
@click="signInWithGoogle"
|
||||
>
|
||||
<i class="pi pi-google mr-2"></i>
|
||||
{{
|
||||
isSignIn
|
||||
? t('auth.login.loginWithGoogle')
|
||||
: t('auth.signup.signUpWithGoogle')
|
||||
}}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
class="h-10"
|
||||
severity="secondary"
|
||||
outlined
|
||||
@click="signInWithGithub"
|
||||
>
|
||||
<i class="pi pi-github mr-2"></i>
|
||||
{{
|
||||
isSignIn
|
||||
? t('auth.login.loginWithGithub')
|
||||
: t('auth.signup.signUpWithGithub')
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
<!-- Terms -->
|
||||
<p class="text-xs text-muted mt-8">
|
||||
{{ t('auth.login.termsText') }}
|
||||
<span class="text-blue-500 cursor-pointer">{{
|
||||
t('auth.login.termsLink')
|
||||
}}</span>
|
||||
{{ t('auth.login.andText') }}
|
||||
<span class="text-blue-500 cursor-pointer">{{
|
||||
t('auth.login.privacyLink')
|
||||
}}</span
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Button from 'primevue/button'
|
||||
import Divider from 'primevue/divider'
|
||||
import { ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { SignInData, SignUpData } from '@/schemas/signInSchema'
|
||||
|
||||
import SignInForm from './signin/SignInForm.vue'
|
||||
import SignUpForm from './signin/SignUpForm.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const { onSuccess } = defineProps<{
|
||||
onSuccess: () => void
|
||||
}>()
|
||||
|
||||
const isSignIn = ref(true)
|
||||
const toggleState = () => {
|
||||
isSignIn.value = !isSignIn.value
|
||||
}
|
||||
|
||||
const signInWithGoogle = () => {
|
||||
// Implement Google login
|
||||
console.log(isSignIn.value)
|
||||
console.log('Google login clicked')
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
const signInWithGithub = () => {
|
||||
// Implement Github login
|
||||
console.log(isSignIn.value)
|
||||
console.log('Github login clicked')
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
const signInWithEmail = (values: SignInData | SignUpData) => {
|
||||
// Implement email login
|
||||
console.log(isSignIn.value)
|
||||
console.log(values)
|
||||
onSuccess()
|
||||
}
|
||||
</script>
|
||||
89
src/components/dialog/content/signin/SignInForm.vue
Normal file
89
src/components/dialog/content/signin/SignInForm.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<Form
|
||||
v-slot="$form"
|
||||
class="flex flex-col gap-6"
|
||||
:resolver="zodResolver(signInSchema)"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<!-- Email Field -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label
|
||||
class="opacity-80 text-base font-medium mb-2"
|
||||
for="comfy-org-sign-in-email"
|
||||
>
|
||||
{{ t('auth.login.emailLabel') }}
|
||||
</label>
|
||||
<InputText
|
||||
pt:root:id="comfy-org-sign-in-email"
|
||||
pt:root:autocomplete="email"
|
||||
class="h-10"
|
||||
name="email"
|
||||
type="text"
|
||||
:placeholder="t('auth.login.emailPlaceholder')"
|
||||
:invalid="$form.email?.invalid"
|
||||
/>
|
||||
<small v-if="$form.email?.invalid" class="text-red-500">{{
|
||||
$form.email.error.message
|
||||
}}</small>
|
||||
</div>
|
||||
|
||||
<!-- Password Field -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<label
|
||||
class="opacity-80 text-base font-medium"
|
||||
for="comfy-org-sign-in-password"
|
||||
>
|
||||
{{ t('auth.login.passwordLabel') }}
|
||||
</label>
|
||||
<span class="text-muted text-base font-medium cursor-pointer">
|
||||
{{ t('auth.login.forgotPassword') }}
|
||||
</span>
|
||||
</div>
|
||||
<Password
|
||||
input-id="comfy-org-sign-in-password"
|
||||
pt:pc-input-text:root:autocomplete="current-password"
|
||||
name="password"
|
||||
:feedback="false"
|
||||
toggle-mask
|
||||
:placeholder="t('auth.login.passwordPlaceholder')"
|
||||
:class="{ 'p-invalid': $form.password?.invalid }"
|
||||
fluid
|
||||
class="h-10"
|
||||
/>
|
||||
<small v-if="$form.password?.invalid" class="text-red-500">{{
|
||||
$form.password.error.message
|
||||
}}</small>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<Button
|
||||
type="submit"
|
||||
:label="t('auth.login.loginButton')"
|
||||
class="h-10 font-medium mt-4"
|
||||
/>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Form, FormSubmitEvent } from '@primevue/forms'
|
||||
import { zodResolver } from '@primevue/forms/resolvers/zod'
|
||||
import Button from 'primevue/button'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import Password from 'primevue/password'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { type SignInData, signInSchema } from '@/schemas/signInSchema'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: SignInData]
|
||||
}>()
|
||||
|
||||
const onSubmit = (event: FormSubmitEvent) => {
|
||||
if (event.valid) {
|
||||
emit('submit', event.values as SignInData)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
165
src/components/dialog/content/signin/SignUpForm.vue
Normal file
165
src/components/dialog/content/signin/SignUpForm.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<Form
|
||||
v-slot="$form"
|
||||
class="flex flex-col gap-6"
|
||||
:resolver="zodResolver(signUpSchema)"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
<!-- Email Field -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label
|
||||
class="opacity-80 text-base font-medium mb-2"
|
||||
for="comfy-org-sign-up-email"
|
||||
>
|
||||
{{ t('auth.signup.emailLabel') }}
|
||||
</label>
|
||||
<InputText
|
||||
pt:root:id="comfy-org-sign-up-email"
|
||||
pt:root:autocomplete="email"
|
||||
class="h-10"
|
||||
name="email"
|
||||
type="text"
|
||||
:placeholder="t('auth.signup.emailPlaceholder')"
|
||||
:invalid="$form.email?.invalid"
|
||||
/>
|
||||
<small v-if="$form.email?.invalid" class="text-red-500">{{
|
||||
$form.email.error.message
|
||||
}}</small>
|
||||
</div>
|
||||
|
||||
<!-- Password Field -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex justify-between items-center mb-2">
|
||||
<label
|
||||
class="opacity-80 text-base font-medium"
|
||||
for="comfy-org-sign-up-password"
|
||||
>
|
||||
{{ t('auth.signup.passwordLabel') }}
|
||||
</label>
|
||||
</div>
|
||||
<Password
|
||||
v-model="password"
|
||||
input-id="comfy-org-sign-up-password"
|
||||
pt:pc-input-text:root:autocomplete="new-password"
|
||||
name="password"
|
||||
:feedback="false"
|
||||
toggle-mask
|
||||
:placeholder="t('auth.signup.passwordPlaceholder')"
|
||||
:class="{ 'p-invalid': $form.password?.invalid }"
|
||||
fluid
|
||||
class="h-10"
|
||||
/>
|
||||
<div class="flex flex-col gap-1">
|
||||
<small
|
||||
v-if="$form.password?.dirty || $form.password?.invalid"
|
||||
class="text-sm"
|
||||
>
|
||||
{{ t('validation.password.requirements') }}:
|
||||
<ul class="mt-1 space-y-1">
|
||||
<li
|
||||
:class="{
|
||||
'text-red-500': !passwordChecks.length
|
||||
}"
|
||||
>
|
||||
{{ t('validation.password.minLength') }}
|
||||
</li>
|
||||
<li
|
||||
:class="{
|
||||
'text-red-500': !passwordChecks.uppercase
|
||||
}"
|
||||
>
|
||||
{{ t('validation.password.uppercase') }}
|
||||
</li>
|
||||
<li
|
||||
:class="{
|
||||
'text-red-500': !passwordChecks.lowercase
|
||||
}"
|
||||
>
|
||||
{{ t('validation.password.lowercase') }}
|
||||
</li>
|
||||
<li
|
||||
:class="{
|
||||
'text-red-500': !passwordChecks.number
|
||||
}"
|
||||
>
|
||||
{{ t('validation.password.number') }}
|
||||
</li>
|
||||
<li
|
||||
:class="{
|
||||
'text-red-500': !passwordChecks.special
|
||||
}"
|
||||
>
|
||||
{{ t('validation.password.special') }}
|
||||
</li>
|
||||
</ul>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password Field -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<label
|
||||
class="opacity-80 text-base font-medium mb-2"
|
||||
for="comfy-org-sign-up-confirm-password"
|
||||
>
|
||||
{{ t('auth.login.confirmPasswordLabel') }}
|
||||
</label>
|
||||
<Password
|
||||
name="confirmPassword"
|
||||
input-id="comfy-org-sign-up-confirm-password"
|
||||
pt:pc-input-text:root:autocomplete="new-password"
|
||||
:feedback="false"
|
||||
toggle-mask
|
||||
:placeholder="t('auth.login.confirmPasswordPlaceholder')"
|
||||
:class="{ 'p-invalid': $form.confirmPassword?.invalid }"
|
||||
fluid
|
||||
class="h-10"
|
||||
/>
|
||||
<small v-if="$form.confirmPassword?.error" class="text-red-500">{{
|
||||
$form.confirmPassword.error.message
|
||||
}}</small>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<Button
|
||||
type="submit"
|
||||
:label="t('auth.signup.signUpButton')"
|
||||
class="h-10 font-medium mt-4"
|
||||
/>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Form, FormSubmitEvent } from '@primevue/forms'
|
||||
import { zodResolver } from '@primevue/forms/resolvers/zod'
|
||||
import Button from 'primevue/button'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import Password from 'primevue/password'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { type SignUpData, signUpSchema } from '@/schemas/signInSchema'
|
||||
|
||||
const { t } = useI18n()
|
||||
const password = ref('')
|
||||
|
||||
// TODO: Use dynamic form to better organize the password checks.
|
||||
// Ref: https://primevue.org/forms/#dynamic
|
||||
const passwordChecks = computed(() => ({
|
||||
length: password.value.length >= 8 && password.value.length <= 32,
|
||||
uppercase: /[A-Z]/.test(password.value),
|
||||
lowercase: /[a-z]/.test(password.value),
|
||||
number: /\d/.test(password.value),
|
||||
special: /[^A-Za-z0-9]/.test(password.value)
|
||||
}))
|
||||
|
||||
const emit = defineEmits<{
|
||||
submit: [values: SignUpData]
|
||||
}>()
|
||||
|
||||
const onSubmit = (event: FormSubmitEvent) => {
|
||||
if (event.valid) {
|
||||
emit('submit', event.values as SignUpData)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1051,5 +1051,56 @@
|
||||
"noTemplatesToExport": "No templates to export",
|
||||
"failedToFetchLogs": "Failed to fetch server logs",
|
||||
"migrateToLitegraphReroute": "Reroute nodes will be removed in future versions. Click to migrate to litegraph-native reroute."
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"title": "Log in to your account",
|
||||
"newUser": "New here?",
|
||||
"signUp": "Sign up",
|
||||
"emailLabel": "Email",
|
||||
"emailPlaceholder": "Enter your email",
|
||||
"passwordLabel": "Password",
|
||||
"passwordPlaceholder": "Enter your password",
|
||||
"confirmPasswordLabel": "Confirm Password",
|
||||
"confirmPasswordPlaceholder": "Enter the same password again",
|
||||
"forgotPassword": "Forgot password?",
|
||||
"loginButton": "Log in",
|
||||
"orContinueWith": "Or continue with",
|
||||
"loginWithGoogle": "Log in with Google",
|
||||
"loginWithGithub": "Log in with Github",
|
||||
"termsText": "By clicking \"Next\" or \"Sign Up\", you agree to our",
|
||||
"termsLink": "Terms of Use",
|
||||
"andText": "and",
|
||||
"privacyLink": "Privacy Policy",
|
||||
"success": "Login successful",
|
||||
"failed": "Login failed"
|
||||
},
|
||||
"signup": {
|
||||
"title": "Create an account",
|
||||
"alreadyHaveAccount": "Already have an account?",
|
||||
"emailLabel": "Email",
|
||||
"emailPlaceholder": "Enter your email",
|
||||
"passwordLabel": "Password",
|
||||
"passwordPlaceholder": "Enter new password",
|
||||
"signUpButton": "Sign up",
|
||||
"signIn": "Sign in",
|
||||
"signUpWithGoogle": "Sign up with Google",
|
||||
"signUpWithGithub": "Sign up with Github"
|
||||
}
|
||||
},
|
||||
"validation": {
|
||||
"invalidEmail": "Invalid email address",
|
||||
"required": "Required",
|
||||
"minLength": "Must be at least {length} characters",
|
||||
"maxLength": "Must be no more than {length} characters",
|
||||
"password": {
|
||||
"requirements": "Password requirements",
|
||||
"minLength": "Must be between 8 and 32 characters",
|
||||
"uppercase": "Must contain at least one uppercase letter",
|
||||
"lowercase": "Must contain at least one lowercase letter",
|
||||
"number": "Must contain at least one number",
|
||||
"special": "Must contain at least one special character",
|
||||
"match": "Passwords must match"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,42 @@
|
||||
"message": "Este flujo de trabajo contiene nodos de API, que requieren que inicies sesión en tu cuenta para poder ejecutar.",
|
||||
"title": "Se requiere iniciar sesión para usar los nodos de API"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"andText": "y",
|
||||
"confirmPasswordLabel": "Confirmar contraseña",
|
||||
"confirmPasswordPlaceholder": "Ingresa la misma contraseña nuevamente",
|
||||
"emailLabel": "Correo electrónico",
|
||||
"emailPlaceholder": "Ingresa tu correo electrónico",
|
||||
"failed": "Inicio de sesión fallido",
|
||||
"forgotPassword": "¿Olvidaste tu contraseña?",
|
||||
"loginButton": "Iniciar sesión",
|
||||
"loginWithGithub": "Iniciar sesión con Github",
|
||||
"loginWithGoogle": "Iniciar sesión con Google",
|
||||
"newUser": "¿Eres nuevo aquí?",
|
||||
"orContinueWith": "O continuar con",
|
||||
"passwordLabel": "Contraseña",
|
||||
"passwordPlaceholder": "Ingresa tu contraseña",
|
||||
"privacyLink": "Política de privacidad",
|
||||
"signUp": "Regístrate",
|
||||
"success": "Inicio de sesión exitoso",
|
||||
"termsLink": "Términos de uso",
|
||||
"termsText": "Al hacer clic en \"Siguiente\" o \"Registrarse\", aceptas nuestros",
|
||||
"title": "Inicia sesión en tu cuenta"
|
||||
},
|
||||
"signup": {
|
||||
"alreadyHaveAccount": "¿Ya tienes una cuenta?",
|
||||
"emailLabel": "Correo electrónico",
|
||||
"emailPlaceholder": "Ingresa tu correo electrónico",
|
||||
"passwordLabel": "Contraseña",
|
||||
"passwordPlaceholder": "Ingresa una nueva contraseña",
|
||||
"signIn": "Iniciar sesión",
|
||||
"signUpButton": "Registrarse",
|
||||
"signUpWithGithub": "Registrarse con Github",
|
||||
"signUpWithGoogle": "Registrarse con Google",
|
||||
"title": "Crea una cuenta"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"errorMessage": "Error al copiar al portapapeles",
|
||||
"errorNotSupported": "API del portapapeles no soportada en su navegador",
|
||||
@@ -1043,6 +1079,21 @@
|
||||
"next": "Siguiente",
|
||||
"selectUser": "Selecciona un usuario"
|
||||
},
|
||||
"validation": {
|
||||
"invalidEmail": "Dirección de correo electrónico inválida",
|
||||
"maxLength": "No debe tener más de {length} caracteres",
|
||||
"minLength": "Debe tener al menos {length} caracteres",
|
||||
"password": {
|
||||
"lowercase": "Debe contener al menos una letra minúscula",
|
||||
"match": "Las contraseñas deben coincidir",
|
||||
"minLength": "Debe tener entre 8 y 32 caracteres",
|
||||
"number": "Debe contener al menos un número",
|
||||
"requirements": "Requisitos de la contraseña",
|
||||
"special": "Debe contener al menos un carácter especial",
|
||||
"uppercase": "Debe contener al menos una letra mayúscula"
|
||||
},
|
||||
"required": "Requerido"
|
||||
},
|
||||
"welcome": {
|
||||
"getStarted": "Empezar",
|
||||
"title": "Bienvenido a ComfyUI"
|
||||
|
||||
@@ -8,6 +8,42 @@
|
||||
"message": "Ce flux de travail contient des nœuds API, qui nécessitent que vous soyez connecté à votre compte pour pouvoir fonctionner.",
|
||||
"title": "Connexion requise pour utiliser les nœuds API"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"andText": "et",
|
||||
"confirmPasswordLabel": "Confirmer le mot de passe",
|
||||
"confirmPasswordPlaceholder": "Entrez à nouveau le même mot de passe",
|
||||
"emailLabel": "Email",
|
||||
"emailPlaceholder": "Entrez votre email",
|
||||
"failed": "Échec de la connexion",
|
||||
"forgotPassword": "Mot de passe oublié?",
|
||||
"loginButton": "Se connecter",
|
||||
"loginWithGithub": "Se connecter avec Github",
|
||||
"loginWithGoogle": "Se connecter avec Google",
|
||||
"newUser": "Nouveau ici?",
|
||||
"orContinueWith": "Ou continuer avec",
|
||||
"passwordLabel": "Mot de passe",
|
||||
"passwordPlaceholder": "Entrez votre mot de passe",
|
||||
"privacyLink": "Politique de confidentialité",
|
||||
"signUp": "S'inscrire",
|
||||
"success": "Connexion réussie",
|
||||
"termsLink": "Conditions d'utilisation",
|
||||
"termsText": "En cliquant sur \"Suivant\" ou \"S'inscrire\", vous acceptez nos",
|
||||
"title": "Connectez-vous à votre compte"
|
||||
},
|
||||
"signup": {
|
||||
"alreadyHaveAccount": "Vous avez déjà un compte?",
|
||||
"emailLabel": "Email",
|
||||
"emailPlaceholder": "Entrez votre email",
|
||||
"passwordLabel": "Mot de passe",
|
||||
"passwordPlaceholder": "Entrez un nouveau mot de passe",
|
||||
"signIn": "Se connecter",
|
||||
"signUpButton": "S'inscrire",
|
||||
"signUpWithGithub": "S'inscrire avec Github",
|
||||
"signUpWithGoogle": "S'inscrire avec Google",
|
||||
"title": "Créer un compte"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"errorMessage": "Échec de la copie dans le presse-papiers",
|
||||
"errorNotSupported": "L'API du presse-papiers n'est pas prise en charge par votre navigateur",
|
||||
@@ -1043,6 +1079,21 @@
|
||||
"next": "Suivant",
|
||||
"selectUser": "Sélectionnez un utilisateur"
|
||||
},
|
||||
"validation": {
|
||||
"invalidEmail": "Adresse e-mail invalide",
|
||||
"maxLength": "Ne doit pas dépasser {length} caractères",
|
||||
"minLength": "Doit contenir au moins {length} caractères",
|
||||
"password": {
|
||||
"lowercase": "Doit contenir au moins une lettre minuscule",
|
||||
"match": "Les mots de passe doivent correspondre",
|
||||
"minLength": "Doit contenir entre 8 et 32 caractères",
|
||||
"number": "Doit contenir au moins un chiffre",
|
||||
"requirements": "Exigences du mot de passe",
|
||||
"special": "Doit contenir au moins un caractère spécial",
|
||||
"uppercase": "Doit contenir au moins une lettre majuscule"
|
||||
},
|
||||
"required": "Requis"
|
||||
},
|
||||
"welcome": {
|
||||
"getStarted": "Commencer",
|
||||
"title": "Bienvenue sur ComfyUI"
|
||||
|
||||
@@ -8,6 +8,42 @@
|
||||
"message": "このワークフローにはAPIノードが含まれており、実行するためにはアカウントにサインインする必要があります。",
|
||||
"title": "APIノードを使用するためにはサインインが必要です"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"andText": "および",
|
||||
"confirmPasswordLabel": "パスワードの確認",
|
||||
"confirmPasswordPlaceholder": "もう一度同じパスワードを入力してください",
|
||||
"emailLabel": "メール",
|
||||
"emailPlaceholder": "メールアドレスを入力してください",
|
||||
"failed": "ログイン失敗",
|
||||
"forgotPassword": "パスワードを忘れましたか?",
|
||||
"loginButton": "ログイン",
|
||||
"loginWithGithub": "Githubでログイン",
|
||||
"loginWithGoogle": "Googleでログイン",
|
||||
"newUser": "新規ユーザーですか?",
|
||||
"orContinueWith": "または以下で続ける",
|
||||
"passwordLabel": "パスワード",
|
||||
"passwordPlaceholder": "パスワードを入力してください",
|
||||
"privacyLink": "プライバシーポリシー",
|
||||
"signUp": "サインアップ",
|
||||
"success": "ログイン成功",
|
||||
"termsLink": "利用規約",
|
||||
"termsText": "「次へ」または「サインアップ」をクリックすると、私たちの",
|
||||
"title": "アカウントにログインする"
|
||||
},
|
||||
"signup": {
|
||||
"alreadyHaveAccount": "すでにアカウントをお持ちですか?",
|
||||
"emailLabel": "メール",
|
||||
"emailPlaceholder": "メールアドレスを入力してください",
|
||||
"passwordLabel": "パスワード",
|
||||
"passwordPlaceholder": "新しいパスワードを入力してください",
|
||||
"signIn": "サインイン",
|
||||
"signUpButton": "サインアップ",
|
||||
"signUpWithGithub": "Githubでサインアップ",
|
||||
"signUpWithGoogle": "Googleでサインアップ",
|
||||
"title": "アカウントを作成する"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"errorMessage": "クリップボードへのコピーに失敗しました",
|
||||
"errorNotSupported": "お使いのブラウザではクリップボードAPIがサポートされていません",
|
||||
@@ -1043,6 +1079,21 @@
|
||||
"next": "次へ",
|
||||
"selectUser": "ユーザーを選択"
|
||||
},
|
||||
"validation": {
|
||||
"invalidEmail": "無効なメールアドレス",
|
||||
"maxLength": "{length}文字以下でなければなりません",
|
||||
"minLength": "{length}文字以上でなければなりません",
|
||||
"password": {
|
||||
"lowercase": "少なくとも1つの小文字を含む必要があります",
|
||||
"match": "パスワードが一致する必要があります",
|
||||
"minLength": "8文字から32文字の間でなければなりません",
|
||||
"number": "少なくとも1つの数字を含む必要があります",
|
||||
"requirements": "パスワードの要件",
|
||||
"special": "少なくとも1つの特殊文字を含む必要があります",
|
||||
"uppercase": "少なくとも1つの大文字を含む必要があります"
|
||||
},
|
||||
"required": "必須"
|
||||
},
|
||||
"welcome": {
|
||||
"getStarted": "はじめる",
|
||||
"title": "ComfyUIへようこそ"
|
||||
|
||||
@@ -8,6 +8,42 @@
|
||||
"message": "이 워크플로우에는 API 노드가 포함되어 있으며, 실행하려면 계정에 로그인해야 합니다.",
|
||||
"title": "API 노드 사용에 필요한 로그인"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"andText": "및",
|
||||
"confirmPasswordLabel": "비밀번호 확인",
|
||||
"confirmPasswordPlaceholder": "동일한 비밀번호를 다시 입력하세요",
|
||||
"emailLabel": "이메일",
|
||||
"emailPlaceholder": "이메일을 입력하세요",
|
||||
"failed": "로그인 실패",
|
||||
"forgotPassword": "비밀번호를 잊으셨나요?",
|
||||
"loginButton": "로그인",
|
||||
"loginWithGithub": "Github로 로그인",
|
||||
"loginWithGoogle": "구글로 로그인",
|
||||
"newUser": "처음이신가요?",
|
||||
"orContinueWith": "또는 다음으로 계속",
|
||||
"passwordLabel": "비밀번호",
|
||||
"passwordPlaceholder": "비밀번호를 입력하세요",
|
||||
"privacyLink": "개인정보 보호정책",
|
||||
"signUp": "가입하기",
|
||||
"success": "로그인 성공",
|
||||
"termsLink": "이용 약관",
|
||||
"termsText": "\"다음\" 또는 \"가입하기\"를 클릭하면 우리의",
|
||||
"title": "계정에 로그인"
|
||||
},
|
||||
"signup": {
|
||||
"alreadyHaveAccount": "이미 계정이 있으신가요?",
|
||||
"emailLabel": "이메일",
|
||||
"emailPlaceholder": "이메일을 입력하세요",
|
||||
"passwordLabel": "비밀번호",
|
||||
"passwordPlaceholder": "새 비밀번호를 입력하세요",
|
||||
"signIn": "로그인",
|
||||
"signUpButton": "가입하기",
|
||||
"signUpWithGithub": "Github로 가입하기",
|
||||
"signUpWithGoogle": "구글로 가입하기",
|
||||
"title": "계정 생성"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"errorMessage": "클립보드에 복사하지 못했습니다",
|
||||
"errorNotSupported": "브라우저가 클립보드 API를 지원하지 않습니다.",
|
||||
@@ -1043,6 +1079,21 @@
|
||||
"next": "다음",
|
||||
"selectUser": "사용자 선택"
|
||||
},
|
||||
"validation": {
|
||||
"invalidEmail": "유효하지 않은 이메일 주소",
|
||||
"maxLength": "{length}자를 초과할 수 없습니다",
|
||||
"minLength": "{length}자 이상이어야 합니다",
|
||||
"password": {
|
||||
"lowercase": "적어도 하나의 소문자를 포함해야 합니다",
|
||||
"match": "비밀번호가 일치해야 합니다",
|
||||
"minLength": "8자에서 32자 사이여야 합니다",
|
||||
"number": "적어도 하나의 숫자를 포함해야 합니다",
|
||||
"requirements": "비밀번호 요구사항",
|
||||
"special": "적어도 하나의 특수 문자를 포함해야 합니다",
|
||||
"uppercase": "적어도 하나의 대문자를 포함해야 합니다"
|
||||
},
|
||||
"required": "필수"
|
||||
},
|
||||
"welcome": {
|
||||
"getStarted": "시작하기",
|
||||
"title": "ComfyUI에 오신 것을 환영합니다"
|
||||
|
||||
@@ -8,6 +8,42 @@
|
||||
"message": "Этот рабочий процесс содержит API Nodes, которые требуют входа в вашу учетную запись для выполнения.",
|
||||
"title": "Требуется вход для использования API Nodes"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"andText": "и",
|
||||
"confirmPasswordLabel": "Подтвердите пароль",
|
||||
"confirmPasswordPlaceholder": "Введите тот же пароль еще раз",
|
||||
"emailLabel": "Электронная почта",
|
||||
"emailPlaceholder": "Введите вашу электронную почту",
|
||||
"failed": "Вход не удался",
|
||||
"forgotPassword": "Забыли пароль?",
|
||||
"loginButton": "Войти",
|
||||
"loginWithGithub": "Войти через Github",
|
||||
"loginWithGoogle": "Войти через Google",
|
||||
"newUser": "Вы здесь впервые?",
|
||||
"orContinueWith": "Или продолжить с",
|
||||
"passwordLabel": "Пароль",
|
||||
"passwordPlaceholder": "Введите ваш пароль",
|
||||
"privacyLink": "Политикой конфиденциальности",
|
||||
"signUp": "Зарегистрироваться",
|
||||
"success": "Вход выполнен успешно",
|
||||
"termsLink": "Условиями использования",
|
||||
"termsText": "Нажимая \"Далее\" или \"Зарегистрироваться\", вы соглашаетесь с нашими",
|
||||
"title": "Войдите в свой аккаунт"
|
||||
},
|
||||
"signup": {
|
||||
"alreadyHaveAccount": "Уже есть аккаунт?",
|
||||
"emailLabel": "Электронная почта",
|
||||
"emailPlaceholder": "Введите вашу электронную почту",
|
||||
"passwordLabel": "Пароль",
|
||||
"passwordPlaceholder": "Введите новый пароль",
|
||||
"signIn": "Войти",
|
||||
"signUpButton": "Зарегистрироваться",
|
||||
"signUpWithGithub": "Зарегистрироваться через Github",
|
||||
"signUpWithGoogle": "Зарегистрироваться через Google",
|
||||
"title": "Создать аккаунт"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"errorMessage": "Не удалось скопировать в буфер обмена",
|
||||
"errorNotSupported": "API буфера обмена не поддерживается в вашем браузере",
|
||||
@@ -1043,6 +1079,21 @@
|
||||
"next": "Далее",
|
||||
"selectUser": "Выберите пользователя"
|
||||
},
|
||||
"validation": {
|
||||
"invalidEmail": "Недействительный адрес электронной почты",
|
||||
"maxLength": "Должно быть не более {length} символов",
|
||||
"minLength": "Должно быть не менее {length} символов",
|
||||
"password": {
|
||||
"lowercase": "Должен содержать хотя бы одну строчную букву",
|
||||
"match": "Пароли должны совпадать",
|
||||
"minLength": "Должно быть от 8 до 32 символов",
|
||||
"number": "Должен содержать хотя бы одну цифру",
|
||||
"requirements": "Требования к паролю",
|
||||
"special": "Должен содержать хотя бы один специальный символ",
|
||||
"uppercase": "Должен содержать хотя бы одну заглавную букву"
|
||||
},
|
||||
"required": "Обязательно"
|
||||
},
|
||||
"welcome": {
|
||||
"getStarted": "Начать",
|
||||
"title": "Добро пожаловать в ComfyUI"
|
||||
|
||||
@@ -8,6 +8,42 @@
|
||||
"message": "此工作流包含API节点,需要您登录账户才能运行。",
|
||||
"title": "使用API节点需要登录"
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"andText": "和",
|
||||
"confirmPasswordLabel": "确认密码",
|
||||
"confirmPasswordPlaceholder": "再次输入相同的密码",
|
||||
"emailLabel": "电子邮件",
|
||||
"emailPlaceholder": "输入您的电子邮件",
|
||||
"failed": "登录失败",
|
||||
"forgotPassword": "忘记密码?",
|
||||
"loginButton": "登录",
|
||||
"loginWithGithub": "使用Github登录",
|
||||
"loginWithGoogle": "使用Google登录",
|
||||
"newUser": "新来的?",
|
||||
"orContinueWith": "或者继续使用",
|
||||
"passwordLabel": "密码",
|
||||
"passwordPlaceholder": "输入您的密码",
|
||||
"privacyLink": "隐私政策",
|
||||
"signUp": "注册",
|
||||
"success": "登录成功",
|
||||
"termsLink": "使用条款",
|
||||
"termsText": "点击“下一步”或“注册”即表示您同意我们的",
|
||||
"title": "登录您的账户"
|
||||
},
|
||||
"signup": {
|
||||
"alreadyHaveAccount": "已经有账户了?",
|
||||
"emailLabel": "电子邮件",
|
||||
"emailPlaceholder": "输入您的电子邮件",
|
||||
"passwordLabel": "密码",
|
||||
"passwordPlaceholder": "输入新密码",
|
||||
"signIn": "登录",
|
||||
"signUpButton": "注册",
|
||||
"signUpWithGithub": "使用Github注册",
|
||||
"signUpWithGoogle": "使用Google注册",
|
||||
"title": "创建一个账户"
|
||||
}
|
||||
},
|
||||
"clipboard": {
|
||||
"errorMessage": "复制到剪贴板失败",
|
||||
"errorNotSupported": "您的浏览器不支持剪贴板API",
|
||||
@@ -1043,6 +1079,21 @@
|
||||
"next": "下一步",
|
||||
"selectUser": "选择用户"
|
||||
},
|
||||
"validation": {
|
||||
"invalidEmail": "无效的电子邮件地址",
|
||||
"maxLength": "不能超过{length}个字符",
|
||||
"minLength": "必须至少有{length}个字符",
|
||||
"password": {
|
||||
"lowercase": "必须包含至少一个小写字母",
|
||||
"match": "密码必须匹配",
|
||||
"minLength": "必须在8到32个字符之间",
|
||||
"number": "必须包含至少一个数字",
|
||||
"requirements": "密码要求",
|
||||
"special": "必须包含至少一个特殊字符",
|
||||
"uppercase": "必须包含至少一个大写字母"
|
||||
},
|
||||
"required": "必填"
|
||||
},
|
||||
"welcome": {
|
||||
"getStarted": "开始使用",
|
||||
"title": "欢迎使用 ComfyUI"
|
||||
|
||||
36
src/schemas/signInSchema.ts
Normal file
36
src/schemas/signInSchema.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
import { t } from '@/i18n'
|
||||
|
||||
export const signInSchema = z.object({
|
||||
email: z
|
||||
.string()
|
||||
.email(t('validation.invalidEmail'))
|
||||
.min(1, t('validation.required')),
|
||||
password: z.string().min(1, t('validation.required'))
|
||||
})
|
||||
|
||||
export type SignInData = z.infer<typeof signInSchema>
|
||||
|
||||
export const signUpSchema = z
|
||||
.object({
|
||||
email: z
|
||||
.string()
|
||||
.email(t('validation.invalidEmail'))
|
||||
.min(1, t('validation.required')),
|
||||
password: z
|
||||
.string()
|
||||
.min(8, t('validation.minLength', { length: 8 }))
|
||||
.max(32, t('validation.maxLength', { length: 32 }))
|
||||
.regex(/[A-Z]/, t('validation.password.uppercase'))
|
||||
.regex(/[a-z]/, t('validation.password.lowercase'))
|
||||
.regex(/\d/, t('validation.password.number'))
|
||||
.regex(/[^A-Za-z0-9]/, t('validation.password.special')),
|
||||
confirmPassword: z.string().min(1, t('validation.required'))
|
||||
})
|
||||
.refine((data) => data.password === data.confirmPassword, {
|
||||
message: t('validation.password.match'),
|
||||
path: ['confirmPassword']
|
||||
})
|
||||
|
||||
export type SignUpData = z.infer<typeof signUpSchema>
|
||||
@@ -7,6 +7,7 @@ import ManagerProgressDialogContent from '@/components/dialog/content/ManagerPro
|
||||
import MissingModelsWarning from '@/components/dialog/content/MissingModelsWarning.vue'
|
||||
import PromptDialogContent from '@/components/dialog/content/PromptDialogContent.vue'
|
||||
import SettingDialogContent from '@/components/dialog/content/SettingDialogContent.vue'
|
||||
import SignInContent from '@/components/dialog/content/SignInContent.vue'
|
||||
import ManagerDialogContent from '@/components/dialog/content/manager/ManagerDialogContent.vue'
|
||||
import ManagerHeader from '@/components/dialog/content/manager/ManagerHeader.vue'
|
||||
import ManagerProgressFooter from '@/components/dialog/footer/ManagerProgressFooter.vue'
|
||||
@@ -232,7 +233,7 @@ export const useDialogService = () => {
|
||||
component: ApiNodesSignInContent,
|
||||
props: {
|
||||
apiNodes,
|
||||
onLogin: () => resolve(true),
|
||||
onLogin: () => showSignInDialog().then((result) => resolve(result)),
|
||||
onCancel: () => resolve(false)
|
||||
},
|
||||
headerComponent: ComfyOrgHeader,
|
||||
@@ -247,6 +248,26 @@ export const useDialogService = () => {
|
||||
})
|
||||
}
|
||||
|
||||
async function showSignInDialog(): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
dialogStore.showDialog({
|
||||
key: 'global-signin',
|
||||
component: SignInContent,
|
||||
headerComponent: ComfyOrgHeader,
|
||||
props: {
|
||||
onSuccess: () => resolve(true)
|
||||
},
|
||||
dialogComponentProps: {
|
||||
closable: false,
|
||||
onClose: () => resolve(false)
|
||||
}
|
||||
})
|
||||
}).then((result) => {
|
||||
dialogStore.closeDialog({ key: 'global-signin' })
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
||||
async function prompt({
|
||||
title,
|
||||
message,
|
||||
@@ -332,6 +353,7 @@ export const useDialogService = () => {
|
||||
showManagerProgressDialog,
|
||||
showErrorDialog,
|
||||
showApiNodesSignInDialog,
|
||||
showSignInDialog,
|
||||
prompt,
|
||||
confirm
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user