Browse Source

Merge branch 'develop' into feat/pnpm

pull/5903/head
Wing-Kam Wong 1 year ago
parent
commit
c205833a59
  1. 13
      README.md
  2. 4
      packages/nc-gui/components/project/InviteProjectCollabSection.vue
  3. 2
      packages/nc-lib-gui/package.json
  4. 2
      packages/nocodb-sdk/package.json
  5. 4
      packages/nocodb/package.json
  6. 2
      packages/nocodb/src/run/testDocker.ts
  7. 4
      packages/nocodb/src/services/api-docs/swagger/templates/params.ts
  8. 21
      packages/nocodb/src/services/project-users/project-users.service.ts
  9. 2
      packages/nocodb/src/version-upgrader/NcUpgrader.ts
  10. 23
      tests/playwright/pages/Account/Users.ts
  11. 72
      tests/playwright/tests/db/usersAccounts/accountUserManagement.spec.ts
  12. 12
      tests/playwright/tests/db/usersAccounts/rolesCreate.spec.ts

13
README.md

@ -192,14 +192,15 @@ npm start
Access Dashboard using: [http://localhost:8080/dashboard](http://localhost:8080/dashboard)
# Screenshots
![2](https://github.com/nocodb/nocodb/assets/86527202/a127c05e-2121-4af2-a342-128e0e2d0291)
![3](https://github.com/nocodb/nocodb/assets/86527202/674da952-8a06-4848-a0e8-a7b02d5f5c88)
![4](https://github.com/nocodb/nocodb/assets/86527202/cbc5152a-9caf-4f77-a8f7-92a9d06d025b)
![5](https://github.com/nocodb/nocodb/assets/86527202/dc75dfdc-c486-4f5a-a853-2a8f9e6b569a)
![1](https://user-images.githubusercontent.com/35857179/194844858-d353bd15-1edf-406c-889b-ba60f76831f4.png)
![2](https://user-images.githubusercontent.com/35857179/194844872-1a1094b9-761b-4ab6-a0ab-8e11dcae6571.png)
![3](https://user-images.githubusercontent.com/35857179/194844881-23f12c4c-7a5f-403e-928c-ef4c53b2665d.png)
![4](https://user-images.githubusercontent.com/35857179/194844885-faaf042f-bad2-4924-84f0-2c08813271d8.png)
![5](https://user-images.githubusercontent.com/35857179/194844886-a17006e0-979d-493f-83c4-0e72f5a9b716.png)
![6](https://user-images.githubusercontent.com/35857179/194844890-b9f265ae-6e40-4fa5-9267-d1367c27c8e6.png)
![7](https://user-images.githubusercontent.com/35857179/194844891-bee9aea3-aff3-4247-a918-b2f3fbbc672e.png)
![7](https://github.com/nocodb/nocodb/assets/86527202/be64e619-7295-43e2-aa95-cace4462b17f)
![8](https://github.com/nocodb/nocodb/assets/86527202/4538bf5a-371f-4ec1-a867-8197e5824286)
![8](https://user-images.githubusercontent.com/35857179/194844893-82d5e21b-ae61-41bd-9990-31ad659bf490.png)
![9](https://user-images.githubusercontent.com/35857179/194844897-cfd79946-e413-4c97-b16d-eb4d7678bb79.png)
![10](https://user-images.githubusercontent.com/35857179/194844902-c0122570-0dd5-41cf-a26f-6f8d71fefc99.png)

4
packages/nc-gui/components/project/InviteProjectCollabSection.vue

@ -26,10 +26,10 @@ const usersData = ref<{
const isInvitingCollaborators = ref(false)
const inviteCollaborator = async () => {
isInvitingCollaborators.value = true
if (isInvitingCollaborators.value) return
isInvitingCollaborators.value = true
try {
usersData.value = await inviteUser(inviteData)
usersData.roles = inviteData.roles

2
packages/nc-lib-gui/package.json

@ -1,6 +1,6 @@
{
"name": "nc-lib-gui",
"version": "0.111.3",
"version": "0.111.4",
"description": "NocoDB GUI",
"author": {
"name": "NocoDB",

2
packages/nocodb-sdk/package.json

@ -1,6 +1,6 @@
{
"name": "nocodb-sdk",
"version": "0.111.3",
"version": "0.111.4",
"description": "NocoDB SDK",
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",

4
packages/nocodb/package.json

@ -1,6 +1,6 @@
{
"name": "nocodb",
"version": "0.111.3",
"version": "0.111.4",
"description": "NocoDB Backend",
"main": "dist/bundle.js",
"author": {
@ -129,7 +129,7 @@
"mysql2": "^3.2.0",
"nanoid": "^3.1.20",
"nc-help": "0.2.88",
"nc-lib-gui": "0.111.3",
"nc-lib-gui": "0.111.4",
"nc-plugin": "^0.1.3",
"ncp": "^2.0.0",
"nestjs-kafka": "^1.0.6",

2
packages/nocodb/src/run/testDocker.ts

@ -40,7 +40,7 @@ process.env[`DEBUG`] = 'xc*';
console.log(admin_response.data);
}
for (let i = 0; i < 8; i++) {
for (let i = 0; i < 4; i++) {
if (!(await User.getByEmail(`user-${i}@nocodb.com`))) {
const response = await axios.post(
`http://localhost:${

4
packages/nocodb/src/services/api-docs/swagger/templates/params.ts

@ -1,4 +1,4 @@
import { RelationTypes, UITypes } from 'nocodb-sdk';
import { isLinksOrLTAR, RelationTypes, UITypes } from 'nocodb-sdk'
import type { LinkToAnotherRecordColumn } from '~/models';
import type { SwaggerColumn } from '../getSwaggerColumnMetas';
@ -100,7 +100,7 @@ export const columnNameQueryParam = {
export const columnNameParam = (columns: SwaggerColumn[]) => {
const columnNames = [];
for (const { column } of columns) {
if (column.uidt !== UITypes.LinkToAnotherRecord || column.system) continue;
if (!isLinksOrLTAR(column) || column.system) continue;
columnNames.push(column.title);
}

21
packages/nocodb/src/services/project-users/project-users.service.ts

@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import {
AppEvents,
extractRolesObj,
OrgUserRoles,
PluginCategory,
ProjectRoles,
@ -53,6 +54,26 @@ export class ProjectUsersService {
param.projectUser,
);
if (
getProjectRolePower({
project_roles: extractRolesObj(param.projectUser.roles),
}) > getProjectRolePower(param.req.user)
) {
NcError.badRequest(`Insufficient privilege to invite with this role`);
}
if (
![
ProjectRoles.CREATOR,
ProjectRoles.EDITOR,
ProjectRoles.COMMENTER,
ProjectRoles.VIEWER,
ProjectRoles.NO_ACCESS,
].includes(param.projectUser.roles as ProjectRoles)
) {
NcError.badRequest('Invalid role');
}
const emails = (param.projectUser.email || '')
.toLowerCase()
.split(/\s*,\s*/)

2
packages/nocodb/src/version-upgrader/NcUpgrader.ts

@ -68,7 +68,7 @@ export default class NcUpgrader {
'',
'nc_store',
{
value: JSON.stringify(config),
value: JSON.stringify({ version: config.version }),
},
{
key: NcUpgrader.STORE_KEY,

23
tests/playwright/pages/Account/Users.ts

@ -33,9 +33,7 @@ export class AccountUsersPage extends BasePage {
return this.accountPage.get().locator(`[data-testid="nc-super-user-list"]`);
}
async invite({ email: _email, role }: { email: string; role: string }) {
const email = this.prefixEmail(_email);
async invite({ email, role }: { email: string; role: string }) {
await this.inviteUserBtn.click();
await this.inviteUserModal.locator(`input[placeholder="E-mail"]`).fill(email);
await this.inviteUserModal.locator(`.nc-user-roles`).click();
@ -58,21 +56,18 @@ export class AccountUsersPage extends BasePage {
await this.inviteUserModal.locator(`button.ant-btn-icon-only:visible`).first().click();
}
getUserRow({ email: _email }: { email: string }) {
const email = this.prefixEmail(_email);
async getUserRow({ email }: { email: string }) {
// ensure page is loaded
await this.get().waitFor();
return this.get().locator(`tr:has-text("${email}")`);
}
async updateRole({ email, role }: { email: string; role: string }) {
const userRow = this.getUserRow({ email });
const userRow = await this.getUserRow({ email });
await userRow.locator(`.nc-user-roles`).click();
// todo: replace delay with waitForSelector
await new Promise(resolve => setTimeout(resolve, 400));
await this.rootPage.locator(`.nc-users-list-role-option:visible:has-text("${role}")`).click();
await this.verifyToast({ message: 'Successfully updated the user details' });
await this.rootPage.locator(`.nc-users-list-role-option:visible:has-text("${role}")`).waitFor();
await this.rootPage.locator(`.nc-users-list-role-option:visible:has-text("${role}")`).last().click();
await this.rootPage.locator(`.nc-users-list-role-option`).last().waitFor({ state: 'hidden' });
}
async inviteMore() {
@ -80,7 +75,7 @@ export class AccountUsersPage extends BasePage {
}
async openRowActionMenu({ email }: { email: string }) {
const userRow = this.getUserRow({ email });
const userRow = await this.getUserRow({ email });
return userRow.locator(`.nc-user-row-action`).click();
}

72
tests/playwright/tests/db/usersAccounts/accountUserManagement.spec.ts

@ -1,32 +1,55 @@
import { test } from '@playwright/test';
import { expect, test } from '@playwright/test';
import { AccountPage } from '../../../pages/Account';
import { AccountUsersPage } from '../../../pages/Account/Users';
import { SignupPage } from '../../../pages/SignupPage';
import setup, { unsetup } from '../../../setup';
import { WorkspacePage } from '../../../pages/WorkspacePage';
import { getDefaultPwd } from '../../../tests/utils/general';
import { Api } from 'nocodb-sdk';
import { DashboardPage } from '../../../pages/Dashboard';
import { LoginPage } from '../../../pages/LoginPage';
let api: Api<any>;
const roleDb = [
{ email: 'creator@nocodb.com', role: 'Organization Level Creator', url: '' },
{ email: 'viewer@nocodb.com', role: 'Organization Level Viewer', url: '' },
{ email: 'org_creator@nocodb.com', role: 'Organization Level Creator', url: '' },
{ email: 'org_viewer@nocodb.com', role: 'Organization Level Viewer', url: '' },
];
test.describe.skip('User roles', () => {
test.describe('User roles', () => {
let accountUsersPage: AccountUsersPage;
let accountPage: AccountPage;
let signupPage: SignupPage;
let workspacePage: WorkspacePage;
let loginPage: LoginPage;
let dashboard: DashboardPage;
// @ts-ignore
let context: any;
test.beforeEach(async ({ page }) => {
context = await setup({ page, isEmptyProject: true });
context = await setup({ page, isEmptyProject: true, isSuperUser: true });
dashboard = new DashboardPage(page, context.project);
accountPage = new AccountPage(page);
accountUsersPage = new AccountUsersPage(accountPage);
signupPage = new SignupPage(accountPage.rootPage);
workspacePage = new WorkspacePage(accountPage.rootPage);
loginPage = new LoginPage(accountPage.rootPage);
try {
api = new Api({
baseURL: `http://localhost:8080/`,
headers: {
'xc-auth': context.token,
},
});
} catch (e) {
console.log(e);
}
// check if user already exists; if so- remove them
for (let i = 0; i < roleDb.length; i++) {
const user = await api.orgUsers.list();
if (user.list.length > 0) {
const u = user.list.find((u: any) => u.email === roleDb[i].email);
if (u) await api.orgUsers.delete(u.id);
}
}
});
test.afterEach(async () => {
@ -45,18 +68,21 @@ test.describe.skip('User roles', () => {
role: roleDb[i].role,
});
await accountUsersPage.closeInvite();
await signupAndVerify(i);
await accountPage.signOut();
const loginPage = new LoginPage(accountPage.rootPage);
await loginPage.fillEmail({ email: 'user@nocodb.com', withoutPrefix: true });
await loginPage.fillPassword(getDefaultPwd());
await loginPage.submit();
}
// update role
await signupAndVerify(0);
await accountUsersPage.goto();
await signupAndVerify(1);
await dashboard.signOut();
await loginPage.signIn({
email: 'user@nocodb.com',
password: getDefaultPwd(),
withoutPrefix: true,
});
await accountUsersPage.goto();
// change role
for (let i = 0; i < roleDb.length; i++) {
await accountUsersPage.updateRole({
email: roleDb[i].email,
@ -81,10 +107,16 @@ test.describe.skip('User roles', () => {
await signupPage.signUp({
email: roleDb[roleIdx].email,
password: getDefaultPwd(),
withoutPrefix: true,
});
await workspacePage.checkWorkspaceCreateButton({
exists: roleDb[roleIdx].role === 'Organization Level Creator',
});
// wait for page rendering to complete after sign up
await dashboard.rootPage.waitForTimeout(1000);
if (roleDb[roleIdx].role === 'Organization Level Creator') {
expect(await dashboard.leftSidebar.btn_newProject.isVisible()).toBeTruthy();
} else {
expect(await dashboard.leftSidebar.btn_newProject.isVisible()).toBeFalsy();
}
}
});

12
tests/playwright/tests/db/usersAccounts/rolesCreate.spec.ts

@ -1,11 +1,10 @@
import { test } from '@playwright/test';
import { DashboardPage } from '../../../pages/Dashboard';
import setup, { unsetup } from '../../../setup';
import { SettingsPage } from '../../../pages/Dashboard/Settings';
import { SignupPage } from '../../../pages/SignupPage';
import { ProjectsPage } from '../../../pages/ProjectsPage';
import { getDefaultPwd } from '../../../tests/utils/general';
import { WorkspacePage } from '../../../pages/WorkspacePage';
import { isEE } from '../../../setup/db';
const roleDb = [
{ email: 'creator@nocodb.com', role: 'creator', url: '' },
@ -15,27 +14,26 @@ const roleDb = [
];
test.describe.skip('User roles', () => {
if (isEE()) {
test.skip();
}
let dashboard: DashboardPage;
let settings: SettingsPage;
let signupPage: SignupPage;
let projectsPage: ProjectsPage;
let workspacePage: WorkspacePage;
let context: any;
test.beforeEach(async ({ page }) => {
context = await setup({ page, isEmptyProject: false });
dashboard = new DashboardPage(page, context.project);
settings = dashboard.settings;
signupPage = new SignupPage(page);
projectsPage = new ProjectsPage(page);
workspacePage = new WorkspacePage(page);
});
test.afterEach(async () => {
await unsetup(context);
});
test.skip('Create role', async () => {
test('Create role', async () => {
test.slow();
for (let i = 0; i < roleDb.length; i++) {

Loading…
Cancel
Save