Install
@@ -185,7 +185,6 @@ onMounted(async () => {
.caption {
font-size: 0.7rem;
- color: #242f3e;
}
.avatar {
diff --git a/packages/nc-gui/components/dashboard/settings/Modal.vue b/packages/nc-gui/components/dashboard/settings/Modal.vue
index 52dba591fc..6b775a87bb 100644
--- a/packages/nc-gui/components/dashboard/settings/Modal.vue
+++ b/packages/nc-gui/components/dashboard/settings/Modal.vue
@@ -77,20 +77,24 @@ const tabsInfo: TabGroup = {
$e('c:settings:team-auth')
},
},
- appStore: {
- // App Store
- title: t('title.appStore'),
- icon: StoreFrontOutline,
- subTabs: {
- new: {
- title: 'Apps',
- body: AppStore,
- },
- },
- onClick: () => {
- $e('c:settings:appstore')
- },
- },
+ ...(isUIAllowed('appStore')
+ ? {
+ appStore: {
+ // App Store
+ title: t('title.appStore'),
+ icon: StoreFrontOutline,
+ subTabs: {
+ new: {
+ title: 'Apps',
+ body: AppStore,
+ },
+ },
+ onClick: () => {
+ $e('c:settings:appstore')
+ },
+ },
+ }
+ : {}),
projMetaData: {
// Project Metadata
title: t('title.projMeta'),
diff --git a/packages/nc-gui/composables/useUIPermission/index.ts b/packages/nc-gui/composables/useUIPermission/index.ts
index ffc2e1e83e..cc2681e7aa 100644
--- a/packages/nc-gui/composables/useUIPermission/index.ts
+++ b/packages/nc-gui/composables/useUIPermission/index.ts
@@ -11,6 +11,14 @@ const hasPermission = (role: Role | ProjectRole, hasRole: boolean, permission: P
if (isString(rolePermission) && rolePermission === '*') return true
+ if ('include' in rolePermission && rolePermission.include) {
+ return !!rolePermission.include[permission as keyof typeof rolePermission.include]
+ }
+
+ if ('exclude' in rolePermission && rolePermission.exclude) {
+ return !rolePermission.exclude[permission as keyof typeof rolePermission.exclude]
+ }
+
return rolePermission[permission as keyof typeof rolePermission]
}
diff --git a/packages/nc-gui/composables/useUIPermission/rolePermissions.ts b/packages/nc-gui/composables/useUIPermission/rolePermissions.ts
index 887553d3e7..eed4e4704d 100644
--- a/packages/nc-gui/composables/useUIPermission/rolePermissions.ts
+++ b/packages/nc-gui/composables/useUIPermission/rolePermissions.ts
@@ -2,58 +2,81 @@ import { ProjectRole, Role } from '~/lib'
const rolePermissions = {
// general role permissions
+
+ /**
+ * Each permission value means the following
+ * `*` - which is wildcard, means all permissions are allowed
+ * `include` - which is an object, means only the permissions listed in the object are allowed
+ * `exclude` - which is an object, means all permissions are allowed except the ones listed in the object
+ * `undefined` or `{}` - which is the default value, means no permissions are allowed
+ * */
+
/** todo: enable wildcard permission
* limited permission due to unexpected behaviour in shared base if opened in same window */
- [Role.Super]: {
- projectTheme: true,
- },
- [Role.Admin]: {},
- [Role.Guest]: {},
+ [Role.Super]: '*',
+ [Role.Admin]: {} as Record
,
+ [Role.Guest]: {} as Record,
[Role.User]: {
- projectCreate: true,
- projectActions: true,
- projectSettings: true,
+ include: {
+ projectCreate: true,
+ projectActions: true,
+ projectSettings: true,
+ },
},
// Project role permissions
- [ProjectRole.Creator]: '*',
- [ProjectRole.Owner]: '*',
+ [ProjectRole.Creator]: {
+ exclude: {
+ appStore: true,
+ },
+ },
+ [ProjectRole.Owner]: {
+ exclude: {
+ appStore: true,
+ },
+ },
[ProjectRole.Editor]: {
- smartSheet: true,
- xcDatatableEditable: true,
- column: true,
- tableAttachment: true,
- tableRowUpdate: true,
- dataInsert: true,
- rowComments: true,
- gridViewOptions: true,
- sortSync: true,
- fieldsSync: true,
- gridColUpdate: true,
- filterSync: true,
- csvImport: true,
- apiDocs: true,
- projectSettings: true,
- newUser: false,
+ include: {
+ smartSheet: true,
+ xcDatatableEditable: true,
+ column: true,
+ tableAttachment: true,
+ tableRowUpdate: true,
+ dataInsert: true,
+ rowComments: true,
+ gridViewOptions: true,
+ sortSync: true,
+ fieldsSync: true,
+ gridColUpdate: true,
+ filterSync: true,
+ csvImport: true,
+ apiDocs: true,
+ projectSettings: true,
+ newUser: false,
+ },
},
[ProjectRole.Commenter]: {
- smartSheet: true,
- column: true,
- rowComments: true,
- projectSettings: true,
+ include: {
+ smartSheet: true,
+ column: true,
+ rowComments: true,
+ projectSettings: true,
+ },
},
[ProjectRole.Viewer]: {
- smartSheet: true,
- column: true,
- projectSettings: true,
+ include: {
+ smartSheet: true,
+ column: true,
+ projectSettings: true,
+ },
},
} as const
-type RolePermissions = Omit
+type RolePermissions = Omit
-type GetKeys = T extends Record ? keyof T : never
+type GetKeys = T extends Record> ? Key : never
-export type Permission = RolePermissions[K] extends Record
+export type Permission = RolePermissions[K] extends Record
? GetKeys
: never
diff --git a/packages/nc-gui/layouts/base.vue b/packages/nc-gui/layouts/base.vue
index dab22ba952..715f128d16 100644
--- a/packages/nc-gui/layouts/base.vue
+++ b/packages/nc-gui/layouts/base.vue
@@ -13,6 +13,8 @@ const hasSider = ref(false)
const sidebar = ref()
+const { isUIAllowed } = useUIPermission()
+
const logout = () => {
signOut()
navigateTo('/signin')
@@ -87,6 +89,19 @@ hooks.hook('page:finish', () => {
+
+
+
+
+
diff --git a/packages/nc-gui/middleware/auth.global.ts b/packages/nc-gui/middleware/auth.global.ts
index 7932c2df24..81d147fcea 100644
--- a/packages/nc-gui/middleware/auth.global.ts
+++ b/packages/nc-gui/middleware/auth.global.ts
@@ -1,6 +1,6 @@
import { message } from 'ant-design-vue'
import { defineNuxtRouteMiddleware, navigateTo } from '#app'
-import { useApi, useGlobal } from '#imports'
+import { useApi, useGlobal, useRoles } from '#imports'
/**
* Global auth middleware
@@ -38,6 +38,8 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
const { api } = useApi()
+ const { allRoles } = useRoles()
+
/** if user isn't signed in and google auth is enabled, try to check if sign-in data is present */
if (!state.signedIn && state.appInfo.value.googleAuthEnabled) await tryGoogleAuth()
@@ -68,6 +70,12 @@ export default defineNuxtRouteMiddleware(async (to, from) => {
return navigateTo(from.path)
}
} else {
+ /** If page is limited to certain users verify the user have the roles */
+ if (to.meta.allowedRoles && to.meta.allowedRoles.every((role) => !allRoles.value[role])) {
+ message.error("You don't have enough permission to access the page.")
+ return navigateTo('/')
+ }
+
/** if users are accessing the projects without having enough permissions, redirect to My Projects page */
if (to.params.projectId && from.params.projectId !== to.params.projectId) {
const user = await api.auth.me({ project_id: to?.params?.projectId as string })
diff --git a/packages/nc-gui/nuxt-shim.d.ts b/packages/nc-gui/nuxt-shim.d.ts
index e1cc40b10a..1e00d96034 100644
--- a/packages/nc-gui/nuxt-shim.d.ts
+++ b/packages/nc-gui/nuxt-shim.d.ts
@@ -28,6 +28,7 @@ declare module 'vue-router' {
public?: boolean
hideHeader?: boolean
title?: string
+ allowedRoles?: Role[]
}
interface RouteParams {
diff --git a/packages/nc-gui/pages/index/apps.vue b/packages/nc-gui/pages/index/apps.vue
new file mode 100644
index 0000000000..5b3d81bf2c
--- /dev/null
+++ b/packages/nc-gui/pages/index/apps.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
{{ $t('title.appStore') }}
+
+
+
+
+
diff --git a/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts b/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts
index f44674c0f1..b024ef7ab4 100644
--- a/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts
+++ b/packages/nocodb/src/lib/meta/helpers/ncMetaAclMw.ts
@@ -57,7 +57,11 @@ export default function (handlerFn, permissionName) {
return (
hasRole &&
projectAcl[name] &&
- (projectAcl[name] === '*' || projectAcl[name][permissionName])
+ (projectAcl[name] === '*' ||
+ (projectAcl[name].exclude &&
+ !projectAcl[name].exclude[permissionName]) ||
+ (projectAcl[name].include &&
+ projectAcl[name].include[permissionName]))
);
});
if (!isAllowed) {
diff --git a/packages/nocodb/src/lib/utils/projectAcl.ts b/packages/nocodb/src/lib/utils/projectAcl.ts
index cf0b1f91b8..21a9e452b8 100644
--- a/packages/nocodb/src/lib/utils/projectAcl.ts
+++ b/packages/nocodb/src/lib/utils/projectAcl.ts
@@ -1,273 +1,299 @@
export default {
- owner: '*',
- creator: '*',
+ owner: {
+ exclude: {
+ pluginList: true,
+ pluginTest: true,
+ pluginRead: true,
+ pluginUpdate: true,
+ isPluginActive: true,
+ },
+ },
+ creator: {
+ exclude: {
+ pluginList: true,
+ pluginTest: true,
+ pluginRead: true,
+ pluginUpdate: true,
+ isPluginActive: true,
+ },
+ },
guest: {},
editor: {
- hideAllColumns: true,
- showAllColumns: true,
- auditRowUpdate: true,
- passwordChange: true,
- // new permissions
- // project
- projectGet: true,
- projectList: true,
- projectCost: true,
- //table
- tableList: true,
- tableGet: true,
+ include: {
+ hideAllColumns: true,
+ showAllColumns: true,
+ auditRowUpdate: true,
+ passwordChange: true,
+ // new permissions
+ // project
+ projectGet: true,
+ projectList: true,
+ projectCost: true,
+ //table
+ tableList: true,
+ tableGet: true,
- // data
- dataList: true,
- dataUpdate: true,
- dataDelete: true,
- dataInsert: true,
- dataRead: true,
- dataExist: true,
- dataFindOne: true,
- dataGroupBy: true,
- commentsCount: true,
- exportCsv: true,
- exportExcel: true,
+ // data
+ dataList: true,
+ dataUpdate: true,
+ dataDelete: true,
+ dataInsert: true,
+ dataRead: true,
+ dataExist: true,
+ dataFindOne: true,
+ dataGroupBy: true,
+ commentsCount: true,
+ exportCsv: true,
+ exportExcel: true,
- viewList: true,
- columnList: true,
- viewColumnUpdate: true,
+ viewList: true,
+ columnList: true,
+ viewColumnUpdate: true,
- sortList: true,
- sortCreate: true,
- sortUpdate: true,
- sortDelete: true,
+ sortList: true,
+ sortCreate: true,
+ sortUpdate: true,
+ sortDelete: true,
- filterList: true,
- filterCreate: true,
- filterUpdate: true,
- filterDelete: true,
- filterGet: true,
- filterChildrenRead: true,
+ filterList: true,
+ filterCreate: true,
+ filterUpdate: true,
+ filterDelete: true,
+ filterGet: true,
+ filterChildrenRead: true,
- mmList: true,
- hmList: true,
- mmExcludedList: true,
- hmExcludedList: true,
- btExcludedList: true,
- commentList: true,
- commentRow: true,
+ mmList: true,
+ hmList: true,
+ mmExcludedList: true,
+ hmExcludedList: true,
+ btExcludedList: true,
+ commentList: true,
+ commentRow: true,
- formViewGet: true,
- projectInfoGet: true,
- gridColumnUpdate: true,
- galleryViewGet: true,
+ formViewGet: true,
+ projectInfoGet: true,
+ gridColumnUpdate: true,
+ galleryViewGet: true,
- // old
- xcTableAndViewList: true,
- xcAuditCreate: true,
- xcAttachmentUpload: true,
- xcVirtualTableList: true,
- rolesGet: true,
- tableXcModelGet: true,
- xcRelationsGet: true,
- xcModelsList: true,
- xcViewModelsList: true,
- xcProcedureModelsList: true,
- xcFunctionModelsList: true,
- xcTableModelsList: true,
- xcCronList: true,
- xcRelationList: true,
- tableMetaCreate: true,
- tableMetaDelete: true,
- tableMetaRecreate: true,
- viewMetaCreate: true,
- viewMetaDelete: true,
- viewMetaRecreate: true,
- procedureMetaCreate: true,
- procedureMetaDelete: true,
- procedureMetaRecreate: true,
- functionMetaCreate: true,
- functionMetaDelete: true,
- functionMetaRecreate: true,
+ // old
+ xcTableAndViewList: true,
+ xcAuditCreate: true,
+ xcAttachmentUpload: true,
+ xcVirtualTableList: true,
+ rolesGet: true,
+ tableXcModelGet: true,
+ xcRelationsGet: true,
+ xcModelsList: true,
+ xcViewModelsList: true,
+ xcProcedureModelsList: true,
+ xcFunctionModelsList: true,
+ xcTableModelsList: true,
+ xcCronList: true,
+ xcRelationList: true,
+ tableMetaCreate: true,
+ tableMetaDelete: true,
+ tableMetaRecreate: true,
+ viewMetaCreate: true,
+ viewMetaDelete: true,
+ viewMetaRecreate: true,
+ procedureMetaCreate: true,
+ procedureMetaDelete: true,
+ procedureMetaRecreate: true,
+ functionMetaCreate: true,
+ functionMetaDelete: true,
+ functionMetaRecreate: true,
- tableCreateStatement: true,
- tableInsertStatement: true,
- tableUpdateStatement: true,
- tableSelectStatement: true,
- tableDeleteStatement: true,
+ tableCreateStatement: true,
+ tableInsertStatement: true,
+ tableUpdateStatement: true,
+ tableSelectStatement: true,
+ tableDeleteStatement: true,
- functionList: true,
- sequenceList: true,
- procedureList: true,
- triggerList: true,
- relationList: true,
- relationListAll: true,
- indexList: true,
- list: true,
- viewRead: true,
- functionRead: true,
- procedureRead: true,
+ functionList: true,
+ sequenceList: true,
+ procedureList: true,
+ triggerList: true,
+ relationList: true,
+ relationListAll: true,
+ indexList: true,
+ list: true,
+ viewRead: true,
+ functionRead: true,
+ procedureRead: true,
- getKnexDataTypes: true,
- DB_PROJECT_OPEN_BY_WEB: true,
- PROJECT_READ_BY_WEB: true,
- projectGenerateBackend: true,
- projectGenerateBackendGql: true,
- projectGetTsPolicyPath: true,
- projectGetPolicyPath: true,
- projectGetGqlPolicyPath: true,
- handleApiCall: true,
- executeRawQuery: true,
- projectHasDb: true,
- testConnection: true,
- projectChangeEnv: true,
+ getKnexDataTypes: true,
+ DB_PROJECT_OPEN_BY_WEB: true,
+ PROJECT_READ_BY_WEB: true,
+ projectGenerateBackend: true,
+ projectGenerateBackendGql: true,
+ projectGetTsPolicyPath: true,
+ projectGetPolicyPath: true,
+ projectGetGqlPolicyPath: true,
+ handleApiCall: true,
+ executeRawQuery: true,
+ projectHasDb: true,
+ testConnection: true,
+ projectChangeEnv: true,
- xcRoutesPolicyAllGet: true,
- grpcProtoDownloadZip: true,
+ xcRoutesPolicyAllGet: true,
+ grpcProtoDownloadZip: true,
- xcModelRowAuditAndCommentList: true,
- xcAuditCommentInsert: true,
- xcAuditModelCommentsCount: true,
- xcExportAsCsv: true,
+ xcModelRowAuditAndCommentList: true,
+ xcAuditCommentInsert: true,
+ xcAuditModelCommentsCount: true,
+ xcExportAsCsv: true,
- bulkDataInsert: true,
- bulkDataUpdate: true,
- bulkDataUpdateAll: true,
- bulkDataDelete: true,
- bulkDataDeleteAll: true,
- relationDataRemove: true,
- relationDataAdd: true,
- dataCount: true,
- upload: true,
- uploadViaURL: true,
+ bulkDataInsert: true,
+ bulkDataUpdate: true,
+ bulkDataUpdateAll: true,
+ bulkDataDelete: true,
+ bulkDataDeleteAll: true,
+ relationDataRemove: true,
+ relationDataAdd: true,
+ dataCount: true,
+ upload: true,
+ uploadViaURL: true,
+ },
},
commenter: {
- formViewGet: true,
- passwordChange: true,
- // project
- projectGet: true,
- exportCsv: true,
- exportExcel: true,
+ include: {
+ formViewGet: true,
+ passwordChange: true,
+ // project
+ projectGet: true,
+ exportCsv: true,
+ exportExcel: true,
- //table
- tableGet: true,
- // sort & filter
- sortList: true,
- viewList: true,
- columnList: true,
+ //table
+ tableGet: true,
+ // sort & filter
+ sortList: true,
+ viewList: true,
+ columnList: true,
- mmList: true,
- hmList: true,
- commentList: true,
- commentRow: true,
- projectInfoGet: true,
+ mmList: true,
+ hmList: true,
+ commentList: true,
+ commentRow: true,
+ projectInfoGet: true,
- // data
- dataList: true,
- dataRead: true,
- dataExist: true,
- dataFindOne: true,
- dataGroupBy: true,
- commentsCount: true,
+ // data
+ dataList: true,
+ dataRead: true,
+ dataExist: true,
+ dataFindOne: true,
+ dataGroupBy: true,
+ commentsCount: true,
- galleryViewGet: true,
+ galleryViewGet: true,
- xcTableAndViewList: true,
- xcVirtualTableList: true,
- projectList: true,
- projectCost: true,
- PROJECT_READ_BY_WEB: true,
+ xcTableAndViewList: true,
+ xcVirtualTableList: true,
+ projectList: true,
+ projectCost: true,
+ PROJECT_READ_BY_WEB: true,
- tableXcModelGet: true,
- xcRelationList: true,
- tableList: true,
- functionList: true,
- sequenceList: true,
- procedureList: true,
- triggerList: true,
- relationList: true,
- relationListAll: true,
- indexList: true,
- list: true,
+ tableXcModelGet: true,
+ xcRelationList: true,
+ tableList: true,
+ functionList: true,
+ sequenceList: true,
+ procedureList: true,
+ triggerList: true,
+ relationList: true,
+ relationListAll: true,
+ indexList: true,
+ list: true,
- xcModelRowAuditAndCommentList: true,
- xcAuditCommentInsert: true,
- xcAuditModelCommentsCount: true,
- xcExportAsCsv: true,
- dataCount: true,
+ xcModelRowAuditAndCommentList: true,
+ xcAuditCommentInsert: true,
+ xcAuditModelCommentsCount: true,
+ xcExportAsCsv: true,
+ dataCount: true,
+ },
},
viewer: {
- formViewGet: true,
- passwordChange: true,
- // project
- projectGet: true,
- //table
- tableGet: true,
- // data
- dataList: true,
- dataRead: true,
- dataExist: true,
- dataFindOne: true,
- dataGroupBy: true,
- commentsCount: true,
- exportCsv: true,
- exportExcel: true,
+ include: {
+ formViewGet: true,
+ passwordChange: true,
+ // project
+ projectGet: true,
+ //table
+ tableGet: true,
+ // data
+ dataList: true,
+ dataRead: true,
+ dataExist: true,
+ dataFindOne: true,
+ dataGroupBy: true,
+ commentsCount: true,
+ exportCsv: true,
+ exportExcel: true,
- // sort & filter
- sortList: true,
- filterList: true,
- projectInfoGet: true,
+ // sort & filter
+ sortList: true,
+ filterList: true,
+ projectInfoGet: true,
- galleryViewGet: true,
+ galleryViewGet: true,
- mmList: true,
- hmList: true,
- commentList: true,
- commentRow: false,
+ mmList: true,
+ hmList: true,
+ commentList: true,
+ commentRow: false,
- xcTableAndViewList: true,
- xcVirtualTableList: true,
- projectList: true,
- projectCost: true,
- PROJECT_READ_BY_WEB: true,
+ xcTableAndViewList: true,
+ xcVirtualTableList: true,
+ projectList: true,
+ projectCost: true,
+ PROJECT_READ_BY_WEB: true,
- tableXcModelGet: true,
- xcRelationList: true,
- tableList: true,
- viewList: true,
- functionList: true,
- sequenceList: true,
- procedureList: true,
- columnList: true,
- triggerList: true,
- relationList: true,
- relationListAll: true,
- indexList: true,
- list: true,
- xcExportAsCsv: true,
- dataCount: true
+ tableXcModelGet: true,
+ xcRelationList: true,
+ tableList: true,
+ viewList: true,
+ functionList: true,
+ sequenceList: true,
+ procedureList: true,
+ columnList: true,
+ triggerList: true,
+ relationList: true,
+ relationListAll: true,
+ indexList: true,
+ list: true,
+ xcExportAsCsv: true,
+ dataCount: true,
+ },
},
user_new: {
- passwordChange: true,
- projectList: true,
+ include: {
+ passwordChange: true,
+ projectList: true,
+ },
},
super: '*',
user: {
- upload: true,
- uploadViaURL: true,
- passwordChange: true,
- pluginList: true,
- pluginRead: true,
- pluginTest: true,
- isPluginActive: true,
- pluginUpdate: true,
- projectCreate: true,
- projectList: true,
- projectCost: true,
- handleAxiosCall: true,
- testConnection: true,
- projectCreateByWeb: true,
- projectCreateByWebWithXCDB: true,
- xcPluginRead: true,
- xcMetaTablesImportZipToLocalFsAndDb: true,
- xcMetaTablesExportDbToZip: true,
- auditRowUpdate: true,
+ include: {
+ upload: true,
+ uploadViaURL: true,
+ passwordChange: true,
+ pluginList: true,
+ pluginRead: true,
+ pluginTest: true,
+ isPluginActive: true,
+ pluginUpdate: true,
+ projectCreate: true,
+ projectList: true,
+ projectCost: true,
+ handleAxiosCall: true,
+ testConnection: true,
+ projectCreateByWeb: true,
+ projectCreateByWebWithXCDB: true,
+ xcPluginRead: true,
+ xcMetaTablesImportZipToLocalFsAndDb: true,
+ xcMetaTablesExportDbToZip: true,
+ auditRowUpdate: true,
+ },
},
};
diff --git a/scripts/cypress/integration/common/5a_user_role.js b/scripts/cypress/integration/common/5a_user_role.js
index d3fff9733a..14938cc4ba 100644
--- a/scripts/cypress/integration/common/5a_user_role.js
+++ b/scripts/cypress/integration/common/5a_user_role.js
@@ -184,13 +184,17 @@ export const genTest = (apiType, dbType) => {
it(`[${roles[roleType].name}] Left navigation menu, New User add`, () => {
// project configuration settings
//
- _advSettings(roleType, "userRole");
+ if (roleType !== "owner") {
+ _advSettings(roleType, "userRole");
+ }
});
it(`[${roles[roleType].name}] Access control`, () => {
// Access control validation
//
- _accessControl(roleType, "userRole");
+ if (roleType !== "owner") {
+ _accessControl(roleType, "userRole");
+ }
});
it(`[${roles[roleType].name}] Schema: create table, add/modify/delete column`, () => {
@@ -198,14 +202,18 @@ export const genTest = (apiType, dbType) => {
// - Add/delete table
// - Add/Update/delete column
//
- _editSchema(roleType, "userRole");
+ if (roleType !== "owner") {
+ _editSchema(roleType, "userRole");
+ }
});
it(`[${roles[roleType].name}] Data: add/modify/delete row, update cell contents`, () => {
// Table data related validations
// - Add/delete/modify row
//
- _editData(roleType, "userRole");
+ if (roleType !== "owner") {
+ _editData(roleType, "userRole");
+ }
});
it(`[${roles[roleType].name}] Comments: view/add`, () => {
@@ -213,19 +221,27 @@ export const genTest = (apiType, dbType) => {
// Viewer: only allowed to read
// Everyone else: read &/ update
//
- _editComment(roleType, "userRole");
+ if (roleType !== "owner") {
+ _editComment(roleType, "userRole");
+ }
});
it(`[${roles[roleType].name}] Right navigation menu, share view`, () => {
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
- _viewMenu(roleType, "userRole");
+ if (roleType !== "owner") {
+ _viewMenu(roleType, "userRole");
+ }
});
it(`[${roles[roleType].name}] Download files`, () => {
// to be fixed
- if (roleType === "commenter" || roleType === "viewer") {
+ if (
+ roleType === "commenter" ||
+ roleType === "viewer" ||
+ roleType === "owner"
+ ) {
} else {
// viewer & commenter doesn't contain hideField option in ncv2
// #ID, City, LastUpdate, City => Address, Country <= City, +
@@ -259,11 +275,17 @@ export const genTest = (apiType, dbType) => {
mainPage.unhideField("LastUpdate");
}
});
+
+ it(`[${roles[roleType].name}] App store accessibility`, () => {
+ cy.visit("/#/apps").then(r =>{
+ cy.toastWait('You don\'t have enough permission to access the page.')
+ })
+ });
});
};
// skip owner validation as rest of the cases pretty much cover the same
- // roleValidation('owner')
+ // roleValidation("owner");
roleValidation("creator");
roleValidation("editor");
roleValidation("commenter");
diff --git a/scripts/cypress/integration/common/5c_super_user_role.js b/scripts/cypress/integration/common/5c_super_user_role.js
new file mode 100644
index 0000000000..fe72773dc0
--- /dev/null
+++ b/scripts/cypress/integration/common/5c_super_user_role.js
@@ -0,0 +1,85 @@
+import { loginPage } from '../../support/page_objects/navigation';
+import { roles } from '../../support/page_objects/projectConstants';
+
+export const genTest = (apiType, dbType) => {
+ describe(`${apiType.toUpperCase()} api - Super user test`, () => {
+ before(() => {
+ loginPage.signIn(roles.owner.credentials);
+ cy.saveLocalStorage();
+ });
+
+ beforeEach(() => {
+ cy.restoreLocalStorage();
+ });
+
+ afterEach(() => {
+ cy.saveLocalStorage();
+ });
+
+ after(() => {
+ });
+
+
+ it(`Open App store page and check slack app`, () => {
+
+ cy.visit('/#/apps').then(win => {
+ cy.get('.nc-app-store-title').should('exist');
+ cy.get('.nc-app-store-card-Slack').should('exist');
+
+ // install slack app
+ cy.get('.nc-app-store-card-Slack .install-btn')
+ .invoke('attr', 'style', 'right: 10px')
+
+ cy.get('.nc-app-store-card-Slack .install-btn .nc-app-store-card-install')
+ .click();
+
+ cy.getActiveModal('.nc-modal-plugin-install')
+ .find('[placeholder="Channel Name"]')
+ .type('Test channel')
+
+ cy.getActiveModal('.nc-modal-plugin-install')
+ .find('[placeholder="Webhook URL"]')
+ .type('http://test.com')
+
+
+ cy.getActiveModal('.nc-modal-plugin-install')
+ .find('button:contains("Save")')
+ .click()
+
+ cy.toastWait('Successfully installed')
+
+ cy.get('.nc-app-store-card-Slack .install-btn .nc-app-store-card-install').should('not.exist');
+
+
+ // update slack app config
+ cy.get('.nc-app-store-card-Slack .install-btn .nc-app-store-card-edit').should('exist').click()
+ cy.getActiveModal('.nc-modal-plugin-install')
+ .should('exist')
+ .find('[placeholder="Channel Name"]')
+ .should('have.value', 'Test channel')
+ .clear()
+ .type('Test channel 2')
+
+ cy.getActiveModal('.nc-modal-plugin-install')
+ .get('button:contains("Save")')
+ .click()
+
+
+ cy.toastWait('Successfully installed')
+
+
+ // reset slack app
+ cy.get('.nc-app-store-card-Slack .install-btn .nc-app-store-card-reset').should('exist').click()
+
+ cy.getActiveModal('.nc-modal-plugin-uninstall')
+ .should('exist')
+ .find('button:contains("Confirm")')
+ .click()
+
+ cy.toastWait('Plugin uninstalled successfully')
+
+ });
+
+ });
+ });
+}
diff --git a/scripts/cypress/integration/spec/roleValidation.spec.js b/scripts/cypress/integration/spec/roleValidation.spec.js
index 406bc2f7aa..72acb68583 100644
--- a/scripts/cypress/integration/spec/roleValidation.spec.js
+++ b/scripts/cypress/integration/spec/roleValidation.spec.js
@@ -1,5 +1,5 @@
-import { mainPage, settingsPage } from "../../support/page_objects/mainPage";
-import { roles } from "../../support/page_objects/projectConstants";
+import { mainPage, settingsPage } from '../../support/page_objects/mainPage';
+import { roles } from '../../support/page_objects/projectConstants';
// Left hand navigation bar, validation for
// 1. Audit menu
@@ -9,61 +9,62 @@ import { roles } from "../../support/page_objects/projectConstants";
export function _advSettings(roleType, mode) {
cy.log(roleType, mode);
- if (mode === "baseShare") {
+ if (mode === 'baseShare') {
// open modal
- cy.get(".nc-project-menu").should("exist").click();
- cy.getActiveMenu(".nc-dropdown-project-menu")
+ cy.get('.nc-project-menu').should('exist').click();
+ cy.getActiveMenu('.nc-dropdown-project-menu')
.find(`[data-menu-id="language"]`)
- .should("exist");
+ .should('exist');
// click again to close modal
- cy.get(".nc-project-menu").should("exist").click();
+ cy.get('.nc-project-menu').should('exist').click();
return;
}
let validationString =
- true == roles[roleType].validations.advSettings ? "exist" : "not.exist";
+ true == roles[roleType].validations.advSettings ? 'exist' : 'not.exist';
// cy.get(".nc-team-settings").should(validationString);
- cy.get(".nc-project-menu").should("exist").click();
- cy.getActiveMenu(".nc-dropdown-project-menu")
+ cy.get('.nc-project-menu').should('exist').click();
+ cy.getActiveMenu('.nc-dropdown-project-menu')
.find(`[data-menu-id="preview-as"]`)
.should(validationString);
- cy.getActiveMenu(".nc-dropdown-project-menu")
+ cy.getActiveMenu('.nc-dropdown-project-menu')
.find(`[data-menu-id="teamAndSettings"]:visible`)
.should(validationString);
if (true === roles[roleType].validations.advSettings) {
- cy.getActiveMenu(".nc-dropdown-project-menu")
+ cy.getActiveMenu('.nc-dropdown-project-menu')
.find(`[data-menu-id="teamAndSettings"]:visible`)
.should(validationString)
.click();
- cy.get(`[data-menu-id="teamAndAuth"]`).should("exist");
- cy.get(`[data-menu-id="appStore"]`).should("exist");
- cy.get(`[data-menu-id="projMetaData"]`).should("exist");
- cy.get(`[data-menu-id="audit"]`).should("exist");
+ cy.get(`[data-menu-id="teamAndAuth"]`).should('exist');
+ if (roleType === 'owner')
+ cy.get(`[data-menu-id="appStore"]`).should('exist');
+ cy.get(`[data-menu-id="projMetaData"]`).should('exist');
+ cy.get(`[data-menu-id="audit"]`).should('exist');
settingsPage.closeMenu();
} else {
- cy.get(".nc-project-menu").should("exist").click();
+ cy.get('.nc-project-menu').should('exist').click();
}
// float menu in preview mode
- if ("preview" === mode) {
- cy.get(".nc-floating-preview-btn").should("exist");
- cy.get(".nc-floating-preview-btn")
+ if ('preview' === mode) {
+ cy.get('.nc-floating-preview-btn').should('exist');
+ cy.get('.nc-floating-preview-btn')
.find(`[type="radio"][value="${roles[roleType].name}"]`)
- .should("be.checked");
+ .should('be.checked');
}
// cy.get("body").click("bottomRight");
}
export function _editSchema(roleType, mode) {
- let columnName = "City";
+ let columnName = 'City';
let validationString =
- true === roles[roleType].validations.editSchema ? "exist" : "not.exist";
+ true === roles[roleType].validations.editSchema ? 'exist' : 'not.exist';
cy.openTableTab(columnName, 25);
@@ -71,18 +72,18 @@ export function _editSchema(roleType, mode) {
cy.get(`.nc-add-new-table`).should(validationString);
// delete table option
- cy.get(`.nc-project-tree-tbl-City`).should("exist").rightclick();
- cy.get(".ant-dropdown-content:visible").should(validationString);
+ cy.get(`.nc-project-tree-tbl-City`).should('exist').rightclick();
+ cy.get('.ant-dropdown-content:visible').should(validationString);
- if (validationString === "exist") {
- cy.getActiveMenu(".nc-dropdown-tree-view-context-menu")
+ if (validationString === 'exist') {
+ cy.getActiveMenu('.nc-dropdown-tree-view-context-menu')
.find('[role="menuitem"]')
- .contains("Delete")
- .should("exist");
- cy.getActiveMenu(".nc-dropdown-tree-view-context-menu")
+ .contains('Delete')
+ .should('exist');
+ cy.getActiveMenu('.nc-dropdown-tree-view-context-menu')
.find('[role="menuitem"]')
- .contains("Rename")
- .should("exist");
+ .contains('Rename')
+ .should('exist');
// click on a cell to close table context menu
mainPage.getCell(columnName, 3).click();
@@ -90,104 +91,104 @@ export function _editSchema(roleType, mode) {
// add new column option
//
- cy.get(".nc-column-add").should(validationString);
+ cy.get('.nc-column-add').should(validationString);
// update column (edit/ delete menu)
- cy.get(".nc-ui-dt-dropdown").should(validationString);
-
- if (validationString === "exist") {
- cy.get(".nc-import-menu").should("exist").click();
- cy.getActiveMenu(".nc-dropdown-import-menu").should("exist");
- cy.getActiveMenu(".nc-dropdown-import-menu")
- .find(".ant-dropdown-menu-item")
- .contains("Airtable");
- cy.getActiveMenu(".nc-dropdown-import-menu")
- .find(".ant-dropdown-menu-item")
- .contains("CSV file");
- cy.getActiveMenu(".nc-dropdown-import-menu")
- .find(".ant-dropdown-menu-item")
- .contains("JSON file");
- cy.getActiveMenu(".nc-dropdown-import-menu")
- .find(".ant-dropdown-menu-item")
- .contains("Microsoft Excel");
+ cy.get('.nc-ui-dt-dropdown').should(validationString);
+
+ if (validationString === 'exist') {
+ cy.get('.nc-import-menu').should('exist').click();
+ cy.getActiveMenu('.nc-dropdown-import-menu').should('exist');
+ cy.getActiveMenu('.nc-dropdown-import-menu')
+ .find('.ant-dropdown-menu-item')
+ .contains('Airtable');
+ cy.getActiveMenu('.nc-dropdown-import-menu')
+ .find('.ant-dropdown-menu-item')
+ .contains('CSV file');
+ cy.getActiveMenu('.nc-dropdown-import-menu')
+ .find('.ant-dropdown-menu-item')
+ .contains('JSON file');
+ cy.getActiveMenu('.nc-dropdown-import-menu')
+ .find('.ant-dropdown-menu-item')
+ .contains('Microsoft Excel');
}
}
export function _editData(roleType, mode) {
- let columnName = "City";
+ let columnName = 'City';
let validationString =
- true === roles[roleType].validations.editData ? "exist" : "not.exist";
+ true === roles[roleType].validations.editData ? 'exist' : 'not.exist';
cy.openTableTab(columnName, 25);
// add row button
- cy.get(".nc-add-new-row-btn:visible").should(validationString);
+ cy.get('.nc-add-new-row-btn:visible').should(validationString);
// add button at bottom of page
mainPage.getCell(columnName, 25).scrollIntoView();
- cy.get(".nc-grid-add-new-cell:visible").should(validationString);
+ cy.get('.nc-grid-add-new-cell:visible').should(validationString);
// update row option (right click)
//
- mainPage.getCell("City", 5).rightclick();
+ mainPage.getCell('City', 5).rightclick();
cy.wait(100);
- cy.get(".ant-dropdown-content:visible").should(validationString);
+ cy.get('.ant-dropdown-content:visible').should(validationString);
- if (validationString === "exist") {
+ if (validationString === 'exist') {
// right click options will exist (only for 'exist' case)
//
- cy.getActiveMenu(".nc-dropdown-grid-context-menu")
- .contains("Insert New Row")
+ cy.getActiveMenu('.nc-dropdown-grid-context-menu')
+ .contains('Insert New Row')
.should(validationString);
- cy.getActiveMenu(".nc-dropdown-grid-context-menu")
- .contains("Clear cell")
+ cy.getActiveMenu('.nc-dropdown-grid-context-menu')
+ .contains('Clear cell')
.should(validationString);
- cy.getActiveMenu(".nc-dropdown-grid-context-menu")
- .contains("Delete Row")
+ cy.getActiveMenu('.nc-dropdown-grid-context-menu')
+ .contains('Delete Row')
.should(validationString);
- cy.getActiveMenu(".nc-dropdown-grid-context-menu")
- .contains("Delete Selected Rows")
+ cy.getActiveMenu('.nc-dropdown-grid-context-menu')
+ .contains('Delete Selected Rows')
.should(validationString);
// cy.get("body").type("{esc}");
- mainPage.getCell("City", 13).click();
+ mainPage.getCell('City', 13).click();
// update cell contents option using row expander should be enabled
//
mainPage
.getRow(1)
- .find(".nc-row-no")
- .should("exist")
+ .find('.nc-row-no')
+ .should('exist')
.eq(0)
- .trigger("mouseover", { force: true });
- cy.get(".nc-row-expand").should("exist").eq(10).click({ force: true });
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .find("button")
- .contains("Save row")
- .should("exist");
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .find("button")
- .contains("Cancel")
- .should("exist")
+ .trigger('mouseover', { force: true });
+ cy.get('.nc-row-expand').should('exist').eq(10).click({ force: true });
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .find('button')
+ .contains('Save row')
+ .should('exist');
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .find('button')
+ .contains('Cancel')
+ .should('exist')
.click();
} else {
// update cell contents option using row expander should be disabled
//
- cy.get(".nc-row-expand").should("exist").eq(10).click({ force: true });
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .find("button:disabled")
- .contains("Save row")
- .should("exist");
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .find("button")
- .contains("Cancel")
- .should("exist")
+ cy.get('.nc-row-expand').should('exist').eq(10).click({ force: true });
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .find('button:disabled')
+ .contains('Save row')
+ .should('exist');
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .find('button')
+ .contains('Cancel')
+ .should('exist')
.click();
}
// double click cell entries to edit
//
- mainPage.getCell("City", 5).dblclick().find("input").should(validationString);
+ mainPage.getCell('City', 5).dblclick().find('input').should(validationString);
}
// read &/ update comment
@@ -195,11 +196,11 @@ export function _editData(roleType, mode) {
// Everyone else: read &/ update
//
export function _editComment(roleType, mode) {
- let columnName = "City";
+ let columnName = 'City';
let validationString =
true === roles[roleType].validations.editComment
- ? "Comment added successfully"
- : "Not allowed";
+ ? 'Comment added successfully'
+ : 'Not allowed';
cy.openTableTab(columnName, 25);
@@ -207,7 +208,7 @@ export function _editComment(roleType, mode) {
// click on comment icon & type comment
//
- cy.get(".nc-row-expand").should("exist").eq(10).click({ force: true });
+ cy.get('.nc-row-expand').should('exist').eq(10).click({ force: true });
// Expected response:
// Viewer: Not able to see comment option
@@ -216,32 +217,32 @@ export function _editComment(roleType, mode) {
// cy.wait(3000);
- if ("viewer" === roleType) {
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .should("exist")
- .find(".nc-toggle-comments")
- .should("not.exist");
+ if ('viewer' === roleType) {
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .should('exist')
+ .find('.nc-toggle-comments')
+ .should('not.exist');
} else {
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .should("exist")
- .find(".nc-toggle-comments")
- .should("exist")
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .should('exist')
+ .find('.nc-toggle-comments')
+ .should('exist')
.click();
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .find(".nc-comment-box")
- .should("exist")
- .type("Comment-1{enter}");
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .find('.nc-comment-box')
+ .should('exist')
+ .type('Comment-1{enter}');
// cy.toastWait('Comment added successfully')
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .find(".nc-toggle-comments")
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .find('.nc-toggle-comments')
.click();
}
- cy.getActiveDrawer(".nc-drawer-expanded-form")
- .find("button")
- .contains("Cancel")
- .should("exist")
+ cy.getActiveDrawer('.nc-drawer-expanded-form')
+ .find('button')
+ .contains('Cancel')
+ .should('exist')
.click();
}
@@ -249,7 +250,7 @@ export function _editComment(roleType, mode) {
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
export function _viewMenu(roleType, mode) {
- let columnName = "City";
+ let columnName = 'City';
// Lock, Download, Upload
let menuWithSubmenuCount = 3;
@@ -260,16 +261,16 @@ export function _viewMenu(roleType, mode) {
cy.openTableTab(columnName, 25);
let validationString =
- true === roles[roleType].validations.shareView ? "exist" : "not.exist";
+ true === roles[roleType].validations.shareView ? 'exist' : 'not.exist';
- if (roleType === "editor") {
+ if (roleType === 'editor') {
// Download / Upload CSV
menuWithSubmenuCount = 2;
// Get API Snippet and ERD
menuWithoutSubmenuCount = 2;
// ERD
- if (mode === "baseShare") menuWithoutSubmenuCount = 1;
- } else if (roleType === "commenter" || roleType === "viewer") {
+ if (mode === 'baseShare') menuWithoutSubmenuCount = 1;
+ } else if (roleType === 'commenter' || roleType === 'viewer') {
// Download CSV & Download excel
menuWithSubmenuCount = 0;
// Get API Snippet and ERD
@@ -277,7 +278,7 @@ export function _viewMenu(roleType, mode) {
}
// view list field (default GRID view)
- cy.get(`.nc-view-item`).should("exist");
+ cy.get(`.nc-view-item`).should('exist');
// view create option, exists only for owner/ creator
cy.get(`.nc-create-grid-view`).should(validationString);
@@ -287,47 +288,47 @@ export function _viewMenu(roleType, mode) {
// share view permissions are role specific
// actions menu (more), only download csv should be visible for non-previlaged users
- cy.get(".nc-actions-menu-btn").click();
- cy.getActiveMenu(".nc-dropdown-actions-menu")
- .find(".ant-dropdown-menu-submenu:visible")
- .should("have.length", menuWithSubmenuCount);
- cy.getActiveMenu(".nc-dropdown-actions-menu")
- .find(".ant-dropdown-menu-item:visible")
- .should("have.length", menuWithoutSubmenuCount);
+ cy.get('.nc-actions-menu-btn').click();
+ cy.getActiveMenu('.nc-dropdown-actions-menu')
+ .find('.ant-dropdown-menu-submenu:visible')
+ .should('have.length', menuWithSubmenuCount);
+ cy.getActiveMenu('.nc-dropdown-actions-menu')
+ .find('.ant-dropdown-menu-item:visible')
+ .should('have.length', menuWithoutSubmenuCount);
// click again to close menu
- cy.get(".nc-actions-menu-btn").click();
+ cy.get('.nc-actions-menu-btn').click();
}
export function _topRightMenu(roleType, mode) {
// kludge; download csv menu persists until clicked
- let columnName = "City";
+ let columnName = 'City';
// cy.closeTableTab(columnName);
// cy.openTableTab(columnName, 25);
let validationString =
- true == roles[roleType].validations.shareView ? "exist" : "not.exist";
+ true == roles[roleType].validations.shareView ? 'exist' : 'not.exist';
cy.get(`.nc-share-base`).should(validationString);
- cy.get(".nc-menu-translate").should("exist");
- cy.get(".nc-menu-accounts").should("exist");
+ cy.get('.nc-menu-translate').should('exist');
+ cy.get('.nc-menu-accounts').should('exist');
}
// Access control list
//
export function disableTableAccess(tbl, role) {
const cls = `.nc-acl-${tbl}-${role}-chkbox`;
- cy.get(cls).find("input").should("be.checked").click({ force: true });
- cy.get(cls).find("input").should("not.be.checked");
+ cy.get(cls).find('input').should('be.checked').click({ force: true });
+ cy.get(cls).find('input').should('not.be.checked');
}
export function enableTableAccess(tbl, role) {
const cls = `.nc-acl-${tbl}-${role}-chkbox`;
- cy.get(cls).find("input").should("not.be.checked").click({ force: true });
- cy.get(cls).find("input").should("be.checked");
+ cy.get(cls).find('input').should('not.be.checked').click({ force: true });
+ cy.get(cls).find('input').should('be.checked');
}
export function _accessControl(roleType, previewMode) {
- let validationString = roleType === "creator" ? "exist" : "not.exist";
+ let validationString = roleType === 'creator' ? 'exist' : 'not.exist';
cy.get(`.nc-project-tree-tbl-Language`).should(validationString);
cy.get(`.nc-project-tree-tbl-CustomerList`).should(validationString);
diff --git a/scripts/cypress/integration/test/pg-restRoles.js b/scripts/cypress/integration/test/pg-restRoles.js
index 194d22e051..fa868a3df1 100644
--- a/scripts/cypress/integration/test/pg-restRoles.js
+++ b/scripts/cypress/integration/test/pg-restRoles.js
@@ -2,6 +2,7 @@ let t0 = require("./explicitLogin");
let t01 = require("../common/00_pre_configurations");
let t5a = require("../common/5a_user_role");
let t5b = require("../common/5b_preview_role");
+let t5c = require("../common/5c_super_user_role");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
@@ -12,6 +13,7 @@ const nocoTestSuite = (apiType, dbType) => {
t5a.genTest(apiType, dbType);
// t5b.genTest(apiType, dbType);
+ t5c.genTest(apiType, dbType);
};
nocoTestSuite("rest", "postgres");
diff --git a/scripts/cypress/integration/test/restRoles.js b/scripts/cypress/integration/test/restRoles.js
index 69a80b009a..b636dff4ec 100644
--- a/scripts/cypress/integration/test/restRoles.js
+++ b/scripts/cypress/integration/test/restRoles.js
@@ -2,6 +2,7 @@ let t0 = require("./explicitLogin");
let t01 = require("../common/00_pre_configurations");
let t5a = require("../common/5a_user_role");
let t5b = require("../common/5b_preview_role");
+let t5c = require("../common/5c_super_user_role");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
@@ -12,6 +13,8 @@ const nocoTestSuite = (apiType, dbType) => {
t5a.genTest(apiType, dbType);
// t5b.genTest(apiType, dbType);
+ t5c.genTest(apiType, dbType);
+
};
nocoTestSuite("rest", "mysql");
diff --git a/scripts/cypress/integration/test/xcdb-restRoles.js b/scripts/cypress/integration/test/xcdb-restRoles.js
index 985978fc6d..fd6edd531d 100644
--- a/scripts/cypress/integration/test/xcdb-restRoles.js
+++ b/scripts/cypress/integration/test/xcdb-restRoles.js
@@ -2,6 +2,7 @@ let t0 = require("./explicitLogin");
let t01 = require("../common/00_pre_configurations");
let t5a = require("../common/5a_user_role");
let t5b = require("../common/5b_preview_role");
+let t5c = require("../common/5c_super_user_role");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
@@ -12,6 +13,7 @@ const nocoTestSuite = (apiType, dbType) => {
t5a.genTest(apiType, dbType);
// t5b.genTest(apiType, dbType);
+ t5c.genTest(apiType, dbType);
};
nocoTestSuite("rest", "xcdb");
diff --git a/scripts/cypress/support/commands.js b/scripts/cypress/support/commands.js
index de6139aa1d..ab89891b1a 100644
--- a/scripts/cypress/support/commands.js
+++ b/scripts/cypress/support/commands.js
@@ -479,7 +479,7 @@ Cypress.Commands.add("signOut", () => {
cy.get(".nc-menu-accounts", { timeout: 30000 }).should("exist").click();
cy.getActiveMenu(".nc-dropdown-user-accounts-menu")
.find(".ant-dropdown-menu-item")
- .eq(1)
+ .last()
.click();
// cy.wait(5000);