Browse Source

fix: wrap with div if root element is NuxtLayout to avoid navigation error

pull/7650/head
Pranav C 9 months ago
parent
commit
b14492ac17
  1. 8
      packages/nc-gui/layouts/general.vue
  2. 292
      packages/nc-gui/pages/account/index.vue
  3. 107
      packages/nc-gui/pages/forgot-password.vue
  4. 66
      packages/nc-gui/pages/index/[typeOrId]/form/[viewId].vue
  5. 264
      packages/nc-gui/pages/profile/[[username]].vue
  6. 154
      packages/nc-gui/pages/projects/index.vue
  7. 118
      packages/nc-gui/pages/reset/[id].vue
  8. 190
      packages/nc-gui/pages/signin.vue
  9. 216
      packages/nc-gui/pages/signup/[[token]].vue

8
packages/nc-gui/layouts/general.vue

@ -5,7 +5,9 @@ export default {
</script> </script>
<template> <template>
<NuxtLayout name="default"> <div>
<slot name="sidebar" /> <NuxtLayout name="default">
</NuxtLayout> <slot name="sidebar" />
</NuxtLayout>
</div>
</template> </template>

292
packages/nc-gui/pages/account/index.vue

@ -28,177 +28,179 @@ const logout = async () => {
</script> </script>
<template> <template>
<NuxtLayout name="empty"> <div>
<div class="mx-auto h-full"> <NuxtLayout name="empty">
<div class="h-full overflow-y-auto flex"> <div class="mx-auto h-full">
<!-- Side tabs --> <div class="h-full overflow-y-auto flex">
<!-- Side tabs -->
<div class="h-full bg-white nc-user-sidebar fixed">
<NcMenu <div class="h-full bg-white nc-user-sidebar fixed">
v-model:openKeys="openKeys" <NcMenu
v-model:selectedKeys="selectedKeys" v-model:openKeys="openKeys"
:inline-indent="16" v-model:selectedKeys="selectedKeys"
class="tabs-menu h-full" :inline-indent="16"
mode="inline" class="tabs-menu h-full"
> mode="inline"
<div
v-if="!$route.params.baseType"
v-e="['c:navbar:home']"
data-testid="nc-noco-brand-icon"
class="transition-all duration-200 px-2 mx-2 mt-1.5 cursor-pointer transform hover:bg-gray-100 my-1 nc-noco-brand-icon h-8 rounded-md min-w-60"
@click="navigateTo('/')"
>
<div class="flex flex-row gap-x-2 items-center h-8.5">
<GeneralIcon icon="arrowLeft" class="-mt-0.1" />
<div class="flex text-sm font-medium text-gray-800">{{ $t('labels.backToWorkspace') }}</div>
</div>
</div>
<div class="text-sm text-gray-600 ml-4 p-2 mt-3 gray-600 font-medium">{{ $t('labels.account') }}</div>
<NcMenuItem
key="profile"
class="item"
:class="{
active: $route.params.page === 'profile',
}"
@click="navigateTo('/account/profile')"
> >
<div class="flex items-center space-x-2"> <div
<GeneralIcon icon="user" class="!h-3.5 !w-3.5" /> v-if="!$route.params.baseType"
v-e="['c:navbar:home']"
<div class="select-none">{{ $t('labels.profile') }}</div> data-testid="nc-noco-brand-icon"
</div> class="transition-all duration-200 px-2 mx-2 mt-1.5 cursor-pointer transform hover:bg-gray-100 my-1 nc-noco-brand-icon h-8 rounded-md min-w-60"
</NcMenuItem> @click="navigateTo('/')"
>
<NcMenuItem <div class="flex flex-row gap-x-2 items-center h-8.5">
key="tokens" <GeneralIcon icon="arrowLeft" class="-mt-0.1" />
class="item" <div class="flex text-sm font-medium text-gray-800">{{ $t('labels.backToWorkspace') }}</div>
:class="{ </div>
active: $route.params.page === 'tokens',
}"
@click="navigateTo('/account/tokens')"
>
<div class="flex items-center space-x-2">
<component :is="iconMap.code" />
<div class="select-none">API {{ $t('title.tokens') }}</div>
</div> </div>
</NcMenuItem>
<NcMenuItem
v-if="isUIAllowed('superAdminAppStore') && !isEeUI"
key="apps"
class="item"
:class="{
active: $route.params.page === 'apps',
}"
@click="navigateTo('/account/apps')"
>
<div class="flex items-center space-x-2">
<component :is="iconMap.appStore" />
<div class="select-none text-sm">{{ $t('title.appStore') }}</div> <div class="text-sm text-gray-600 ml-4 p-2 mt-3 gray-600 font-medium">{{ $t('labels.account') }}</div>
</div>
</NcMenuItem>
<a-sub-menu key="users" class="!bg-white !my-0">
<template #icon>
<GeneralIcon icon="users" class="!h-3.5 !w-3.5" />
</template>
<template #title>{{ $t('objects.users') }}</template>
<NcMenuItem <NcMenuItem
v-if="isUIAllowed('superAdminUserManagement') && !isEeUI" key="profile"
key="list" class="item"
class="text-xs item"
:class="{ :class="{
active: $route.params.nestedPage === 'list', active: $route.params.page === 'profile',
}" }"
@click="navigateTo('/account/users/list')" @click="navigateTo('/account/profile')"
> >
<span class="ml-4">{{ $t('title.userManagement') }}</span> <div class="flex items-center space-x-2">
<GeneralIcon icon="user" class="!h-3.5 !w-3.5" />
<div class="select-none">{{ $t('labels.profile') }}</div>
</div>
</NcMenuItem> </NcMenuItem>
<NcMenuItem <NcMenuItem
key="password-reset" key="tokens"
class="text-xs item" class="item"
:class="{ :class="{
active: $route.params.nestedPage === 'password-reset', active: $route.params.page === 'tokens',
}" }"
@click="navigateTo('/account/users/password-reset')" @click="navigateTo('/account/tokens')"
> >
<span class="ml-4">{{ $t('title.resetPasswordMenu') }}</span> <div class="flex items-center space-x-2">
<component :is="iconMap.code" />
<div class="select-none">API {{ $t('title.tokens') }}</div>
</div>
</NcMenuItem> </NcMenuItem>
<NcMenuItem <NcMenuItem
v-if="isUIAllowed('superAdminAppSettings') && !isEeUI" v-if="isUIAllowed('superAdminAppStore') && !isEeUI"
key="settings" key="apps"
class="text-xs item" class="item"
:class="{ :class="{
active: $route.params.nestedPage === 'settings', active: $route.params.page === 'apps',
}" }"
@click="navigateTo('/account/users/settings')" @click="navigateTo('/account/apps')"
> >
<span class="ml-4">{{ $t('activity.settings') }}</span> <div class="flex items-center space-x-2">
</NcMenuItem> <component :is="iconMap.appStore" />
</a-sub-menu>
</NcMenu>
</div>
<!-- Sub Tabs -->
<div class="flex flex-col w-full ml-65"> <div class="select-none text-sm">{{ $t('title.appStore') }}</div>
<div class="flex flex-row p-3 items-center h-14"> </div>
<div class="flex-1" /> </NcMenuItem>
<a-sub-menu key="users" class="!bg-white !my-0">
<LazyGeneralReleaseInfo /> <template #icon>
<GeneralIcon icon="users" class="!h-3.5 !w-3.5" />
<a-tooltip v-if="!appInfo.ee" placement="bottom" :mouse-enter-delay="1"> </template>
<template #title>{{ $t('title.switchLanguage') }}</template> <template #title>{{ $t('objects.users') }}</template>
<NcMenuItem
v-if="isUIAllowed('superAdminUserManagement') && !isEeUI"
key="list"
class="text-xs item"
:class="{
active: $route.params.nestedPage === 'list',
}"
@click="navigateTo('/account/users/list')"
>
<span class="ml-4">{{ $t('title.userManagement') }}</span>
</NcMenuItem>
<NcMenuItem
key="password-reset"
class="text-xs item"
:class="{
active: $route.params.nestedPage === 'password-reset',
}"
@click="navigateTo('/account/users/password-reset')"
>
<span class="ml-4">{{ $t('title.resetPasswordMenu') }}</span>
</NcMenuItem>
<NcMenuItem
v-if="isUIAllowed('superAdminAppSettings') && !isEeUI"
key="settings"
class="text-xs item"
:class="{
active: $route.params.nestedPage === 'settings',
}"
@click="navigateTo('/account/users/settings')"
>
<span class="ml-4">{{ $t('activity.settings') }}</span>
</NcMenuItem>
</a-sub-menu>
</NcMenu>
</div>
<div class="flex pr-4 items-center"> <!-- Sub Tabs -->
<LazyGeneralLanguage class="cursor-pointer text-2xl hover:text-gray-800" />
</div> <div class="flex flex-col w-full ml-65">
</a-tooltip> <div class="flex flex-row p-3 items-center h-14">
<div class="flex-1" />
<template v-if="signedIn">
<NcDropdown :trigger="['click']" overlay-class-name="nc-dropdown-user-accounts-menu"> <LazyGeneralReleaseInfo />
<NcButton type="text" size="small">
<component <a-tooltip v-if="!appInfo.ee" placement="bottom" :mouse-enter-delay="1">
:is="iconMap.threeDotVertical" <template #title>{{ $t('title.switchLanguage') }}</template>
data-testid="nc-menu-accounts"
class="md:text-lg cursor-pointer hover:text-gray-800 nc-menu-accounts" <div class="flex pr-4 items-center">
@click.prevent <LazyGeneralLanguage class="cursor-pointer text-2xl hover:text-gray-800" />
/> </div>
</NcButton> </a-tooltip>
<template #overlay> <template v-if="signedIn">
<div class="!py-1 !rounded-md bg-white overflow-hidden"> <NcDropdown :trigger="['click']" overlay-class-name="nc-dropdown-user-accounts-menu">
<div class="!rounded-b group" data-testid="nc-menu-accounts__sign-out"> <NcButton type="text" size="small">
<div v-e="['a:navbar:user:sign-out']" class="nc-account-dropdown-item group" @click="logout"> <component
<component :is="iconMap.signout" class="group-hover:text-accent" />&nbsp; :is="iconMap.threeDotVertical"
data-testid="nc-menu-accounts"
<span class="prose group-hover:text-primary"> class="md:text-lg cursor-pointer hover:text-gray-800 nc-menu-accounts"
{{ $t('general.signOut') }} @click.prevent
</span> />
</NcButton>
<template #overlay>
<div class="!py-1 !rounded-md bg-white overflow-hidden">
<div class="!rounded-b group" data-testid="nc-menu-accounts__sign-out">
<div v-e="['a:navbar:user:sign-out']" class="nc-account-dropdown-item group" @click="logout">
<component :is="iconMap.signout" class="group-hover:text-accent" />&nbsp;
<span class="prose group-hover:text-primary">
{{ $t('general.signOut') }}
</span>
</div>
</div> </div>
</div> </div>
</div> </template>
</template> </NcDropdown>
</NcDropdown> </template>
</template> </div>
</div> <div
<div class="flex flex-col container mx-auto"
class="flex flex-col container mx-auto" :style="{
:style="{ height: 'calc(100vh - 3.5rem)',
height: 'calc(100vh - 3.5rem)', }"
}" >
> <div class="mt-2 h-full">
<div class="mt-2 h-full"> <NuxtPage />
<NuxtPage /> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </NuxtLayout>
</NuxtLayout> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

107
packages/nc-gui/pages/forgot-password.vue

@ -61,61 +61,68 @@ function navigateSignIn() {
</script> </script>
<template> <template>
<NuxtLayout> <div>
<div class="md:bg-primary bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center"> <NuxtLayout>
<div <div class="md:bg-primary bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center">
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)" <div
> class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)"
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" /> >
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" />
<div class="self-center flex flex-col justify-center items-center text-center gap-2">
<h1 class="prose-2xl font-bold my-4 w-full">{{ $t('title.resetPassword') }}</h1> <div class="self-center flex flex-col justify-center items-center text-center gap-2">
<h1 class="prose-2xl font-bold my-4 w-full">{{ $t('title.resetPassword') }}</h1>
<template v-if="!success">
<div class="prose-sm">{{ $t('msg.info.passwordRecovery.message_1') }}</div> <template v-if="!success">
<div class="prose-sm mb-4">{{ $t('msg.info.passwordRecovery.message_2') }}</div> <div class="prose-sm">{{ $t('msg.info.passwordRecovery.message_1') }}</div>
</template> <div class="prose-sm mb-4">{{ $t('msg.info.passwordRecovery.message_2') }}</div>
</template>
<template v-else>
<div class="prose-sm text-success flex items-center leading-8 gap-2"> <template v-else>
{{ $t('msg.info.passwordRecovery.success') }} <ClaritySuccessLine /> <div class="prose-sm text-success flex items-center leading-8 gap-2">
</div> {{ $t('msg.info.passwordRecovery.success') }} <ClaritySuccessLine />
</div>
<nuxt-link @click="navigateSignIn">{{ $t('general.signIn') }}</nuxt-link> <nuxt-link @click="navigateSignIn">{{ $t('general.signIn') }}</nuxt-link>
</template> </template>
</div> </div>
<a-form ref="formValidator" layout="vertical" :model="form" no-style @finish="resetPassword"> <a-form ref="formValidator" layout="vertical" :model="form" no-style @finish="resetPassword">
<Transition name="layout"> <Transition name="layout">
<div v-if="error" class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1"> <div v-if="error" class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1">
<div class="flex items-center gap-2 justify-center"> <div class="flex items-center gap-2 justify-center">
<MaterialSymbolsWarning /> <MaterialSymbolsWarning />
<div class="break-words">{{ error }}</div> <div class="break-words">{{ error }}</div>
</div>
</div>
</Transition>
<a-form-item :label="$t('labels.email')" name="email" :rules="formRules.email">
<a-input
v-model:value="form.email"
size="large"
:placeholder="$t('msg.info.signUp.workEmail')"
@focus="resetError"
/>
</a-form-item>
<div class="self-center flex flex-col gap-4 items-center justify-center w-full">
<button class="scaling-btn bg-opacity-100" type="submit">
<span class="flex items-center gap-2">
<component :is="iconMap.signin" />
{{ $t('activity.sendEmail') }}
</span>
</button>
<div class="text-end prose-sm">
{{ $t('msg.info.signUp.alreadyHaveAccount') }}
<nuxt-link @click="navigateSignIn">{{ $t('general.signIn') }}</nuxt-link>
</div> </div>
</div> </div>
</Transition> </a-form>
</div>
<a-form-item :label="$t('labels.email')" name="email" :rules="formRules.email">
<a-input v-model:value="form.email" size="large" :placeholder="$t('msg.info.signUp.workEmail')" @focus="resetError" />
</a-form-item>
<div class="self-center flex flex-col gap-4 items-center justify-center w-full">
<button class="scaling-btn bg-opacity-100" type="submit">
<span class="flex items-center gap-2">
<component :is="iconMap.signin" />
{{ $t('activity.sendEmail') }}
</span>
</button>
<div class="text-end prose-sm">
{{ $t('msg.info.signUp.alreadyHaveAccount') }}
<nuxt-link @click="navigateSignIn">{{ $t('general.signIn') }}</nuxt-link>
</div>
</div>
</a-form>
</div> </div>
</div> </NuxtLayout>
</NuxtLayout> </div>
</template> </template>
<style lang="scss"> <style lang="scss">

66
packages/nc-gui/pages/index/[typeOrId]/form/[viewId].vue

@ -62,38 +62,40 @@ watch(
</script> </script>
<template> <template>
<NuxtLayout> <div>
<NuxtPage v-if="!passwordDlg" /> <NuxtLayout>
<NuxtPage v-if="!passwordDlg" />
<a-modal
v-model:visible="passwordDlg" <a-modal
:class="{ active: passwordDlg }" v-model:visible="passwordDlg"
:closable="false" :class="{ active: passwordDlg }"
width="min(100%, 450px)" :closable="false"
centered width="min(100%, 450px)"
:footer="null" centered
:mask-closable="false" :footer="null"
wrap-class-name="nc-modal-shared-form-password-dlg" :mask-closable="false"
@close="passwordDlg = false" wrap-class-name="nc-modal-shared-form-password-dlg"
> @close="passwordDlg = false"
<div class="w-full flex flex-col gap-4"> >
<h2 class="text-xl font-semibold">{{ $t('msg.thisSharedViewIsProtected') }}</h2> <div class="w-full flex flex-col gap-4">
<h2 class="text-xl font-semibold">{{ $t('msg.thisSharedViewIsProtected') }}</h2>
<a-form layout="vertical" no-style :model="form" @finish="loadSharedView">
<a-form-item name="password" :rules="[{ required: true, message: $t('msg.error.signUpRules.passwdRequired') }]"> <a-form layout="vertical" no-style :model="form" @finish="loadSharedView">
<a-input-password v-model:value="form.password" size="large" :placeholder="$t('msg.enterPassword')" /> <a-form-item name="password" :rules="[{ required: true, message: $t('msg.error.signUpRules.passwdRequired') }]">
</a-form-item> <a-input-password v-model:value="form.password" size="large" :placeholder="$t('msg.enterPassword')" />
</a-form-item>
<Transition name="layout">
<div v-if="passwordError" class="mb-2 text-sm text-red-500">{{ passwordError }}</div> <Transition name="layout">
</Transition> <div v-if="passwordError" class="mb-2 text-sm text-red-500">{{ passwordError }}</div>
</Transition>
<!-- Unlock -->
<button type="submit" class="mt-4 scaling-btn bg-opacity-100">{{ $t('general.unlock') }}</button> <!-- Unlock -->
</a-form> <button type="submit" class="mt-4 scaling-btn bg-opacity-100">{{ $t('general.unlock') }}</button>
</div> </a-form>
</a-modal> </div>
</NuxtLayout> </a-modal>
</NuxtLayout>
</div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

264
packages/nc-gui/pages/profile/[[username]].vue

@ -11,153 +11,157 @@ await loadProfile(route.params.username as string)
</script> </script>
<template> <template>
<NuxtLayout> <div>
<a-layout class="h-[75vh] overflow-y-auto flex"> <NuxtLayout>
<a-layout-sider :collapsed="false" width="320" class="h-max px-5" :trigger="null" collapsible theme="light"> <a-layout class="h-[75vh] overflow-y-auto flex">
<div class="mx-2"> <a-layout-sider :collapsed="false" width="320" class="h-max px-5" :trigger="null" collapsible theme="light">
<div class="my-3"> <div class="mx-2">
<a-avatar v-if="profile.avatar" :size="150" :src="profile.avatar" /> <div class="my-3">
<a-avatar v-else :size="150"> <a-avatar v-if="profile.avatar" :size="150" :src="profile.avatar" />
<template #icon> <a-avatar v-else :size="150">
<MdiAccount class="w-full h-full p-[15px]" /> <template #icon>
</template> <MdiAccount class="w-full h-full p-[15px]" />
</a-avatar> </template>
</div> </a-avatar>
<div class="nc-profile-display-name text-[30px] my-2 font-bold"> </div>
{{ profile.display_name }} <div class="nc-profile-display-name text-[30px] my-2 font-bold">
</div> {{ profile.display_name }}
</div>
<div class="nc-profile-user-name text-[18px] my-2">@{{ profile.user_name }}</div>
<div class="nc-profile-bio text-[15px] my-4"> <div class="nc-profile-user-name text-[18px] my-2">@{{ profile.user_name }}</div>
{{ profile.bio }}
</div>
<div class="nc-profile-follower my-2"> <div class="nc-profile-bio text-[15px] my-4">
<div class="flex items-center mr-4"> {{ profile.bio }}
<MdiAccountSupervisorOutline class="text-lg" />
{{ profile.followerCount }} followers{{ profile.followingCount }} Following
</div> </div>
</div>
<div v-if="profile.id !== user.id" class="nc-profile-follow-btn my-4"> <div class="nc-profile-follower my-2">
<a-button <div class="flex items-center mr-4">
v-if="!isFollowing" <MdiAccountSupervisorOutline class="text-lg" />
class="!bg-primary !border-none w-full text-center !text-white rounded" {{ profile.followerCount }} followers{{ profile.followingCount }} Following
size="large" </div>
@click="followUser(profile.id)" </div>
>
Follow
</a-button>
<a-button
v-else
class="!bg-primary !border-none w-full text-center !text-white rounded"
size="large"
@click="unfollowUser(profile.id)"
>
Unfollow
</a-button>
</div>
<div class="nc-profile-edit-btn my-4"> <div v-if="profile.id !== user.id" class="nc-profile-follow-btn my-4">
<a-button class="!bg-primary !border-none w-full text-center !text-white rounded" size="large"> <a-button
Edit Profile v-if="!isFollowing"
</a-button> class="!bg-primary !border-none w-full text-center !text-white rounded"
</div> size="large"
@click="followUser(profile.id)"
>
Follow
</a-button>
<a-button
v-else
class="!bg-primary !border-none w-full text-center !text-white rounded"
size="large"
@click="unfollowUser(profile.id)"
>
Unfollow
</a-button>
</div>
<div v-if="profile.location" class="nc-profile-location my-2"> <div class="nc-profile-edit-btn my-4">
<div class="flex items-center mr-4"><MdiMapMarkerOutline class="text-lg mr-2" /> {{ profile.location }}</div> <a-button class="!bg-primary !border-none w-full text-center !text-white rounded" size="large">
</div> Edit Profile
</a-button>
</div>
<div v-if="profile.website" class="nc-profile-website my-2"> <div v-if="profile.location" class="nc-profile-location my-2">
<div class="flex items-center mr-4"> <div class="flex items-center mr-4"><MdiMapMarkerOutline class="text-lg mr-2" /> {{ profile.location }}</div>
<MdiLinkVariant class="text-lg mr-2" />
<a class="!no-underline" :href="profile.website" rel="noopener noreferrer" target="_blank">{{ profile.website }}</a>
</div> </div>
</div>
<div class="nc-profile-statistics my-10"> <div v-if="profile.website" class="nc-profile-website my-2">
<div class="text-[20px] font-bold">Statistics</div>
<div class="mt-5">
<div class="flex items-center mr-4"> <div class="flex items-center mr-4">
<MdiCircleMedium class="text-lg text-[#4E2BDC]" /> <MdiLinkVariant class="text-lg mr-2" />
<span class="text-[16px]">Database</span> <a class="!no-underline" :href="profile.website" rel="noopener noreferrer" target="_blank">{{
</div> profile.website
<div class="mt-2"> }}</a>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Columns </a-button>
<span class="ml-2 text-[12px]">x5</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Views </a-button>
<span class="ml-2 text-[12px]">x21</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Tables </a-button>
<span class="ml-2 text-[12px]">x158</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Databases </a-button>
<span class="ml-2 text-[12px]">x9</span>
</div>
</div> </div>
</div> </div>
<div class="mt-5">
<div class="flex items-center mr-4"> <div class="nc-profile-statistics my-10">
<MdiCircleMedium class="text-lg text-[#E9ED2A]" /> <div class="text-[20px] font-bold">Statistics</div>
<span class="text-[16px]">Automations</span> <div class="mt-5">
</div> <div class="flex items-center mr-4">
<div class="mt-2"> <MdiCircleMedium class="text-lg text-[#4E2BDC]" />
<div class="nc-profile-statistics-badge inline-block m-1"> <span class="text-[16px]">Database</span>
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Columns </a-button>
<span class="ml-2 text-[12px]">x5</span>
</div> </div>
<div class="nc-profile-statistics-badge inline-block m-1"> <div class="mt-2">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Views </a-button> <div class="nc-profile-statistics-badge inline-block m-1">
<span class="ml-2 text-[12px]">x21</span> <a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Columns </a-button>
<span class="ml-2 text-[12px]">x5</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Views </a-button>
<span class="ml-2 text-[12px]">x21</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Tables </a-button>
<span class="ml-2 text-[12px]">x158</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Databases </a-button>
<span class="ml-2 text-[12px]">x9</span>
</div>
</div> </div>
<div class="nc-profile-statistics-badge inline-block m-1"> </div>
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Tables </a-button> <div class="mt-5">
<span class="ml-2 text-[12px]">x158</span> <div class="flex items-center mr-4">
<MdiCircleMedium class="text-lg text-[#E9ED2A]" />
<span class="text-[16px]">Automations</span>
</div> </div>
<div class="nc-profile-statistics-badge inline-block m-1"> <div class="mt-2">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Databases </a-button> <div class="nc-profile-statistics-badge inline-block m-1">
<span class="ml-2 text-[12px]">x9</span> <a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Columns </a-button>
<span class="ml-2 text-[12px]">x5</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Views </a-button>
<span class="ml-2 text-[12px]">x21</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Tables </a-button>
<span class="ml-2 text-[12px]">x158</span>
</div>
<div class="nc-profile-statistics-badge inline-block m-1">
<a-button class="!rounded-2xl !bg-[#F2F4F7]" size="small"> Databases </a-button>
<span class="ml-2 text-[12px]">x9</span>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </a-layout-sider>
</a-layout-sider> <a-layout-content class="h-max px-5 py-2 scrollbar-thumb-gray-500">
<a-layout-content class="h-max px-5 py-2 scrollbar-thumb-gray-500"> <a-tabs>
<a-tabs> <a-tab-pane key="overview" class="w-full">
<a-tab-pane key="overview" class="w-full"> <template #tab>
<template #tab> <div class="flex items-center mr-4">
<div class="flex items-center mr-4"> <MdiBookOpenBlankVariant class="text-lg mr-2" />
<MdiBookOpenBlankVariant class="text-lg mr-2" /> Overview
Overview </div>
</div> </template>
</template> <LazyProfileOverview />
<LazyProfileOverview /> </a-tab-pane>
</a-tab-pane> <a-tab-pane key="stars" class="w-full">
<a-tab-pane key="stars" class="w-full"> <template #tab>
<template #tab> <div class="flex items-center mr-4">
<div class="flex items-center mr-4"> <MdiStarOutline class="text-lg mr-2" />
<MdiStarOutline class="text-lg mr-2" /> <span class="mr-2">Stars</span>
<span class="mr-2">Stars</span> <a-badge
<a-badge count="25"
count="25" :number-style="{
:number-style="{ backgroundColor: '#B5B5B7',
backgroundColor: '#B5B5B7', color: '#FFFFFF',
color: '#FFFFFF', }"
}" />
/> </div>
</div> </template>
</template> <LazyProfileStars />
<LazyProfileStars /> </a-tab-pane>
</a-tab-pane> </a-tabs>
</a-tabs> </a-layout-content>
</a-layout-content> </a-layout>
</a-layout> </NuxtLayout>
</NuxtLayout> </div>
</template> </template>

154
packages/nc-gui/pages/projects/index.vue

@ -57,88 +57,90 @@ const deleteProject = (base: BaseType) => {
</script> </script>
<template> <template>
<NuxtLayout> <div>
<template #sidebar> <NuxtLayout>
<div class="flex flex-col h-full"> <template #sidebar>
<div class="flex p-4"> <div class="flex flex-col h-full">
<v-menu class="select-none"> <div class="flex p-4">
<template #activator="{ props }"> <v-menu class="select-none">
<div <template #activator="{ props }">
class="color-transition hover:(bg-gray-100) mr-auto select-none flex items-center gap-2 leading-8 cursor-pointer rounded-full border-1 border-gray-300 px-5 py-2 shadow prose-lg font-semibold" <div
@click="props.onClick" class="color-transition hover:(bg-gray-100) mr-auto select-none flex items-center gap-2 leading-8 cursor-pointer rounded-full border-1 border-gray-300 px-5 py-2 shadow prose-lg font-semibold"
> @click="props.onClick"
<component :is="iconMap.plus" class="text-primary text-2xl" /> >
{{ $t('title.newProj') }} <component :is="iconMap.plus" class="text-primary text-2xl" />
{{ $t('title.newProj') }}
</div>
</template>
<v-list class="!py-0 flex flex-col bg-white rounded-lg shadow-md border-1 border-gray-300 mt-2 ml-2">
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/base/create')"
>
<component :is="iconMap.plus" class="col-span-2 mr-1 mt-[1px] text-primary text-lg" />
<div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div>
</div>
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/base/create-external')"
>
<component :is="iconMap.database" class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" />
<div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" />
</div>
</v-list>
</v-menu>
</div>
<a-menu class="pr-4 flex-1 border-0">
<a-menu-item
v-for="(option, index) in navDrawerOptions"
:key="index"
class="!rounded-r-lg"
@click="activePage = option.title"
>
<div class="flex items-center gap-4">
<component :is="option.icon" />
<span class="font-semibold">
{{ option.title }}
</span>
</div> </div>
</template> </a-menu-item>
</a-menu>
<v-list class="!py-0 flex flex-col bg-white rounded-lg shadow-md border-1 border-gray-300 mt-2 ml-2">
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/base/create')"
>
<component :is="iconMap.plus" class="col-span-2 mr-1 mt-[1px] text-primary text-lg" />
<div class="col-span-10 text-sm xl:text-md">{{ $t('activity.createProject') }}</div>
</div>
<div
class="grid grid-cols-12 cursor-pointer hover:bg-gray-200 flex items-center p-2"
@click="navigateTo('/base/create-external')"
>
<component :is="iconMap.database" class="col-span-2 mr-1 mt-[1px] text-green-500 text-lg" />
<div class="col-span-10 text-sm xl:text-md" v-html="$t('activity.createProjectExtended.extDB')" />
</div>
</v-list>
</v-menu>
</div>
<a-menu class="pr-4 flex-1 border-0"> <general-social />
<a-menu-item
v-for="(option, index) in navDrawerOptions"
:key="index"
class="!rounded-r-lg"
@click="activePage = option.title"
>
<div class="flex items-center gap-4">
<component :is="option.icon" />
<span class="font-semibold">
{{ option.title }}
</span>
</div>
</a-menu-item>
</a-menu>
<general-social />
<general-sponsors :nav="true" />
</div>
</template>
<div class="flex-1 mb-12"> <general-sponsors :nav="true" />
<div class="flex">
<div class="flex-1 text-2xl md:text-4xl font-bold text-gray-500 p-4">
{{ activePage }}
</div> </div>
</template>
<div class="self-end flex text-4xl mb-1">
<MaterialSymbolsGridView <div class="flex-1 mb-12">
:class="route.name === 'index-index' ? '!text-primary' : ''" <div class="flex">
class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full" <div class="flex-1 text-2xl md:text-4xl font-bold text-gray-500 p-4">
@click="navigateTo('/')" {{ activePage }}
/> </div>
<MaterialSymbolsFormatListBulletedRounded
:class="route.name === 'index-index-list' ? '!text-primary' : ''" <div class="self-end flex text-4xl mb-1">
class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full" <MaterialSymbolsGridView
@click="navigateTo('/list')" :class="route.name === 'index-index' ? '!text-primary' : ''"
/> class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full"
@click="navigateTo('/')"
/>
<MaterialSymbolsFormatListBulletedRounded
:class="route.name === 'index-index-list' ? '!text-primary' : ''"
class="cursor-pointer p-2 hover:bg-gray-300/50 rounded-full"
@click="navigateTo('/list')"
/>
</div>
</div> </div>
</div>
<a-divider class="!mb-4 lg:(!mb-8)" /> <a-divider class="!mb-4 lg:(!mb-8)" />
<NuxtPage :bases="bases" @delete-base="deleteProject" /> <NuxtPage :bases="bases" @delete-base="deleteProject" />
</div> </div>
<a-modal></a-modal> <a-modal></a-modal>
</NuxtLayout> </NuxtLayout>
</div>
</template> </template>

118
packages/nc-gui/pages/reset/[id].vue

@ -61,72 +61,76 @@ function resetError() {
</script> </script>
<template> <template>
<NuxtLayout> <div>
<div class="md:bg-primary signin bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center"> <NuxtLayout>
<div <div
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)" class="md:bg-primary signin bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center"
> >
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" /> <div
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)"
>
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" />
<div class="self-center flex flex-col justify-center items-center text-center gap-2"> <div class="self-center flex flex-col justify-center items-center text-center gap-2">
<h1 class="prose-2xl font-bold my-4 w-full">{{ $t('title.resetPassword') }}</h1> <h1 class="prose-2xl font-bold my-4 w-full">{{ $t('title.resetPassword') }}</h1>
<div class="prose-sm text-success flex items-center leading-8 gap-2"> <div class="prose-sm text-success flex items-center leading-8 gap-2">
{{ $t('msg.info.passwordRecovery.success') }} <ClaritySuccessLine /> {{ $t('msg.info.passwordRecovery.success') }} <ClaritySuccessLine />
</div> </div>
<nuxt-link to="/signin">{{ $t('general.signIn') }}</nuxt-link> <nuxt-link to="/signin">{{ $t('general.signIn') }}</nuxt-link>
</div> </div>
<a-form ref="formValidator" layout="vertical" :model="form" no-style @finish="resetPassword"> <a-form ref="formValidator" layout="vertical" :model="form" no-style @finish="resetPassword">
<Transition name="layout"> <Transition name="layout">
<div v-if="error" class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1"> <div v-if="error" class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1">
<div class="flex items-center gap-2 justify-center"> <div class="flex items-center gap-2 justify-center">
<MaterialSymbolsWarning /> <MaterialSymbolsWarning />
<div class="break-words">{{ error }}</div> <div class="break-words">{{ error }}</div>
</div>
</div> </div>
</Transition>
<a-form-item
:label="$t('placeholder.password.new')"
name="password"
:rules="[{ required: true, message: t('msg.error.signUpRules.passwdRequired') }]"
>
<a-input-password
v-model:value="form.password"
:placeholder="$t('placeholder.password.new')"
class="password"
@focus="resetError"
/>
</a-form-item>
<a-form-item
:label="$t('placeholder.password.confirm')"
name="newPassword"
:rules="[{ required: true, message: t('msg.error.signUpRules.passwdRequired') }]"
>
<a-input-password
v-model:value="form.newPassword"
type="password"
class="password"
:placeholder="$t('placeholder.password.confirm')"
@focus="resetError"
/>
</a-form-item>
<div class="self-center flex flex-col gap-4 items-center justify-center w-full">
<NcButton type="primary" :is-loading="isLoading" html-type="submit">
<span class="flex items-center gap-2">
<component :is="iconMap.signin" />
{{ $t('general.reset') }}
</span>
</NcButton>
</div> </div>
</Transition> </a-form>
</div>
<a-form-item
:label="$t('placeholder.password.new')"
name="password"
:rules="[{ required: true, message: t('msg.error.signUpRules.passwdRequired') }]"
>
<a-input-password
v-model:value="form.password"
:placeholder="$t('placeholder.password.new')"
class="password"
@focus="resetError"
/>
</a-form-item>
<a-form-item
:label="$t('placeholder.password.confirm')"
name="newPassword"
:rules="[{ required: true, message: t('msg.error.signUpRules.passwdRequired') }]"
>
<a-input-password
v-model:value="form.newPassword"
type="password"
class="password"
:placeholder="$t('placeholder.password.confirm')"
@focus="resetError"
/>
</a-form-item>
<div class="self-center flex flex-col gap-4 items-center justify-center w-full">
<NcButton type="primary" :is-loading="isLoading" html-type="submit">
<span class="flex items-center gap-2">
<component :is="iconMap.signin" />
{{ $t('general.reset') }}
</span>
</NcButton>
</div>
</a-form>
</div> </div>
</div> </NuxtLayout>
</NuxtLayout> </div>
</template> </template>
<style lang="scss"> <style lang="scss">

190
packages/nc-gui/pages/signin.vue

@ -92,114 +92,116 @@ function navigateForgotPassword() {
</script> </script>
<template> <template>
<NuxtLayout> <div>
<div <NuxtLayout>
data-testid="nc-form-signin"
class="md:bg-primary bg-opacity-5 signin h-full min-h-[600px] flex flex-col justify-center items-center nc-form-signin"
>
<div <div
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)" data-testid="nc-form-signin"
class="md:bg-primary bg-opacity-5 signin h-full min-h-[600px] flex flex-col justify-center items-center nc-form-signin"
> >
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" /> <div
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)"
>
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" />
<h1 class="prose-2xl font-bold self-center my-4">{{ $t('general.signIn') }}</h1> <h1 class="prose-2xl font-bold self-center my-4">{{ $t('general.signIn') }}</h1>
<a-form ref="formValidator" :model="form" layout="vertical" no-style @finish="signIn"> <a-form ref="formValidator" :model="form" layout="vertical" no-style @finish="signIn">
<template v-if="!appInfo.disableEmailAuth"> <template v-if="!appInfo.disableEmailAuth">
<Transition name="layout"> <Transition name="layout">
<div v-if="error" class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1"> <div v-if="error" class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1">
<div class="flex items-center gap-2 justify-center"> <div class="flex items-center gap-2 justify-center">
<MaterialSymbolsWarning /> <MaterialSymbolsWarning />
<div class="break-words">{{ error }}</div> <div class="break-words">{{ error }}</div>
</div>
</div> </div>
</Transition>
<a-form-item :label="$t('labels.email')" name="email" :rules="formRules.email">
<a-input
v-model:value="form.email"
data-testid="nc-form-signin__email"
size="large"
:placeholder="$t('msg.info.signUp.workEmail')"
@focus="resetError"
/>
</a-form-item>
<a-form-item :label="$t('labels.password')" name="password" :rules="formRules.password">
<a-input-password
v-model:value="form.password"
data-testid="nc-form-signin__password"
size="large"
class="password"
:placeholder="$t('msg.info.signUp.enterPassword')"
@focus="resetError"
/>
</a-form-item>
<div class="hidden md:block text-right">
<nuxt-link class="prose-sm" @click="navigateForgotPassword">
{{ $t('msg.info.signUp.forgotPassword') }}
</nuxt-link>
</div> </div>
</Transition>
<a-form-item :label="$t('labels.email')" name="email" :rules="formRules.email">
<a-input
v-model:value="form.email"
data-testid="nc-form-signin__email"
size="large"
:placeholder="$t('msg.info.signUp.workEmail')"
@focus="resetError"
/>
</a-form-item>
<a-form-item :label="$t('labels.password')" name="password" :rules="formRules.password">
<a-input-password
v-model:value="form.password"
data-testid="nc-form-signin__password"
size="large"
class="password"
:placeholder="$t('msg.info.signUp.enterPassword')"
@focus="resetError"
/>
</a-form-item>
<div class="hidden md:block text-right">
<nuxt-link class="prose-sm" @click="navigateForgotPassword">
{{ $t('msg.info.signUp.forgotPassword') }}
</nuxt-link>
</div>
</template>
<div class="self-center flex flex-col flex-wrap gap-4 items-center mt-4 justify-center">
<template v-if="!appInfo.disableEmailAuth">
<button data-testid="nc-form-signin__submit" class="scaling-btn bg-opacity-100" type="submit">
<span class="flex items-center gap-2">
<component :is="iconMap.signin" />
{{ $t('general.signIn') }}
</span>
</button>
</template> </template>
<a
v-if="appInfo.googleAuthEnabled" <div class="self-center flex flex-col flex-wrap gap-4 items-center mt-4 justify-center">
:href="`${appInfo.ncSiteUrl}/auth/google`" <template v-if="!appInfo.disableEmailAuth">
class="scaling-btn bg-opacity-100 after:(!bg-white) !text-primary !no-underline" <button data-testid="nc-form-signin__submit" class="scaling-btn bg-opacity-100" type="submit">
>
<span class="flex items-center gap-2">
<LogosGoogleGmail />
{{ $t('labels.signInWithProvider', { provider: 'Google' }) }}
</span>
</a>
<div
v-if="appInfo.oidcAuthEnabled"
class="self-center flex flex-col flex-wrap gap-4 items-center mt-4 justify-center"
>
<a :href="`${appInfo.ncSiteUrl}/auth/oidc`" class="!text-primary !no-underline">
<button type="button" class="scaling-btn bg-opacity-100">
<span class="flex items-center gap-2"> <span class="flex items-center gap-2">
<MdiLogin /> <component :is="iconMap.signin" />
{{ $t('general.signIn') }}
<template v-if="!appInfo.disableEmailAuth">
{{ $t('labels.signUpWithProvider', { provider: appInfo.oidcProviderName || 'OpenID Connect' }) }}
</template>
<template v-else>
{{ $t('general.signIn') }}
</template>
</span> </span>
</button> </button>
</template>
<a
v-if="appInfo.googleAuthEnabled"
:href="`${appInfo.ncSiteUrl}/auth/google`"
class="scaling-btn bg-opacity-100 after:(!bg-white) !text-primary !no-underline"
>
<span class="flex items-center gap-2">
<LogosGoogleGmail />
{{ $t('labels.signInWithProvider', { provider: 'Google' }) }}
</span>
</a> </a>
</div>
<div v-if="!appInfo.inviteOnlySignup" class="text-end prose-sm"> <div
{{ $t('msg.info.signUp.dontHaveAccount') }} v-if="appInfo.oidcAuthEnabled"
<nuxt-link @click="navigateSignUp">{{ $t('general.signUp') }}</nuxt-link> class="self-center flex flex-col flex-wrap gap-4 items-center mt-4 justify-center"
</div> >
<template v-if="!appInfo.disableEmailAuth"> <a :href="`${appInfo.ncSiteUrl}/auth/oidc`" class="!text-primary !no-underline">
<div class="md:hidden"> <button type="button" class="scaling-btn bg-opacity-100">
<nuxt-link class="prose-sm" @click="navigateForgotPassword"> <span class="flex items-center gap-2">
{{ $t('msg.info.signUp.forgotPassword') }} <MdiLogin />
</nuxt-link>
<template v-if="!appInfo.disableEmailAuth">
{{ $t('labels.signUpWithProvider', { provider: appInfo.oidcProviderName || 'OpenID Connect' }) }}
</template>
<template v-else>
{{ $t('general.signIn') }}
</template>
</span>
</button>
</a>
</div> </div>
</template>
</div> <div v-if="!appInfo.inviteOnlySignup" class="text-end prose-sm">
</a-form> {{ $t('msg.info.signUp.dontHaveAccount') }}
<nuxt-link @click="navigateSignUp">{{ $t('general.signUp') }}</nuxt-link>
</div>
<template v-if="!appInfo.disableEmailAuth">
<div class="md:hidden">
<nuxt-link class="prose-sm" @click="navigateForgotPassword">
{{ $t('msg.info.signUp.forgotPassword') }}
</nuxt-link>
</div>
</template>
</div>
</a-form>
</div>
</div> </div>
</div> </NuxtLayout>
</NuxtLayout> </div>
</template> </template>
<style lang="scss"> <style lang="scss">

216
packages/nc-gui/pages/signup/[[token]].vue

@ -127,124 +127,126 @@ onMounted(async () => {
</script> </script>
<template> <template>
<NuxtLayout> <div>
<div class="md:bg-primary bg-opacity-5 signup h-full min-h-[600px] flex flex-col justify-center items-center"> <NuxtLayout>
<div <div class="md:bg-primary bg-opacity-5 signup h-full min-h-[600px] flex flex-col justify-center items-center">
class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)" <div
> class="bg-white mt-[60px] relative flex flex-col justify-center gap-2 w-full max-w-[500px] mx-auto p-8 md:(rounded-lg border-1 border-gray-200 shadow-xl)"
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" /> >
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent ring-opacity-100)" :animate="isLoading" />
<h1 class="prose-2xl font-bold self-center my-4">
{{ $t('general.signUp') }}
{{ $route.query.redirect_to === '/referral' ? '& REFER' : '' }}
{{ $route.query.redirect_to === '/pricing' ? '& BUY' : '' }}
</h1>
<h2 v-if="appInfo.firstUser" class="prose !text-primary font-semibold self-center">
{{ $t('msg.info.signUp.superAdmin') }}
</h2>
<a-form ref="formValidator" :model="form" layout="vertical" no-style @finish="signUp">
<template v-if="!appInfo.disableEmailAuth">
<Transition name="layout">
<div
v-if="error"
class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1"
data-testid="nc-signup-error"
>
<div class="flex items-center gap-2 justify-center">
<MaterialSymbolsWarning />
<div class="break-words">{{ error }}</div>
</div>
</div>
</Transition>
<a-form-item :label="$t('labels.email')" name="email" :rules="formRules.email">
<a-input
v-model:value="form.email"
size="large"
:placeholder="$t('msg.info.signUp.workEmail')"
@focus="resetError"
/>
</a-form-item>
<a-form-item :label="$t('labels.password')" name="password" :rules="formRules.password">
<a-input-password
v-model:value="form.password"
size="large"
class="password"
:placeholder="$t('msg.info.signUp.enterPassword')"
@focus="resetError"
/>
</a-form-item>
</template>
<div class="self-center flex flex-col flex-wrap gap-4 items-center mt-4">
<template v-if="!appInfo.disableEmailAuth">
<button class="scaling-btn bg-opacity-100" type="submit">
<span class="flex items-center gap-2">
<MaterialSymbolsRocketLaunchOutline />
{{ $t('general.signUp') }} <h1 class="prose-2xl font-bold self-center my-4">
</span> {{ $t('general.signUp') }}
</button> {{ $route.query.redirect_to === '/referral' ? '& REFER' : '' }}
{{ $route.query.redirect_to === '/pricing' ? '& BUY' : '' }}
</h1>
<h2 v-if="appInfo.firstUser" class="prose !text-primary font-semibold self-center">
{{ $t('msg.info.signUp.superAdmin') }}
</h2>
<a-form ref="formValidator" :model="form" layout="vertical" no-style @finish="signUp">
<template v-if="!appInfo.disableEmailAuth">
<Transition name="layout">
<div
v-if="error"
class="self-center mb-4 bg-red-500 text-white rounded-lg w-3/4 mx-auto p-1"
data-testid="nc-signup-error"
>
<div class="flex items-center gap-2 justify-center">
<MaterialSymbolsWarning />
<div class="break-words">{{ error }}</div>
</div>
</div>
</Transition>
<a-form-item :label="$t('labels.email')" name="email" :rules="formRules.email">
<a-input
v-model:value="form.email"
size="large"
:placeholder="$t('msg.info.signUp.workEmail')"
@focus="resetError"
/>
</a-form-item>
<a-form-item :label="$t('labels.password')" name="password" :rules="formRules.password">
<a-input-password
v-model:value="form.password"
size="large"
class="password"
:placeholder="$t('msg.info.signUp.enterPassword')"
@focus="resetError"
/>
</a-form-item>
</template> </template>
<a <div class="self-center flex flex-col flex-wrap gap-4 items-center mt-4">
v-if="appInfo.googleAuthEnabled" <template v-if="!appInfo.disableEmailAuth">
:href="`${appInfo.ncSiteUrl}/auth/google`" <button class="scaling-btn bg-opacity-100" type="submit">
class="scaling-btn bg-opacity-100 after:(!bg-white) !text-primary !no-underline"
>
<span class="flex items-center gap-2">
<LogosGoogleGmail />
{{ $t('labels.signUpWithProvider', { provider: 'Google' }) }}
</span>
</a>
<div
v-if="appInfo.oidcAuthEnabled"
class="self-center flex flex-col flex-wrap gap-4 items-center mt-4 justify-center"
>
<a :href="`${appInfo.ncSiteUrl}/auth/oidc`" class="!text-primary !no-underline">
<button type="button" class="scaling-btn bg-opacity-100">
<span class="flex items-center gap-2"> <span class="flex items-center gap-2">
<MdiLogin /> <MaterialSymbolsRocketLaunchOutline />
<template v-if="!appInfo.disableEmailAuth">
{{ $t('labels.signUpWithProvider', { provider: appInfo.oidcProviderName || 'OpenID Connect' }) }} {{ $t('general.signUp') }}
</template>
<template v-else>
{{ $t('general.signUp') }}
</template>
</span> </span>
</button> </button>
</template>
<a
v-if="appInfo.googleAuthEnabled"
:href="`${appInfo.ncSiteUrl}/auth/google`"
class="scaling-btn bg-opacity-100 after:(!bg-white) !text-primary !no-underline"
>
<span class="flex items-center gap-2">
<LogosGoogleGmail />
{{ $t('labels.signUpWithProvider', { provider: 'Google' }) }}
</span>
</a> </a>
</div>
<div v-if="!appInfo.disableEmailAuth" class="flex items-center gap-2"> <div
<a-switch v-if="appInfo.oidcAuthEnabled"
v-model:checked="subscribe" class="self-center flex flex-col flex-wrap gap-4 items-center mt-4 justify-center"
size="small" >
class="my-1 hover:(ring ring-accent ring-opacity-100) focus:(!ring !ring-accent ring-opacity-100)" <a :href="`${appInfo.ncSiteUrl}/auth/oidc`" class="!text-primary !no-underline">
/> <button type="button" class="scaling-btn bg-opacity-100">
<div class="prose-xs text-gray-500">{{ $t('msg.subscribeToOurWeeklyNewsletter') }}</div> <span class="flex items-center gap-2">
</div> <MdiLogin />
<template v-if="!appInfo.disableEmailAuth">
{{ $t('labels.signUpWithProvider', { provider: appInfo.oidcProviderName || 'OpenID Connect' }) }}
</template>
<template v-else>
{{ $t('general.signUp') }}
</template>
</span>
</button>
</a>
</div>
<div class="text-end prose-sm"> <div v-if="!appInfo.disableEmailAuth" class="flex items-center gap-2">
{{ $t('msg.info.signUp.alreadyHaveAccount') }} <a-switch
v-model:checked="subscribe"
size="small"
class="my-1 hover:(ring ring-accent ring-opacity-100) focus:(!ring !ring-accent ring-opacity-100)"
/>
<div class="prose-xs text-gray-500">{{ $t('msg.subscribeToOurWeeklyNewsletter') }}</div>
</div>
<nuxt-link @click="navigateSignIn">{{ $t('general.signIn') }}</nuxt-link> <div class="text-end prose-sm">
</div> {{ $t('msg.info.signUp.alreadyHaveAccount') }}
</div>
</a-form>
</div>
<div class="prose-sm mt-4 text-gray-500"> <nuxt-link @click="navigateSignIn">{{ $t('general.signIn') }}</nuxt-link>
{{ $t('msg.bySigningUp') }} </div>
<a class="prose-sm !text-gray-500 underline" target="_blank" href="https://nocodb.com/policy-nocodb" rel="noopener"> </div>
{{ $t('title.termsOfService') }}</a </a-form>
> </div>
<div class="prose-sm mt-4 text-gray-500">
{{ $t('msg.bySigningUp') }}
<a class="prose-sm !text-gray-500 underline" target="_blank" href="https://nocodb.com/policy-nocodb" rel="noopener">
{{ $t('title.termsOfService') }}</a
>
</div>
</div> </div>
</div> </NuxtLayout>
</NuxtLayout> </div>
</template> </template>
<style lang="scss"> <style lang="scss">

Loading…
Cancel
Save