Browse Source

Merge pull request #7650 from nocodb/nc-feat/sso-google

Nc feat/sso google
pull/7670/head
Pranav C 6 months ago committed by GitHub
parent
commit
6a68b0825b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      packages/nc-gui/layouts/general.vue
  2. 2
      packages/nc-gui/pages/account/index.vue
  3. 9
      packages/nc-gui/pages/forgot-password.vue
  4. 2
      packages/nc-gui/pages/index/[typeOrId]/form/[viewId].vue
  5. 6
      packages/nc-gui/pages/profile/[[username]].vue
  6. 2
      packages/nc-gui/pages/projects/index.vue
  7. 6
      packages/nc-gui/pages/reset/[id].vue
  8. 2
      packages/nc-gui/pages/signin.vue
  9. 2
      packages/nc-gui/pages/signup/[[token]].vue
  10. 29
      tests/playwright/pages/Account/Authentication.ts
  11. 31
      tests/playwright/pages/SsoIdpPage/GoogleLoginPage.ts

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

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

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

@ -28,6 +28,7 @@ const logout = async () => {
</script>
<template>
<div>
<NuxtLayout name="empty">
<div class="mx-auto h-full">
<div class="h-full overflow-y-auto flex">
@ -199,6 +200,7 @@ const logout = async () => {
</div>
</div>
</NuxtLayout>
</div>
</template>
<style lang="scss" scoped>

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

@ -61,6 +61,7 @@ function navigateSignIn() {
</script>
<template>
<div>
<NuxtLayout>
<div class="md:bg-primary bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center">
<div
@ -96,7 +97,12 @@ function navigateSignIn() {
</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-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">
@ -116,6 +122,7 @@ function navigateSignIn() {
</div>
</div>
</NuxtLayout>
</div>
</template>
<style lang="scss">

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

@ -62,6 +62,7 @@ watch(
</script>
<template>
<div>
<NuxtLayout>
<NuxtPage v-if="!passwordDlg" />
@ -94,6 +95,7 @@ watch(
</div>
</a-modal>
</NuxtLayout>
</div>
</template>
<style lang="scss" scoped>

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

@ -11,6 +11,7 @@ await loadProfile(route.params.username as string)
</script>
<template>
<div>
<NuxtLayout>
<a-layout class="h-[75vh] overflow-y-auto flex">
<a-layout-sider :collapsed="false" width="320" class="h-max px-5" :trigger="null" collapsible theme="light">
@ -72,7 +73,9 @@ await loadProfile(route.params.username as string)
<div v-if="profile.website" class="nc-profile-website my-2">
<div class="flex items-center mr-4">
<MdiLinkVariant class="text-lg mr-2" />
<a class="!no-underline" :href="profile.website" rel="noopener noreferrer" target="_blank">{{ profile.website }}</a>
<a class="!no-underline" :href="profile.website" rel="noopener noreferrer" target="_blank">{{
profile.website
}}</a>
</div>
</div>
@ -160,4 +163,5 @@ await loadProfile(route.params.username as string)
</a-layout-content>
</a-layout>
</NuxtLayout>
</div>
</template>

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

@ -57,6 +57,7 @@ const deleteProject = (base: BaseType) => {
</script>
<template>
<div>
<NuxtLayout>
<template #sidebar>
<div class="flex flex-col h-full">
@ -141,4 +142,5 @@ const deleteProject = (base: BaseType) => {
<a-modal></a-modal>
</NuxtLayout>
</div>
</template>

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

@ -61,8 +61,11 @@ function resetError() {
</script>
<template>
<div>
<NuxtLayout>
<div class="md:bg-primary signin bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center">
<div
class="md:bg-primary signin bg-opacity-5 forgot-password h-full min-h-[600px] flex flex-col justify-center items-center"
>
<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)"
>
@ -127,6 +130,7 @@ function resetError() {
</div>
</div>
</NuxtLayout>
</div>
</template>
<style lang="scss">

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

@ -92,6 +92,7 @@ function navigateForgotPassword() {
</script>
<template>
<div>
<NuxtLayout>
<div
data-testid="nc-form-signin"
@ -200,6 +201,7 @@ function navigateForgotPassword() {
</div>
</div>
</NuxtLayout>
</div>
</template>
<style lang="scss">

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

@ -127,6 +127,7 @@ onMounted(async () => {
</script>
<template>
<div>
<NuxtLayout>
<div class="md:bg-primary bg-opacity-5 signup h-full min-h-[600px] flex flex-col justify-center items-center">
<div
@ -245,6 +246,7 @@ onMounted(async () => {
</div>
</div>
</NuxtLayout>
</div>
</template>
<style lang="scss">

29
tests/playwright/pages/Account/Authentication.ts

@ -35,8 +35,10 @@ export class AccountAuthenticationPage extends BasePage {
return this.rootPage.locator(`[data-test-id="nc-${provider}-provider-${title}"]`);
}
async deleteProvider(provider: 'saml' | 'oidc', title: string) {
await this.rootPage.locator(`.nc-${provider}-${title}-more-option`).click();
async deleteProvider(provider: 'saml' | 'oidc' | 'google', title: string) {
await this.rootPage
.locator(provider === 'google' ? '.nc-google-more-option' : `.nc-${provider}-${title}-more-option`)
.click();
await this.waitForResponse({
uiAction: () => this.rootPage.locator(`[data-test-id="nc-${provider}-delete"]`).click(),
httpMethodsToMatch: ['DELETE'],
@ -44,7 +46,7 @@ export class AccountAuthenticationPage extends BasePage {
});
}
async toggleProvider(provider: 'saml' | 'oidc', title: string) {
async toggleProvider(provider: 'saml' | 'oidc' | 'google', title: string) {
await this.waitForResponse({
uiAction: () => this.get().locator(`.nc-${provider}-${title}-enable .nc-switch`).click(),
httpMethodsToMatch: ['PATCH'],
@ -159,4 +161,25 @@ export class AccountAuthenticationPage extends BasePage {
requestUrlPathToMatch: '/api/v2/sso-client',
});
}
async createGoogleProvider(p: { clientId: string; clientSecret: string }) {
await this.rootPage.locator(`.nc-google-more-option`).click();
await this.rootPage.locator(`[data-test-id="nc-google-edit"]`).click();
const googleModal = this.accountPage.rootPage.locator('.nc-google-modal');
// wait until redirect url is generated
await googleModal.locator('[data-test-id="nc-google-redirect-url"]:has-text("http://")').waitFor();
await googleModal.locator('[data-test-id="nc-google-client-id"]').fill(p.clientId);
await googleModal.locator('[data-test-id="nc-google-client-secret"]').fill(p.clientSecret);
await this.waitForResponse({
uiAction: () => googleModal.locator('[data-test-id="nc-google-save-btn"]').click(),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: '/api/v2/sso-client',
});
}
async verifyGoogleProviderCount(param: { count: number }) {}
}

31
tests/playwright/pages/SsoIdpPage/GoogleLoginPage.ts

@ -0,0 +1,31 @@
import { Page } from '@playwright/test';
import BasePage from '../Base';
import { ProjectsPage } from '../ProjectsPage';
import { expect } from '@playwright/test';
export class GoogleLoginPage extends BasePage {
readonly projectsPage: ProjectsPage;
constructor(rootPage: Page) {
super(rootPage);
this.projectsPage = new ProjectsPage(rootPage);
}
async goto(title = 'test') {
// reload page to get latest app info
await this.rootPage.reload({ waitUntil: 'networkidle' });
// click sign in with SAML
await this.rootPage.locator(`a:has-text("Sign in with google")`).click();
await this.rootPage.waitForNavigation({ url: /accounts\.google\.com/ });
}
get() {
return this.rootPage.locator('html');
}
async signIn(_: { email: string }) {
// skipping for now as it requires google account
// todo: later we can mock backend(google oauth2 endpoint calls) to test this
}
}
Loading…
Cancel
Save