Browse Source

Merge pull request #1292 from nocodb/develop

0.84.11 Pre-Release
pull/1295/head
աɨռɢӄաօռɢ 3 years ago committed by GitHub
parent
commit
873e682146
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      .all-contributorsrc
  2. 23
      .github/ISSUE_TEMPLATE/I18n_translations.md
  3. 2
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 32
      .github/ISSUE_TEMPLATE/i18n-translation-request.md
  5. 184
      .github/workflows/ci-cd.yml
  6. 34
      .github/workflows/release-close-issue.yml
  7. 12
      .github/workflows/release-docker.yml
  8. 16
      .github/workflows/release-draft.yml
  9. 52
      .github/workflows/release-nocodb.yml
  10. 124
      .github/workflows/release-npm.yml
  11. 23
      .github/workflows/sync-to-develop.yml
  12. 1
      .gitignore
  13. 1
      README.md
  14. 97
      package-lock.json
  15. 1
      package.json
  16. 12
      packages/nc-cli/package-lock.json
  17. 6
      packages/nc-common/package-lock.json
  18. 6
      packages/nc-gui/components/auth/roles.vue
  19. 115
      packages/nc-gui/components/auth/userManagement.vue
  20. 72
      packages/nc-gui/components/base/shareBase.vue
  21. 2
      packages/nc-gui/components/project/spreadsheet/components/expandedForm.vue
  22. 2
      packages/nc-gui/components/project/spreadsheet/components/extras.vue
  23. 22
      packages/nc-gui/components/project/spreadsheet/components/importExport/columnMappingModal.vue
  24. 15
      packages/nc-gui/components/project/spreadsheet/components/moreActions.vue
  25. 2
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue
  26. 5
      packages/nc-gui/components/project/spreadsheet/mixins/spreadsheet.js
  27. 2
      packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue
  28. 205
      packages/nc-gui/components/utils/dlgTableCreate.vue
  29. 34
      packages/nc-gui/helpers/formulaList.js
  30. 4
      packages/nc-gui/helpers/sqlUi/MssqlUi.js
  31. 2
      packages/nc-gui/helpers/sqlUi/MysqlUi.js
  32. 2
      packages/nc-gui/helpers/sqlUi/SqliteUi.js
  33. 378
      packages/nc-gui/lang/de.json
  34. 2
      packages/nc-gui/layouts/default.vue
  35. 2
      packages/nc-gui/pages/projects/index.vue
  36. 28
      packages/nc-migrator-archived/package-lock.json
  37. 34
      packages/noco-docs/content/en/engineering/publish.md
  38. 65
      packages/noco-docs/content/en/engineering/translation.md
  39. 6
      packages/noco-i18n/package-lock.json
  40. 7
      packages/nocodb/src/__tests__/rest.test.ts
  41. 22
      packages/nocodb/src/lib/dataMapper/lib/sql/CustomKnex.ts
  42. 4
      packages/nocodb/src/lib/noco/NcProjectBuilder.ts
  43. 5
      packages/nocodb/src/lib/noco/meta/NcMetaIO.ts
  44. 9
      packages/nocodb/src/lib/noco/meta/NcMetaIOImpl.ts
  45. 42
      packages/nocodb/src/lib/noco/rest/RestAuthCtrl.ts
  46. 4
      packages/nocodb/src/lib/sqlUi/MssqlUi.ts
  47. 2
      packages/nocodb/src/lib/sqlUi/MysqlUi.ts
  48. 2
      packages/nocodb/src/lib/sqlUi/SqliteUi.ts
  49. 104
      scripts/cypress/cypress.json
  50. 17
      scripts/cypress/docker-compose-pg.yml
  51. 64
      scripts/cypress/integration/common/00_pre_configurations.js
  52. 188
      scripts/cypress/integration/common/1a_table_operations.js
  53. 325
      scripts/cypress/integration/common/1b_table_column_operations.js
  54. 297
      scripts/cypress/integration/common/1c_sql_view.js
  55. 171
      scripts/cypress/integration/common/1d_pg_table_view_drag_drop_reorder.js
  56. 268
      scripts/cypress/integration/common/1d_table_view_drag_drop_reorder.js
  57. 321
      scripts/cypress/integration/common/1e_meta_sync.js
  58. 202
      scripts/cypress/integration/common/1e_pg_meta_sync.js
  59. 106
      scripts/cypress/integration/common/2a_table_with_belongs_to_colulmn.js
  60. 153
      scripts/cypress/integration/common/2b_table_with_m2m_column.js
  61. 421
      scripts/cypress/integration/common/3a_filter_sort_fields_operations.js
  62. 440
      scripts/cypress/integration/common/3b_formula_column.js
  63. 192
      scripts/cypress/integration/common/3c_lookup_column.js
  64. 8
      scripts/cypress/integration/common/3d_rollup_column.js
  65. 143
      scripts/cypress/integration/common/4a_table_view_grid_gallery_form.js
  66. 11
      scripts/cypress/integration/common/4b_table_view_share.js
  67. 6
      scripts/cypress/integration/common/4c_form_view_detailed.js
  68. 7
      scripts/cypress/integration/common/4d_table_view_grid_locked.js
  69. 391
      scripts/cypress/integration/common/4e_form_view_share.js
  70. 813
      scripts/cypress/integration/common/4f_grid_view_share.js
  71. 471
      scripts/cypress/integration/common/4f_pg_grid_view_share.js
  72. 396
      scripts/cypress/integration/common/5a_user_role.js
  73. 234
      scripts/cypress/integration/common/5b_preview_role.js
  74. 62
      scripts/cypress/integration/common/6b_downloadCsv.js
  75. 452
      scripts/cypress/integration/common/6c_swagger_api.js
  76. 11
      scripts/cypress/integration/common/6d_language_validation.js
  77. 117
      scripts/cypress/integration/common/6e_project_operations.js
  78. 10
      scripts/cypress/integration/common/6f_attachments.js
  79. 207
      scripts/cypress/integration/common/6g_base_share.js
  80. 538
      scripts/cypress/integration/common/7a_create_project_from_excel.js
  81. 30
      scripts/cypress/integration/test/explicitLogin.js
  82. 22
      scripts/cypress/integration/test/gqlMisc.js
  83. 14
      scripts/cypress/integration/test/gqlRoles.js
  84. 32
      scripts/cypress/integration/test/gqlTableOps.js
  85. 22
      scripts/cypress/integration/test/gqlViews.js
  86. 52
      scripts/cypress/integration/test/masterSuiteGql.js
  87. 52
      scripts/cypress/integration/test/masterSuiteRest.js
  88. 61
      scripts/cypress/integration/test/pg-restMisc.js
  89. 47
      scripts/cypress/integration/test/pg-restRoles.js
  90. 65
      scripts/cypress/integration/test/pg-restTableOps.js
  91. 55
      scripts/cypress/integration/test/pg-restViews.js
  92. 24
      scripts/cypress/integration/test/restMisc.js
  93. 14
      scripts/cypress/integration/test/restRoles.js
  94. 32
      scripts/cypress/integration/test/restTableOps.js
  95. 22
      scripts/cypress/integration/test/restViews.js
  96. 22
      scripts/cypress/integration/test/xcdb-gqlMisc.js
  97. 14
      scripts/cypress/integration/test/xcdb-gqlRoles.js
  98. 32
      scripts/cypress/integration/test/xcdb-gqlTableOps.js
  99. 22
      scripts/cypress/integration/test/xcdb-gqlViews.js
  100. 24
      scripts/cypress/integration/test/xcdb-restMisc.js
  101. Some files were not shown because too many files have changed in this diff Show More

9
.all-contributorsrc

@ -612,6 +612,15 @@
"contributions": [ "contributions": [
"code" "code"
] ]
},
{
"login": "LancerComet",
"name": "LancerComet",
"avatar_url": "https://avatars.githubusercontent.com/u/10321350?v=4",
"profile": "https://github.com/LancerComet",
"contributions": [
"code"
]
} }
], ],
"contributorsPerLine": 7, "contributorsPerLine": 7,

23
.github/ISSUE_TEMPLATE/I18n_translations.md

@ -0,0 +1,23 @@
# i18n translation request
**Please enter the following details**
1. Select applicalbe
- [ ] **New language support request**
- [ ] **Existing language translation corrections request**
Verify if language support already exists in NocoDB i18n master spreadsheet [here](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
2. Associated language code (pick from [here](https://developers.google.com/admin-sdk/directory/v1/languages)):
3. Google spreadsheet
- Procedure to share google spread sheet can be found [here](https://support.google.com/docs/answer/2494822?hl=en&co=GENIE.Platform%3DDesktop#zippy=%2Cshare-a-file-publicly)
- When requested, select public sharable link.
- Alternatively, you can download & attach spreadsheet here along with the issue as well.
- [ ] **Attached**
- [ ] **Shared link**:
4. Summary of the changes made
- You can highlight modified items in Spreadsheet attached/shared, to help us quickly identify change set
5. Any specific message to be conveyed to moderators?
- Help us simplify process if you find something hard about it

2
.github/ISSUE_TEMPLATE/feature_request.md

@ -2,7 +2,7 @@
name: Feature request name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
title: "[Feature] " title: "[Feature] "
labels: Feature labels: ''
assignees: '' assignees: ''
--- ---

32
.github/ISSUE_TEMPLATE/i18n-translation-request.md

@ -0,0 +1,32 @@
---
name: i18n translation request
about: translation & localisation support
title: "[i18n] Language support extension- <language code>"
labels: i18n translation
assignees: dstala
---
# i18n translation request
**Please enter the following details**
1. Select applicalbe
- [ ] **New language support request**
- [ ] **Existing language translation corrections request**
Verify if language support already exists in the NocoDB i18n master spreadsheet [here](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
2. Associated language code (pick from [here](https://developers.google.com/admin-sdk/directory/v1/languages)):
3. Google spreadsheet
- Procedure to share google spreadsheet can be found [here](https://support.google.com/docs/answer/2494822?hl=en&co=GENIE.Platform%3DDesktop#zippy=%2Cshare-a-file-publicly)
- When requested, select public sharable link.
- Alternatively, you can download & attach a spreadsheet here along with the issue as well.
- [ ] **Attached**
- [ ] **Shared link**:
4. Summary of the changes made
- You can highlight modified items in the Spreadsheet attached/shared, to help us quickly identify changeset
5. Any specific message to be conveyed to moderators?
- Help us simplify the process if you find something hard about it

184
.github/workflows/ci-cd.yml

@ -4,13 +4,15 @@
name: "CI/CD" name: "CI/CD"
on: on:
push: push:
branches-ignore:
- master
paths: paths:
- "packages/nc-gui/**" - "packages/nc-gui/**"
- "scripts/cypress/**" - "scripts/cypress/**"
- "packages/nocodb/**" - "packages/nocodb/**"
- ".github/workflows/ci-cd.yml" - ".github/workflows/ci-cd.yml"
pull_request: pull_request:
branches: [master, develop] branches: [develop]
paths: paths:
- "packages/nc-gui/**" - "packages/nc-gui/**"
- "scripts/cypress/**" - "scripts/cypress/**"
@ -18,6 +20,178 @@ on:
- ".github/workflows/ci-cd.yml" - ".github/workflows/ci-cd.yml"
jobs: jobs:
cypress-pg-restTableOps-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restViews-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restRoles-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restMisc-run:
runs-on: ubuntu-20.04
steps:
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set env
run: echo "NODE_ENV=test" >> $GITHUB_ENV
- name: Cypress run
uses: cypress-io/github-action@v2
with:
start: |
npm run start:api
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
spec: "./scripts/cypress/integration/test/pg-restMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
uses: actions/upload-artifact@v2
with:
name: restTableOps-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-restTableOps-run: cypress-restTableOps-run:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
@ -225,7 +399,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restTableOps.js" spec: "./scripts/cypress/integration/test/xcdb-restTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200
@ -269,7 +442,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restViews.js" spec: "./scripts/cypress/integration/test/xcdb-restViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200
@ -313,7 +485,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restRoles.js" spec: "./scripts/cypress/integration/test/xcdb-restRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200
@ -357,7 +528,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restMisc.js" spec: "./scripts/cypress/integration/test/xcdb-restMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200
@ -577,7 +747,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlTableOps.js" spec: "./scripts/cypress/integration/test/xcdb-gqlTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200
@ -621,7 +790,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlViews.js" spec: "./scripts/cypress/integration/test/xcdb-gqlViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200
@ -665,7 +833,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlRoles.js" spec: "./scripts/cypress/integration/test/xcdb-gqlRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200
@ -709,7 +876,6 @@ jobs:
start: | start: |
npm run start:xcdb-api npm run start:xcdb-api
npm run start:web npm run start:web
docker-compose -f ./scripts/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-gqlMisc.js" spec: "./scripts/cypress/integration/test/xcdb-gqlMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js" wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/runtime.js"
wait-on-timeout: 1200 wait-on-timeout: 1200

34
.github/workflows/release-close-issue.yml

@ -0,0 +1,34 @@
name: 'Close Issues with Labels'
on:
# Triggered manually
workflow_dispatch:
inputs:
issue_label:
description: "All issues with such label will be closed"
required: true
version:
description: "Which version is this issue fixed in"
required: true
# Triggered by release-nocodb.yml
workflow_call:
inputs:
issue_label:
description: "All issues with such label will be closed"
required: true
type: string
version:
description: "Which version is this issue fixed in"
required: true
type: string
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: close-resolved-issues
uses: wingkwong/close-issues-based-on-label@master
env:
LABEL: ${{ github.event.inputs.issue_label || inputs.issue_label }}
VERSION: ${{ github.event.inputs.version || inputs.version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

12
.github/workflows/release-docker.yml

@ -1,11 +1,19 @@
name: "Release : Docker" name: "Release : Docker"
on: on:
# Triggered manually
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
description: "Docker image tag" description: "Docker image tag"
required: true required: true
# Triggered by release-nocodb.yml
workflow_call:
inputs:
tag:
description: "Docker image tag"
required: true
type: string
jobs: jobs:
buildx: buildx:
@ -59,13 +67,13 @@ jobs:
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2
with: with:
context: ${{ env.working-directory }} context: ${{ env.working-directory }}
build-args: NC_VERSION=${{ github.event.inputs.tag }} build-args: NC_VERSION=${{ github.event.inputs.tag || inputs.tag }}
platforms: linux/amd64,linux/arm64,linux/arm/v7 platforms: linux/amd64,linux/arm64,linux/arm/v7
cache-from: type=local,src=/tmp/.buildx-cache cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new cache-to: type=local,dest=/tmp/.buildx-cache-new
push: true push: true
tags: | tags: |
nocodb/nocodb:${{ github.event.inputs.tag }} nocodb/nocodb:${{ github.event.inputs.tag || inputs.tag }}
nocodb/nocodb:latest nocodb/nocodb:latest
# Temp fix # Temp fix

16
.github/workflows/release-draft.yml

@ -1,6 +1,7 @@
name: "Release : Draft Notes" name: "Release : Draft Notes"
on: on:
# Triggered manually
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
@ -9,6 +10,17 @@ on:
prev_tag: prev_tag:
description: "Previous Tag" description: "Previous Tag"
required: true required: true
# Triggered by release-nocodb.yml
workflow_call:
inputs:
tag:
description: "Tag"
required: true
type: string
prev_tag:
description: "Previous Tag"
required: true
type: string
jobs: jobs:
build: build:
@ -22,7 +34,7 @@ jobs:
github.git.createRef({ github.git.createRef({
owner: context.repo.owner, owner: context.repo.owner,
repo: context.repo.repo, repo: context.repo.repo,
ref: "refs/tags/${{ github.event.inputs.tag }}", ref: "refs/tags/${{ github.event.inputs.tag || inputs.tag }} ",
sha: context.sha sha: context.sha
}) })
@ -33,4 +45,4 @@ jobs:
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: 14 node-version: 14
- run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GH_TOKEN }} --draft --tags ${{ github.event.inputs.tag }}..${{ github.event.inputs.prev_tag }}" - run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GH_TOKEN }} --draft --tags ${{ github.event.inputs.tag || inputs.tag }}..${{ github.event.inputs.prev_tag || inputs.prev_tag }} "

52
.github/workflows/release-nocodb.yml

@ -0,0 +1,52 @@
name: 'NocoDB Release'
on:
# Triggered manually
workflow_dispatch:
inputs:
tag:
description: "Target Tag"
required: true
prev_tag:
description: "Previous Tag"
required: true
jobs:
# Close all issues with target tags 'Fixed' & 'Resolved'
close-fixed-issues:
needs: release-npm
uses: ./.github/workflows/release-close-issue.yml
with:
issue_label: 'Fixed'
version: ${{ github.event.inputs.tag }}
close-resolved-issues:
needs: close-fixed-issues
uses: ./.github/workflows/release-close-issue.yml
with:
issue_label: 'Resolved'
version: ${{ github.event.inputs.tag }}
# Build, install, publish frontend and backend to npm
release-npm:
uses: ./.github/workflows/release-npm.yml
with:
tag: ${{ github.event.inputs.tag }}
# Draft Release Note
release-draft-note:
needs: close-issues
uses: ./.github/workflows/release-draft.yml
with:
tag: ${{ github.event.inputs.tag }}
prev_tag: ${{ github.event.inputs.prev_tag }}
# Build docker image and push to docker hub
release-docker:
needs: release-draft-note
uses: ./.github/workflows/release-docker.yml
with:
tag: ${{ github.event.inputs.tag }}
# Sync changes to develop
sync-to-develop:
needs: release-docker
uses: ./.github/workflows/sync-to-develop.yml

124
.github/workflows/release-npm.yml

@ -1,15 +1,19 @@
name: "Release : NPM packages" name: "Release : NPM packages"
on: on:
# Triggered manually
workflow_dispatch: workflow_dispatch:
inputs: inputs:
tag: tag:
description: "Tag" description: "Tag"
required: true required: true
prev_tag: type: string
description: "Previous Tag" # Triggered by release-nocodb.yml
workflow_call:
inputs:
tag:
description: "Tag"
required: true required: true
jobs: jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -31,7 +35,7 @@ jobs:
npm run build:copy:jsdeliver npm run build:copy:jsdeliver
cd ../.. cd ../..
npm install npm install
VERSION=${{github.event.inputs.tag}} node scripts/upgradeNcGui.js node scripts/upgradeNcGui.js && cd packages/nocodb && npm run obfuscate:build:publish VERSION=${{ github.event.inputs.tag || inputs.tag }} node scripts/upgradeNcGui.js node scripts/upgradeNcGui.js && cd packages/nocodb && npm run obfuscate:build:publish
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create Pull Request - name: Create Pull Request
@ -44,113 +48,17 @@ jobs:
# committer: GitHub <noreply@github.com> # committer: GitHub <noreply@github.com>
# author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> # author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: true signoff: true
branch: release-patches branch: 'release/${{ github.event.inputs.tag || inputs.tag }}'
delete-branch: true delete-branch: true
title: 'Release ${{github.event.inputs.tag}}' title: 'Release ${{ github.event.inputs.tag || inputs.tag }}'
labels: | labels: |
automerge Bot: Automated PR
- name: Check outputs - name: Check outputs
run: | run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}" echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- name: automerge
- name: automerge uses: "pascalgn/automerge-action@v0.14.3"
uses: "pascalgn/automerge-action@v0.14.3" env:
env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" PULL_REQUEST: "${{ steps.cpr.outputs.pull-request-number }}"
PULL_REQUEST: "${{ steps.cpr.outputs.pull-request-number }}"
buildx:
runs-on: ubuntu-latest
needs: [release]
env:
working-directory: ./packages/nocodb
strategy:
matrix:
node-version: [ 12 ]
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- uses: bahmutov/npm-install@v1
with:
working-directory: ${{ env.working-directory }}
- name: Build nocodb and docker files
run: |
npm run build
npm run docker:build
working-directory: ${{ env.working-directory }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: ${{ env.working-directory }}
build-args: NC_VERSION=${{ github.event.inputs.tag }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
push: true
tags: |
nocodb/nocodb:${{ github.event.inputs.tag }}
nocodb/nocodb:latest
# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
- name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
draft:
runs-on: ubuntu-latest
needs: [release]
steps:
- name: Create tag
uses: actions/github-script@v3
with:
github-token: ${{ secrets.GH_TOKEN }}
script: |
github.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "refs/tags/${{ github.event.inputs.tag }}",
sha: context.sha
})
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v2
with:
node-version: 14
- run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GH_TOKEN }} --draft --tags ${{ github.event.inputs.tag }}..${{ github.event.inputs.prev_tag }}"

23
.github/workflows/sync-to-develop.yml

@ -0,0 +1,23 @@
name: 'Sync changes back to develop branch from master'
on:
# Triggered manually
workflow_dispatch:
# Triggered by release-nocodb.yml
workflow_call:
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Merge from master to develop
uses: robotology/gh-action-nightly-merge@v1.3.1
with:
stable_branch: 'master'
development_branch: 'develop'
allow_ff: true
allow_forks: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored

@ -83,3 +83,4 @@ mongod
# Cypress # Cypress
#========= #=========
shared.json shared.json
/scripts/Cypress/screenshots

1
README.md

@ -389,6 +389,7 @@ Our mission is to provide the most powerful no-code interface for databases whic
<td align="center"><a href="https://github.com/willnewii"><img src="https://avatars.githubusercontent.com/u/652003?v=4?s=100" width="100px;" alt=""/><br /><sub><b>诗人的咸鱼</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=willnewii" title="Code">💻</a></td> <td align="center"><a href="https://github.com/willnewii"><img src="https://avatars.githubusercontent.com/u/652003?v=4?s=100" width="100px;" alt=""/><br /><sub><b>诗人的咸鱼</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=willnewii" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/bitbytejoy"><img src="https://avatars.githubusercontent.com/u/11807034?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bitbytejoy</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=bitbytejoy" title="Code">💻</a></td> <td align="center"><a href="https://github.com/bitbytejoy"><img src="https://avatars.githubusercontent.com/u/11807034?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bitbytejoy</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=bitbytejoy" title="Code">💻</a></td>
<td align="center"><a href="http://blog.pan93.com"><img src="https://avatars.githubusercontent.com/u/28441561?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pan93412</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=pan93412" title="Code">💻</a></td> <td align="center"><a href="http://blog.pan93.com"><img src="https://avatars.githubusercontent.com/u/28441561?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pan93412</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=pan93412" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/LancerComet"><img src="https://avatars.githubusercontent.com/u/10321350?v=4?s=100" width="100px;" alt=""/><br /><sub><b>LancerComet</b></sub></a><br /><a href="https://github.com/nocodb/nocodb/commits?author=LancerComet" title="Code">💻</a></td>
</tr> </tr>
</table> </table>

97
package-lock.json generated

@ -2656,6 +2656,11 @@
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true "dev": true
}, },
"buffer-writer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw=="
},
"builtins": { "builtins": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
@ -7654,6 +7659,11 @@
"p-reduce": "^1.0.0" "p-reduce": "^1.0.0"
} }
}, },
"packet-reader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ=="
},
"parallel-transform": { "parallel-transform": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
@ -7779,6 +7789,67 @@
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
}, },
"pg": {
"version": "8.7.3",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.7.3.tgz",
"integrity": "sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==",
"requires": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
"pg-connection-string": "^2.5.0",
"pg-pool": "^3.5.1",
"pg-protocol": "^1.5.0",
"pg-types": "^2.1.0",
"pgpass": "1.x"
}
},
"pg-connection-string": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ=="
},
"pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="
},
"pg-pool": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.1.tgz",
"integrity": "sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ=="
},
"pg-protocol": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ=="
},
"pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"requires": {
"pg-int8": "1.0.1",
"postgres-array": "~2.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.4",
"postgres-interval": "^1.1.0"
}
},
"pgpass": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"requires": {
"split2": "^4.1.0"
},
"dependencies": {
"split2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
"integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ=="
}
}
},
"pify": { "pify": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
@ -7815,6 +7886,29 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
"dev": true "dev": true
}, },
"postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="
},
"postgres-bytea": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
"integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU="
},
"postgres-date": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="
},
"postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"requires": {
"xtend": "^4.0.0"
}
},
"pretty-bytes": { "pretty-bytes": {
"version": "5.6.0", "version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@ -10030,8 +10124,7 @@
"xtend": { "xtend": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
"dev": true
}, },
"y18n": { "y18n": {
"version": "4.0.3", "version": "4.0.3",

1
package.json

@ -28,6 +28,7 @@
}, },
"dependencies": { "dependencies": {
"mysql2": "^2.3.3", "mysql2": "^2.3.3",
"pg": "^8.7.3",
"sqlite3": "^5.0.2" "sqlite3": "^5.0.2"
} }
} }

12
packages/nc-cli/package-lock.json generated

@ -6610,9 +6610,9 @@
} }
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.14.6", "version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==", "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -21377,9 +21377,9 @@
"integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q=="
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.14.6", "version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==" "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
}, },
"for-in": { "for-in": {
"version": "1.0.2", "version": "1.0.2",

6
packages/nc-common/package-lock.json generated

@ -5208,9 +5208,9 @@
"dev": true "dev": true
}, },
"handlebars": { "handlebars": {
"version": "4.7.6", "version": "4.7.7",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.5", "minimist": "^1.2.5",

6
packages/nc-gui/components/auth/roles.vue

@ -23,11 +23,11 @@
<!-- </v-toolbar-title>--> <!-- </v-toolbar-title>-->
<v-spacer /> <v-spacer />
<!-- tooltip="Reload roles" -->
<x-btn <x-btn
v-ge="['roles','reload']" v-ge="['roles','reload']"
outlined outlined
tooltip="Reload roles" :tooltip="$t('activity.reloadRoles')"
color="primary" color="primary"
small small
:disabled="loading" :disabled="loading"
@ -36,7 +36,7 @@
<v-icon small left> <v-icon small left>
refresh refresh
</v-icon> </v-icon>
Reload {{ $t('general.reload')}}
</x-btn> </x-btn>
<x-btn <x-btn
v-ge="['roles','add new']" v-ge="['roles','add new']"

115
packages/nc-gui/components/auth/userManagement.vue

@ -20,10 +20,11 @@
</v-text-field> </v-text-field>
<v-spacer /> <v-spacer />
<!-- tooltip="Reload roles" -->
<x-btn <x-btn
v-ge="['roles','reload']" v-ge="['roles','reload']"
outlined outlined
tooltip="Reload roles" :tooltip="$t('activity.reloadRoles')"
color="primary" color="primary"
small small
:disabled="loading" :disabled="loading"
@ -33,13 +34,15 @@
<v-icon small left> <v-icon small left>
refresh refresh
</v-icon> </v-icon>
Reload <!-- Reload -->
{{ $t('general.reload')}}
</x-btn> </x-btn>
<!-- tooltip="Add new role" -->
<x-btn <x-btn
v-if="_isUIAllowed('newUser')" v-if="_isUIAllowed('newUser')"
v-ge="['roles','add new']" v-ge="['roles','add new']"
outlined outlined
tooltip="Add new role" :tooltip="$t('tooltip.addRole')"
color="primary" color="primary"
small small
:disabled="loading" :disabled="loading"
@ -48,7 +51,8 @@
<v-icon small left> <v-icon small left>
mdi-plus mdi-plus
</v-icon> </v-icon>
New User <!-- New User -->
{{ $t('activity.newUser')}}
</x-btn> </x-btn>
</v-toolbar> </v-toolbar>
@ -91,17 +95,20 @@
<v-icon small> <v-icon small>
mdi-email-outline mdi-email-outline
</v-icon> </v-icon>
Email <!-- Email -->
{{ $t('labels.email')}}
</th> </th>
<th class="font-weight-regular caption"> <th class="font-weight-regular caption">
<v-icon small> <v-icon small>
mdi-drama-masks mdi-drama-masks
</v-icon> </v-icon>
Roles <!-- Roles -->
{{ $t('objects.roles')}}
</th> </th>
<th class="font-weight-regular caption"> <th class="font-weight-regular caption">
<!-- <v-icon small class="mt-n1">mdi-cursor-default-outline</v-icon>--> <!-- <v-icon small class="mt-n1">mdi-cursor-default-outline</v-icon>-->
Actions <!-- Actions -->
{{ $t('labels.actions')}}
</th> </th>
</tr> </tr>
</thead> </thead>
@ -145,9 +152,10 @@
<!-- </v-edit-dialog>--> <!-- </v-edit-dialog>-->
</td> </td>
<td> <td>
<!-- tooltip="Edit User" -->
<x-icon <x-icon
v-if="item.project_id" v-if="item.project_id"
tooltip="Edit User" :tooltip="$t('activity.editUser')"
icon-class="" icon-class=""
color="primary" color="primary"
small small
@ -155,30 +163,41 @@
> >
mdi-pencil-outline mdi-pencil-outline
</x-icon> </x-icon>
<span v-if="!item.project_id">
<x-icon <x-icon
v-if="!item.project_id" tooltip="Add user to project"
tooltip="Add user to project" color="primary"
color="primary" small
small @click="inviteUser(item.email)"
@click="inviteUser(item.email)" >
> mdi-plus
mdi-plus </x-icon>
</x-icon> <!-- <x-icon
tooltip="Remove user from NocoDB"
class="ml-2"
color="error"
small
@click.prevent.stop="deleteId = item.id; deleteItem = item.id;showConfirmDlg = true;deleteUserType='DELETE_FROM_NOCODB'"
>
mdi-delete-forever-outline
</x-icon> -->
</span>
<!-- tooltip="Remove user from project" -->
<x-icon <x-icon
v-else v-else
tooltip="Remove user from project" :tooltip="$t('activity.deleteUser')"
class="ml-2" class="ml-2"
color="error" color="error"
small small
@click.prevent.stop="deleteId = item.id; deleteItem = item.id;showConfirmDlg = true" @click.prevent.stop="deleteId = item.id; deleteItem = item.id;showConfirmDlg = true;deleteUserType='DELETE_FROM_PROJECT'"
> >
mdi-delete-outline mdi-delete-outline
</x-icon> </x-icon>
<!-- tooltip="Resend invite email" -->
<x-icon <x-icon
v-if="item.invite_token" v-if="item.invite_token"
tooltip="Resend invite email" :tooltip="$t('activity.resendInvite')"
icon-class="mt-n1" icon-class="mt-n1"
color="primary" color="primary"
small small
@ -187,9 +206,10 @@
mdi-email-send-outline mdi-email-send-outline
</x-icon> </x-icon>
<!-- tooltip="Copy invite url" -->
<x-icon <x-icon
v-if="item.invite_token" v-if="item.invite_token"
tooltip="Copy invite url" :tooltip="$t('activity.copyInviteURL')"
icon-class="" icon-class=""
color="primary" color="primary"
small small
@ -201,12 +221,13 @@
</tr> </tr>
</template> </template>
</v-data-table> </v-data-table>
<!-- tooltip="Add new user" -->
<div class="mt-10 text-center"> <div class="mt-10 text-center">
<x-btn <x-btn
v-if="_isUIAllowed('newUser')" v-if="_isUIAllowed('newUser')"
v-ge="['roles','add new']" v-ge="['roles','add new']"
outlined outlined
tooltip="Add new user" :tooltip="$t('msg.info.addUser')"
color="primary" color="primary"
small small
:disabled="loading" :disabled="loading"
@ -215,7 +236,8 @@
<v-icon small left> <v-icon small left>
mdi-plus mdi-plus
</v-icon> </v-icon>
New User <!-- New User -->
{{ $t('activity.newUser') }}
</x-btn> </x-btn>
</div> </div>
@ -296,7 +318,7 @@
<dlg-label-submit-cancel <dlg-label-submit-cancel
type="primary" type="primary"
:actions-mtd="confirmDelete" :actions-mtd="confirmDelete"
heading="Do you want to remove the user from project?" :heading="dialogMessage"
:dialog-show="showConfirmDlg" :dialog-show="showConfirmDlg"
/> />
@ -304,7 +326,7 @@
<v-dialog v-model="userEditDialog" :width="invite_token ? 700 :700" @close="invite_token = null"> <v-dialog v-model="userEditDialog" :width="invite_token ? 700 :700" @close="invite_token = null">
<v-card v-if="selectedUser" style="min-height: 100%"> <v-card v-if="selectedUser" style="min-height: 100%">
<v-card-title> <v-card-title>
Share : {{ $store.getters['project/GtrProjectName'] }} {{ $t('activity.share') }} : {{ $store.getters['project/GtrProjectName'] }}
<!-- <!--
<h4 class="text-center text-capitalize mt-2 d-100 display-1"> <h4 class="text-center text-capitalize mt-2 d-100 display-1">
<template v-if="invite_token"> <template v-if="invite_token">
@ -333,7 +355,8 @@
Edit User Edit User
</template> </template>
<template v-else> <template v-else>
Invite Team <!-- Invite Team -->
{{ $t('activity.inviteTeam') }}
</template> </template>
</div> </div>
<div class="pa-4 nc-invite-container"> <div class="pa-4 nc-invite-container">
@ -357,9 +380,10 @@
</v-alert> </v-alert>
<p class="caption grey--text mt-3"> <p class="caption grey--text mt-3">
Looks like you have not configured mailer yet! <br>Please copy above {{ $t('msg.info.userInviteNoSMTP') }}
invite <!-- Looks like you have not configured mailer yet! <br>Please copy above -->
link and send it to <!-- invite -->
<!-- link and send it to -->
{{ invite_token && (invite_token.email || invite_token.emails && invite_token.emails.join(', ')) }}. {{ invite_token && (invite_token.email || invite_token.emails && invite_token.emails.join(', ')) }}.
</p> </p>
@ -398,7 +422,10 @@
@input="edited=true" @input="edited=true"
> >
<template #label> <template #label>
<span class="caption">Email</span> <span class="caption">
<!-- Email -->
{{ $t('labels.email') }}
</span>
</template> </template>
</v-text-field> </v-text-field>
</v-col> </v-col>
@ -433,6 +460,8 @@
</v-form> </v-form>
<!-- </v-card-text> <!-- </v-card-text>
<v-card-actions class="justify-center">--> <v-card-actions class="justify-center">-->
<!-- tooltip="Save Changes" -->
<div class="text-center mt-0"> <div class="text-center mt-0">
<x-btn <x-btn
v-ge="['rows','save']" v-ge="['rows','save']"
@ -445,7 +474,7 @@
<v-icon small left> <v-icon small left>
{{ selectedUser.id ? 'save' : 'mdi-send' }} {{ selectedUser.id ? 'save' : 'mdi-send' }}
</v-icon> </v-icon>
{{ selectedUser.id ? 'Save' : 'Invite' }} {{ selectedUser.id ? $t('general.save') : $t('activity.invite') }}
</x-btn> </x-btn>
</div> </div>
</template> </template>
@ -497,7 +526,8 @@ export default {
} }
], ],
userList: [], userList: [],
roleDescriptions: {} roleDescriptions: {},
deleteUserType: '' // [DELETE_FROM_PROJECT, DELETE_FROM_NOCODB]
}), }),
computed: { computed: {
roleNames() { roleNames() {
@ -530,6 +560,12 @@ export default {
set(i) { set(i) {
this.selectedUser = this.users[i] this.selectedUser = this.users[i]
} }
},
dialogMessage() {
let msg = 'Do you want to remove the user'
if (this.deleteUserType === 'DELETE_FROM_PROJECT') { msg += ' from Project' } else if (this.deleteUserType === 'DELETE_FROM_NOCODB') { msg += ' from NocoDB' }
msg += '?'
return msg
} }
}, },
watch: { watch: {
@ -669,30 +705,30 @@ export default {
console.log(e) console.log(e)
} }
}, },
async deleteUser(id) { async deleteUser(id, type) {
try { try {
await this.$axios.delete('/admin/' + id, { await this.$axios.delete('/admin/' + id, {
params: { params: {
project_id: this.$route.params.project_id, project_id: this.$route.params.project_id,
email: this.deleteItem.email email: this.deleteItem.email,
type
}, },
headers: { headers: {
'xc-auth': this.$store.state.users.token 'xc-auth': this.$store.state.users.token
} }
}) })
this.$toast.success('Successfully removed the user from project').goAway(3000) this.$toast.success(`Successfully removed the user from ${type === 'DELETE_FROM_PROJECT' ? 'project' : 'NocoDB'}`).goAway(3000)
await this.loadUsers() await this.loadUsers()
} catch (e) { } catch (e) {
this.$toast.error(e.response.data.msg).goAway(3000) this.$toast.error(e.response.data.msg).goAway(3000)
} }
}, },
async confirmDelete(hideDialog) { async confirmDelete(hideDialog) {
if (hideDialog) { if (hideDialog) {
this.showConfirmDlg = false this.showConfirmDlg = false
return return
} }
await this.deleteUser(this.deleteId) await this.deleteUser(this.deleteId, this.deleteUserType)
this.showConfirmDlg = false this.showConfirmDlg = false
}, },
addUser() { addUser() {
@ -832,6 +868,7 @@ export default {
* *
* @author Naveen MR <oof1lab@gmail.com> * @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com> * @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
* *
* @license GNU AGPL version 3 or any later version * @license GNU AGPL version 3 or any later version
* *

72
packages/nc-gui/components/base/shareBase.vue

@ -3,23 +3,46 @@
<v-icon color="grey" small> <v-icon color="grey" small>
mdi-open-in-new mdi-open-in-new
</v-icon> </v-icon>
<span class="grey--text caption">Shared base link</span> <span class="grey--text caption">
<!-- Shared base link -->
{{ $t('activity.shareBase.link') }}
</span>
<div class="nc-container"> <div class="nc-container">
<v-chip v-if="base.enabled" :color="colors[4]" style="" class="rounded pl-1 pr-0 d-100 nc-url-chip pr-3"> <v-chip v-if="base.enabled" :color="colors[4]" style="" class="rounded pl-1 pr-0 d-100 nc-url-chip pr-3">
<div class="nc-url-wrapper d-flex mx-1 align-center d-100"> <div class="nc-url-wrapper d-flex mx-1 align-center d-100">
<span class="nc-url flex-grow-1 caption ">{{ url }}</span> <span class="nc-url flex-grow-1 caption ">{{ url }}</span>
<v-spacer /> <v-spacer />
<v-divider vertical /> <v-divider vertical />
<x-icon tooltip="reload" @click="recreate">
<!-- tooltip="reload" -->
<x-icon
:tooltip="$t('general.reload')"
@click="recreate"
>
mdi-reload mdi-reload
</x-icon> </x-icon>
<x-icon tooltip="copy URL" @click="copyUrl">
<!-- tooltip="copy URL" -->
<x-icon
:tooltip="$t('activity.copyUrl')"
@click="copyUrl"
>
mdi-content-copy mdi-content-copy
</x-icon> </x-icon>
<x-icon tooltip="open new tab" @click="navigateToSharedBase">
<!-- tooltip="open new tab" -->
<x-icon
:tooltip="$t('activity.openTab')"
@click="navigateToSharedBase"
>
mdi-open-in-new mdi-open-in-new
</x-icon> </x-icon>
<x-icon tooltip="copy embeddable HTML code" @click="generateEmbeddableIframe">
<!-- tooltip="copy embeddable HTML code" -->
<x-icon
:tooltip="$t('activity.iFrame')"
@click="generateEmbeddableIframe"
>
mdi-xml mdi-xml
</x-icon> </x-icon>
</div> </div>
@ -31,8 +54,14 @@
<template #activator="{on}"> <template #activator="{on}">
<div class="my-2" v-on="on"> <div class="my-2" v-on="on">
<div class="font-weight-bold nc-disable-shared-base"> <div class="font-weight-bold nc-disable-shared-base">
<span v-if="base.enabled">Anyone with the link</span> <span v-if="base.enabled">
<span v-else>Disabled shared base</span> <!-- Anyone with the link -->
{{ $t('activity.shareBase.enable') }}
</span>
<span v-else>
<!-- Disable shared base -->
{{ $t('activity.shareBase.disable') }}
</span>
<v-icon small> <v-icon small>
mdi-menu-down-outline mdi-menu-down-outline
</v-icon> </v-icon>
@ -45,7 +74,10 @@
<v-icon small class="mr-1"> <v-icon small class="mr-1">
mdi-link-variant mdi-link-variant
</v-icon> </v-icon>
<span class="caption">Anyone with the link</span> <span class="caption">
<!-- Anyone with the link -->
{{ $t('activity.shareBase.enable') }}
</span>
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item dense @click="disableSharedBase"> <v-list-item dense @click="disableSharedBase">
@ -53,18 +85,28 @@
<v-icon small class="mr-1"> <v-icon small class="mr-1">
mdi-link-variant-off mdi-link-variant-off
</v-icon> </v-icon>
<span class="caption">Disable shared base</span> <span class="caption">
<!-- Disable shared base -->
{{ $t('activity.shareBase.link') }}
</span>
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
</v-list> </v-list>
</v-menu> </v-menu>
<div class=" caption"> <div class=" caption">
<template v-if="base.enabled"> <template v-if="base.enabled">
<span v-if="base.roles === 'editor'">Anyone on the internet with this link can edit</span> <span v-if="base.roles === 'editor'">
<span v-else-if="base.roles === 'viewer'">Anyone on the internet with this link can view</span> Anyone on the internet with this link can edit
<!-- {{ $t('msg.info.shareBasePrivate') }} -->
</span>
<span v-else-if="base.roles === 'viewer'">
<!-- Anyone on the internet with this link can view -->
{{ $t('msg.info.shareBasePublic') }}
</span>
</template> </template>
<template v-else> <template v-else>
Generate publicly shareable readonly base <!-- Generate publicly shareable readonly base -->
{{ $t('msg.info.shareBasePrivate') }}
</template> </template>
</div> </div>
</div> </div>
@ -84,12 +126,14 @@
<v-list dense> <v-list dense>
<v-list-item @click="createSharedBase('editor')"> <v-list-item @click="createSharedBase('editor')">
<v-list-item-title> <v-list-item-title>
Editor <!-- Editor -->
{{ $t('objects.roleType.editor') }}
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
<v-list-item @click="createSharedBase('viewer')"> <v-list-item @click="createSharedBase('viewer')">
<v-list-item-title> <v-list-item-title>
Viewer <!-- Viewer -->
{{ $t('objects.roleType.viewer') }}
</v-list-item-title> </v-list-item-title>
</v-list-item> </v-list-item>
</v-list> </v-list>

2
packages/nc-gui/components/project/spreadsheet/components/expandedForm.vue

@ -437,7 +437,7 @@ export default {
this.$emit('input', this.localState) this.$emit('input', this.localState)
this.$emit('update:isNew', false) this.$emit('update:isNew', false)
this.$toast.success(`${this.primaryValue()} updated successfully.`, { this.$toast.success(`${this.primaryValue() || "Row"} updated successfully.`, {
position: 'bottom-right' position: 'bottom-right'
}).goAway(3000) }).goAway(3000)
} catch (e) { } catch (e) {

2
packages/nc-gui/components/project/spreadsheet/components/extras.vue

@ -76,7 +76,7 @@
<v-list-item <v-list-item
dense dense
target="_blank" target="_blank"
href="https://calendly.com/nocodb" href="https://calendly.com/nocodb-meeting"
> >
<!-- Book a Free DEMO --> <!-- Book a Free DEMO -->
<v-list-item-title> <v-list-item-title>

22
packages/nc-gui/components/project/spreadsheet/components/importExport/columnMappingModal.vue

@ -158,8 +158,28 @@ export default {
return 'Source data contains some invalid numbers' return 'Source data contains some invalid numbers'
} }
break break
case UITypes.Checkbox:
if (
this.parsedCsv && this.parsedCsv.data && this.parsedCsv.data.slice(0, 500)
.some((r) => {
if (r => r[row.sourceCn] !== null && r[row.sourceCn] !== undefined) {
var input = r[row.sourceCn]
if (typeof input === 'string') {
input = input.replace(/["']/g, "").toLowerCase().trim()
return (
input == "false" || input == "no" || input == "n" || input == "0" ||
input == "true" || input == "yes" || input == "y" || input == "1"
) ? false : true
}
return input != 1 && input != 0 && input != true && input != false
}
return false
})
) {
return 'Source data contains some invalid boolean values'
}
break
} }
return true return true
}, },
mapDefaultColumns() { mapDefaultColumns() {

15
packages/nc-gui/components/project/spreadsheet/components/moreActions.vue

@ -106,6 +106,7 @@ import FileSaver from 'file-saver'
import DropOrSelectFileModal from '~/components/import/dropOrSelectFileModal' import DropOrSelectFileModal from '~/components/import/dropOrSelectFileModal'
import ColumnMappingModal from '~/components/project/spreadsheet/components/importExport/columnMappingModal' import ColumnMappingModal from '~/components/project/spreadsheet/components/importExport/columnMappingModal'
import CSVTemplateAdapter from '~/components/import/templateParsers/CSVTemplateAdapter' import CSVTemplateAdapter from '~/components/import/templateParsers/CSVTemplateAdapter'
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'
export default { export default {
name: 'ExportImport', name: 'ExportImport',
@ -276,9 +277,19 @@ export default {
for (let i = 0, progress = 0; i < data.length; i += 500) { for (let i = 0, progress = 0; i < data.length; i += 500) {
const batchData = data.slice(i, i + 500).map(row => columnMappings.reduce((res, col) => { const batchData = data.slice(i, i + 500).map(row => columnMappings.reduce((res, col) => {
// todo: parse data // todo: parse data
if (col.enabled && col.destCn) { if (col.enabled && col.destCn) {
res[col.destCn] = row[col.sourceCn] const v = this.meta && this.meta.columns.find(c => c._cn === col.destCn)
var input = row[col.sourceCn]
// parse potential boolean values
if (v.uidt == UITypes.Checkbox) {
input = input.replace(/["']/g, "").toLowerCase().trim()
if (input == "false" || input == "no" || input == "n") {
input = "0"
} else if (input == "true" || input == "yes" || input == "y") {
input = "1"
}
}
res[col.destCn] = input
} }
return res return res
}, {})) }, {}))

2
packages/nc-gui/components/project/spreadsheet/components/virtualCell/components/listItems.vue

@ -162,7 +162,7 @@ export default {
offset: this.size * (this.page - 1), offset: this.size * (this.page - 1),
...this.queryParams, ...this.queryParams,
where where
}, this.mm.vtn, this.parentId) }, this.mm.vtn, this.parentId || -1)
} else { } else {
this.data = await this.api.paginatedList({ this.data = await this.api.paginatedList({
limit: this.size, limit: this.size,

5
packages/nc-gui/components/project/spreadsheet/mixins/spreadsheet.js

@ -163,7 +163,10 @@ export default {
concatenatedXWhere() { concatenatedXWhere() {
let where = '' let where = ''
if (this.searchField && this.searchQuery.trim()) { if (this.searchField && this.searchQuery.trim()) {
if (['text', 'string'].includes(this.sqlUi.getAbstractType(this.availableColumns.find(({ _cn }) => _cn === this.searchField) || this.availableColumns[0]))) { const col = this.availableColumns.find(({ _cn }) => _cn === this.searchField) || this.availableColumns[0]
// bigint values are displayed in string format in UI
// when searching bigint values, the operator should be 'eq' instead of 'like'
if (['text', 'string'].includes(this.sqlUi.getAbstractType(col)) && col.dt !== 'bigint') {
where = `(${this.searchField},like,%${this.searchQuery.trim()}%)` where = `(${this.searchField},like,%${this.searchQuery.trim()}%)`
} else { } else {
where = `(${this.searchField},eq,${this.searchQuery.trim()})` where = `(${this.searchField},eq,${this.searchQuery.trim()})`

2
packages/nc-gui/components/project/spreadsheet/views/xcGridView.vue

@ -237,7 +237,7 @@
/> />
</td> </td>
</tr> </tr>
<tr v-if="isPkAvail && !isLocked && !isPublicView && isEditable && relationType !== 'bt'"> <tr v-if="!isLocked && !isPublicView && isEditable && relationType !== 'bt'">
<td :colspan="visibleColLength + 1" class="text-left pointer nc-grid-add-new-cell" @click="insertNewRow(true)"> <td :colspan="visibleColLength + 1" class="text-left pointer nc-grid-add-new-cell" @click="insertNewRow(true)">
<v-tooltip top> <v-tooltip top>
<template #activator="{on}"> <template #activator="{on}">

205
packages/nc-gui/components/utils/dlgTableCreate.vue

@ -7,112 +7,114 @@
@keydown.enter="$emit('create', table)" @keydown.enter="$emit('create', table)"
> >
<v-card class="elevation-1 backgroundColor nc-create-table-card"> <v-card class="elevation-1 backgroundColor nc-create-table-card">
<v-card-title class="primary subheading white--text py-2"> <v-form ref="form" v-model="valid">
Create A New Table <v-card-title class="primary subheading white--text py-2">
</v-card-title> Create A New Table
</v-card-title>
<v-card-text class=" py-6 px-10 "> <v-card-text class=" py-6 px-10 ">
<v-text-field <v-text-field
ref="input" ref="input"
v-model="table.alias" v-model="table.alias"
solo solo
flat flat
persistent-hint persistent-hint
dense dense
hide-details1 hide-details1
:rules="[validateTableName]" :rules="[validateTableName]"
hint="Enter table name" hint="Enter table name"
class="mt-4 caption nc-table-name" class="mt-4 caption nc-table-name"
/> />
<v-text-field <v-text-field
v-if="!projectPrefix" v-if="!projectPrefix"
v-model="table.name" v-model="table.name"
solo solo
flat flat
dense dense
persistent-hint persistent-hint
hint="Table name as saved in database" hint="Table name as saved in database"
class="mt-4 caption nc-table-name-alias" class="mt-4 caption nc-table-name-alias"
/> />
<div class=" mt-5"> <div class=" mt-5">
<label class="add-default-title grey--text">Add Default Columns</label> <label class="add-default-title grey--text">Add Default Columns</label>
<div class=" d-flex caption justify-space-between"> <div class=" d-flex caption justify-space-between">
<v-checkbox <v-checkbox
v-model="table.columns" v-model="table.columns"
dense dense
class="mt-0 " class="mt-0 "
color="info" color="info"
hide-details hide-details
value="id" value="id"
@click.capture.prevent.stop="()=>{ @click.capture.prevent.stop="()=>{
$toast.info('ID column is required, you can rename this later if required.').goAway(3000); $toast.info('ID column is required, you can rename this later if required.').goAway(3000);
if(!table.columns.includes('id')){ if(!table.columns.includes('id')){
table.columns.push('id'); table.columns.push('id');
} }
}" }"
> >
<template #label> <template #label>
<span class="caption">id</span> <span class="caption">id</span>
</template> </template>
</v-checkbox> </v-checkbox>
<v-checkbox <v-checkbox
v-model="table.columns" v-model="table.columns"
dense dense
class="mt-0 " class="mt-0 "
color="info" color="info"
hide-details hide-details
value="title" value="title"
> >
<template #label> <template #label>
<span class="caption">title</span> <span class="caption">title</span>
</template> </template>
</v-checkbox> </v-checkbox>
<v-checkbox <v-checkbox
v-model="table.columns" v-model="table.columns"
dense dense
class="mt-0 " class="mt-0 "
color="info" color="info"
hide-details hide-details
value="created_at" value="created_at"
> >
<template #label> <template #label>
<span class="caption">created_at</span> <span class="caption">created_at</span>
</template> </template>
</v-checkbox> </v-checkbox>
<v-checkbox <v-checkbox
v-model="table.columns" v-model="table.columns"
dense dense
class="mt-0 " class="mt-0 "
color="info" color="info"
hide-details hide-details
value="updated_at" value="updated_at"
> >
<template #label> <template #label>
<span class="caption">updated_at</span> <span class="caption">updated_at</span>
</template> </template>
</v-checkbox> </v-checkbox>
</div>
</div> </div>
</div> </v-card-text>
</v-card-text> <v-divider />
<v-divider />
<v-card-actions class="py-4 px-10"> <v-card-actions class="py-4 px-10">
<v-spacer /> <v-spacer />
<v-btn class="" @click="dialogShow = false"> <v-btn class="" @click="dialogShow = false">
Cancel Cancel
</v-btn> </v-btn>
<v-btn <v-btn
:disabled="!(table.name && table.name.length) || !(table.alias && table.alias.length)" :disabled="!(table.name && table.name.length) || !(table.alias && table.alias.length) || !valid"
color="primary" color="primary"
class="nc-create-table-submit" class="nc-create-table-submit"
@click="$emit('create',table)" @click="$emit('create',table)"
> >
Submit Submit
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
</v-form>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
@ -134,7 +136,8 @@ export default {
'created_at', 'created_at',
'updated_at'] 'updated_at']
}, },
validateTableName validateTableName,
valid: false
} }
}, },
computed: { computed: {

34
packages/nc-gui/helpers/formulaList.js

@ -1,32 +1,32 @@
const validations = { const validations = {
AVG: { AVG: {
validation: { validation: {
args: { min: 1 } args: { min: 1 },
} },
}, },
ADD: { ADD: {
validation: { validation: {
args: { min: 1 } args: { min: 1 },
} },
}, },
AND: { AND: {
validation: { validation: {
args: { min: 1 } args: { min: 1 },
} },
}, },
OR: { OR: {
validation: { validation: {
args: { min: 1 } args: { min: 1 },
} },
}, },
CONCAT: { CONCAT: {
validation: { args: { min: 1 } } validation: { args: { min: 1 } },
}, },
TRIM: { TRIM: {
validation: { args: { min: 1 } } validation: { args: { min: 1 } },
}, },
UPPER: { UPPER: {
validation: { args: { rqd: 1 } } validation: { args: { rqd: 1 } },
}, },
LOWER: { validation: { args: { rqd: 1 } } }, LOWER: { validation: { args: { rqd: 1 } } },
LEN: { validation: { args: { rqd: 1 } } }, LEN: { validation: { args: { rqd: 1 } } },
@ -43,18 +43,18 @@ const validations = {
SQRT: { validation: { args: { rqd: 1 } } }, SQRT: { validation: { args: { rqd: 1 } } },
ABS: { validation: { args: { rqd: 1 } } }, ABS: { validation: { args: { rqd: 1 } } },
NOW: { validation: { args: { rqd: 0 } } }, NOW: { validation: { args: { rqd: 0 } } },
REPLACE: { validation: { args: { rqd: 2 } } }, REPLACE: { validation: { args: { rqd: 3 } } },
SEARCH: { validation: { args: { rqd: 2 } } }, SEARCH: { validation: { args: { rqd: 2 } } },
INT: { validation: { args: { rqd: 1 } } }, INT: { validation: { args: { rqd: 1 } } },
RIGHT: { validation: { args: { rqd: 2 } } }, RIGHT: { validation: { args: { rqd: 2 } } },
LEFT: { LEFT: {
validation: { args: { rqd: 1 } } validation: { args: { rqd: 1 } },
}, },
SUBSTR: { validation: { args: { min: 2, max: 3 } } }, SUBSTR: { validation: { args: { min: 2, max: 3 } } },
MID: { validation: { args: { rqd: 1 } } }, MID: { validation: { args: { rqd: 1 } } },
IF: { validation: { args: { min: 2, max: 3 } } }, IF: { validation: { args: { min: 2, max: 3 } } },
SWITCH: { validation: { args: { min: 3 } } } SWITCH: { validation: { args: { min: 3 } } },
} };
export default Object.keys(validations) export default Object.keys(validations);
export { validations } export { validations };

4
packages/nc-gui/helpers/sqlUi/MssqlUi.js

@ -921,16 +921,14 @@ export class MssqlUi {
static getAbstractType(col) { static getAbstractType(col) {
switch ((col.dt || col.dt).toLowerCase()) { switch ((col.dt || col.dt).toLowerCase()) {
case 'bigint':
case 'smallint': case 'smallint':
case 'bit': case 'bit':
case 'tinyint': case 'tinyint':
case 'int': case 'int':
return 'integer' return 'integer'
case 'bigint':
case 'binary': case 'binary':
return 'string'
case 'char': case 'char':
return 'string' return 'string'

2
packages/nc-gui/helpers/sqlUi/MysqlUi.js

@ -842,7 +842,6 @@ export class MysqlUi {
case 'int': case 'int':
case 'smallint': case 'smallint':
case 'mediumint': case 'mediumint':
case 'bigint':
case 'bit': case 'bit':
return 'integer' return 'integer'
@ -897,6 +896,7 @@ export class MysqlUi {
case 'set': case 'set':
return 'set' return 'set'
case 'bigint':
case 'geometry': case 'geometry':
case 'point': case 'point':
case 'linestring': case 'linestring':

2
packages/nc-gui/helpers/sqlUi/SqliteUi.js

@ -683,7 +683,6 @@ export class SqliteUi {
case 'tinyint': case 'tinyint':
case 'smallint': case 'smallint':
case 'mediumint': case 'mediumint':
case 'bigint':
case 'int2': case 'int2':
case 'int8': case 'int8':
return 'integer' return 'integer'
@ -702,6 +701,7 @@ export class SqliteUi {
case 'blob': case 'blob':
return 'blob' return 'blob'
case 'bigint':
case 'character': case 'character':
case 'varchar': case 'varchar':
return 'string' return 'string'

378
packages/nc-gui/lang/de.json

@ -1,10 +1,10 @@
{ {
"general": { "general": {
"home": "Heim", "home": "Start",
"load": "Belastung", "load": "Laden",
"open": "Offen", "open": "Öffnen",
"close": "Nah dran", "close": "Schließen",
"yes": "ja", "yes": "Ja",
"no": "Nein", "no": "Nein",
"ok": "OK", "ok": "OK",
"and": "Und", "and": "Und",
@ -14,7 +14,7 @@
"remove": "Entfernen", "remove": "Entfernen",
"save": "Speichern", "save": "Speichern",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"submit": "einreichen", "submit": "Übermitteln",
"create": "Erstellen", "create": "Erstellen",
"delete": "Löschen", "delete": "Löschen",
"update": "Aktualisieren", "update": "Aktualisieren",
@ -22,20 +22,20 @@
"reload": "Neu laden", "reload": "Neu laden",
"reset": "Zurücksetzen", "reset": "Zurücksetzen",
"install": "Installieren", "install": "Installieren",
"show": "Show", "show": "Zeigen",
"hide": "Verstecken", "hide": "Verstecken",
"showAll": "Zeige alles", "showAll": "Alles zeigen",
"hideAll": "Versteck alles", "hideAll": "Alles verstecken",
"showMore": "Zeig mehr", "showMore": "Mehr anzeigen",
"showOptions": "Optionen anzeigen.", "showOptions": "Optionen anzeigen",
"hideOptions": "Optionen ausblenden.", "hideOptions": "Optionen ausblenden",
"showMenu": "Zeige das Menü", "showMenu": "Menü anzeigen",
"hideMenu": "Menü ausblenden.", "hideMenu": "Menü ausblenden",
"addAll": "Füge alle Hinzu", "addAll": "Alles hinzufügen",
"removeAll": "Alles entfernen", "removeAll": "Alles entfernen",
"signUp": "Anmeldung", "signUp": "Anmelden",
"signIn": "EINLOGGEN", "signIn": "Einloggen",
"signOut": "Austragen", "signOut": "Ausloggen",
"required": "Erforderlich", "required": "Erforderlich",
"preferred": "Bevorzugt", "preferred": "Bevorzugt",
"mandatory": "Verpflichtend", "mandatory": "Verpflichtend",
@ -45,24 +45,24 @@
"project": "Projekt", "project": "Projekt",
"projects": "Projekte", "projects": "Projekte",
"table": "Tabelle", "table": "Tabelle",
"tables": "Tische", "tables": "Tabellen",
"field": "Bereich", "field": "Feld",
"fields": "Felder", "fields": "Felder",
"column": "Spalte", "column": "Spalte",
"columns": "Säulen", "columns": "Spalten",
"page": "Buchseite", "page": "Seite",
"pages": "Seiten", "pages": "Seiten",
"record": "Aufzeichnen", "record": "Aufzeichnen",
"records": "Aufzeichnungen", "records": "Aufzeichnungen",
"webhook": "WEBHOOK.", "webhook": "Webhook",
"webhooks": "WebHooks", "webhooks": "Webhooks",
"view": "Aussicht", "view": "Ansicht",
"views": "Ansichten", "views": "Ansichten",
"viewType": { "viewType": {
"grid": "Grid", "grid": "Gitter",
"gallery": "Galerie", "gallery": "Galerie",
"form": "Formular", "form": "Formular",
"kanban": "Kanban.", "kanban": "Kanban",
"calendar": "Kalender" "calendar": "Kalender"
}, },
"user": "Nutzer", "user": "Nutzer",
@ -71,21 +71,21 @@
"roles": "Rollen", "roles": "Rollen",
"roleType": { "roleType": {
"owner": "Eigentümer", "owner": "Eigentümer",
"creator": "Schöpfer", "creator": "Ersteller",
"editor": "Editor", "editor": "Bearbeiter",
"commenter": "Kommentator", "commenter": "Kommentator",
"viewer": "Zuschauer" "viewer": "Zuschauer"
} }
}, },
"datatype": { "datatype": {
"ID": "ICH WÜRDE", "ID": "ID",
"ForeignKey": "Unbekannter Schlüssel", "ForeignKey": "Unbekannter Schlüssel",
"SingleLineText": "Einzelsteintext", "SingleLineText": "Einzeiliger Text",
"LongText": "Langer Text", "LongText": "Langer Text",
"Attachment": "Anhang", "Attachment": "Anhang",
"Checkbox": "Kontrollkästchen", "Checkbox": "Kontrollkästchen",
"MultiSelect": "Mehrfachauswahl", "MultiSelect": "Mehrfachauswahl",
"SingleSelect": "Single Select.", "SingleSelect": "Einfache Auswahl",
"Collaborator": "Mitarbeiter", "Collaborator": "Mitarbeiter",
"Date": "Datum", "Date": "Datum",
"Year": "Jahr", "Year": "Jahr",
@ -98,15 +98,15 @@
"Currency": "Währung", "Currency": "Währung",
"Percent": "Prozent", "Percent": "Prozent",
"Duration": "Dauer", "Duration": "Dauer",
"Rating": "Nennen", "Rating": "Klassifizierung",
"Formula": "Formel", "Formula": "Formel",
"Rollup": "Aufrollen", "Rollup": "Rollup",
"Count": "Zählen", "Count": "Zählen",
"Lookup": "Nachschlagen", "Lookup": "Nachschlagen",
"DateTime": "Terminzeit", "DateTime": "Datum/Zeit",
"CreateTime": "Zeit schaffen", "CreateTime": "Zeit erstellen",
"LastModifiedTime": "Letzte geänderte Zeit", "LastModifiedTime": "Zuletzt bearbeitet",
"AutoNumber": "Auto Nummer", "AutoNumber": "Auto-Numerierung",
"Barcode": "Barcode", "Barcode": "Barcode",
"Button": "Taste", "Button": "Taste",
"Password": "Passwort" "Password": "Passwort"
@ -115,78 +115,78 @@
"isEqual": "ist gleich", "isEqual": "ist gleich",
"isNotEqual": "ist nicht gleich", "isNotEqual": "ist nicht gleich",
"isLike": "ist wie", "isLike": "ist wie",
"isNot like": "Ist nicht wie", "isNot like": "ist nicht wie",
"isEmpty": "ist leer", "isEmpty": "ist leer",
"isNotEmpty": "ist nicht leer", "isNotEmpty": "ist nicht leer",
"isNull": "ist Null", "isNull": "ist Null",
"isNotNull": "ist nicht null" "isNotNull": "ist nicht Null"
}, },
"title": { "title": {
"newProj": "Neues Projekt", "newProj": "Neues Projekt",
"myProject": "Meine Projekte", "myProject": "Meine Projekte",
"formTitle": "Titel bilden", "formTitle": "Formular Titel",
"collabView": "Kollaborative Sicht", "collabView": "Mitarbeitersicht",
"lockedView": "Gesperrter Blick", "lockedView": "Gesperrter Blick",
"personalView": "Persönliche Ansicht", "personalView": "Persönliche Ansicht",
"appStore": "Appstore", "appStore": "Appstore",
"team&auth": "Team & Auth.", "team&auth": "Team & Auth.",
"rolesUserMgmt": "Rollen & Benutzermanagement", "rolesUserMgmt": "Rollen & Benutzermanagement",
"userMgmt": "Benutzermanagement.", "userMgmt": "Benutzermanagement",
"apiTokenMgmt": "API-Tokens-Management.", "apiTokenMgmt": "API-Tokens-Management",
"rolesMgmt": "Rollenmanagement.", "rolesMgmt": "Rollenmanagement",
"projMeta": "Projektmetadaten", "projMeta": "Projektmetadaten",
"metaMgmt": "Meta-Management.", "metaMgmt": "Meta-Management",
"metadata": "Metadaten", "metadata": "Metadaten",
"exportImportMeta": "Metadaten exportieren / importieren", "exportImportMeta": "Metadaten exportieren / importieren",
"metaOperations": "Metadatenoperationen.", "metaOperations": "Metadatenoperationen",
"audit": "Prüfung", "audit": "Audit",
"auditLogs": "Audit-Log", "auditLogs": "Audit-Log",
"sqlMigrations": "SQL-Migrationen", "sqlMigrations": "SQL-Migrationen",
"dbCredentials": "Datenbank-Anmeldeinformationen", "dbCredentials": "Datenbank-Anmeldeinformationen",
"advancedParameters": "SSL & Erweiterte Parameter", "advancedParameters": "SSL & Erweiterte Parameter",
"headCreateProject": "Projekt erstellen | NocOdb", "headCreateProject": "Projekt erstellen | NocoDB",
"headLogin": "Anmelden | NocOdb", "headLogin": "Anmelden | NocoDB",
"resetPassword": "Setzen Sie Ihr Passwort zurück" "resetPassword": "Passwort zurücksetzen"
}, },
"labels": { "labels": {
"projName": "Projektname", "projName": "Projektname",
"viewName": "Name anzeigen.", "viewName": "Name anzeigen",
"viewLink": "Link anzeigen.", "viewLink": "Link anzeigen",
"columnName": "Spaltenname", "columnName": "Spaltenname",
"columnType": "Säulentyp", "columnType": "Spaltentyp",
"roleName": "Rollenname", "roleName": "Rollenname",
"roleDescription": "Rollenbeschreibung", "roleDescription": "Rollenbeschreibung",
"databaseType": "Geben Sie in der Datenbank ein", "databaseType": "Typ in der Datenbank",
"lengthValue": "Länge / Wert", "lengthValue": "Länge / Wert",
"dbType": "Datenbanktyp.", "dbType": "Datenbanktyp",
"sqliteFile": "SQLite-Datei.", "sqliteFile": "SQLite-Datei",
"hostAddress": "Host-Adresse", "hostAddress": "Host-Adresse",
"port": "Port-Nummer", "port": "Port-Nummer",
"username": "Nutzername", "username": "Benutzername",
"password": "Passwort", "password": "Passwort",
"action": "Aktion", "action": "Aktion",
"actions": "Aktionen", "actions": "Aktionen",
"operation": "Betrieb", "operation": "Vorgang",
"operationType": "Betriebstyp.", "operationType": "Vorgangstyp",
"operationSubType": "Betriebsuntertyp", "operationSubType": "Vorgangsuntertyp",
"description": "Beschreibung", "description": "Beschreibung",
"authentication": "Authentifizierung", "authentication": "Authentifizierung",
"token": "Zeichen", "token": "Token",
"where": "Wo", "where": "Wo",
"cache": "Zwischenspeicher", "cache": "Zwischenspeicher",
"chat": "Plaudern", "chat": "Chat",
"email": "Email", "email": "Email",
"storage": "Lager", "storage": "Speicher",
"uiAcl": "UI-ACL.", "uiAcl": "UI-ACL.",
"models": "Modelle", "models": "Modelle",
"syncState": "Sync-Zustand", "syncState": "Sync-Stand",
"created": "Erstellt", "created": "Erstellt",
"sqlOutput": "SQL-Ausgang", "sqlOutput": "SQL-Ausgabe",
"dbCreateIfNotExists": "Datenbank: Erstellen, falls nicht vorhanden", "dbCreateIfNotExists": "Datenbank: Erstellen, falls nicht vorhanden",
"clientKey": "Client-Schlüssel", "clientKey": "Client-Schlüssel",
"clientCert": "Client Cert.", "clientCert": "Client Cert",
"serverCA": "Server CA", "serverCA": "Server CA",
"requriedCa": "CA Erforderlich", "requriedCa": "Erforderliches CA",
"requriedIdentity": "Erforderliche Identität", "requriedIdentity": "Erforderliche Identität",
"inflection": { "inflection": {
"tableName": "Flexion - Tabellenname", "tableName": "Flexion - Tabellenname",
@ -194,7 +194,7 @@
}, },
"community": { "community": {
"starUs1": "Stern", "starUs1": "Stern",
"starUs2": "uns auf Github.", "starUs2": "uns auf Github",
"bookDemo": "Buchen Sie eine kostenlose Demo", "bookDemo": "Buchen Sie eine kostenlose Demo",
"getAnswered": "Erhalten Sie Antworten auf Ihre Fragen", "getAnswered": "Erhalten Sie Antworten auf Ihre Fragen",
"joinDiscord": "Discord beitreten", "joinDiscord": "Discord beitreten",
@ -204,9 +204,9 @@
}, },
"activity": { "activity": {
"createProject": "Projekt erstellen", "createProject": "Projekt erstellen",
"importProject": "Projektimport", "importProject": "Projekt importieren",
"searchProject": "Projekt suchen", "searchProject": "Projekt suchen",
"editProject": "Projekt bearbeiten.", "editProject": "Projekt bearbeiten",
"stopProject": "Projekt stoppen", "stopProject": "Projekt stoppen",
"startProject": "Projekt starten", "startProject": "Projekt starten",
"restartProject": "Projekt neu starten", "restartProject": "Projekt neu starten",
@ -214,21 +214,21 @@
"refreshProject": "Projekte aktualisieren", "refreshProject": "Projekte aktualisieren",
"saveProject": "Projekt speichern", "saveProject": "Projekt speichern",
"createProjectExtended": { "createProjectExtended": {
"extDB": "Erstellen mit einer<br>externen Datenbank", "extDB": "Erstellen durch Verbinden <br>mit einer externen Datenbank",
"excel": "Projekt von Excel erstellen", "excel": "Projekt aus Excel erstellen",
"template": "Projekt aus der Vorlage erstellen" "template": "Projekt aus Vorlage erstellen"
}, },
"OkSaveProject": "OK & Save Project", "OkSaveProject": "OK & Project speichern",
"upgrade": { "upgrade": {
"available": "Upgrade verfügbar", "available": "Upgrade verfügbar",
"releaseNote": "Versionshinweise", "releaseNote": "Versionshinweise",
"howTo": "Wie aktualisiere ich?" "howTo": "Wie wird aktualisiert?"
}, },
"translate": "Hilfe umsetzen", "translate": "Übersetzen helfen",
"account": { "account": {
"authToken": "Copy Auth-Token", "authToken": "Auth-Token kopieren",
"swagger": "Swagger Apis Doc.", "swagger": "Swagger Apis Doc",
"projInfo": "Projektinfo kopieren.", "projInfo": "Projektinfo kopieren",
"themes": "Themen" "themes": "Themen"
}, },
"sort": "Sortieren", "sort": "Sortieren",
@ -237,70 +237,70 @@
"addFilter": "Filter hinzufügen", "addFilter": "Filter hinzufügen",
"share": "Teilen", "share": "Teilen",
"shareBase": { "shareBase": {
"disable": "Freigegebene Basis deaktivieren.", "disable": "Freigegebene Datenbank deaktivieren",
"enable": "Jeder mit dem Link", "enable": "Jeder mit dem Link",
"link": "Gemeinsamer Basis-Link" "link": "Freigegebene Datenbank-Link"
}, },
"invite": "Einladen", "invite": "Einladen",
"inviteMore": "Mehr einladen", "inviteMore": "Mehr einladen",
"inviteTeam": "Team einladen", "inviteTeam": "Team einladen",
"inviteToken": "Einladen", "inviteToken": "Token einladen",
"newUser": "Neuer Benutzer", "newUser": "Neuer Benutzer",
"editUser": "Benutzer bearbeiten", "editUser": "Benutzer bearbeiten",
"deleteUser": "Benutzer vom Projekt entfernen", "deleteUser": "Benutzer vom Projekt entfernen",
"resendInvite": "Senden Sie die E-Mail-Adresse ein", "resendInvite": "Einladungs-Email erneut versenden",
"copyInviteURL": "Kopieren Laden Sie die URL ein", "copyInviteURL": "Einladungs-URL kopieren",
"newRole": "Neue Rolle", "newRole": "Neue Rolle",
"reloadRoles": "Rollen neu laden", "reloadRoles": "Rollen neu laden",
"nextPage": "Nächste Seite", "nextPage": "Nächste Seite",
"prevPage": "Vorherige Seite", "prevPage": "Vorherige Seite",
"nextRecord": "Nächster Rekord", "nextRecord": "Nächster Eintrag",
"previousRecord": "Bisherigen Rekord", "previousRecord": "Vorheriger Eintrag",
"copyApiURL": "API-URL kopieren", "copyApiURL": "API-URL kopieren",
"createTable": "Tabelle erstellen", "createTable": "Tabelle erstellen",
"refreshTable": "Tabellen erfrischt.", "refreshTable": "Tabellen aktualisieren",
"renameTable": "Tisch umbenennen", "renameTable": "Tabelle umbenennen",
"addField": "Fügen Sie diesem Tisch neues Feld hinzu", "addField": "Neues Feld zu dieser Tabelle hinzufügen",
"setPrimary": "Als Primärwert einstellen", "setPrimary": "Als Primärwert festlegen",
"addRow": "Neue Row hinzufügen", "addRow": "Neue Spalte hinzufügen",
"saveRow": "REIBEN REIBEN", "saveRow": "Spalte speichern",
"insertRow": "Neue Reihe einfügen", "insertRow": "Neue Reihe einfügen",
"deleteRow": "Zeile löschen", "deleteRow": "Zeile löschen",
"deleteSelectedRow": "Ausgewählte Zeilen löschen", "deleteSelectedRow": "Ausgewählte Zeilen löschen",
"importExcel": "Excel importieren", "importExcel": "Import Excel",
"downloadCSV": "Download als CSV.", "downloadCSV": "Download als CSV",
"uploadCSV": "Laden Sie CSV hoch", "uploadCSV": "Hochladen CSV",
"import": "Importieren", "import": "Importieren",
"importMetadata": "Metadaten importieren", "importMetadata": "Metadaten importieren",
"exportMetadata": "Metadaten exportieren", "exportMetadata": "Metadaten exportieren",
"clearMetadata": "Metadaten löschen", "clearMetadata": "Metadaten löschen",
"exportToFile": "Export in die Datei.", "exportToFile": "Export in Datei",
"changePwd": "Kennwort ändern", "changePwd": "Kennwort ändern",
"createView": "Eine Ansicht erstellen.", "createView": "Ansicht erstellen",
"shareView": "Ansicht teilen.", "shareView": "Ansicht teilen",
"listSharedView": "Gemeinsame Ansichtsliste", "listSharedView": "Geteilte Ansichtsliste",
"ListView": "Ansichten Liste.", "ListView": "Ansichtenliste",
"copyView": "Ansicht kopieren", "copyView": "Ansicht kopieren",
"renameView": "Ansicht umbenennen", "renameView": "Ansicht umbenennen",
"deleteView": "Ansicht löschen", "deleteView": "Ansicht löschen",
"createGrid": "Grid-Sicht erstellen.", "createGrid": "Raster-Ansicht erstellen",
"createGallery": "Ansicht der Galerie erstellen.", "createGallery": "Galerie-Ansicht erstellen",
"createCalendar": "Kalender-Sicht erstellen.", "createCalendar": "Kalender-Ansicht erstellen",
"createKanban": "Kanban-Sicht erstellen.", "createKanban": "Kanban-Ansicht erstellen",
"createForm": "Formula erstellen.", "createForm": "Formular-Ansicht erstellen",
"showSystemFields": "Systemfelder anzeigen.", "showSystemFields": "Systemfelder anzeigen",
"copyUrl": "URL kopieren", "copyUrl": "URL kopieren",
"openTab": "Neue Registerkarte öffnen.", "openTab": "Neue Registerkarte öffnen",
"iFrame": "Kopieren Sie eingebettete HTML-Code", "iFrame": "Eingebettete HTML-Code kopieren",
"addWebhook": "Fügen Sie einen neuen WebHook hinzu", "addWebhook": "Neuen WebHook hinzufügen",
"newToken": "Neues Token hinzufügen", "newToken": "Neuen Token hinzufügen",
"exportZip": "Zip-Datei exportieren", "exportZip": "Zip-Datei exportieren",
"importZip": "Zip-Datei importieren", "importZip": "Zip-Datei importieren",
"metaSync": "Jetzt synchronisieren", "metaSync": "Jetzt synchronisieren",
"settings": "Einstellungen", "settings": "Einstellungen",
"previewAs": "Vorschau anzeigen als", "previewAs": "Vorschau anzeigen als",
"resetReview": "Vorschau zurücksetzen.", "resetReview": "Vorschau zurücksetzen",
"testDbConn": "Datenbankverbindung testen.", "testDbConn": "Datenbankverbindung testen",
"removeDbFromEnv": "Datenbank aus der Umgebung entfernen", "removeDbFromEnv": "Datenbank aus der Umgebung entfernen",
"editConnJson": "Verbindung JSON bearbeiten", "editConnJson": "Verbindung JSON bearbeiten",
"sponsorUs": "Sponsor uns.", "sponsorUs": "Sponsor uns.",
@ -313,112 +313,112 @@
"apiGQL": "Zugänglich über Graphql-APIs", "apiGQL": "Zugänglich über Graphql-APIs",
"theme": { "theme": {
"dark": "Es kommt in Schwarz (^ ⇧b)", "dark": "Es kommt in Schwarz (^ ⇧b)",
"light": "Kommt es schwarz? (^ ⇧b)" "light": "Kommt es in schwarz? (^ ⇧b)"
}, },
"addTable": "Neue Tabelle hinzufügen", "addTable": "Neue Tabelle hinzufügen",
"inviteMore": "Laden Sie mehr Benutzer ein", "inviteMore": "Mehr Benutzer einladen",
"toggleNavDraw": "Navigationsschublade umschalten", "toggleNavDraw": "Navigationsbereich umschalten",
"reloadApiToken": "API-Token neu laden", "reloadApiToken": "API-Token neu laden",
"generateNewApiToken": "Neues API-Token generieren", "generateNewApiToken": "Neuen API-Token generieren",
"addRole": "Neue Rolle hinzufügen", "addRole": "Neue Rolle hinzufügen",
"metaReloadList": "Listenliste neu laden", "metaReloadList": "Liste neu laden",
"metaSync": "Metadaten synchronisieren.", "metaSync": "Metadaten synchronisieren",
"sqlMigration": "Migrationen neu laden", "sqlMigration": "Migrationen neu laden",
"updateRestart": "Update & Neustart.", "updateRestart": "Update & Neustart",
"cancelReturn": "Abbrechen und Rückkehr.", "cancelReturn": "Abbrechen und Zurück",
"exportMetadata": "Exportieren Sie alle Metadaten von den Metastabellen in Meta-Verzeichnis.", "exportMetadata": "Alle Metadaten von den Metatabellen in Meta-Verzeichnis exportieren.",
"importMetadata": "Importieren Sie alle Metadaten aus dem Meta-Verzeichnis in Meta-Tabellen.", "importMetadata": "Alle Metadaten vom Meta-Verzeichnis in Metatabellen importieren.",
"clearMetadata": "Alle Metadaten aus Meta-Tabellen löschen.", "clearMetadata": "Alle Metadaten aus Meta-Tabellen löschen.",
"clientKey": "Wählen Sie .key-Datei aus", "clientKey": "Auswahl .key-Datei",
"clientCert": "Wählen Sie .Cert-Datei", "clientCert": "Auswahl .cert-Datei",
"clientCA": "Wählen Sie CA-Datei" "clientCA": "Auswahl CA-Datei"
}, },
"placeholder": { "placeholder": {
"projName": "Geben Sie den Projektnamen ein", "projName": "Projektnamen eingeben",
"password": { "password": {
"enter": "Geben Sie das Passwort ein", "enter": "Passwort eingeben",
"current": "Jetziges Passwort", "current": "Aktuelles Passwort",
"new": "Neues Passwort", "new": "Neues Passwort",
"save": "Passwort speichern", "save": "Passwort speichern",
"confirm": "Bestätige neues Passwort" "confirm": "Neues Passwort bestätigen"
}, },
"searchProjectTree": "Tische suchen.", "searchProjectTree": "Tabellen suchen",
"searchFields": "Suchfelder", "searchFields": "Felder suchen",
"searchColumn": "Suchen Sie {Suchen} Säule", "searchColumn": "Suche {search} Spalte",
"searchApps": "Apps suchen", "searchApps": "Apps suchen",
"searchModels": "Suchmodelle", "searchModels": "Suche Modelle",
"noItemsFound": "Keine Elemente gefunden", "noItemsFound": "Keine Elemente gefunden",
"defaultValue": "Standardwert", "defaultValue": "Standardwert",
"filterByEmail": "Filtern per E-Mail" "filterByEmail": "Filtern nach E-Mail"
}, },
"msg": { "msg": {
"info": { "info": {
"footerInfo": "Reihen pro Seite.", "footerInfo": "Reihen pro Seite",
"upload": "Wählen Sie Datei zum Hochladen", "upload": "Datei zum Hochladen auswählen",
"upload_sub": "oder Drag & Drop-Datei", "upload_sub": "oder Drag & Drop Datei",
"excelSupport": "Unterstützt: .xls ,.xlsx ,.xlsm, .ods, .ots", "excelSupport": "Unterstützt: .xls ,.xlsx ,.xlsm, .ods, .ots",
"excelURL": "Geben Sie Excel-Datei-URL ein", "excelURL": "Excel-Datei-URL eingeben",
"footMsg": "Anzahl der Zeilen, um den Datentyp analysieren zu können", "footMsg": "Anzahl der Zeilen, um den Datentyp analysieren zu können",
"excelImport": "Blatt (s) stehen für den Import zur Verfügung", "excelImport": "Blatt (s) stehen für den Import zur Verfügung",
"exportMetadata": "Möchten Sie Metadaten von Meta-Tabellen exportieren?", "exportMetadata": "Möchten Sie Metadaten von Meta-Tabellen exportieren?",
"importMetadata": "Möchten Sie Metadaten von Metastischen importieren?", "importMetadata": "Möchten Sie Metadaten von Metatabellen importieren?",
"clearMetadata": "Möchten Sie Metadaten von Meta-Tischen löschen?", "clearMetadata": "Möchten Sie Metadaten von Meta-Tabellen löschen?",
"projectEmptyMessage": "Beginnen Sie mit dem Erstellen eines neuen Projekts", "projectEmptyMessage": "Beginnen mit dem Erstellen eines neuen Projekts",
"stopProject": "Möchten Sie das Projekt aufhalten?", "stopProject": "Möchten Sie das Projekt beenden?",
"startProject": "Möchten Sie das Projekt starten?", "startProject": "Möchten Sie das Projekt starten?",
"restartProject": "Möchten Sie das Projekt neu starten?", "restartProject": "Möchten Sie das Projekt neu starten?",
"deleteProject": "Möchten Sie das Projekt löschen?", "deleteProject": "Möchten Sie das Projekt löschen?",
"shareBasePrivate": "Öffentlich genutzbare readontly Base generieren", "shareBasePrivate": "Öffentlich freigegebene Nur-Lese-Datenbank generieren",
"shareBasePublic": "Jeder im Internet mit diesem Link kann sehen", "shareBasePublic": "Jeder im Internet mit diesem Link kann sehen",
"userInviteNoSMTP": "Sieht aus, als hätten Sie den Mailer noch nicht konfiguriert! \\ n Bitte kopieren Sie den obigen Link einladen und senden Sie es an", "userInviteNoSMTP": "Sieht aus, als hätten Sie den Mailer noch nicht konfiguriert! \\ n Bitte kopieren Sie den obigen Einladungs-Link und senden Sie ihn an",
"dragDropHide": "Ziehen Sie die Felder hierher, um sich zu verstecken", "dragDropHide": "Ziehen Sie die Felder hierher, um sie zu verstecken",
"formInput": "Geben Sie das Formular-Eingabetikett ein", "formInput": "Formularbezeichnung eingeben",
"formHelpText": "Fügen Sie etwas Hilfe Text hinzu", "formHelpText": "Fügen Sie einen Hilfs-Text hinzu",
"onlyCreator": "Nur für den Ersteller sichtbar", "onlyCreator": "Nur für den Ersteller sichtbar",
"formDesc": "Formularbeschreibung hinzufügen.", "formDesc": "Formularbeschreibung hinzufügen",
"beforeEnablePwd": "Den Zugriff mit einem Passwort einschränken", "beforeEnablePwd": "Den Zugriff mit einem Passwort einschränken",
"afterEnablePwd": "Zugriff ist Passwort eingeschränkt", "afterEnablePwd": "Zugriff ist Passwort-geschützt",
"privateLink": "Diese Ansicht wird über einen privaten Link geteilt", "privateLink": "Diese Ansicht wird durch einen privaten Link geteilt",
"privateLinkAdditionalInfo": "Personen mit privatem Link können nur Zellen sehen, die in dieser Ansicht angezeigt werden", "privateLinkAdditionalInfo": "Personen mit einem privatem Link können nur Zellen sehen, die in dieser Ansicht angezeigt werden",
"afterFormSubmitted": "Nachdem das Formular eingereicht wird", "afterFormSubmitted": "Nachdem das Formular übermittelt wurde",
"apiOptions": "Zugriff auf Projekt via.", "apiOptions": "Zugriff auf das Projekt via",
"submitAnotherForm": "'Senden Sie ein anderes Formular einreichen'", "submitAnotherForm": "Weiteres Formular übermitteln'-Button anzeigen",
"showBlankForm": "Zeigen Sie nach 5 Sekunden ein leeres Formular an", "showBlankForm": "Ein leeres Formular nach 5 Sekunden anzeigen",
"emailForm": "E-Mail an mich an", "emailForm": "E-Mail mich unter",
"showSysFields": "Systemfelder anzeigen.", "showSysFields": "Systemfelder anzeigen",
"filterAutoApply": "Automatisch anwenden.", "filterAutoApply": "Automatisch anwenden",
"showMessage": "Diese Nachricht anzeigen.", "showMessage": "Diese Nachricht anzeigen",
"viewNotShared": "Aktuelle Ansicht wird nicht geteilt!", "viewNotShared": "Aktuelle Ansicht wird nicht geteilt!",
"showAllViews": "Alle gemeinsamen Ansichten dieser Tabelle anzeigen", "showAllViews": "Alle geteilten Ansichten dieser Tabelle anzeigen",
"collabView": "Mitarbeitern mit Bearbeitungsberechtigungen oder höher können die Ansichtskonfiguration ändern.", "collabView": "Mitarbeitern mit Bearbeitungsberechtigung oder höher können die Ansichtskonfiguration ändern",
"lockedView": "Niemand kann die Ansichtskonfiguration bearbeiten, bis er freigeschaltet ist.", "lockedView": "Niemand kann die Ansichtskonfiguration bearbeiten, bis sie freigeschaltet ist.",
"personalView": "Nur Sie können die Ansichtskonfiguration bearbeiten. Weitere persönliche Ansichten der Ankäufer sind standardmäßig ausgeblendet.", "personalView": "Nur Sie können die Ansichtskonfiguration bearbeiten. Weitere Mitarbeiter-Ansichten sind standardmäßig ausgeblendet.",
"ownerDesc": "Können Ersteller hinzufügen / entfernen. Und Full-Edit-Datenbankstrukturen und -felder.", "ownerDesc": "Kann Ersteller hinzufügen / entfernen und Datenbankstrukturen und -felder voll bearbeiten.",
"creatorDesc": "Kann Datenbankstrukturen und Werte vollständig bearbeiten.", "creatorDesc": "Kann Datenbankstrukturen und Werte vollständig bearbeiten.",
"editorDesc": "Können Datensätze bearbeiten, aber die Struktur von Datenbanken / Feldern nicht ändern.", "editorDesc": "Kann Datensätze bearbeiten, aber die Struktur von Datenbanken / Feldern nicht ändern.",
"commenterDesc": "Kann die Datensätze anzeigen und kommentieren, aber nichts bearbeiten", "commenterDesc": "Kann die Datensätze anzeigen und kommentieren, aber nichts bearbeiten",
"viewerDesc": "Kann die Datensätze anzeigen, aber nichts bearbeiten", "viewerDesc": "Kann die Einträge anzeigen, aber nichts bearbeiten",
"addUser": "Neuen Benutzer hinzufügen", "addUser": "Neuen Benutzer hinzufügen",
"staticRoleInfo": "Systemdefinierte Rollen können nicht bearbeitet werden", "staticRoleInfo": "Systemdefinierte Rollen können nicht bearbeitet werden",
"exportZip": "Exportieren Sie das Projekt Meta in ZIP-Datei und downloaden.", "exportZip": "Projekt-Meta in ZIP-Datei exportieren und downloaden",
"importZip": "Importieren Sie das Projekt Meta-ZIP-Datei und starten Sie erneut.", "importZip": "Projekt Meta-ZIP-Datei importieren und neu starten.",
"importText": "Importieren von NOCODB-Projekt, indem Sie Metadaten-ZIP-Datei hochladen", "importText": "Importieren von NOCODB-Projekt durch Hochladen von Metadaten-ZIP-Datei",
"metaNoChange": "Keine Änderung identifiziert", "metaNoChange": "Keine Änderung identifiziert",
"sqlMigration": "Schema-Migrationen werden automatisch erstellt. Erstellen Sie eine Tabelle und aktualisieren Sie diese Seite.", "sqlMigration": "Schema-Migrationen werden automatisch erstellt. Tabelle erstellen und diese Seite aktualisieren.",
"dbConnectionStatus": "Umwelt validiert.", "dbConnectionStatus": "Umgebung validiert",
"dbConnected": "Verbindung war erfolgreich", "dbConnected": "Verbindung war erfolgreich",
"notifications": { "notifications": {
"no_new": "Keine neuen Benachrichtigungen", "no_new": "Keine neuen Benachrichtigungen",
"clear": "Löschen" "clear": "Leeren"
}, },
"sponsor": { "sponsor": {
"header": "Sie können uns helfen!", "header": "Sie können uns helfen!",
"message": "Wir sind ein winziges Team, das Vollzeit, um die NOCODB-Open-Source zu erstellen. Wir glauben, dass ein Werkzeug wie NOCODB für jeden Problemlöser im Internet frei verfügbar sein sollte." "message": "Wir sind ein winziges Team, das Vollzeit arbeitet, um die NOCODB-Open-Source zu machen. Wir glauben, daß ein Werkzeug wie NOCODB für jeden Problemlöser im Internet frei verfügbar sein sollte."
}, },
"loginMsg": "Melden Sie sich bei NOCODB an", "loginMsg": "In NocoDB einloggen",
"passwordRecovery": { "passwordRecovery": {
"message_1": "Bitte geben Sie die E-Mail-Adresse an, die Sie bei der Anmeldung verwendet haben.", "message_1": "Bitte geben Sie die E-Mail-Adresse an, die Sie bei der Anmeldung verwendet haben.",
"message_2": "Wir senden Ihnen eine E-Mail mit einem Link, um Ihr Passwort zurückzusetzen.", "message_2": "Wir senden Ihnen eine E-Mail mit einem Link, um das Passwort zurückzusetzen.",
"success": "Bitte überprüfen Sie Ihre E-Mail, um das Passwort zurückzusetzen" "success": "Bitte überprüfen Sie Ihre E-Mail, um das Passwort zurückzusetzen"
}, },
"signUp": { "signUp": {
@ -427,14 +427,14 @@
"workEmail": "Geben Sie Ihre Arbeits-E-Mail ein", "workEmail": "Geben Sie Ihre Arbeits-E-Mail ein",
"enterPassword": "Geben Sie Ihr Passwort ein", "enterPassword": "Geben Sie Ihr Passwort ein",
"forgotPassword": "Passwort vergessen ?", "forgotPassword": "Passwort vergessen ?",
"dontHaveAccount": "Ich habe kein Konto?" "dontHaveAccount": "Sie haben kein Konto?"
}, },
"addView": { "addView": {
"grid": "Grid-Ansicht hinzufügen.", "grid": "Gitter-Ansicht hinzufügen",
"gallery": "Galerieansicht hinzufügen", "gallery": "Galerie-Ansicht hinzufügen",
"form": "Fügen Sie den Formularansicht hinzu", "form": "Formular-Ansicht hinzufügen",
"kanban": "Kanban-Sicht hinzufügen", "kanban": "Kanban-Ansicht hinzufügen",
"calendar": "Kalenderansicht hinzufügen" "calendar": "Kalender-Ansicht hinzufügen"
} }
}, },
"error": { "error": {
@ -447,9 +447,9 @@
"dbConnectionFailed": "Verbindungsfehler:", "dbConnectionFailed": "Verbindungsfehler:",
"signUpRules": { "signUpRules": {
"emailReqd": "E-Mail ist erforderlich", "emailReqd": "E-Mail ist erforderlich",
"emailInvalid": "Email muss gültig sein", "emailInvalid": "Email muß gültig sein",
"passwdRequired": "Passwort ist erforderlich", "passwdRequired": "Passwort ist erforderlich",
"passwdLength": "Ihr Passwort muss mindestens 8 Zeichen sein" "passwdLength": "Ihr Passwort muß mindestens 8 Zeichen haben"
} }
}, },
"toast": { "toast": {
@ -459,12 +459,12 @@
"stopProject": "Projekt wurde erfolgreich angehalten", "stopProject": "Projekt wurde erfolgreich angehalten",
"startProject": "Projekt begann erfolgreich", "startProject": "Projekt begann erfolgreich",
"restartProject": "Projekt neu gestartet", "restartProject": "Projekt neu gestartet",
"deleteProject": "Projekt erfolgreich gelöscht.", "deleteProject": "Projekt erfolgreich gelöscht",
"authToken": "Auth-Token in die Zwischenablage kopiert", "authToken": "Auth-Token in die Zwischenablage kopiert",
"projInfo": "Kopie Projektinformationen in die Zwischenablage", "projInfo": "Projektinformationen in die Zwischenablage kopiert",
"inviteUrlCopy": "Kopierte Laden Sie die URL in die Zwischenablage ein", "inviteUrlCopy": "Einladungs-URL in die Zwischenablage kopiert",
"createView": "Erfolgreich erstellt", "createView": "Ansicht erfolgreich erstellt",
"formEmailSMTP": "Bitte aktivieren Sie das SMTP-Plugin in App Store, um die E-Mail-Benachrichtigung zu aktivieren", "formEmailSMTP": "Bitte aktivieren Sie das SMTP-Plugin im App Store, um die E-Mail-Benachrichtigung zu aktivieren",
"collabView": "Erfolgreich auf die kollaborative Ansicht gewechselt", "collabView": "Erfolgreich auf die kollaborative Ansicht gewechselt",
"lockedView": "Erfolgreich auf gesperrte Ansicht gewechselt", "lockedView": "Erfolgreich auf gesperrte Ansicht gewechselt",
"futureRelease": "Kommt bald!" "futureRelease": "Kommt bald!"

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

@ -47,7 +47,7 @@
</v-toolbar-items> </v-toolbar-items>
<!-- <template v-if="!isThisMobile "> <!-- <template v-if="!isThisMobile ">
<a class="align-self-center" style="" target="_blank" href="https://calendly.com/nocodb"> <a class="align-self-center" style="" target="_blank" href="https://calendly.com/nocodb-meeting">
<x-icon size="20" tooltip="Book a free demo" color="white" icon.class="mr-3">mdi-calendar-month</x-icon> <x-icon size="20" tooltip="Book a free demo" color="white" icon.class="mr-3">mdi-calendar-month</x-icon>

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

@ -624,7 +624,7 @@
v-if="!_isZh" v-if="!_isZh"
dense dense
target="_blank" target="_blank"
href="https://calendly.com/nocodb" href="https://calendly.com/nocodb-meeting"
> >
<v-list-item-icon> <v-list-item-icon>
<v-icon <v-icon

28
packages/nc-migrator-archived/package-lock.json generated

@ -123,15 +123,23 @@
"dev": true "dev": true
}, },
"ajv": { "ajv": {
"version": "6.10.2", "version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true, "dev": true,
"requires": { "requires": {
"fast-deep-equal": "^2.0.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2" "uri-js": "^4.2.2"
},
"dependencies": {
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
}
} }
}, },
"ansi-align": { "ansi-align": {
@ -1383,12 +1391,6 @@
} }
} }
}, },
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
"dev": true
},
"fast-diff": { "fast-diff": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
@ -4233,9 +4235,9 @@
} }
}, },
"pathval": { "pathval": {
"version": "1.1.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
"dev": true "dev": true
}, },
"pg-connection-string": { "pg-connection-string": {

34
packages/noco-docs/content/en/engineering/publish.md

@ -6,10 +6,16 @@ category: "Engineering"
menuTitle: "Making a release" menuTitle: "Making a release"
--- ---
> This is exclusive to NocoDB team members only <alert>
This is exclusive to NocoDB team members only.
</alert>
<alert types='danger'>
The version 0.84.8 will be used as an example. Please change it during the release.
</alert>
## 1. Merge ```develop``` to ```master``` ## 1. Merge ```develop``` to ```master```
- When several features are included in develop branch and they are ready to be released, make a PR from `develop` branch to `master` branch. At least one NocoDB team member approval is required. - When several features are included in ``develop`` branch and they are ready to be released, make a PR with the title ``0.84.8 Pre-Release`` from `develop` branch to `master` branch. At least one NocoDB team member approval is required.
## 2. Publish frontend ## 2. Publish frontend
- Navigate to `packages/nc-gui` and execute following command. - Navigate to `packages/nc-gui` and execute following command.
@ -20,7 +26,7 @@ menuTitle: "Making a release"
- Install the latest published version of `nc-lib-gui` in `packages/nocodb`, package version can be extracted from result of step 1 or copy it from `packages/nc-lib-gui/package.json`. While installing, add `-E` to install exact version of the package. - Install the latest published version of `nc-lib-gui` in `packages/nocodb`, package version can be extracted from result of step 1 or copy it from `packages/nc-lib-gui/package.json`. While installing, add `-E` to install exact version of the package.
- Example: for latest published version `0.84.8` - Example: for latest published version `0.84.8`
```bash ```bash
npm i -E nc-lib-gui@0.84.8 npm i -E nc-lib-gui@0.84.8
``` ```
@ -31,11 +37,25 @@ menuTitle: "Making a release"
npm run obfuscate:build:publish npm run obfuscate:build:publish
``` ```
## 5. Prepare release notes ## 5. Close all issues
- Go to Issue page and close all issues with tags ``Fixed`` or ``Resolved``.
## 6. Commit release changes
- Commit those changes made by previous steps with the commit message ``chore(publish): v0.84.8``.
## 7. Prepare release notes
- Populate release note by running following github action (on `master` branch) - `Release : Draft Notes`. While running the action you have to provide 2 inputs: - Populate release note by running following github action (on `master` branch) - `Release : Draft Notes`. While running the action you have to provide 2 inputs:
- **Tag** : Provide current package version - **Tag** : Provide current package version
- **Previous Tag** : Provide previously released tag version - **Previous Tag** : Provide previously released tag version
## 6. Publish docker & release ## 8. Publish docker & release
- Publish docker image by running `Release : Docker` action in github (on `master` branch), where you have to provide the package version/tag. - Publish docker image by running `Release : Docker` action in github (on `master` branch), where you have to provide the package version/tag. It may take half an hour. Test it locally after it is done.
- Update the populated release (remove issues which is not related to release) draft and publish. In release note you can use `Auto-generate release notes` button to populate release content from commits & PR.
- Update the populated release (remove issues which is not related to release) draft and publish. In release note you can use `Auto-generate release notes` button to populate release content from commits & PR.
## 9. Sync the changes back to develop branch
- Pull the latest chagnes for both branches to your local
- Switch to ``develop`` branch
- Run ``git merge master``
- Push the diff to remote repository

65
packages/noco-docs/content/en/engineering/translation.md

@ -0,0 +1,65 @@
---
title: "i18n"
description: "Contribute to NocoDB's i18n translation"
position: 2000
category: "Engineering"
menuTitle: "i18n"
---
NocoDB supports many foreign languages & we welcome community contributions via an easy to use [google-spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172).
Your help in fixing i18n goes a long way supporting NocoDB. Please follow below simple procedure to request corrections to existing translation errors.
## How to contribute ? (for community members)
### 1. How to change a string value ?
- Make a copy of [Google spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
<img width="995" alt="Screenshot 2022-02-10 at 1 47 06 PM" src="https://user-images.githubusercontent.com/86527202/153368423-d1d898ef-bdcb-48c4-a772-b75e2c66566d.png">
- Find your language code [here](https://developers.google.com/admin-sdk/directory/v1/languages)
- Go to the column containing your language code. Make necessary changes. Origin text in ENGLISH can be found in `Column B` of master spreadsheet.
- Create a new [issue in Github](https://github.com/nocodb/nocodb/issues/new?assignees=dstala&labels=i18n+translation&template=i18n-translation-request.md&title=%5Bi18n%5D+Language+support+extension-+%3Clanguage+code%3E) request with a link to your spreadsheet from Step-1 (for us to verify & update master spreadsheet).
- NocoDB Maintainers will take changes and merge it.
- It's that simple!
### 2. How to add a new language ?
Your native language not in list, we will be glad to support with your help! Please follow below steps
- Make a copy of [Google spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
<img width="995" alt="Screenshot 2022-02-10 at 1 47 06 PM" src="https://user-images.githubusercontent.com/86527202/153368423-d1d898ef-bdcb-48c4-a772-b75e2c66566d.png">
- Find your language code [here](https://developers.google.com/admin-sdk/directory/v1/languages)
- Replace cell $AB$1 (rightmost, containing text `en`) with language code obtained above.
- Google will generate first version translation in column AB. Review. Make changes as you find appropriate for various items listed. Origin text in ENGLISH can be found in `Column B` of master spreadsheet.
- Create new [issue](https://github.com/nocodb/nocodb/issues/new?assignees=dstala&labels=i18n+translation&template=i18n-translation-request.md&title=%5Bi18n%5D+Language+support+extension-+%3Clanguage+code%3E) request with a link to your spreadsheet from Step-1 (for us to verify & update master spreadsheet).
---
## How to accept i18n contributions ? (for NocoDB maintainers)
> _This is exclusive to NocoDB maintainers only_
### 1. Adding / Updating a string
- Open master [Spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
- For the string/ text under consideration, look-up in existing sheet if it exists already
- [New string already exists] Consider re-using it; align string key if required
- [New string need to be inserted] Insert a new record into appropriate categories as defined below
- Download spreadsheet as .csv (File > Download > Comma-seperated values (.csv, current sheet)
- Use noco-i18n-from-cli to generate new language JSON file
- Copy respective i18n/\*.json files to `nocodb/packages/nc-gui/lang`
### 2. String Categories
- **General**: simple & common tokens (save, cancel, submit, open, close, home, and such)
- **Objects**: objects from NocoDB POV (project, table, field, column, view, page, and such)
- **Title**: screen headers (compact) (menu headers, modal headers)
- **Lables**: text box/ radio/ field headers (few words) (Labels over textbox, radio buttons, and such)
- **Activity**/ actions: work items (few words) (Create Project, Delete Table, Add Row, and such)
- **Tooltip**: additional information associated with work items (usually lengthy) (Additional information provided for activity)
- **Placeholder**: placeholders associated with various textboxes (Text placeholders)
- **Msg**
- Info: general/success category for everything
- Error: warnings & errors
- Toast: pop-up toast messages
> Note: string name should be in camelCase. Use above list as priority order in case of ambiguity.

6
packages/noco-i18n/package-lock.json generated

@ -5537,9 +5537,9 @@
} }
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.14.7", "version": "1.14.8",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
"dev": true "dev": true
}, },
"for-in": { "for-in": {

7
packages/nocodb/src/__tests__/rest.test.ts

@ -189,6 +189,13 @@ describe('{Auth, CRUD, HasMany, Belongs} Tests', () => {
.send({ email: EMAIL_ID, password: 'wrongPassword' }) .send({ email: EMAIL_ID, password: 'wrongPassword' })
.expect(400, done); .expect(400, done);
}); });
it('Signup with no credentials', done => {
request(app)
.post('/auth/signin')
.send({})
.expect(400, done)
})
it('Forgot password with a non-existing email id', function(done) { it('Forgot password with a non-existing email id', function(done) {
request(app) request(app)

22
packages/nocodb/src/lib/dataMapper/lib/sql/CustomKnex.ts

@ -92,9 +92,10 @@ const appendWhereCondition = function(
knexRef, knexRef,
isHaving = false isHaving = false
) { ) {
const clientType = knexRef?.client?.config?.client;
const opMapping = { const opMapping = {
...opMappingGen, ...opMappingGen,
...(knexRef?.client?.config?.client === 'pg' ? { like: 'ilike' } : {}) ...(clientType === 'pg' ? { like: 'ilike' } : {})
}; };
const camKey = isHaving ? 'Having' : 'Where'; const camKey = isHaving ? 'Having' : 'Where';
const key = isHaving ? 'having' : 'where'; const key = isHaving ? 'having' : 'where';
@ -430,11 +431,19 @@ const appendWhereCondition = function(
); );
break; break;
case '': case '':
knexRef[`${key}`]( const column = columnAliases[matches[2]] || matches[2];
columnAliases[matches[2]] || matches[2], const operator = opMapping[matches[3]];
opMapping[matches[3]], const target = matches[4];
matches[4] if (matches[3] == 'like' && clientType === 'pg') {
); // handle uuid case
knexRef[`${key}`](
knexRef?.client.raw(`??::TEXT ${operator} '${target}'`, [
column
])
);
} else {
knexRef[`${key}`](column, operator, target);
}
break; break;
default: default:
throw new Error(`${matches[1] || ''} Invalid operation.`); throw new Error(`${matches[1] || ''} Invalid operation.`);
@ -991,6 +1000,7 @@ export { Knex };
* *
* @author Naveen MR <oof1lab@gmail.com> * @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com> * @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
* *
* @license GNU AGPL version 3 or any later version * @license GNU AGPL version 3 or any later version
* *

4
packages/nocodb/src/lib/noco/NcProjectBuilder.ts

@ -696,7 +696,7 @@ export default class NcProjectBuilder {
for (const connectionConfig of dbs) { for (const connectionConfig of dbs) {
try { try {
const sqlClient = NcConnectionMgr.getSqlClient({ const sqlClient = NcConnectionMgr.getSqlClient({
dbAlias: connectionConfig?.mets?.dbAlias, dbAlias: connectionConfig?.meta?.dbAlias,
env: this.config.env, env: this.config.env,
config: this.config, config: this.config,
projectId: this.id projectId: this.id
@ -892,7 +892,7 @@ export default class NcProjectBuilder {
for (const connectionConfig of dbs) { for (const connectionConfig of dbs) {
NcConnectionMgr.delete({ NcConnectionMgr.delete({
dbAlias: connectionConfig?.mets?.dbAlias, dbAlias: connectionConfig?.meta?.dbAlias,
env: this.config.env, env: this.config.env,
projectId: this.id projectId: this.id
}); });

5
packages/nocodb/src/lib/noco/meta/NcMetaIO.ts

@ -168,11 +168,15 @@ export default abstract class NcMetaIO {
roles: string roles: string
): Promise<any>; ): Promise<any>;
// Remove user in project level
public abstract projectRemoveUser( public abstract projectRemoveUser(
projectId: string, projectId: string,
userId: any userId: any
): Promise<any>; ): Promise<any>;
// Remove user globally
public abstract removeXcUser(userId: any): Promise<any>;
public abstract projectStatusUpdate( public abstract projectStatusUpdate(
projectId: string, projectId: string,
status: string status: string
@ -235,6 +239,7 @@ export { META_TABLES };
* *
* @author Naveen MR <oof1lab@gmail.com> * @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com> * @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
* *
* @license GNU AGPL version 3 or any later version * @license GNU AGPL version 3 or any later version
* *

9
packages/nocodb/src/lib/noco/meta/NcMetaIOImpl.ts

@ -573,6 +573,14 @@ export default class NcMetaIOImpl extends NcMetaIO {
.delete(); .delete();
} }
public removeXcUser(userId: any): Promise<any> {
return this.knexConnection('xc_users')
.where({
id: userId
})
.delete();
}
get isRest(): boolean { get isRest(): boolean {
return this.config?.envs?.[this.config.workingEnv]?.db?.some( return this.config?.envs?.[this.config.workingEnv]?.db?.some(
db => db?.meta?.api?.type === 'rest' db => db?.meta?.api?.type === 'rest'
@ -616,6 +624,7 @@ export default class NcMetaIOImpl extends NcMetaIO {
* *
* @author Naveen MR <oof1lab@gmail.com> * @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com> * @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
* *
* @license GNU AGPL version 3 or any later version * @license GNU AGPL version 3 or any later version
* *

42
packages/nocodb/src/lib/noco/rest/RestAuthCtrl.ts

@ -635,7 +635,13 @@ export default class RestAuthCtrl {
try { try {
if (!user || !user.email) { if (!user || !user.email) {
if (err) { if (err) {
return res.status(400).send(err); // This exception was thrown directly before.
// In order to avoid breaking change, both "msg" and "message" are returned.
const message = err.message ?? ''
return res.status(400).send({
msg: message,
message
});
} }
if (info) { if (info) {
return res.status(400).send(info); return res.status(400).send(info);
@ -694,7 +700,13 @@ export default class RestAuthCtrl {
try { try {
if (!user || !user.email) { if (!user || !user.email) {
if (err) { if (err) {
return res.status(400).send(err); // This exception was thrown directly before.
// In order to avoid breaking change, both "msg" and "message" are returned.
const message = err.message ?? ''
return res.status(400).send({
msg: message,
message
});
} }
if (info) { if (info) {
return res.status(400).send(info); return res.status(400).send(info);
@ -753,7 +765,13 @@ export default class RestAuthCtrl {
try { try {
if (!user || !user.email) { if (!user || !user.email) {
if (err) { if (err) {
return res.status(400).send(err); // This exception was thrown directly before.
// In order to avoid breaking change, both "msg" and "message" are returned.
const message = err.message ?? ''
return res.status(400).send({
msg: message,
message
});
} }
if (info) { if (info) {
return res.status(400).send(info); return res.status(400).send(info);
@ -1355,7 +1373,7 @@ export default class RestAuthCtrl {
protected async deleteAdmin(req, res, next): Promise<any> { protected async deleteAdmin(req, res, next): Promise<any> {
try { try {
const { project_id } = req.query; const { project_id, type } = req.query;
if (req.session?.passport?.user?.id === +req.params.id) { if (req.session?.passport?.user?.id === +req.params.id) {
return next(new Error("Admin can't delete themselves!")); return next(new Error("Admin can't delete themselves!"));
@ -1372,11 +1390,16 @@ export default class RestAuthCtrl {
); );
} }
} }
if (type === 'DELETE_FROM_PROJECT') {
XcCache.del(`${req?.query?.email}___${req?.req?.project_id}`); // remove user from Project
XcCache.del(`${req?.query?.email}___${req?.req?.project_id}`);
// await this.users.where('id', req.params.id).del(); await this.xcMeta.projectRemoveUser(project_id, req.params.id);
await this.xcMeta.projectRemoveUser(project_id, req.params.id); } else if (type === 'DELETE_FROM_NOCODB') {
// remove user from NocoDB
await this.xcMeta.removeXcUser(req.params.id);
} else {
new Error('Invalid type is provided.');
}
} catch (e) { } catch (e) {
return next(e); return next(e);
} }
@ -1748,6 +1771,7 @@ export default class RestAuthCtrl {
* *
* @author Naveen MR <oof1lab@gmail.com> * @author Naveen MR <oof1lab@gmail.com>
* @author Pranav C Balan <pranavxc@gmail.com> * @author Pranav C Balan <pranavxc@gmail.com>
* @author Wing-Kam Wong <wingkwong.code@gmail.com>
* *
* @license GNU AGPL version 3 or any later version * @license GNU AGPL version 3 or any later version
* *

4
packages/nocodb/src/lib/sqlUi/MssqlUi.ts

@ -937,16 +937,14 @@ export class MssqlUi {
static getAbstractType(col): any { static getAbstractType(col): any {
switch ((col.dt || col.dt).toLowerCase()) { switch ((col.dt || col.dt).toLowerCase()) {
case 'bigint':
case 'smallint': case 'smallint':
case 'bit': case 'bit':
case 'tinyint': case 'tinyint':
case 'int': case 'int':
return 'integer'; return 'integer';
case 'bigint':
case 'binary': case 'binary':
return 'string';
case 'char': case 'char':
return 'string'; return 'string';

2
packages/nocodb/src/lib/sqlUi/MysqlUi.ts

@ -868,7 +868,6 @@ export class MysqlUi {
case 'int': case 'int':
case 'smallint': case 'smallint':
case 'mediumint': case 'mediumint':
case 'bigint':
case 'bit': case 'bit':
return 'integer'; return 'integer';
@ -922,6 +921,7 @@ export class MysqlUi {
case 'set': case 'set':
return 'set'; return 'set';
case 'bigint':
case 'geometry': case 'geometry':
case 'point': case 'point':
case 'linestring': case 'linestring':

2
packages/nocodb/src/lib/sqlUi/SqliteUi.ts

@ -694,7 +694,6 @@ export class SqliteUi {
case 'tinyint': case 'tinyint':
case 'smallint': case 'smallint':
case 'mediumint': case 'mediumint':
case 'bigint':
case 'int2': case 'int2':
case 'int8': case 'int8':
return 'integer'; return 'integer';
@ -713,6 +712,7 @@ export class SqliteUi {
case 'blob': case 'blob':
return 'blob'; return 'blob';
case 'bigint':
case 'character': case 'character':
case 'varchar': case 'varchar':
return 'string'; return 'string';

104
scripts/cypress/cypress.json

@ -1,52 +1,56 @@
{ {
"baseUrl": "http://localhost:3000/", "baseUrl": "http://localhost:3000/",
"testFiles": [ "testFiles": [
"test/restTableOps.js", "test/restTableOps.js",
"test/restViews.js", "test/restViews.js",
"test/restRoles.js", "test/restRoles.js",
"test/restMisc.js", "test/restMisc.js",
"test/xcdb-restTableOps.js", "test/xcdb-restTableOps.js",
"test/xcdb-restViews.js", "test/xcdb-restViews.js",
"test/xcdb-restRoles.js", "test/xcdb-restRoles.js",
"test/xcdb-restMisc.js", "test/xcdb-restMisc.js",
"test/gqlTableOps.js", "test/gqlTableOps.js",
"test/gqlViews.js", "test/gqlViews.js",
"test/gqlRoles.js", "test/gqlRoles.js",
"test/gqlMisc.js", "test/gqlMisc.js",
"test/xcdb-gqlTableOps.js", "test/xcdb-gqlTableOps.js",
"test/xcdb-gqlViews.js", "test/xcdb-gqlViews.js",
"test/xcdb-gqlRoles.js", "test/xcdb-gqlRoles.js",
"test/xcdb-gqlMisc.js" "test/xcdb-gqlMisc.js",
], "test/pg-restTableOps.js",
"defaultCommandTimeout": 13000, "test/pg-restViews.js",
"pageLoadTimeout": 600000, "test/pg-restRoles.js",
"viewportWidth": 1980, "test/pg-restMisc.js"
"viewportHeight": 1000, ],
"video": false, "defaultCommandTimeout": 13000,
"retries": 0, "pageLoadTimeout": 600000,
"screenshotOnRunFailure": false, "viewportWidth": 1980,
"numTestsKeptInMemory": 0, "viewportHeight": 1000,
"env": { "video": false,
"testMode": "extREST.extGQL.xcdbREST.xcdbGQL", "retries": 0,
"db": { "screenshotOnRunFailure": false,
"host": "127.0.0.1", "numTestsKeptInMemory": 0,
"user": "root", "env": {
"password": "password" "testMode": [
} { "apiType": "rest", "dbType": "xcdb" },
}, { "apiType": "graphql", "dbType": "xcdb" },
"supportedOptionsForTestModes": [ { "apiType": "rest", "dbType": "mysql" },
"extGQL", { "apiType": "graphql", "dbType": "mysql" },
"extREST", { "apiType": "rest", "dbType": "postgres" }
"xcdbREST", ],
"xcdbREST", "db": {
"can configure multiple too, seperated by a . as in extREST.extGQL" "host": "127.0.0.1",
], "user": "root",
"fixturesFolder": "scripts/cypress/fixtures", "password": "password"
"integrationFolder": "scripts/cypress/integration", },
"pluginsFile": "scripts/cypress/plugins/index.js", "screenshot": false
"screenshotsFolder": "scripts/cypress/screenshots", },
"videosFolder": "scripts/cypress/videos", "fixturesFolder": "scripts/cypress/fixtures",
"downloadsFolder": "scripts/cypress/downloads", "integrationFolder": "scripts/cypress/integration",
"supportFile": "scripts/cypress/support/index.js", "pluginsFile": "scripts/cypress/plugins/index.js",
"chromeWebSecurity": false "screenshotsFolder": "scripts/cypress/screenshots",
"videosFolder": "scripts/cypress/videos",
"downloadsFolder": "scripts/cypress/downloads",
"supportFile": "scripts/cypress/support/index.js",
"chromeWebSecurity": false
} }

17
scripts/cypress/docker-compose-pg.yml

@ -0,0 +1,17 @@
version: "2.1"
services:
pg96:
image: postgres:9.6
restart: always
environment:
POSTGRES_PASSWORD: password
ports:
- 5432:5432
volumes:
- ../../packages/nocodb/tests/pg-sakila-db:/docker-entrypoint-initdb.d
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5

64
scripts/cypress/integration/common/00_pre_configurations.js

@ -7,8 +7,6 @@ import {
staticProjects, staticProjects,
roles, roles,
isTestSuiteActive, isTestSuiteActive,
getPrimarySuite,
isSecondarySuite,
getCurrentMode, getCurrentMode,
isXcdb, isXcdb,
setProjectString, setProjectString,
@ -157,8 +155,8 @@ function prepareSqliteQuery(projId) {
return sqliteQuery; return sqliteQuery;
} }
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`Project pre-configurations`, () => { describe(`Project pre-configurations`, () => {
it("Admin SignUp", () => { it("Admin SignUp", () => {
cy.task("log", "This will be output to the terminal"); cy.task("log", "This will be output to the terminal");
@ -168,6 +166,7 @@ export const genTest = (type, xcdb) => {
const createProject = (proj) => { const createProject = (proj) => {
it(`Create ${proj.basic.name} project`, () => { it(`Create ${proj.basic.name} project`, () => {
cy.snip("ProjectPage");
// click home button // click home button
cy.get(".nc-noco-brand-icon").click(); cy.get(".nc-noco-brand-icon").click();
@ -182,7 +181,7 @@ export const genTest = (type, xcdb) => {
projectsPage.createProject(proj.basic, proj.config); projectsPage.createProject(proj.basic, proj.config);
} }
if (xcdb) { if (dbType === "xcdb") {
// store base URL- to re-visit and delete form view later // store base URL- to re-visit and delete form view later
let projId; let projId;
cy.url() cy.url()
@ -223,59 +222,24 @@ export const genTest = (type, xcdb) => {
// if (isTestSuiteActive('rest', false)) createProject(staticProjects.externalREST) // if (isTestSuiteActive('rest', false)) createProject(staticProjects.externalREST)
// if (isTestSuiteActive('graphql', false)) createProject(staticProjects.externalGQL) // if (isTestSuiteActive('graphql', false)) createProject(staticProjects.externalGQL)
if ("rest" == type) { if ("rest" === apiType) {
if (true == xcdb) { if ("xcdb" === dbType) {
createProject(staticProjects.sampleREST); createProject(staticProjects.sampleREST);
} else { } else if (dbType === "mysql") {
createProject(staticProjects.externalREST); createProject(staticProjects.externalREST);
} else if (dbType === "postgres") {
createProject(staticProjects.pgExternalREST);
} }
} else if ("graphql" == type) { } else if ("graphql" === apiType) {
if (true == xcdb) { if ("xcdb" === dbType) {
createProject(staticProjects.sampleGQL); createProject(staticProjects.sampleGQL);
} else { } else if (dbType === "mysql") {
createProject(staticProjects.externalGQL); createProject(staticProjects.externalGQL);
} else if (dbType === "postgres") {
createProject(staticProjects.pgExternalGQL);
} }
} }
}); });
// describe('Static user creations (different roles)', () => {
// beforeEach(() => {
// loginPage.signIn(roles.owner.credentials)
// projectsPage.openProject(getPrimarySuite().basic.name)
// })
// const addUser = (user) => {
// it(`RoleType: ${user.name}`, () => {
// mainPage.addNewUserToProject(user.credentials, user.name)
// })
// }
// addUser(roles.creator)
// addUser(roles.editor)
// addUser(roles.commenter)
// addUser(roles.viewer)
// })
// describe('Static users- add to other static projects', () => {
// const addUserToProject = (proj) => {
// it(`Add users to ${proj.basic.name}`, () => {
// loginPage.signIn(roles.owner.credentials)
// projectsPage.openProject(proj.basic.name)
// mainPage.addExistingUserToProject(roles.creator.credentials.username, roles.creator.name)
// mainPage.addExistingUserToProject(roles.editor.credentials.username, roles.editor.name)
// mainPage.addExistingUserToProject(roles.commenter.credentials.username, roles.commenter.name)
// mainPage.addExistingUserToProject(roles.viewer.credentials.username, roles.viewer.name)
// })
// }
// if (isSecondarySuite('rest', true)) addUserToProject(staticProjects.sampleREST)
// if (isSecondarySuite('graphql', true)) addUserToProject(staticProjects.sampleGQL)
// if (isSecondarySuite('rest', false)) addUserToProject(staticProjects.externalREST)
// if (isSecondarySuite('graphql', false)) addUserToProject(staticProjects.externalGQL)
// })
}; };
/** /**

188
scripts/cypress/integration/common/1a_table_operations.js

@ -1,99 +1,103 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${xcdb ? "Meta - " : ""}${type.toUpperCase()} api - Table`, () => { describe(`${
before(() => { dbType === "xcdb" ? "Meta - " : ""
cy.get(".mdi-close").click({ multiple: true }); }${apiType.toUpperCase()} api - Table`, () => {
}); before(() => {
cy.get(".mdi-close").click({ multiple: true });
after(() => { });
cy.get(".mdi-close").click({ multiple: true });
}); after(() => {
cy.get(".mdi-close").click({ multiple: true });
const name = "tablex"; });
// create a new random table const name = "tablex";
it("Create Table", () => {
cy.createTable(name); // create a new random table
}); it("Create Table", () => {
cy.createTable(name);
// delete newly created table });
it("Delete Table", () => {
cy.deleteTable(name); // delete newly created table
}); it("Delete Table", () => {
cy.deleteTable(name, dbType);
const getAuditCell = (row, col) => { });
return cy.get("table > tbody > tr").eq(row).find("td").eq(col);
}; const getAuditCell = (row, col) => {
return cy.get("table > tbody > tr").eq(row).find("td").eq(col);
it("Open Audit tab", () => { };
mainPage.navigationDraw(mainPage.AUDIT).click();
it("Open Audit tab", () => {
// wait for column headers to appear mainPage.navigationDraw(mainPage.AUDIT).click();
//
cy.get("thead > tr > th.caption").should("have.length", 5); cy.snip("AuditPage");
// Audit table entries // wait for column headers to appear
// [Header] Operation Type, Operation Sub Type, Description, User, Created //
// [0] TABLE, DELETED, delete table table-x, user@nocodb.com, ... cy.get("thead > tr > th.caption").should("have.length", 5);
// [1] TABLE, Created, created table table-x, user@nocodb.com, ...
// Audit table entries
getAuditCell(0, 0).contains("TABLE").should("exist"); // [Header] Operation Type, Operation Sub Type, Description, User, Created
getAuditCell(0, 1).contains("DELETED").should("exist"); // [0] TABLE, DELETED, delete table table-x, user@nocodb.com, ...
getAuditCell(0, 3).contains("user@nocodb.com").should("exist"); // [1] TABLE, Created, created table table-x, user@nocodb.com, ...
getAuditCell(1, 0).contains("TABLE").should("exist"); getAuditCell(0, 0).contains("TABLE").should("exist");
getAuditCell(1, 1).contains("CREATED").should("exist"); getAuditCell(0, 1).contains("DELETED").should("exist");
getAuditCell(1, 3).contains("user@nocodb.com").should("exist"); getAuditCell(0, 3).contains("user@nocodb.com").should("exist");
});
getAuditCell(1, 0).contains("TABLE").should("exist");
it("Table Rename operation", () => { getAuditCell(1, 1).contains("CREATED").should("exist");
cy.renameTable("City", "CityX"); getAuditCell(1, 3).contains("user@nocodb.com").should("exist");
});
// verify
// 1. Table name in project tree has changed it("Table Rename operation", () => {
cy.get(".nc-project-tree").contains("CityX").should("exist"); cy.renameTable("City", "CityX");
// 2. Table tab name has changed // verify
cy.get(`.project-tab:contains('CityX'):visible`).should("exist"); // 1. Table name in project tree has changed
cy.get(".nc-project-tree").contains("CityX").should("exist");
// 3. contents of the table are valid
mainPage // 2. Table tab name has changed
.getCell(`City`, 1) cy.get(`.project-tab:contains('CityX'):visible`).should("exist");
.contains("A Corua (La Corua)")
.should("exist"); // 3. contents of the table are valid
mainPage
cy.closeTableTab("CityX"); .getCell(`City`, 1)
.contains("A Corua (La Corua)")
// 4. verify linked contents in other table .should("exist");
// 4a. Address table, has many field
cy.openTableTab("Address", 25); cy.closeTableTab("CityX");
mainPage.getCell("City <= Address", 1).scrollIntoView(); // 4. verify linked contents in other table
mainPage // 4a. Address table, has many field
.getCell("City <= Address", 1) cy.openTableTab("Address", 25);
.find(".name")
.contains("Lethbridge") mainPage.getCell("City <= Address", 1).scrollIntoView();
.should("exist"); mainPage
cy.closeTableTab("Address"); .getCell("City <= Address", 1)
.find(".name")
// 4b. Country table, belongs to field .contains("Lethbridge")
cy.openTableTab("Country", 25); .should("exist");
cy.closeTableTab("Address");
mainPage
.getCell("Country => City", 1) // 4b. Country table, belongs to field
.find(".name") cy.openTableTab("Country", 25);
.contains("Kabul")
.should("exist"); mainPage
cy.closeTableTab("Country"); .getCell("Country => City", 1)
.find(".name")
// revert re-name operation to not impact rest of test suite .contains("Kabul")
cy.renameTable("CityX", "City"); .should("exist");
cy.closeTableTab("Country");
// revert re-name operation to not impact rest of test suite
cy.renameTable("CityX", "City");
});
}); });
});
}; };
/** /**

325
scripts/cypress/integration/common/1b_table_column_operations.js

@ -1,165 +1,176 @@
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
import { import {
isTestSuiteActive, isTestSuiteActive,
isXcdb, isXcdb,
} from "../../support/page_objects/projectConstants"; } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
function addNewRow(index, cellValue) { function addNewRow(index, cellValue) {
cy.get(".nc-add-new-row-btn:visible").should("exist"); cy.get(".nc-add-new-row-btn:visible").should("exist");
cy.get(".nc-add-new-row-btn").click({ force: true }); cy.get(".nc-add-new-row-btn").click({ force: true });
cy.get("#data-table-form-Title > input").first().type(cellValue); cy.get("#data-table-form-Title > input").first().type(cellValue);
cy.getActiveModal() cy.snipActiveModal("Modal_AddNewRow");
.find("button") cy.getActiveModal()
.contains("Save Row") .find("button")
.click({ force: true }); .contains("Save Row")
.click({ force: true });
cy.toastWait("updated successfully");
mainPage.getCell("Title", index).contains(cellValue).should("exist"); cy.toastWait("updated successfully");
} mainPage.getCell("Title", index).contains(cellValue).should("exist");
}
describe(`${type.toUpperCase()} api - Table Column`, () => {
const name = "tablex"; describe(`${apiType.toUpperCase()} api - Table Column`, () => {
const colName = "column_name_a"; const name = "tablex";
const updatedColName = "updated_column_name"; const colName = "column_name_a";
const randVal = "Test@1234.com"; const updatedColName = "updated_column_name";
const updatedRandVal = "Updated@1234.com"; const randVal = "Test@1234.com";
const updatedRandVal = "Updated@1234.com";
before(() => {
cy.createTable(name); before(() => {
cy.createTable(name);
});
// delete table
after(() => {
cy.deleteTable(name, dbType);
});
it("Create Table Column", () => {
cy.get(`.project-tab:contains(${name}):visible`).should("exist");
mainPage.addColumn(colName, name);
cy.get(`th:contains(${colName})`).should("exist");
});
// edit the newly created column
it("Edit table column - change datatype", () => {
if (!isXcdb()) {
cy.get(`th:contains(${colName}) .mdi-menu-down`)
.trigger("mouseover", { force: true })
.click({ force: true });
cy.get(".nc-column-edit").click();
// change column type and verify
cy.get(".nc-ui-dt-dropdown").click();
cy.contains("LongText").click();
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
cy.toastWait("Update table successful");
cy.get(`th[data-col="${colName}"] .mdi-text-subject`).should(
"exist"
);
cy.get(`th:contains(${colName}) .mdi-menu-down`)
.trigger("mouseover", { force: true })
.click({ force: true });
cy.get(".nc-column-edit").click();
}
});
// edit the newly created column
it("Edit table column - rename", () => {
cy.get(`th:contains(${colName}) .mdi-menu-down`)
.trigger("mouseover", { force: true })
.click({ force: true });
cy.get(".nc-column-edit").click();
// rename column and verify
cy.get(".nc-column-name-input input").clear().type(updatedColName);
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${colName})`).should("not.exist");
cy.get(`th:contains(${updatedColName})`).should("exist");
});
// delete the newly created column
it("Delete table column", () => {
cy.get(`th:contains(${updatedColName})`).should("exist");
cy.get(`th:contains(${updatedColName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
cy.get(".nc-column-delete").click();
cy.get("button:contains(Confirm)").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${updatedColName})`).should("not.exist");
});
it("Add new row", () => {
addNewRow(1, randVal);
});
it("Update row", () => {
mainPage
.getRow(1)
.find(".nc-row-expand-icon")
.click({ force: true });
cy.get("#data-table-form-Title > input")
.first()
.clear()
.type(updatedRandVal);
cy.getActiveModal()
.find("button")
.contains("Save Row")
.click({ force: true });
cy.toastWait("updated successfully");
mainPage.getCell("Title", 1).contains(randVal).should("not.exist");
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.should("exist");
});
it("Delete row", () => {
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.rightclick({ force: true });
// delete row
cy.getActiveMenu()
.find('.v-list-item:contains("Delete Row")')
.first()
.click({ force: true });
// cy.toastWait('Deleted row successfully')
cy.get("td").contains(randVal).should("not.exist");
});
it("Select all row check-box validation", () => {
// add multiple rows
addNewRow(1, "a1");
addNewRow(2, "a2");
addNewRow(3, "a3");
addNewRow(4, "a4");
addNewRow(5, "a5");
// check-box, select-all. 0 indicates table header
mainPage
.getRow(0)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
// delete selected rows
mainPage.getCell("Title", 1).rightclick({ force: true });
cy.getActiveMenu()
.contains("Delete Selected Row")
.click({ force: true });
// verify if everything is wiped off
mainPage.getCell("Title", 1).contains("a1").should("not.exist");
});
}); });
// delete table
after(() => {
cy.deleteTable(name);
});
it("Create Table Column", () => {
cy.get(`.project-tab:contains(${name}):visible`).should("exist");
mainPage.addColumn(colName, name);
cy.get(`th:contains(${colName})`).should("exist");
});
// edit the newly created column
it("Edit table column - change datatype", () => {
if (!isXcdb()) {
cy.get(`th:contains(${colName}) .mdi-menu-down`)
.trigger("mouseover", { force: true })
.click({ force: true });
cy.get(".nc-column-edit").click();
// change column type and verify
cy.get(".nc-ui-dt-dropdown").click();
cy.contains("LongText").click();
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
cy.toastWait("Update table successful");
cy.get(`th[data-col="${colName}"] .mdi-text-subject`).should("exist");
cy.get(`th:contains(${colName}) .mdi-menu-down`)
.trigger("mouseover", { force: true })
.click({ force: true });
cy.get(".nc-column-edit").click();
}
});
// edit the newly created column
it("Edit table column - rename", () => {
cy.get(`th:contains(${colName}) .mdi-menu-down`)
.trigger("mouseover", { force: true })
.click({ force: true });
cy.get(".nc-column-edit").click();
// rename column and verify
cy.get(".nc-column-name-input input").clear().type(updatedColName);
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${colName})`).should("not.exist");
cy.get(`th:contains(${updatedColName})`).should("exist");
});
// delete the newly created column
it("Delete table column", () => {
cy.get(`th:contains(${updatedColName})`).should("exist");
cy.get(`th:contains(${updatedColName}) .mdi-menu-down`)
.trigger("mouseover")
.click();
cy.get(".nc-column-delete").click();
cy.get("button:contains(Confirm)").click();
cy.toastWait("Update table successful");
cy.get(`th:contains(${updatedColName})`).should("not.exist");
});
it("Add new row", () => {
addNewRow(1, randVal);
});
it("Update row", () => {
mainPage.getRow(1).find(".nc-row-expand-icon").click({ force: true });
cy.get("#data-table-form-Title > input")
.first()
.clear()
.type(updatedRandVal);
cy.getActiveModal()
.find("button")
.contains("Save Row")
.click({ force: true });
cy.toastWait("updated successfully");
mainPage.getCell("Title", 1).contains(randVal).should("not.exist");
mainPage.getCell("Title", 1).contains(updatedRandVal).should("exist");
});
it("Delete row", () => {
mainPage
.getCell("Title", 1)
.contains(updatedRandVal)
.rightclick({ force: true });
// delete row
cy.getActiveMenu()
.find('.v-list-item:contains("Delete Row")')
.first()
.click({ force: true });
// cy.toastWait('Deleted row successfully')
cy.get("td").contains(randVal).should("not.exist");
});
it("Select all row check-box validation", () => {
// add multiple rows
addNewRow(1, "a1");
addNewRow(2, "a2");
addNewRow(3, "a3");
addNewRow(4, "a4");
addNewRow(5, "a5");
// check-box, select-all. 0 indicates table header
mainPage
.getRow(0)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
// delete selected rows
mainPage.getCell("Title", 1).rightclick({ force: true });
cy.getActiveMenu().contains("Delete Selected Row").click({ force: true });
// verify if everything is wiped off
mainPage.getCell("Title", 1).contains("a1").should("not.exist");
});
});
}; };
/** /**

297
scripts/cypress/integration/common/1c_sql_view.js

@ -1,140 +1,173 @@
import { import {
isTestSuiteActive, isTestSuiteActive,
isXcdb, isXcdb,
} from "../../support/page_objects/projectConstants"; } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} SQL Views`, () => { describe(`${apiType.toUpperCase()} SQL Views`, () => {
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {
// void // void
}); });
it(`XCDB: SQL View Column operations`, () => { it(`XCDB: SQL View Column operations`, () => {
// Open one of the views & verify validity of first two entries // Open one of the views & verify validity of first two entries
if (isXcdb()) { if (isXcdb()) {
cy.openViewsTab("CustomerList", 25); cy.openViewsTab("CustomerList", 25);
// Record-1 validation // Record-1 validation
mainPage.getCell(`ID`, 1).contains("1").should("exist"); mainPage.getCell(`ID`, 1).contains("1").should("exist");
mainPage.getCell(`Name`, 1).contains("MARY SMITH").should("exist"); mainPage
mainPage .getCell(`Name`, 1)
.getCell(`Address`, 1) .contains("MARY SMITH")
.contains("1913 Hanoi Way") .should("exist");
.should("exist"); mainPage
mainPage.getCell(`ZipCode`, 1).contains("35200").should("exist"); .getCell(`Address`, 1)
.contains("1913 Hanoi Way")
// Record-2 validation .should("exist");
mainPage.getCell(`ID`, 2).contains("2").should("exist"); mainPage
mainPage .getCell(`ZipCode`, 1)
.getCell(`Name`, 2) .contains("35200")
.contains("PATRICIA JOHNSON") .should("exist");
.should("exist");
mainPage // Record-2 validation
.getCell(`Address`, 2) mainPage.getCell(`ID`, 2).contains("2").should("exist");
.contains("1121 Loja Avenue") mainPage
.should("exist"); .getCell(`Name`, 2)
mainPage.getCell(`ZipCode`, 2).contains("17886").should("exist"); .contains("PATRICIA JOHNSON")
.should("exist");
// Column operations: Hide mainPage
mainPage.hideField(`ZipCode`); .getCell(`Address`, 2)
mainPage.unhideField(`ZipCode`); .contains("1121 Loja Avenue")
.should("exist");
// Column operations: Sort mainPage
mainPage.sortField("Name", "Z -> A"); .getCell(`ZipCode`, 2)
mainPage.getCell(`Name`, 1).contains("ZACHARY HITE").should("exist"); .contains("17886")
mainPage.clearSort(); .should("exist");
// Column operations: Filter // Column operations: Hide
mainPage.filterField("Name", "is like", "MARY"); mainPage.hideField(`ZipCode`);
mainPage.getCell(`Name`, 1).contains("MARY SMITH").should("exist"); mainPage.unhideField(`ZipCode`);
mainPage.filterReset();
// Column operations: Sort
cy.closeViewsTab("CustomerList"); mainPage.sortField("Name", "Z -> A");
} mainPage
}); .getCell(`Name`, 1)
.contains("ZACHARY HITE")
it(`SQL View Column operations`, () => { .should("exist");
if (!isXcdb()) { mainPage.clearSort();
// Open one of the views & verify validity of first two entries
// Column operations: Filter
cy.openViewsTab("ActorInfo", 25); mainPage.filterField("Name", "is like", "MARY");
mainPage
// Record-1 validation .getCell(`Name`, 1)
mainPage.getCell(`ActorId`, 1).contains("1").should("exist"); .contains("MARY SMITH")
mainPage.getCell(`FirstName`, 1).contains("PENELOPE").should("exist"); .should("exist");
mainPage.getCell(`LastName`, 1).contains("GUINESS").should("exist"); mainPage.filterReset();
mainPage
.getCell(`FilmInfo`, 1) cy.closeViewsTab("CustomerList");
.contains("Animation: ANACONDA CONFESSIONS;") }
.should("exist"); });
// Record-2 validation it(`SQL View Column operations`, () => {
mainPage.getCell(`ActorId`, 2).contains("2").should("exist"); if (!isXcdb()) {
mainPage.getCell(`FirstName`, 2).contains("NICK").should("exist"); // Open one of the views & verify validity of first two entries
mainPage.getCell(`LastName`, 2).contains("WAHLBERG").should("exist");
mainPage cy.openViewsTab("ActorInfo", 25);
.getCell(`FilmInfo`, 2)
.contains("Action: BULL SHAWSHANK; Animation: FIGHT JAWBREAKER;") // Record-1 validation
.should("exist"); mainPage.getCell(`ActorId`, 1).contains("1").should("exist");
mainPage
// Column operations: Hide .getCell(`FirstName`, 1)
mainPage.hideField("FilmInfo"); .contains("PENELOPE")
mainPage.unhideField("FilmInfo"); .should("exist");
mainPage
// Column operations: Sort .getCell(`LastName`, 1)
mainPage.sortField("FirstName", "Z -> A"); .contains("GUINESS")
mainPage.getCell(`FirstName`, 1).contains("ZERO").should("exist"); .should("exist");
mainPage.clearSort(); mainPage
.getCell(`FilmInfo`, 1)
// Column operations: Filter .contains("Animation: ANACONDA CONFESSIONS")
mainPage.filterField("FirstName", "is like", "PENELOPE"); .should("exist");
mainPage.getCell(`FirstName`, 1).contains("PENELOPE").should("exist");
mainPage.filterReset(); // Record-2 validation
mainPage.getCell(`ActorId`, 2).contains("2").should("exist");
cy.closeViewsTab("ActorInfo"); mainPage
} .getCell(`FirstName`, 2)
}); .contains("NICK")
.should("exist");
it(`SQL View List`, () => { mainPage
// confirm if other views exist .getCell(`LastName`, 2)
// .contains("WAHLBERG")
cy.openViewsTab("CustomerList", 25); .should("exist");
cy.closeViewsTab("CustomerList"); mainPage
.getCell(`FilmInfo`, 2)
cy.openViewsTab("FilmList", 25); .contains("Action: BULL SHAWSHANK")
cy.closeViewsTab("FilmList"); .should("exist");
cy.openViewsTab("SalesByFilmCategory", 16); // Column operations: Hide
cy.closeViewsTab("SalesByFilmCategory"); mainPage.hideField("FilmInfo");
mainPage.unhideField("FilmInfo");
if (!isXcdb()) {
cy.openViewsTab("NicerButSlowerFilmList", 25); // Column operations: Sort
cy.closeViewsTab("NicerButSlowerFilmList"); mainPage.sortField("FirstName", "Z -> A");
mainPage
// SalesByStore && StaffList contain no entries. Hence marking row count to 0 .getCell(`FirstName`, 1)
cy.openViewsTab("SalesByStore", 0); .contains("ZERO")
cy.closeViewsTab("SalesByStore"); .should("exist");
mainPage.clearSort();
cy.openViewsTab("StaffList", 0);
cy.closeViewsTab("StaffList"); // Column operations: Filter
} else { mainPage.filterField("FirstName", "is like", "PENELOPE");
cy.openViewsTab("SalesByStore", 2); mainPage
cy.closeViewsTab("SalesByStore"); .getCell(`FirstName`, 1)
.contains("PENELOPE")
cy.openViewsTab("StaffList", 2); .should("exist");
cy.closeViewsTab("StaffList"); mainPage.filterReset();
}
}); cy.closeViewsTab("ActorInfo");
}
after(() => { });
// void
it(`SQL View List`, () => {
// confirm if other views exist
//
cy.openViewsTab("CustomerList", 25);
cy.closeViewsTab("CustomerList");
cy.openViewsTab("FilmList", 25);
cy.closeViewsTab("FilmList");
cy.openViewsTab("SalesByFilmCategory", 16);
cy.closeViewsTab("SalesByFilmCategory");
if (!isXcdb()) {
cy.openViewsTab("NicerButSlowerFilmList", 25);
cy.closeViewsTab("NicerButSlowerFilmList");
// SalesByStore && StaffList contain no entries. Hence marking row count to 0
cy.openViewsTab("SalesByStore", 0);
cy.closeViewsTab("SalesByStore");
cy.openViewsTab("StaffList", 0);
cy.closeViewsTab("StaffList");
} else {
cy.openViewsTab("SalesByStore", 2);
cy.closeViewsTab("SalesByStore");
cy.openViewsTab("StaffList", 2);
cy.closeViewsTab("StaffList");
}
});
after(() => {
// void
});
}); });
});
}; };
/** /**

171
scripts/cypress/integration/common/1d_pg_table_view_drag_drop_reorder.js

@ -0,0 +1,171 @@
import {
isTestSuiteActive,
isXcdb,
getProjectString,
isPostgres,
} from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${apiType.toUpperCase()} Table/view drag-drop reorder`, () => {
function validateTreeField(index, tblName) {
cy.get(`:nth-child(${index}) > .v-list-item__title > .caption`)
.contains(tblName)
.should("exist");
}
/*
Original order of list items
Actor, Address, Category, City, Country, Customer, FIlm, FilmText, Language, Payment, Rental Staff
ActorInfo, CustomerList, FilmList, NiceButSlowerFilmList, SalesByFilmCategory, SalesByStore, StaffList
*/
it(`Table & SQL View list, Drag/drop`, () => {
// expand tree-view menu
// cy.get(".nc-project-tree")
// .find(".v-list-item__title:contains(Tables)", { timeout: 10000 })
// .should("exist")
// .first()
// .click({ force: true });
validateTreeField(1, "Actor");
// move Actor field down, above Staff (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Film"
);
validateTreeField(7, "Actor");
// move ActorInfo (View) field up to first place (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "ActorInfo");
validateTreeField(2, "Address");
validateTreeField(8, "Actor");
// restore ActorInfo field (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Staff"
);
// restore Actor field (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Address"
);
validateTreeField(1, "Actor");
validateTreeField(2, "Address");
if (isPostgres()) {
validateTreeField(17, "Staff");
validateTreeField(18, "ActorInfo");
validateTreeField(19, "CustomerList");
} else {
validateTreeField(12, "Staff");
validateTreeField(13, "ActorInfo");
validateTreeField(14, "CustomerList");
}
// undo project-tree expand operation
cy.get(".nc-project-tree")
.find(".v-list-item__title:contains(Tables)", {
timeout: 10000,
})
.should("exist")
.first()
.click({ force: true });
});
// create new view as specified by 'viewType'
// can be - grid/ gallery/ form
// wait for toast to appear
//
function createView(viewType) {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
cy.snipActiveModal(`Modal_createView_${viewType}`);
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}
// verify view 'viewName' to be present at position 'index'
// index starts from 0
function validateViewField(index, viewName) {
cy.get(".nc-view-item.nc-draggable-child")
.eq(index)
.contains(viewName)
.should("exist");
}
it(`View (Gallery/ Grid/ Form) re-order`, () => {
cy.openTableTab("Actor", 25);
// create 3 views, use default names
// Actor1, Actor2, Actor3
createView("grid");
createView("gallery");
createView("form");
// validate position order
validateViewField(0, "Actor");
validateViewField(1, "Actor1");
validateViewField(2, "Actor2");
validateViewField(3, "Actor3");
// move Actor3 field on top (drag, drop)
cy.get(".nc-child-draggable-icon-Actor3").drag(
`.nc-child-draggable-icon-${
isXcdb() ? `nc_${getProjectString()}__` : ``
}actor`
);
// validate new position order, Actor3 on top
validateViewField(0, "Actor3");
validateViewField(1, "Actor");
validateViewField(2, "Actor1");
validateViewField(3, "Actor2");
// delete all created views
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// wind up
cy.closeTableTab("Actor");
});
});
};
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

268
scripts/cypress/integration/common/1d_table_view_drag_drop_reorder.js

@ -1,139 +1,143 @@
import { import {
isTestSuiteActive, isTestSuiteActive,
isXcdb, isXcdb,
getProjectString, getProjectString,
} from "../../support/page_objects/projectConstants"; } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} Table/view drag-drop reorder`, () => { describe(`${apiType.toUpperCase()} Table/view drag-drop reorder`, () => {
function validateTreeField(index, tblName) { function validateTreeField(index, tblName) {
cy.get(`:nth-child(${index}) > .v-list-item__title > .caption`) cy.get(`:nth-child(${index}) > .v-list-item__title > .caption`)
.contains(tblName) .contains(tblName)
.should("exist"); .should("exist");
} }
/* /*
Original order of list items Original order of list items
Actor, Address, Category, City, Country, Customer, FIlm, FilmText, Language, Payment, Rental Staff Actor, Address, Category, City, Country, Customer, FIlm, FilmText, Language, Payment, Rental Staff
ActorInfo, CustomerList, FilmList, NiceButSlowerFilmList, SalesByFilmCategory, SalesByStore, StaffList ActorInfo, CustomerList, FilmList, NiceButSlowerFilmList, SalesByFilmCategory, SalesByStore, StaffList
*/ */
it(`Table & SQL View list, Drag/drop`, () => { it(`Table & SQL View list, Drag/drop`, () => {
// expand tree-view menu // expand tree-view menu
// cy.get(".nc-project-tree") // cy.get(".nc-project-tree")
// .find(".v-list-item__title:contains(Tables)", { timeout: 10000 }) // .find(".v-list-item__title:contains(Tables)", { timeout: 10000 })
// .should("exist") // .should("exist")
// .first() // .first()
// .click({ force: true }); // .click({ force: true });
validateTreeField(1, "Actor"); validateTreeField(1, "Actor");
// move Actor field down, above Staff (drag, drop) // move Actor field down, above Staff (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag( cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Staff" ".nc-child-draggable-icon-Staff"
); );
validateTreeField(12, "Actor"); validateTreeField(12, "Actor");
// move ActorInfo (View) field up to first place (drag, drop) // move ActorInfo (View) field up to first place (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag( cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Address" ".nc-child-draggable-icon-Address"
); );
validateTreeField(1, "ActorInfo"); validateTreeField(1, "ActorInfo");
validateTreeField(2, "Address"); validateTreeField(2, "Address");
validateTreeField(13, "Actor"); validateTreeField(13, "Actor");
// restore ActorInfo field (drag, drop) // restore ActorInfo field (drag, drop)
cy.get(".nc-child-draggable-icon-ActorInfo").drag( cy.get(".nc-child-draggable-icon-ActorInfo").drag(
".nc-child-draggable-icon-Actor" ".nc-child-draggable-icon-Actor"
); );
// restore Actor field (drag, drop) // restore Actor field (drag, drop)
cy.get(".nc-child-draggable-icon-Actor").drag( cy.get(".nc-child-draggable-icon-Actor").drag(
".nc-child-draggable-icon-Address" ".nc-child-draggable-icon-Address"
); );
validateTreeField(1, "Actor"); validateTreeField(1, "Actor");
validateTreeField(2, "Address"); validateTreeField(2, "Address");
validateTreeField(12, "Staff"); validateTreeField(12, "Staff");
validateTreeField(13, "ActorInfo"); validateTreeField(13, "ActorInfo");
validateTreeField(14, "CustomerList"); validateTreeField(14, "CustomerList");
// undo project-tree expand operation // undo project-tree expand operation
cy.get(".nc-project-tree") cy.get(".nc-project-tree")
.find(".v-list-item__title:contains(Tables)", { timeout: 10000 }) .find(".v-list-item__title:contains(Tables)", {
.should("exist") timeout: 10000,
.first() })
.click({ force: true }); .should("exist")
.first()
.click({ force: true });
});
// create new view as specified by 'viewType'
// can be - grid/ gallery/ form
// wait for toast to appear
//
function createView(viewType) {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
cy.snipActiveModal(`Modal_createView_${viewType}`);
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}
// verify view 'viewName' to be present at position 'index'
// index starts from 0
function validateViewField(index, viewName) {
cy.get(".nc-view-item.nc-draggable-child")
.eq(index)
.contains(viewName)
.should("exist");
}
it(`View (Gallery/ Grid/ Form) re-order`, () => {
cy.openTableTab("Actor", 25);
// create 3 views, use default names
// Actor1, Actor2, Actor3
createView("grid");
createView("gallery");
createView("form");
// validate position order
validateViewField(0, "Actor");
validateViewField(1, "Actor1");
validateViewField(2, "Actor2");
validateViewField(3, "Actor3");
// move Actor3 field on top (drag, drop)
cy.get(".nc-child-draggable-icon-Actor3").drag(
`.nc-child-draggable-icon-${
isXcdb() ? `nc_${getProjectString()}__` : ``
}actor`
);
// validate new position order, Actor3 on top
validateViewField(0, "Actor3");
validateViewField(1, "Actor");
validateViewField(2, "Actor1");
validateViewField(3, "Actor2");
// delete all created views
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// wind up
cy.closeTableTab("Actor");
});
}); });
// create new view as specified by 'viewType'
// can be - grid/ gallery/ form
// wait for toast to appear
//
function createView(viewType) {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}
// verify view 'viewName' to be present at position 'index'
// index starts from 0
function validateViewField(index, viewName) {
cy.get(".nc-view-item.nc-draggable-child")
.eq(index)
.contains(viewName)
.should("exist");
}
it(`View (Gallery/ Grid/ Form) re-order`, () => {
cy.openTableTab("Actor", 25);
// create 3 views, use default names
// Actor1, Actor2, Actor3
createView("grid");
createView("gallery");
createView("form");
// validate position order
validateViewField(0, "Actor");
validateViewField(1, "Actor1");
validateViewField(2, "Actor2");
validateViewField(3, "Actor3");
// move Actor3 field on top (drag, drop)
cy.get(".nc-child-draggable-icon-Actor3").drag(
`.nc-child-draggable-icon-${
isXcdb() ? `nc_${getProjectString()}__` : ``
}actor`
);
// validate new position order, Actor3 on top
validateViewField(0, "Actor3");
validateViewField(1, "Actor");
validateViewField(2, "Actor1");
validateViewField(3, "Actor2");
// delete all created views
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// wind up
cy.closeTableTab("Actor");
});
});
}; };
/** /**

321
scripts/cypress/integration/common/1e_meta_sync.js

@ -1,165 +1,174 @@
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation"; import { loginPage } from "../../support/page_objects/navigation";
import { import {
getCurrentMode, getCurrentMode,
getProjectString, getProjectString,
isTestSuiteActive, isTestSuiteActive,
isXcdb, isXcdb,
} from "../../support/page_objects/projectConstants"; } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
let projPrefix = `sakila.`; let projPrefix = `sakila.`;
let dbCmd = `queryDb`; let dbCmd = `queryDb`;
let tblDisplayPrefix = ``; let tblDisplayPrefix = ``;
describe(`${type.toUpperCase()} api - Meta Sync`, () => { describe(`${apiType.toUpperCase()} api - Meta Sync`, () => {
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {
if (isXcdb()) { if (isXcdb()) {
cy.log(getProjectString()); cy.log(getProjectString());
projPrefix = `nc_${getProjectString()}__`; projPrefix = `nc_${getProjectString()}__`;
dbCmd = `sqliteExec`; dbCmd = `sqliteExec`;
tblDisplayPrefix = `nc_${getProjectString()}__`; tblDisplayPrefix = `nc_${getProjectString()}__`;
} }
mainPage.openMetaTab(); mainPage.openMetaTab();
});
after(() => {
mainPage.closeMetaTab();
});
it(`Create table`, () => {
// Create Table
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table2 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
});
it(`Add relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Add relation (FK)
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD INDEX fk1_idx (col1 ASC) VISIBLE`
);
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD CONSTRAINT fk1 FOREIGN KEY (col1) REFERENCES ${projPrefix}table2 (id) ON DELETE NO ACTION ON UPDATE NO ACTION`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New relation added"
);
}
});
it(`Remove relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Remove relation (FK)
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP FOREIGN KEY fk1`
);
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP INDEX fk1_idx`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Relation removed"
);
}
});
it(`Add column`, () => {
// Add Column
let queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol VARCHAR(45) NULL AFTER id`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol TEXT NULL`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol)"
);
});
it(`Rename column`, () => {
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN newCol newColName VARCHAR(45) NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN newCol TO newColName`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newColName), Column removed(newCol)"
);
});
it(`Delete column`, () => {
// Remove Column
// to be fixed for SQLITE
if (!isXcdb()) {
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP COLUMN newColName`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Column removed(newColName)"
);
}
});
it(`Delete table`, () => {
// DROP TABLE
cy.task(dbCmd, `DROP TABLE ${projPrefix}table1`);
cy.task(dbCmd, `DROP TABLE ${projPrefix}table2`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Table removed"
);
});
it(`Hide, Filter, Sort`, () => {
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, col2 INT NULL, col3 INT NULL, col4 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`INSERT INTO ${projPrefix}table1 (id, col1, col2, col3, col4) VALUES (1,1,1,1,1), (2,2,2,2,2), (3,3,3,3,3), (4,4,4,4,4), (5,5,5,5,5), (6,6,6,6,6), (7,7,7,7,7), (8,8,8,8,8), (9,9,9,9,9);`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
mainPage.closeMetaTab();
cy.openTableTab("Table1", 9);
mainPage.hideField("Col1");
mainPage.sortField("Col1", "Z -> A");
mainPage.filterField(`Col1`, ">=", "5");
cy.get(".nc-grid-row").should("have.length", 5);
cy.closeTableTab("Table1");
});
it(`Verify`, () => {
mainPage.openMetaTab();
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN col1 newCol INT NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN col1 TO newCol`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol), Column removed(col1)"
);
cy.openTableTab("Table1", 9);
cy.deleteTable("Table1", dbType);
});
}); });
after(() => {
mainPage.closeMetaTab();
});
it(`Create table`, () => {
// Create Table
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table2 (id INT NOT NULL, col1 INT NULL, PRIMARY KEY (id))`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
});
it(`Add relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Add relation (FK)
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD INDEX fk1_idx (col1 ASC) VISIBLE`
);
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 ADD CONSTRAINT fk1 FOREIGN KEY (col1) REFERENCES ${projPrefix}table2 (id) ON DELETE NO ACTION ON UPDATE NO ACTION`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New relation added"
);
}
});
it(`Remove relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
if (!isXcdb()) {
// Remove relation (FK)
cy.task(dbCmd, `ALTER TABLE ${projPrefix}table1 DROP FOREIGN KEY fk1`);
cy.task(dbCmd, `ALTER TABLE ${projPrefix}table1 DROP INDEX fk1_idx`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Relation removed"
);
}
});
it(`Add column`, () => {
// Add Column
let queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol VARCHAR(45) NULL AFTER id`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 ADD COLUMN newCol TEXT NULL`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol)"
);
});
it(`Rename column`, () => {
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN newCol newColName VARCHAR(45) NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN newCol TO newColName`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newColName), Column removed(newCol)"
);
});
it(`Delete column`, () => {
// Remove Column
// to be fixed for SQLITE
if (!isXcdb()) {
cy.task(
dbCmd,
`ALTER TABLE ${projPrefix}table1 DROP COLUMN newColName`
);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Column removed(newColName)"
);
}
});
it(`Delete table`, () => {
// DROP TABLE
cy.task(dbCmd, `DROP TABLE ${projPrefix}table1`);
cy.task(dbCmd, `DROP TABLE ${projPrefix}table2`);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "Table removed");
});
it(`Hide, Filter, Sort`, () => {
cy.task(
dbCmd,
`CREATE TABLE ${projPrefix}table1 (id INT NOT NULL, col1 INT NULL, col2 INT NULL, col3 INT NULL, col4 INT NULL, PRIMARY KEY (id))`
);
cy.task(
dbCmd,
`INSERT INTO ${projPrefix}table1 (id, col1, col2, col3, col4) VALUES (1,1,1,1,1), (2,2,2,2,2), (3,3,3,3,3), (4,4,4,4,4), (5,5,5,5,5), (6,6,6,6,6), (7,7,7,7,7), (8,8,8,8,8), (9,9,9,9,9);`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
mainPage.closeMetaTab();
cy.openTableTab("Table1", 9);
mainPage.hideField("Col1");
mainPage.sortField("Col1", "Z -> A");
mainPage.filterField(`Col1`, ">=", "5");
cy.get(".nc-grid-row").should("have.length", 5);
cy.closeTableTab("Table1");
});
it(`Verify`, () => {
mainPage.openMetaTab();
// Rename Column
let queryString = `ALTER TABLE ${projPrefix}table1 CHANGE COLUMN col1 newCol INT NULL DEFAULT NULL`;
if (isXcdb())
queryString = `ALTER TABLE ${projPrefix}table1 RENAME COLUMN col1 TO newCol`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newCol), Column removed(col1)"
);
cy.openTableTab("Table1", 9);
cy.deleteTable("Table1");
});
});
}; };
/** /**

202
scripts/cypress/integration/common/1e_pg_meta_sync.js

@ -0,0 +1,202 @@
import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation";
import {
getCurrentMode,
getProjectString,
isTestSuiteActive,
isXcdb,
} from "../../support/page_objects/projectConstants";
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
let projPrefix = `sakila.`;
let dbCmd = `pgExec`;
let tblDisplayPrefix = ``;
describe(`${apiType.toUpperCase()} api - Meta Sync`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
mainPage.openMetaTab();
});
after(() => {
mainPage.closeMetaTab();
});
it(`Create table`, () => {
cy.log("this works");
// Create Table
cy.task(
dbCmd,
`CREATE TABLE table1( id INT NOT NULL, col1 INT NOT NULL, PRIMARY KEY(id))`
);
cy.task(
dbCmd,
`CREATE TABLE table2( id INT NOT NULL, col1 INT NOT NULL, PRIMARY KEY(id))`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
});
it(`Add relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
// Add relation (FK)
cy.task(
dbCmd,
`ALTER TABLE table1 ADD CONSTRAINT fk_idx FOREIGN KEY (id) REFERENCES table2 (id);`
);
// cy.task(
// dbCmd,
// `ALTER TABLE ${projPrefix}table1 ADD CONSTRAINT fk1 FOREIGN KEY (col1) REFERENCES ${projPrefix}table2 (id) ON DELETE NO ACTION ON UPDATE NO ACTION`
// );
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New relation added"
);
});
it(`Remove relation`, () => {
// working with relations in sqlite requires table to be deleted & recreated
//
// Remove relation (FK)
cy.task(dbCmd, `ALTER TABLE table1 DROP CONSTRAINT fk_idx`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Relation removed"
);
});
it(`Add column`, () => {
// Add Column
let queryString = `ALTER TABLE table1 ADD COLUMN newCol INT`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newcol)"
);
});
it(`Rename column`, () => {
// Rename Column
let queryString = `ALTER TABLE table1 RENAME COLUMN newCol TO newColName`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newcolname), Column removed(newcol)"
);
});
it(`Delete column`, () => {
// Remove Column
cy.task(dbCmd, `ALTER TABLE table1 DROP COLUMN newColName`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Column removed(newcolname)"
);
});
it(`Delete table`, () => {
// DROP TABLE
cy.task(dbCmd, `DROP TABLE IF EXISTS table1`);
cy.task(dbCmd, `DROP TABLE IF EXISTS table2`);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"Table removed"
);
});
it(`Hide, Filter, Sort`, () => {
// kludge: bulk insert fail.
cy.task(
dbCmd,
`CREATE TABLE table1( id INT NOT NULL, col1 INT NOT NULL, col2 INT NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL, PRIMARY KEY(id))`
);
cy.wait(3000);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (1,1,1,1,1)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (2,2,2,2,2)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (3,3,3,3,3)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (4,4,4,4,4)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (5,5,5,5,5)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (6,6,6,6,6)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (7,7,7,7,7)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (8,8,8,8,8)`
);
cy.task(
dbCmd,
`INSERT INTO table1 (id, col1, col2, col3, col4) VALUES (9,9,9,9,9)`
);
mainPage.metaSyncValidate(`${tblDisplayPrefix}table1`, "New table");
mainPage.closeMetaTab();
cy.openTableTab("Table1", 9);
mainPage.hideField("Col1");
mainPage.sortField("Col1", "Z -> A");
mainPage.filterField(`Col1`, ">=", "5");
cy.get(".nc-grid-row").should("have.length", 5);
cy.closeTableTab("Table1");
});
it(`Verify`, () => {
mainPage.openMetaTab();
// Rename Column
let queryString = `ALTER TABLE table1 RENAME COLUMN col1 TO newcol`;
cy.task(dbCmd, queryString);
mainPage.metaSyncValidate(
`${tblDisplayPrefix}table1`,
"New column(newcol), Column removed(col1)"
);
cy.openTableTab("Table1", 9);
// kludge- delete table triggered post sql backend operations doesnt carry any trigger toast
cy.deleteTable("Table1", "mysql");
});
});
};
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

106
scripts/cypress/integration/common/2a_table_with_belongs_to_colulmn.js

@ -1,60 +1,72 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Table: belongs to, link record`, () => { describe(`${apiType.toUpperCase()} api - Table: belongs to, link record`, () => {
before(() => { before(() => {
cy.openTableTab("Country", 25); cy.openTableTab("Country", 25);
}); });
after(() => { after(() => {
cy.closeTableTab("Country"); cy.closeTableTab("Country");
}); });
it("Table column header, URL validation", () => { it("Table column header, URL validation", () => {
// column name validation // column name validation
cy.get(`.project-tab:contains(Country):visible`).should("exist"); cy.get(`.project-tab:contains(Country):visible`).should("exist");
// URL validation // URL validation
cy.url().should("contain", `name=Country`); cy.url().should("contain", `name=Country`);
}); });
it("Expand belongs-to column", () => { it("Expand belongs-to column", () => {
// expand first row // expand first row
cy.get('td[data-col="Country => City"] div:visible', { timeout: 12000 }) cy.get('td[data-col="Country => City"] div:visible', {
.first() timeout: 12000,
.click(); })
cy.get('td[data-col="Country => City"] div .mdi-arrow-expand:visible') .first()
.first() .click();
.click(); cy.get(
}); 'td[data-col="Country => City"] div .mdi-arrow-expand:visible'
)
.first()
.click();
cy.snipActiveModal("Modal_BelongsTo");
});
it("Expand Link record, validate", () => {
cy.getActiveModal()
.find("button:contains(Link to 'City')")
.click()
.then(() => {
cy.snipActiveModal("Modal_BT_LinkRecord");
it("Expand Link record, validate", () => { // Link record form validation
cy.getActiveModal() cy.getActiveModal().contains("Link Record").should("exist");
.find("button:contains(Link to 'City')") cy.getActiveModal()
.click() .find("button.mdi-reload")
.then(() => { .should("exist");
// Link record form validation cy.getActiveModal()
cy.getActiveModal().contains("Link Record").should("exist"); .find('button:contains("New Record")')
cy.getActiveModal().find("button.mdi-reload").should("exist"); .should("exist");
cy.getActiveModal() cy.getActiveModal()
.find('button:contains("New Record")') .find(".child-card")
.should("exist"); .eq(0)
cy.getActiveModal() .contains("A Corua (La Corua)")
.find(".child-card") .should("exist");
.eq(0)
.contains("A Corua (La Corua)")
.should("exist");
cy.getActiveModal() cy.getActiveModal()
.find("button.mdi-close") .find("button.mdi-close")
.click() .click()
.then(() => { .then(() => {
cy.getActiveModal().find("button.mdi-close").click(); cy.getActiveModal()
}); .find("button.mdi-close")
.click();
});
});
}); });
}); });
});
}; };
/** /**

153
scripts/cypress/integration/common/2b_table_with_m2m_column.js

@ -1,88 +1,97 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - M2M Column validation`, () => { describe(`${apiType.toUpperCase()} api - M2M Column validation`, () => {
before(() => { before(() => {
cy.openTableTab("Actor", 25); cy.openTableTab("Actor", 25);
}); });
after(() => { after(() => {
cy.closeTableTab("Actor"); cy.closeTableTab("Actor");
}); });
it("Table column header, URL validation", () => { it("Table column header, URL validation", () => {
// column name validation // column name validation
cy.get(`.project-tab:contains(Actor):visible`).should("exist"); cy.get(`.project-tab:contains(Actor):visible`).should("exist");
// URL validation // URL validation
cy.url().should("contain", `name=Actor`); cy.url().should("contain", `name=Actor`);
}); });
it("Expand m2m column", () => { it("Expand m2m column", () => {
// expand first row // expand first row
cy.get('td[data-col="Actor <=> Film"] div', { timeout: 12000 }) cy.get('td[data-col="Actor <=> Film"] div', { timeout: 12000 })
.first() .first()
.click({ force: true }); .click({ force: true });
cy.get('td[data-col="Actor <=> Film"] div .mdi-arrow-expand') cy.get('td[data-col="Actor <=> Film"] div .mdi-arrow-expand')
.first() .first()
.click({ force: true }); .click({ force: true });
// validations cy.snipActiveModal("Modal_ManyToMany");
cy.getActiveModal().contains("Film").should("exist");
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find("button:contains(Link to 'Film')")
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACADEMY DINOSAUR")
.should("exist");
});
it('Expand "Link to" record, validate', () => { // validations
cy.getActiveModal() cy.getActiveModal().contains("Film").should("exist");
.find("button:contains(Link to 'Film')") cy.getActiveModal().find("button.mdi-reload").should("exist");
.click() cy.getActiveModal()
.then(() => { .find("button:contains(Link to 'Film')")
// Link record form validation .should("exist");
cy.getActiveModal().contains("Link Record").should("exist"); cy.getActiveModal()
cy.getActiveModal().find("button.mdi-reload").should("exist"); .find(".child-card")
cy.getActiveModal() .eq(0)
.find('button:contains("New Record")') .contains("ACADEMY DINOSAUR")
.should("exist"); .should("exist");
cy.getActiveModal() });
.find(".child-card")
.eq(0) it('Expand "Link to" record, validate', () => {
.contains("ACE GOLDFINGER") cy.getActiveModal()
.should("exist"); .find("button:contains(Link to 'Film')")
cy.get("body").type("{esc}"); .click()
.then(() => {
cy.snipActiveModal("Modal_M2M_LinkToRecord");
// Link record form validation
cy.getActiveModal().contains("Link Record").should("exist");
cy.getActiveModal()
.find("button.mdi-reload")
.should("exist");
cy.getActiveModal()
.find('button:contains("New Record")')
.should("exist");
cy.getActiveModal()
.find(".child-card")
.eq(0)
.contains("ACE GOLDFINGER")
.should("exist");
cy.get("body").type("{esc}");
});
}); });
});
it("Expand first linked card, validate", () => { it("Expand first linked card, validate", () => {
cy.getActiveModal() cy.getActiveModal()
.find(".child-card") .find(".child-card")
.eq(0) .eq(0)
.contains("ACADEMY DINOSAUR", { timeout: 2000 }) .contains("ACADEMY DINOSAUR", { timeout: 2000 })
.click() .click()
.then(() => { .then(() => {
// Link card validation // Link card validation
cy.getActiveModal() cy.getActiveModal()
.find("h5") .find("h5")
.contains("ACADEMY DINOSAUR") .contains("ACADEMY DINOSAUR")
.should("exist"); .should("exist");
cy.getActiveModal() cy.getActiveModal()
.find('button:contains("Save Row")') .find('button:contains("Save Row")')
.should("exist"); .should("exist");
cy.getActiveModal().find('button:contains("Cancel")').should("exist"); cy.getActiveModal()
.find('button:contains("Cancel")')
.should("exist");
cy.getActiveModal().find('button:contains("Cancel")').click(); cy.getActiveModal()
cy.getActiveModal().find("button.mdi-close").click(); .find('button:contains("Cancel")')
.click();
cy.getActiveModal().find("button.mdi-close").click();
});
}); });
}); });
});
}; };
/** /**

421
scripts/cypress/integration/common/3a_filter_sort_fields_operations.js

@ -1,213 +1,222 @@
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Filter, Fields, Sort`, () => { describe(`${apiType.toUpperCase()} api - Filter, Fields, Sort`, () => {
before(() => { before(() => {
// open country table // open country table
cy.openTableTab("Country", 25); cy.openTableTab("Country", 25);
}); });
after(() => { after(() => {
cy.closeTableTab("Country"); cy.closeTableTab("Country");
}); });
describe(`Pagination`, () => { describe(`Pagination`, () => {
// check pagination // check pagination
it("Check country table - Pagination", () => { it("Check country table - Pagination", () => {
cy.get(".nc-pagination").should("exist"); cy.get(".nc-pagination").should("exist");
// verify > pagination option // verify > pagination option
mainPage.getPagination(">").click(); mainPage.getPagination(">").click();
mainPage mainPage
.getPagination(2) .getPagination(2)
.should("have.class", "v-pagination__item--active"); .should("have.class", "v-pagination__item--active");
// verify < pagination option // verify < pagination option
mainPage.getPagination("<").click(); mainPage.getPagination("<").click();
mainPage mainPage
.getPagination(1) .getPagination(1)
.should("have.class", "v-pagination__item--active"); .should("have.class", "v-pagination__item--active");
}); });
}); });
describe(`Row operations`, () => { describe(`Row operations`, () => {
// create new row using + button in header // create new row using + button in header
// //
it("Add row using tool header button", () => { it("Add row using tool header button", () => {
// add a row to end of Country table // add a row to end of Country table
cy.get(".nc-add-new-row-btn").click(); cy.get(".nc-add-new-row-btn").click();
cy.get("#data-table-form-Country > input").first().type("Test Country"); cy.get("#data-table-form-Country > input")
cy.contains("Save Row").filter("button").click(); .first()
.type("Test Country");
cy.toastWait("updated successfully"); cy.contains("Save Row").filter("button").click();
// verify cy.toastWait("updated successfully");
mainPage.getPagination(5).click();
mainPage // verify
.getCell("Country", 10) mainPage.getPagination(5).click();
.contains("Test Country") mainPage
.should("exist"); .getCell("Country", 10)
}); .contains("Test Country")
.should("exist");
// delete slingle row });
//
it("Delete row", () => { // delete slingle row
// delete row added in previous step //
mainPage.getCell("Country", 10).rightclick(); it("Delete row", () => {
cy.getActiveMenu().contains("Delete Row").click(); // delete row added in previous step
mainPage.getCell("Country", 10).rightclick();
// cy.toastWait('Deleted row successfully') cy.getActiveMenu().contains("Delete Row").click();
// verify // cy.toastWait('Deleted row successfully')
mainPage.getCell("Country", 10).should("not.exist");
}); // verify
mainPage.getCell("Country", 10).should("not.exist");
// create new row using right click menu option });
//
it("Add row using rightclick menu option", () => { // create new row using right click menu option
mainPage.getCell("Country", 9).rightclick({ force: true }); //
cy.getActiveMenu().contains("Insert New Row").click({ force: true }); it("Add row using rightclick menu option", () => {
mainPage mainPage.getCell("Country", 9).rightclick({ force: true });
.getCell("Country", 10)
.dblclick() cy.snipActiveMenu("Menu_GridRightClick");
.find("input")
.type("Test Country-1{enter}"); cy.getActiveMenu()
.contains("Insert New Row")
// cy.toastWait('saved successfully') .click({ force: true });
mainPage
mainPage.getCell("Country", 10).rightclick({ force: true }); .getCell("Country", 10)
cy.getActiveMenu().contains("Insert New Row").click({ force: true }); .dblclick()
mainPage .find("input")
.getCell("Country", 11) .type("Test Country-1{enter}");
.dblclick()
.find("input") // cy.toastWait('saved successfully')
.type("Test Country-2{enter}");
mainPage.getCell("Country", 10).rightclick({ force: true });
// cy.toastWait('saved successfully') cy.getActiveMenu()
.contains("Insert New Row")
// verify .click({ force: true });
mainPage mainPage
.getCell("Country", 10) .getCell("Country", 11)
.contains("Test Country-1") .dblclick()
.should("exist"); .find("input")
mainPage .type("Test Country-2{enter}");
.getCell("Country", 11)
.contains("Test Country-2") // cy.toastWait('saved successfully')
.should("exist");
}); // verify
mainPage
// delete selected rows (multiple) .getCell("Country", 10)
// .contains("Test Country-1")
it("Delete Selected", () => { .should("exist");
mainPage mainPage
.getRow(10) .getCell("Country", 11)
.find(".mdi-checkbox-blank-outline") .contains("Test Country-2")
.click({ force: true }); .should("exist");
mainPage });
.getRow(11)
.find(".mdi-checkbox-blank-outline") // delete selected rows (multiple)
.click({ force: true }); //
it("Delete Selected", () => {
mainPage.getCell("Country", 10).rightclick({ force: true }); mainPage
cy.getActiveMenu() .getRow(10)
.contains("Delete Selected Row") .find(".mdi-checkbox-blank-outline")
.click({ force: true }); .click({ force: true });
mainPage
// cy.toastWait('Deleted 2 selected rows successfully') .getRow(11)
.find(".mdi-checkbox-blank-outline")
// verify .click({ force: true });
mainPage.getCell("Country", 10).should("not.exist");
mainPage.getCell("Country", 11).should("not.exist"); mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu()
mainPage.getPagination(1).click(); .contains("Delete Selected Row")
}); .click({ force: true });
});
// cy.toastWait('Deleted 2 selected rows successfully')
describe(`Sort operations`, () => {
it("Enable sort", () => { // verify
mainPage.sortField('Country', "Z -> A") mainPage.getCell("Country", 10).should("not.exist");
mainPage.getCell("Country", 11).should("not.exist");
// Sort menu operations (Country Column, Z->A)
// cy.get(".nc-sort-menu-btn").click(); mainPage.getPagination(1).click();
// cy.contains("Add Sort Option").click(); });
// cy.get(".nc-sort-field-select div").first().click(); });
// cy.get(
// ".menuable__content__active .v-list-item:contains(Country)" describe(`Sort operations`, () => {
// ).click(); it("Enable sort", () => {
// cy.get(".nc-sort-dir-select div").first().click(); mainPage.sortField("Country", "Z -> A");
// cy.get(
// '.menuable__content__active .v-list-item:contains("Z -> A")' // Sort menu operations (Country Column, Z->A)
// ).click(); // cy.get(".nc-sort-menu-btn").click();
// cy.contains("Add Sort Option").click();
cy.contains("Zambia").should("exist"); // cy.get(".nc-sort-field-select div").first().click();
}); // cy.get(
// ".menuable__content__active .v-list-item:contains(Country)"
it("Disable sort", () => { // ).click();
// remove sort and validate // cy.get(".nc-sort-dir-select div").first().click();
// cy.get(".nc-sort-item-remove-btn").click(); // cy.get(
mainPage.clearSort(); // '.menuable__content__active .v-list-item:contains("Z -> A")'
cy.contains("Zambia").should("not.exist"); // ).click();
});
}); cy.contains("Zambia").should("exist");
});
describe("Field Operation", () => {
it("Hide field", () => { it("Disable sort", () => {
cy.get("th:contains(LastUpdate)").should("be.visible"); // remove sort and validate
// cy.get(".nc-sort-item-remove-btn").click();
// toggle and confirm it's hidden mainPage.clearSort();
// cy.get(".nc-fields-menu-btn").click(); cy.contains("Zambia").should("not.exist");
// cy.get( });
// ".menuable__content__active .v-list-item label:contains(LastUpdate)" });
// ).click();
// cy.get(".nc-fields-menu-btn").click(); describe("Field Operation", () => {
mainPage.hideField('LastUpdate') it("Hide field", () => {
cy.get("th:contains(LastUpdate)").should("not.be.visible"); cy.get("th:contains(LastUpdate)").should("be.visible");
});
// toggle and confirm it's hidden
it("Show field", () => { // cy.get(".nc-fields-menu-btn").click();
// cy.get(".nc-fields-menu-btn").click(); // cy.get(
// cy.get( // ".menuable__content__active .v-list-item label:contains(LastUpdate)"
// ".menuable__content__active .v-list-item label:contains(LastUpdate)" // ).click();
// ).click(); // cy.get(".nc-fields-menu-btn").click();
// cy.get(".nc-fields-menu-btn").click(); mainPage.hideField("LastUpdate");
mainPage.unhideField('LastUpdate') cy.get("th:contains(LastUpdate)").should("not.be.visible");
cy.get("th:contains(LastUpdate)").should("be.visible"); });
});
}); it("Show field", () => {
// cy.get(".nc-fields-menu-btn").click();
describe("Filter operations", () => { // cy.get(
it("Create Filter", () => { // ".menuable__content__active .v-list-item label:contains(LastUpdate)"
mainPage.filterField('Country', 'is equal', 'India'); // ).click();
cy.get("td:contains(India)").should("exist"); // cy.get(".nc-fields-menu-btn").click();
mainPage.unhideField("LastUpdate");
// cy.get(".nc-filter-menu-btn").click(); cy.get("th:contains(LastUpdate)").should("be.visible");
// cy.contains("Add Filter").click(); });
});
// cy.get(".nc-filter-field-select").last().click();
// cy.getActiveMenu().find(".v-list-item:contains(Country)").click(); describe("Filter operations", () => {
// cy.get(".nc-filter-operation-select").last().click(); it("Create Filter", () => {
// cy.getActiveMenu().find('.v-list-item:contains("is equal")').click(); mainPage.filterField("Country", "is equal", "India");
// cy.get(".nc-filter-value-select input:text").last().type("India"); cy.get("td:contains(India)").should("exist");
// cy.get(".nc-filter-menu-btn")
// .click() // cy.get(".nc-filter-menu-btn").click();
// .then(() => { // cy.contains("Add Filter").click();
// cy.get("td:contains(India)").should("exist");
// }); // cy.get(".nc-filter-field-select").last().click();
}); // cy.getActiveMenu().find(".v-list-item:contains(Country)").click();
// cy.get(".nc-filter-operation-select").last().click();
it("Delete Filter", () => { // cy.getActiveMenu().find('.v-list-item:contains("is equal")').click();
// remove sort and check // cy.get(".nc-filter-value-select input:text").last().type("India");
mainPage.filterReset(); // cy.get(".nc-filter-menu-btn")
// cy.get(".nc-filter-menu-btn").click(); // .click()
// cy.get(".nc-filter-item-remove-btn").click(); // .then(() => {
// cy.get(".nc-filter-menu-btn").click(); // cy.get("td:contains(India)").should("exist");
cy.contains("td:contains(India)").should("not.exist"); // });
}); });
it("Delete Filter", () => {
// remove sort and check
mainPage.filterReset();
// cy.get(".nc-filter-menu-btn").click();
// cy.get(".nc-filter-item-remove-btn").click();
// cy.get(".nc-filter-menu-btn").click();
cy.contains("td:contains(India)").should("not.exist");
});
});
}); });
});
}; };
/** /**

440
scripts/cypress/integration/common/3b_formula_column.js

@ -1,221 +1,233 @@
import { import {
isTestSuiteActive, isTestSuiteActive,
isXcdb, isXcdb,
} from "../../support/page_objects/projectConstants"; } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - FORMULA`, () => { describe(`${apiType.toUpperCase()} api - FORMULA`, () => {
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {
// open a table to work on views // open a table to work on views
// //
cy.openTableTab("City", 25); cy.openTableTab("City", 25);
}); });
after(() => { after(() => {
cy.closeTableTab("City"); cy.closeTableTab("City");
}); });
// Given rowname & expected result for first 10 entries, validate // Given rowname & expected result for first 10 entries, validate
// NOTE: Scroll issue with Cypress automation, to fix // NOTE: Scroll issue with Cypress automation, to fix
// validating partial data, row number 5 to 9 // validating partial data, row number 5 to 9
// //
const rowValidation = (rowName, result) => { const rowValidation = (rowName, result) => {
// scroll back // scroll back
cy.get(`tbody > :nth-child(1) > [data-col="City"]`).scrollIntoView(); cy.get(
`tbody > :nth-child(1) > [data-col="City"]`
// for (let i = 0; i < 10; i++) ).scrollIntoView();
for (let i = 3; i < 6; i++)
cy.get(`tbody > :nth-child(${i + 1}) > [data-col="${rowName}"]`) // for (let i = 0; i < 10; i++)
.contains(result[i].toString()) for (let i = 3; i < 6; i++)
.should("exist"); cy.get(`tbody > :nth-child(${i + 1}) > [data-col="${rowName}"]`)
}; .contains(result[i].toString())
.should("exist");
// Routine to create a new look up column };
//
const addFormulaBasedColumn = (columnName, formula) => { // Routine to create a new look up column
// (+) icon at end of column header (to add a new column) //
// opens up a pop up window const addFormulaBasedColumn = (columnName, formula) => {
// // (+) icon at end of column header (to add a new column)
cy.get(".new-column-header").click(); // opens up a pop up window
//
// Column name cy.get(".new-column-header").click();
cy.get(".nc-column-name-input input")
.clear() // Column name
.type(`${columnName}`); cy.get(".nc-column-name-input input").clear().type(`${columnName}`);
// Column data type: to be set to formula in this context // Column data type: to be set to formula in this context
cy.get(".nc-ui-dt-dropdown").click().type("Formula"); cy.get(".nc-ui-dt-dropdown").click().type("Formula");
cy.getActiveMenu().contains("Formula").click({ force: true });
cy.snipActiveMenu("Formula");
// Configure formula
cy.get("label").contains("Formula").parent().click().type(formula).click(); cy.getActiveMenu().contains("Formula").click({ force: true });
// click on Save // Configure formula
cy.get(".nc-col-create-or-edit-card").contains("Save").click({ force: true }); cy.get("label")
.contains("Formula")
cy.toastWait("Formula column saved successfully"); .parent()
.click()
// Verify if column exists. .type(formula)
// .click();
cy.get(`th:contains(${columnName})`).should("exist");
}; // click on Save
cy.get(".nc-col-create-or-edit-card")
// routine to delete column .contains("Save")
// .click({ force: true });
const deleteColumnByName = (columnName) => {
// verify if column exists before delete cy.toastWait("Formula column saved successfully");
cy.get(`th:contains(${columnName})`).should("exist");
// Verify if column exists.
// delete opiton visible on mouse-over //
cy.get(`th:contains(${columnName}) .mdi-menu-down`) cy.get(`th:contains(${columnName})`).should("exist");
.trigger("mouseover") };
.click();
// routine to delete column
// delete/ confirm on pop-up //
cy.get(".nc-column-delete").click(); const deleteColumnByName = (columnName) => {
cy.getActiveModal().find("button:contains(Confirm)").click(); // verify if column exists before delete
cy.get(`th:contains(${columnName})`).should("exist");
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${columnName})`).should("not.exist"); // delete opiton visible on mouse-over
}; cy.get(`th:contains(${columnName}) .mdi-menu-down`)
.trigger("mouseover")
// routine to edit column .click();
//
const editColumnByName = (oldName, newName, newFormula) => { // delete/ confirm on pop-up
// verify if column exists before delete cy.get(".nc-column-delete").click();
cy.get(`th:contains(${oldName})`).should("exist"); cy.getActiveModal().find("button:contains(Confirm)").click();
// delete opiton visible on mouse-over // validate if deleted (column shouldnt exist)
cy.get(`th:contains(${oldName}) .mdi-menu-down`) cy.get(`th:contains(${columnName})`).should("not.exist");
.trigger("mouseover") };
.click();
// routine to edit column
// edit/ save on pop-up //
cy.get(".nc-column-edit").click(); const editColumnByName = (oldName, newName, newFormula) => {
cy.get(".nc-column-name-input input").clear().type(newName); // verify if column exists before delete
cy.get(`th:contains(${oldName})`).should("exist");
cy.get("label")
.contains("Formula") // delete opiton visible on mouse-over
.parent() cy.get(`th:contains(${oldName}) .mdi-menu-down`)
.find("input") .trigger("mouseover")
.clear() .click();
.type(newFormula)
.click(); // edit/ save on pop-up
cy.get(".nc-column-edit").click();
cy.get(".nc-col-create-or-edit-card").contains("Save").click({force: true}); cy.get(".nc-column-name-input input").clear().type(newName);
cy.toastWait("Formula column updated successfully"); cy.get("label")
.contains("Formula")
// validate if deleted (column shouldnt exist) .parent()
cy.get(`th:contains(${oldName})`).should("not.exist"); .find("input")
cy.get(`th:contains(${newName})`).should("exist"); .clear()
}; .type(newFormula)
.click();
///////////////////////////////////////////////////
// Test case cy.get(".nc-col-create-or-edit-card")
.contains("Save")
// On City table (from Sakila DB), first 10 entries recorded here for verification .click({ force: true });
let cityId = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let countryId = [87, 82, 101, 60, 97, 31, 107, 44, 44, 50]; cy.toastWait("Formula column updated successfully");
let city = [
"A corua (La Corua)", // validate if deleted (column shouldnt exist)
"Abha", cy.get(`th:contains(${oldName})`).should("not.exist");
"Abu Dhabi", cy.get(`th:contains(${newName})`).should("exist");
"Acua", };
"Adana",
"Addis Abeba", ///////////////////////////////////////////////////
"Aden", // Test case
"Adoni",
"Ahmadnagar", // On City table (from Sakila DB), first 10 entries recorded here for verification
"Akishima", let cityId = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
]; let countryId = [87, 82, 101, 60, 97, 31, 107, 44, 44, 50];
let city = [
// Temporary locally computed expected results "A corua (La Corua)",
let RESULT_STRING = []; "Abha",
let RESULT_MATH_0 = []; "Abu Dhabi",
let RESULT_MATH_1 = []; "Acua",
let RESULT_MATH_2 = []; "Adana",
"Addis Abeba",
for (let i = 0; i < 10; i++) { "Aden",
// CONCAT, LOWER, UPPER, TRIM "Adoni",
RESULT_STRING[i] = `${city[i].toUpperCase()}${city[ "Ahmadnagar",
i "Akishima",
].toLowerCase()}trimmed`; ];
// ADD, AVG, LEN // Temporary locally computed expected results
RESULT_MATH_0[i] = let RESULT_STRING = [];
cityId[i] + let RESULT_MATH_0 = [];
countryId[i] + let RESULT_MATH_1 = [];
(cityId[i] + countryId[i]) / 2 + let RESULT_MATH_2 = [];
city[i].length;
for (let i = 0; i < 10; i++) {
// CEILING, FLOOR, ROUND, MOD, MIN, MAX // CONCAT, LOWER, UPPER, TRIM
RESULT_MATH_1[i] = RESULT_STRING[i] = `${city[i].toUpperCase()}${city[
Math.ceil(1.4) + i
Math.floor(1.6) + ].toLowerCase()}trimmed`;
Math.round(2.5) +
(cityId[i] % 3) + // ADD, AVG, LEN
Math.min(cityId[i], countryId[i]) + RESULT_MATH_0[i] =
Math.max(cityId[i], countryId[i]); cityId[i] +
countryId[i] +
// LOG, EXP, POWER, SQRT (cityId[i] + countryId[i]) / 2 +
// only integer verification being computed, hence trunc city[i].length;
RESULT_MATH_2[i] = Math.trunc(
Math.log(cityId[i]) + // CEILING, FLOOR, ROUND, MOD, MIN, MAX
Math.exp(cityId[i]) + RESULT_MATH_1[i] =
Math.pow(cityId[i], 3) + Math.ceil(1.4) +
Math.sqrt(countryId[i]) Math.floor(1.6) +
); Math.round(2.5) +
} (cityId[i] % 3) +
Math.min(cityId[i], countryId[i]) +
it("Formula: CONCAT, LOWER, UPPER, TRIM", () => { Math.max(cityId[i], countryId[i]);
addFormulaBasedColumn(
"NC_MATH_0", // LOG, EXP, POWER, SQRT
"ADD(CityId, CountryId) + AVG(CityId, CountryId) + LEN(City)" // only integer verification being computed, hence trunc
); RESULT_MATH_2[i] = Math.trunc(
rowValidation("NC_MATH_0", RESULT_MATH_0); Math.log(cityId[i]) +
}); Math.exp(cityId[i]) +
Math.pow(cityId[i], 3) +
it("Formula: ADD, AVG, LEN", () => { Math.sqrt(countryId[i])
editColumnByName( );
"NC_MATH_0", }
"NC_STR_1",
`CONCAT(UPPER(City), LOWER(City), TRIM(' trimmed '))` it("Formula: ADD, AVG, LEN", () => {
); addFormulaBasedColumn(
rowValidation("NC_STR_1", RESULT_STRING); "NC_MATH_0",
}); "ADD(CityId, CountryId) + AVG(CityId, CountryId) + LEN(City)"
);
it("Formula: CEILING, FLOOR, ROUND, MOD, MIN, MAX", () => { rowValidation("NC_MATH_0", RESULT_MATH_0);
editColumnByName( });
"NC_STR_1",
"NC_MATH_1", it("Formula: CONCAT, LOWER, UPPER, TRIM", () => {
`CEILING(1.4) + FLOOR(1.6) + ROUND(2.5) + MOD(CityId, 3) + MIN(CityId, CountryId) + MAX(CityId, CountryId)` editColumnByName(
); "NC_MATH_0",
rowValidation("NC_MATH_1", RESULT_MATH_1); "NC_STR_1",
}); `CONCAT(UPPER(City), LOWER(City), TRIM(' trimmed '))`
);
it("Formula: LOG, EXP, POWER, SQRT", () => { rowValidation("NC_STR_1", RESULT_STRING);
if (!isXcdb()) { });
// SQLITE doesnt support LOG, EXP, POWER SQRT construct
editColumnByName( it("Formula: CEILING, FLOOR, ROUND, MOD, MIN, MAX", () => {
"NC_MATH_1", editColumnByName(
"NC_MATH_2", "NC_STR_1",
`LOG(CityId) + EXP(CityId) + POWER(CityId, 3) + SQRT(CountryId)` "NC_MATH_1",
); `CEILING(1.4) + FLOOR(1.6) + ROUND(2.5) + MOD(CityId, 3) + MIN(CityId, CountryId) + MAX(CityId, CountryId)`
rowValidation("NC_MATH_2", RESULT_MATH_2); );
} rowValidation("NC_MATH_1", RESULT_MATH_1);
}); });
it("Formula: NOW, EDIT & Delete column", () => { it("Formula: LOG, EXP, POWER, SQRT", () => {
if (!isXcdb()) editColumnByName("NC_MATH_2", "NC_NOW", `NOW()`); if (!isXcdb()) {
else editColumnByName("NC_MATH_1", "NC_NOW", `NOW()`); // SQLITE doesnt support LOG, EXP, POWER SQRT construct
deleteColumnByName("NC_NOW"); editColumnByName(
"NC_MATH_1",
"NC_MATH_2",
`LOG(CityId) + EXP(CityId) + POWER(CityId, 3) + SQRT(CountryId)`
);
rowValidation("NC_MATH_2", RESULT_MATH_2);
}
});
it("Formula: NOW, EDIT & Delete column", () => {
if (!isXcdb()) editColumnByName("NC_MATH_2", "NC_NOW", `NOW()`);
else editColumnByName("NC_MATH_1", "NC_NOW", `NOW()`);
deleteColumnByName("NC_NOW");
});
}); });
});
}; };
/** /**

192
scripts/cypress/integration/common/3c_lookup_column.js

@ -1,101 +1,103 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - LookUp column`, () => { describe(`${apiType.toUpperCase()} api - LookUp column`, () => {
// to retrieve few v-input nodes from their label // to retrieve few v-input nodes from their label
// //
const fetchParentFromLabel = (label) => { const fetchParentFromLabel = (label) => {
cy.get("label").contains(label).parents(".v-input").click(); cy.get("label").contains(label).parents(".v-input").click();
}; };
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {
// open a table to work on views // open a table to work on views
// //
cy.openTableTab("City", 25); cy.openTableTab("City", 25);
});
after(() => {
cy.closeTableTab("City");
});
// Routine to create a new look up column
//
const addLookUpColumn = (childTable, childCol) => {
// (+) icon at end of column header (to add a new column)
// opens up a pop up window
//
cy.get(".new-column-header").click();
// Redundant to feed column name. as alias is displayed & referred for
cy.get(".nc-column-name-input input").clear().type(childCol);
// Column data type: to be set to lookup in this context
cy.get(".nc-ui-dt-dropdown").click();
cy.getActiveMenu().contains("Lookup").click();
// Configure Child table & column names
fetchParentFromLabel("Child Table");
cy.getActiveMenu().contains(childTable).click();
fetchParentFromLabel("Child column");
cy.getActiveMenu().contains(childCol).click();
cy.snipActiveMenu("LookUp");
// click on Save
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
// Verify if column exists.
//
cy.get(`th:contains(${childCol})`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (childCol) => {
// verify if column exists before delete
cy.get(`th:contains(${childCol})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${childCol}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// delete/ confirm on pop-up
cy.get(".nc-column-delete").click();
cy.getActiveModal().find("button:contains(Confirm)").click();
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${childCol})`).should("not.exist");
};
///////////////////////////////////////////////////
// Test case
it("Add Lookup column (Address, PostalCode) & Delete", () => {
addLookUpColumn("Address", "PostalCode");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="PostalCode"]`)
.contains("4166")
.should("exist");
deleteColumnByName("PostalCode");
});
it.skip("Add Lookup column (Country, CountryId) & Delete", () => {
addLookUpColumn("Country", "CountryId");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="CountryId"]`)
.contains("87")
.should("exist");
deleteColumnByName("CountryId");
});
}); });
after(() => {
cy.closeTableTab("City");
});
// Routine to create a new look up column
//
const addLookUpColumn = (childTable, childCol) => {
// (+) icon at end of column header (to add a new column)
// opens up a pop up window
//
cy.get(".new-column-header").click();
// Redundant to feed column name. as alias is displayed & referred for
cy.get(".nc-column-name-input input").clear().type(childCol);
// Column data type: to be set to lookup in this context
cy.get(".nc-ui-dt-dropdown").click();
cy.getActiveMenu().contains("Lookup").click();
// Configure Child table & column names
fetchParentFromLabel("Child Table");
cy.getActiveMenu().contains(childTable).click();
fetchParentFromLabel("Child column");
cy.getActiveMenu().contains(childCol).click();
// click on Save
cy.get(".nc-col-create-or-edit-card").contains("Save").click();
// Verify if column exists.
//
cy.get(`th:contains(${childCol})`).should("exist");
};
// routine to delete column
//
const deleteColumnByName = (childCol) => {
// verify if column exists before delete
cy.get(`th:contains(${childCol})`).should("exist");
// delete opiton visible on mouse-over
cy.get(`th:contains(${childCol}) .mdi-menu-down`)
.trigger("mouseover")
.click();
// delete/ confirm on pop-up
cy.get(".nc-column-delete").click();
cy.getActiveModal().find("button:contains(Confirm)").click();
// validate if deleted (column shouldnt exist)
cy.get(`th:contains(${childCol})`).should("not.exist");
};
///////////////////////////////////////////////////
// Test case
it("Add Lookup column (Address, District) & Delete", () => {
addLookUpColumn("Address", "District");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="District"]`)
.contains("Galicia")
.should("exist");
deleteColumnByName("District");
});
it.skip("Add Lookup column (Country, CountryId) & Delete", () => {
addLookUpColumn("Country", "CountryId");
// Verify first entry, will be displayed as alias here 'childColumn (from childTable)'
cy.get(`tbody > :nth-child(1) > [data-col="CountryId"]`)
.contains("87")
.should("exist");
deleteColumnByName("CountryId");
});
});
}; };
// genTest('rest', false) // genTest('rest', false)

8
scripts/cypress/integration/common/3d_rollup_column.js

@ -1,9 +1,9 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - RollUp column`, () => { describe(`${apiType.toUpperCase()} api - RollUp column`, () => {
// to retrieve few v-input nodes from their label // to retrieve few v-input nodes from their label
// //
const fetchParentFromLabel = (label) => { const fetchParentFromLabel = (label) => {
@ -55,6 +55,8 @@ export const genTest = (type, xcdb) => {
fetchParentFromLabel("Aggregate function"); fetchParentFromLabel("Aggregate function");
cy.getActiveMenu().contains(aggregateFunc).click(); cy.getActiveMenu().contains(aggregateFunc).click();
cy.snipActiveMenu("RollUp");
// click on Save // click on Save
cy.get(".nc-col-create-or-edit-card").contains("Save").click(); cy.get(".nc-col-create-or-edit-card").contains("Save").click();

143
scripts/cypress/integration/common/4a_table_view_grid_gallery_form.js

@ -1,76 +1,81 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Table views: Create/Edit/Delete`, () => {
const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("Country", 25);
});
after(() => { describe(`${apiType.toUpperCase()} api - Table views: Create/Edit/Delete`, () => {
cy.closeTableTab("Country"); const name = "Test" + Date.now();
});
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("Country", 25);
});
after(() => {
cy.closeTableTab("Country");
});
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType} view`, () => {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// validate if view was creted && contains default name 'Country1'
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Country1")
.should("exist");
cy.snip(`View_${viewType}`);
});
// Common routine to create/edit/delete GRID & GALLERY view it(`Edit ${viewType} view name`, () => {
// Input: viewType - 'grid'/'gallery' // click on edit-icon (becomes visible on hovering mouse)
// cy.get(".nc-view-edit-icon").click({
const viewTest = (viewType) => { force: true,
it(`Create ${viewType} view`, () => { timeout: 1000,
// click on 'Grid/Gallery' button on Views bar });
cy.get(`.nc-create-${viewType}-view`).click();
// feed new name
// Pop up window, click Submit (accepting default name for view) cy.get(`.nc-${viewType}-view-item input`).type(
cy.getActiveModal().find("button:contains(Submit)").click(); `${viewType}View-1{enter}`
cy.toastWait("View created successfully"); );
cy.toastWait("View renamed successfully");
// validate if view was creted && contains default name 'Country1'
cy.get(`.nc-view-item.nc-${viewType}-view-item`) // validate
.contains("Country1") cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.should("exist"); .contains(`${viewType}View-1`)
}); .should("exist");
});
it(`Edit ${viewType} view name`, () => {
// click on edit-icon (becomes visible on hovering mouse) it(`Delete ${viewType} view`, () => {
cy.get(".nc-view-edit-icon").click({ force: true, timeout: 1000 }); // number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
// feed new name
cy.get(`.nc-${viewType}-view-item input`).type( // click on delete icon (becomes visible on hovering mouse)
`${viewType}View-1{enter}` cy.get(".nc-view-delete-icon").click({ force: true });
); cy.toastWait("View deleted successfully");
cy.toastWait("View renamed successfully");
// confirm if the number of veiw entries is reduced by 1
// validate cy.get(".nc-view-item").its("length").should("eq", 1);
cy.get(`.nc-view-item.nc-${viewType}-view-item`) });
.contains(`${viewType}View-1`) };
.should("exist");
}); // below four scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
it(`Delete ${viewType} view`, () => { viewTest("gallery");
// number of view entries should be 2 before we delete viewTest("form");
cy.get(".nc-view-item").its("length").should("eq", 2); // viewTest("kanban");
});
// click on delete icon (becomes visible on hovering mouse)
cy.get(".nc-view-delete-icon").click({ force: true });
cy.toastWait("View deleted successfully");
// confirm if the number of veiw entries is reduced by 1
cy.get(".nc-view-item").its("length").should("eq", 1);
});
};
// below four scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
viewTest("gallery");
viewTest("form");
// viewTest("kanban");
});
}; };
/** /**

11
scripts/cypress/integration/common/4b_table_view_share.js

@ -10,12 +10,17 @@ const generateLinkWithPwd = () => {
// .contains("Share View") // .contains("Share View")
// .click(); // .click();
mainPage.shareView().click(); mainPage.shareView().click();
cy.snipActiveModal("Modal_ShareView")
// enable checkbox & feed pwd, save // enable checkbox & feed pwd, save
cy.getActiveModal() cy.getActiveModal()
.find('[role="switch"][type="checkbox"]') .find('[role="switch"][type="checkbox"]')
.click({ force: true }); .click({ force: true });
cy.getActiveModal().find('input[type="password"]').type("1"); cy.getActiveModal().find('input[type="password"]').type("1");
cy.snipActiveModal("Modal_ShareView_Password");
cy.getActiveModal().find('button:contains("Save password")').click(); cy.getActiveModal().find('button:contains("Save password")').click();
cy.toastWait("Successfully updated"); cy.toastWait("Successfully updated");
@ -29,10 +34,10 @@ const generateLinkWithPwd = () => {
}); });
}; };
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Shared VIEWs (GRID)`, () => { describe(`${apiType.toUpperCase()} api - Shared VIEWs (GRID)`, () => {
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {

6
scripts/cypress/integration/common/4c_form_view_detailed.js

@ -3,10 +3,10 @@ import { mainPage } from "../../support/page_objects/mainPage";
let formViewURL; let formViewURL;
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - FORM view`, () => { describe(`${apiType.toUpperCase()} api - FORM view`, () => {
const name = "Test" + Date.now(); const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)

7
scripts/cypress/integration/common/4d_table_view_grid_locked.js

@ -1,10 +1,10 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Lock view`, () => { describe(`${apiType.toUpperCase()} api - Lock view`, () => {
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {
@ -25,6 +25,7 @@ export const genTest = (type, xcdb) => {
// on menu, collaboration view appears first (at index 0) // on menu, collaboration view appears first (at index 0)
// followed by Locked view (at index 1) // followed by Locked view (at index 1)
cy.get(".xc-toolbar").find(".nc-view-lock-menu:enabled").click(); cy.get(".xc-toolbar").find(".nc-view-lock-menu:enabled").click();
cy.snipActiveMenu("Menu_Collaboration")
cy.getActiveMenu().find('[role="menuitem"]').eq(menuOption).click(); cy.getActiveMenu().find('[role="menuitem"]').eq(menuOption).click();
// expected toolbar for Lock view: Only lock-view menu, reload, toggle-nav-drawer to be enabled // expected toolbar for Lock view: Only lock-view menu, reload, toggle-nav-drawer to be enabled

391
scripts/cypress/integration/common/4e_form_view_share.js

@ -3,194 +3,223 @@ import { mainPage } from "../../support/page_objects/mainPage";
let storedURL = ""; let storedURL = "";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - FORM view (Share)`, () => { describe(`${apiType.toUpperCase()} api - FORM view (Share)`, () => {
const name = "Test" + Date.now(); const name = "Test" + Date.now();
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {
// open a table to work on views // open a table to work on views
// //
cy.openTableTab("City", 25); cy.openTableTab("City", 25);
}); });
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => { beforeEach(() => {
cy.saveLocalStorage(); cy.restoreLocalStorage();
}); });
after(() => { afterEach(() => {
cy.closeTableTab("City"); cy.saveLocalStorage();
}); });
// Common routine to create/edit/delete GRID & GALLERY view after(() => {
// Input: viewType - 'grid'/'gallery' cy.closeTableTab("City");
//
const viewTest = (viewType) => {
it(`Create ${viewType} view`, () => {
// click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-create-${viewType}-view`).click();
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// Prepare form
// add header, description
// add post submission message
// swap position for City, LastUpdate fields
// remove City=>Address field
cy.get(".nc-form > .mx-auto").find('[type="checkbox"]').eq(1).click();
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
cy.get(".nc-form").find('[placeholder="Form Title"]').type("A B C D");
cy.get(".nc-form")
.find('[placeholder="Add form description"]')
.type("Some description about form comes here");
cy.get(".nc-form > .mx-auto").find("textarea").type("Congratulations!");
cy.get("#data-table-form-City").drag("#data-table-form-LastUpdate");
cy.get('[title="City => Address"]').drag(".nc-drag-n-drop-to-hide");
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
}); });
});
// Common routine to create/edit/delete GRID & GALLERY view
it(`Share form view`, () => { // Input: viewType - 'grid'/'gallery'
cy.get(".nc-form > .mx-auto") //
.find('[type="checkbox"]') const viewTest = (viewType) => {
.eq(1) it(`Create ${viewType} view`, () => {
.should("be.checked"); // click on 'Grid/Gallery' button on Views bar
cy.get(`.nc-view-item.nc-${viewType}-view-item`) cy.get(`.nc-create-${viewType}-view`).click();
.contains("City1")
.click(); // Pop up window, click Submit (accepting default name for view)
// cy.get(".v-navigation-drawer__content > .container") cy.getActiveModal().find("button:contains(Submit)").click();
// .find(".v-list > .v-list-item")
// .contains("Share View") cy.toastWait("View created successfully");
// .click();
mainPage.shareView().click(); // Prepare form
// add header, description
// copy link text, visit URL // add post submission message
cy.getActiveModal() // swap position for City, LastUpdate fields
.find(".share-link-box") // remove City=>Address field
.contains("/nc/form/", { timeout: 10000 }) cy.get(".nc-form > .mx-auto")
.then(($obj) => { .find('[type="checkbox"]')
let linkText = $obj.text().trim(); .eq(1)
cy.log(linkText); .click();
cy.visit(linkText, { cy.get(".nc-form > .mx-auto")
baseUrl: null, .find('[type="checkbox"]')
.eq(1)
.should("be.checked");
cy.get(".nc-form")
.find('[placeholder="Form Title"]')
.type("A B C D");
cy.get(".nc-form")
.find('[placeholder="Add form description"]')
.type("Some description about form comes here");
cy.get(".nc-form > .mx-auto")
.find("textarea")
.type("Congratulations!");
cy.get("#data-table-form-City").drag(
"#data-table-form-LastUpdate"
);
cy.get('[title="City => Address"]').drag(
".nc-drag-n-drop-to-hide"
);
cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
.eq(1)
.should("be.checked");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
});
}); });
// wait for share view page to load! it(`Share form view`, () => {
cy.get(".nc-form").should("exist"); cy.get(".nc-form > .mx-auto")
.find('[type="checkbox"]')
// New form appeared? Header & description should exist .eq(1)
cy.get(".nc-form", { timeout: 10000 }) .should("be.checked");
.find("h2") cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("A B C D") .contains("City1")
.should("exist"); .click();
cy.get(".nc-form", { timeout: 10000 }) // cy.get(".v-navigation-drawer__content > .container")
.find(".body-1") // .find(".v-list > .v-list-item")
.contains("Some description about form comes here") // .contains("Share View")
.should("exist"); // .click();
mainPage.shareView().click();
// all fields, barring removed field should exist
cy.get('[title="City"]').should("exist"); cy.snipActiveModal("Modal_ShareView");
cy.get('[title="LastUpdate"]').should("exist");
cy.get('[title="Country <= City"]').should("exist"); // copy link text, visit URL
cy.get('[title="City => Address"]').should("not.exist"); cy.getActiveModal()
.find(".share-link-box")
// order of LastUpdate & City field is retained .contains("/nc/form/", { timeout: 10000 })
cy.get(".nc-field-wrapper") .then(($obj) => {
.eq(0) let linkText = $obj.text().trim();
.contains("LastUpdate") cy.log(linkText);
.should("exist"); cy.visit(linkText, {
cy.get(".nc-field-wrapper").eq(1).contains("City").should("exist"); baseUrl: null,
});
// submit form, to read message
cy.get("#data-table-form-City").type("_abc"); // wait for share view page to load!
cy.get("#data-table-form-LastUpdate").click(); cy.get(".nc-form").should("exist");
cy.getActiveModal().find("button").contains("19").click();
cy.getActiveModal().find("button").contains("OK").click(); cy.snip("ShareView_Form");
cy.get("button").contains("Link to 'Country'").click();
cy.getActiveModal() // New form appeared? Header & description should exist
.find(".child-card") cy.get(".nc-form", { timeout: 10000 })
.contains("Afghanistan") .find("h2")
.click(); .contains("A B C D")
.should("exist");
// submit button & validate cy.get(".nc-form", { timeout: 10000 })
cy.get(".nc-form").find("button").contains("Submit").click(); .find(".body-1")
cy.toastWait("Congratulations"); .contains("Some description about form comes here")
cy.get(".v-alert") .should("exist");
.contains("Congratulations")
.should("exist") // all fields, barring removed field should exist
.then(() => { cy.get('[title="City"]').should("exist");
cy.get(".nc-form").should("exist"); cy.get('[title="LastUpdate"]').should("exist");
cy.get('[title="Country <= City"]').should("exist");
// validate if form has appeared again cy.get('[title="City => Address"]').should("not.exist");
cy.get(".nc-form", { timeout: 10000 })
.find("h2") // order of LastUpdate & City field is retained
.contains("A B C D") cy.get(".nc-field-wrapper")
.should("exist"); .eq(0)
cy.get(".nc-form", { timeout: 10000 }) .contains("LastUpdate")
.find(".body-1") .should("exist");
.contains("Some description about form comes here") cy.get(".nc-field-wrapper")
.should("exist"); .eq(1)
}); .contains("City")
}); .should("exist");
});
// submit form, to read message
it(`Delete ${viewType} view`, () => { cy.get("#data-table-form-City").type("_abc");
// go back to base page cy.get("#data-table-form-LastUpdate").click();
cy.visit(storedURL, { cy.getActiveModal()
baseUrl: null, .find("button")
}); .contains("19")
.click();
cy.getActiveModal()
.find("button")
.contains("OK")
.click();
cy.get("button").contains("Link to 'Country'").click();
cy.getActiveModal()
.find(".child-card")
.contains("Afghanistan")
.click();
// submit button & validate
cy.get(".nc-form")
.find("button")
.contains("Submit")
.click();
cy.toastWait("Congratulations");
cy.get(".v-alert")
.contains("Congratulations")
.should("exist")
.then(() => {
cy.get(".nc-form").should("exist");
// validate if form has appeared again
cy.get(".nc-form", { timeout: 10000 })
.find("h2")
.contains("A B C D")
.should("exist");
cy.get(".nc-form", { timeout: 10000 })
.find(".body-1")
.contains(
"Some description about form comes here"
)
.should("exist");
});
});
});
// number of view entries should be 2 before we delete it(`Delete ${viewType} view`, () => {
cy.get(".nc-view-item").its("length").should("eq", 2); // go back to base page
cy.visit(storedURL, {
// click on delete icon (becomes visible on hovering mouse) baseUrl: null,
cy.get(".nc-view-delete-icon").click({ force: true }); });
cy.toastWait("View deleted successfully");
// number of view entries should be 2 before we delete
// confirm if the number of veiw entries is reduced by 1 cy.get(".nc-view-item").its("length").should("eq", 2);
cy.get(".nc-view-item").its("length").should("eq", 1);
// click on delete icon (becomes visible on hovering mouse)
// clean up newly added rows into Country table operations cy.get(".nc-view-delete-icon").click({ force: true });
// this auto verifies successfull addition of rows to table as well cy.toastWait("View deleted successfully");
mainPage.getPagination(25).click();
cy.get(".nc-grid-row").should("have.length", 1); // confirm if the number of veiw entries is reduced by 1
mainPage cy.get(".nc-view-item").its("length").should("eq", 1);
.getRow(1)
.find(".mdi-checkbox-blank-outline") // clean up newly added rows into Country table operations
.click({ force: true }); // this auto verifies successfull addition of rows to table as well
mainPage.getPagination(25).click();
mainPage.getCell("City", 1).rightclick(); cy.get(".nc-grid-row").should("have.length", 1);
cy.getActiveMenu().contains("Delete Selected Row").click(); mainPage
// cy.toastWait('Deleted selected rows successfully') .getRow(1)
}); .find(".mdi-checkbox-blank-outline")
}; .click({ force: true });
// below scenario's will be invoked twice, once for rest & then for graphql mainPage.getCell("City", 1).rightclick();
viewTest("form"); cy.getActiveMenu().contains("Delete Selected Row").click();
}); // cy.toastWait('Deleted selected rows successfully')
});
};
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("form");
});
}; };
/** /**

813
scripts/cypress/integration/common/4f_grid_view_share.js

@ -11,419 +11,444 @@ let storedURL = "";
// 5: default (country table): for update row/column validation // 5: default (country table): for update row/column validation
let viewURL = {}; let viewURL = {};
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
const generateViewLink = (viewName) => {
// click on share view
// cy.get(".v-navigation-drawer__content > .container")
// .find(".v-list > .v-list-item")
// .contains("Share View")
// .click();
mainPage.shareView().click();
// wait, as URL initially will be /undefined
cy.getActiveModal()
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.should("exist");
// copy link text, visit URL
cy.getActiveModal()
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.then(($obj) => {
cy.get("body").type("{esc}");
// viewURL.push($obj.text())
viewURL[viewName] = $obj.text().trim();
});
};
describe(`${type.toUpperCase()} api - GRID view (Share)`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("Address", 25);
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
after(() => {
// close table
// mainPage.deleteCreatedViews()
cy.closeTableTab("Address");
});
// Common routine to create/edit/delete GRID & GALLERY view const generateViewLink = (viewName) => {
// Input: viewType - 'grid'/'gallery' // click on share view
//
const viewTest = (viewType) => {
it(`Create ${viewType.toUpperCase()} view`, () => {
// create a normal public view
cy.get(`.nc-create-${viewType}-view`).click();
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
});
});
it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => {
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Address1")
.click();
mainPage.hideField("Address2");
mainPage.sortField("District", "Z -> A");
mainPage.filterField("Address", "is like", "Ab");
generateViewLink("combined");
cy.log(viewURL["combined"]);
});
it(`Share GRID view : ensure we have only one link even if shared multiple times`, () => {
// generate view link multiple times
generateViewLink("combined");
generateViewLink("combined");
// verify if only one link exists in table
// cy.get(".v-navigation-drawer__content > .container") // cy.get(".v-navigation-drawer__content > .container")
// .find(".v-list > .v-list-item") // .find(".v-list > .v-list-item")
// .contains("Share View") // .contains("Share View")
// .parent()
// .find("button.mdi-dots-vertical")
// .click(); // .click();
mainPage.shareViewList().click(); mainPage.shareView().click();
// cy.getActiveMenu().find(".v-list-item").contains("Views List").click();
cy.get('th:contains("View Link")').should("exist");
cy.get('th:contains("View Link")')
.parent()
.parent()
.next()
.find("tr")
.its("length")
.should("eq", 1)
.then(() => {
// cy.get(".v-overlay__content > .d-flex > .v-icon").click();
// close modal (fix me! add a close button to share view list modal)
cy.get('.v-overlay--active > .v-overlay__scrim').click({force: true});
});
});
it(`Share ${viewType.toUpperCase()} view : Visit URL, Verify title`, () => {
// visit public view
cy.visit(viewURL["combined"], {
baseUrl: null,
});
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 18);
// verify title
cy.get("div.model-name").contains("Address1").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields hidden/open`, () => {
// verify column headers
cy.get('[data-col="Address"]').should("exist");
cy.get('[data-col="Address2"]').should("not.exist");
cy.get('[data-col="District"]').should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields sort/ filter`, () => {
// country column content verification before sort
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
mainPage.getCell("District", 2).contains("Tutuila").should("exist");
mainPage.getCell("District", 3).contains("Tamil Nadu").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`,
`1013 Tabuk Boulevard,West Bengali,96203,158399646978,[object Object],2,,Kanchrapara,`,
`1892 Nabereznyje Telny Lane,Tutuila,28396,478229987054,[object Object],2,,Tafuna,`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
}
};
// download & verify // wait, as URL initially will be /undefined
mainPage.downloadAndVerifyCsv(`Address_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Disable sort`, () => {
// remove sort and validate
mainPage.clearSort();
mainPage
.getCell("District", 1)
.contains("Southern Mindanao")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => {
// Sort menu operations (Country Column, Z->A)
mainPage.sortField("District", "Z -> A");
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => {
// add filter & validate
mainPage.filterField("District", "is like", "Tamil");
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 2);
mainPage.getCell("District", 1).contains("Tamil").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
// for (let i = 0; i < storedRecords.length; i++) {
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
// }
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
}
};
mainPage.downloadAndVerifyCsv(`Address_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Delete Filter`, () => {
// Remove sort and Validate
mainPage.filterReset();
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share GRID view : Virtual column validation > has many`, () => {
// verify column headers
cy.get('[data-col="Address => Customer"]').should("exist");
cy.get('[data-col="Address => Staff"]').should("exist");
cy.get('[data-col="City <= Address"]').should("exist");
cy.get('[data-col="Address <=> Staff"]').should("exist");
// has many field validation
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-plus")
.should("not.exist");
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-arrow-expand")
.click();
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal() cy.getActiveModal()
.find("button") .find(".share-link-box")
.contains("Link to") .contains("/nc/view/", { timeout: 10000 })
.should("not.exist"); .should("exist");
cy.getActiveModal().find(".child-card").contains("2").should("exist");
cy.getActiveModal() // copy link text, visit URL
.find(".child-card")
.find("button")
.should("not.exist");
cy.get("body").type("{esc}");
});
it(`Share GRID view : Virtual column validation > belongs to`, () => {
// belongs to field validation
mainPage
.getCell("City <= Address", 1)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("City <= Address", 1)
.click()
.find("button.mdi-arrow-expand")
.should("not.exist");
mainPage
.getCell("City <= Address", 1)
.find(".v-chip")
.contains("Kanchrapara")
.should("exist");
});
it(`Share GRID view : Virtual column validation > many to many`, () => {
// many-to-many field validation
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-plus")
.should("not.exist");
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-arrow-expand")
.click();
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal() cy.getActiveModal()
.find("button") .find(".share-link-box")
.contains("Link to") .contains("/nc/view/", { timeout: 10000 })
.should("not.exist"); .then(($obj) => {
cy.get("body").type("{esc}"); cy.get("body").type("{esc}");
}); // viewURL.push($obj.text())
viewURL[viewName] = $obj.text().trim();
it(`Delete ${viewType.toUpperCase()} view`, () => { });
// go back to base page };
cy.visit(storedURL, {
baseUrl: null, describe(`${apiType.toUpperCase()} api - GRID view (Share)`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("Address", 25);
cy.saveLocalStorage();
}); });
// number of view entries should be 2 before we delete beforeEach(() => {
cy.get(".nc-view-item").its("length").should("eq", 2); cy.restoreLocalStorage();
});
cy.get(".nc-view-delete-icon").eq(0).click({ force: true }); afterEach(() => {
cy.toastWait("View deleted successfully"); cy.saveLocalStorage();
});
// confirm if the number of veiw entries is reduced by 1 after(() => {
cy.get(".nc-view-item").its("length").should("eq", 1); // close table
}); // mainPage.deleteCreatedViews()
}; cy.closeTableTab("Address");
});
// below scenario's will be invoked twice, once for rest & then for graphql // Common routine to create/edit/delete GRID & GALLERY view
viewTest("grid"); // Input: viewType - 'grid'/'gallery'
}); //
const viewTest = (viewType) => {
describe(`${type.toUpperCase()} api - Grid view/ row-column update verification`, () => { it(`Create ${viewType.toUpperCase()} view`, () => {
before(() => { // create a normal public view
// Address table has belongs to, has many & many-to-many cy.get(`.nc-create-${viewType}-view`).click();
cy.openTableTab("Country", 25); cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
cy.saveLocalStorage();
// store base URL- to re-visit and delete form view later // store base URL- to re-visit and delete form view later
cy.url().then((url) => { cy.url().then((url) => {
storedURL = url; storedURL = url;
generateViewLink("rowColUpdate"); });
}); });
});
it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => {
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Address1")
.click();
mainPage.hideField("Address2");
mainPage.sortField("District", "Z -> A");
mainPage.filterField("Address", "is like", "Ab");
generateViewLink("combined");
cy.log(viewURL["combined"]);
});
it(`Share GRID view : ensure we have only one link even if shared multiple times`, () => {
// generate view link multiple times
generateViewLink("combined");
generateViewLink("combined");
// verify if only one link exists in table
// cy.get(".v-navigation-drawer__content > .container")
// .find(".v-list > .v-list-item")
// .contains("Share View")
// .parent()
// .find("button.mdi-dots-vertical")
// .click();
mainPage.shareViewList().click();
// cy.getActiveMenu().find(".v-list-item").contains("Views List").click();
cy.get('th:contains("View Link")').should("exist");
cy.get('th:contains("View Link")')
.parent()
.parent()
.next()
.find("tr")
.its("length")
.should("eq", 1)
.then(() => {
// cy.get(".v-overlay__content > .d-flex > .v-icon").click();
// close modal (fix me! add a close button to share view list modal)
cy.get(".v-overlay--active > .v-overlay__scrim").click({
force: true,
});
});
});
it(`Share ${viewType.toUpperCase()} view : Visit URL, Verify title`, () => {
// visit public view
cy.visit(viewURL["combined"], {
baseUrl: null,
});
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 18);
cy.snip("ShareView_Grid");
// verify title
cy.get("div.model-name").contains("Address1").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields hidden/open`, () => {
// verify column headers
cy.get('[data-col="Address"]').should("exist");
cy.get('[data-col="Address2"]').should("not.exist");
cy.get('[data-col="District"]').should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields sort/ filter`, () => {
// country column content verification before sort
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
mainPage
.getCell("District", 2)
.contains("Tutuila")
.should("exist");
mainPage
.getCell("District", 3)
.contains("Tamil Nadu")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`,
`1013 Tabuk Boulevard,West Bengali,96203,158399646978,[object Object],2,,Kanchrapara,`,
`1892 Nabereznyje Telny Lane,Tutuila,28396,478229987054,[object Object],2,,Tafuna,`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
}
};
// download & verify
mainPage.downloadAndVerifyCsv(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Disable sort`, () => {
// remove sort and validate
mainPage.clearSort();
mainPage
.getCell("District", 1)
.contains("Southern Mindanao")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => {
// Sort menu operations (Country Column, Z->A)
mainPage.sortField("District", "Z -> A");
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => {
// add filter & validate
mainPage.filterField("District", "is like", "Tamil");
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 2);
mainPage
.getCell("District", 1)
.contains("Tamil")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`,
`1993 Tabuk Lane,Tamil Nadu,64221,648482415405,[object Object],2,,Tambaram,`,
`1661 Abha Drive,Tamil Nadu,14400,270456873752,[object Object],1,,Pudukkottai,`,
];
// for (let i = 0; i < storedRecords.length; i++) {
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
// }
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
for (let j = 0; j < 4; j++) {
expect(strCol[j]).to.be.equal(retCol[j]);
}
}
};
mainPage.downloadAndVerifyCsv(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Delete Filter`, () => {
// Remove sort and Validate
mainPage.filterReset();
mainPage
.getCell("District", 1)
.contains("West Bengali")
.should("exist");
});
it(`Share GRID view : Virtual column validation > has many`, () => {
// verify column headers
cy.get('[data-col="Address => Customer"]').should("exist");
cy.get('[data-col="Address => Staff"]').should("exist");
cy.get('[data-col="City <= Address"]').should("exist");
cy.get('[data-col="Address <=> Staff"]').should("exist");
// has many field validation
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-plus")
.should("not.exist");
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-arrow-expand")
.click();
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find("button")
.contains("Link to")
.should("not.exist");
cy.getActiveModal()
.find(".child-card")
.contains("2")
.should("exist");
cy.getActiveModal()
.find(".child-card")
.find("button")
.should("not.exist");
cy.get("body").type("{esc}");
});
it(`Share GRID view : Virtual column validation > belongs to`, () => {
// belongs to field validation
mainPage
.getCell("City <= Address", 1)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("City <= Address", 1)
.click()
.find("button.mdi-arrow-expand")
.should("not.exist");
mainPage
.getCell("City <= Address", 1)
.find(".v-chip")
.contains("Kanchrapara")
.should("exist");
});
it(`Share GRID view : Virtual column validation > many to many`, () => {
// many-to-many field validation
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-plus")
.should("not.exist");
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-arrow-expand")
.click();
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find("button")
.contains("Link to")
.should("not.exist");
cy.get("body").type("{esc}");
});
it(`Delete ${viewType.toUpperCase()} view`, () => {
// go back to base page
cy.visit(storedURL, {
baseUrl: null,
});
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// confirm if the number of veiw entries is reduced by 1
cy.get(".nc-view-item").its("length").should("eq", 1);
});
};
after(() => { // below scenario's will be invoked twice, once for rest & then for graphql
// close table viewTest("grid");
cy.restoreLocalStorage();
cy.visit(storedURL, {
baseUrl: null,
});
// delete row
mainPage.getPagination(5).click();
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage
.getRow(10)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu().contains("Delete Selected Row").click();
// delete column
cy.get(`th:contains('dummy') .mdi-menu-down`)
.trigger("mouseover")
.click();
cy.get(".nc-column-delete").click();
cy.get("button:contains(Confirm)").click();
cy.toastWait("Update table successful");
mainPage.deleteCreatedViews();
// close table
cy.closeTableTab("Country");
}); });
it(`Generate default Shared GRID view URL`, () => { describe(`${apiType.toUpperCase()} api - Grid view/ row-column update verification`, () => {
// add row before(() => {
cy.get(".nc-add-new-row-btn").click({ force: true }); // Address table has belongs to, has many & many-to-many
cy.get("#data-table-form-Country > input").first().click().type("a"); cy.openTableTab("Country", 25);
cy.contains("Save Row").filter("button").click({ force: true });
cy.toastWait("updated successfully"); cy.saveLocalStorage();
// store base URL- to re-visit and delete form view later
// add column cy.url().then((url) => {
mainPage.addColumn("dummy", "Country"); storedURL = url;
generateViewLink("rowColUpdate");
// visit public view });
cy.log(viewURL["rowColUpdate"]); });
cy.restoreLocalStorage();
cy.visit(viewURL["rowColUpdate"], {
baseUrl: null,
}); //5
// wait for public view page to load!
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 25);
});
it(`Share GRID view : new row visible`, () => { after(() => {
// verify row // close table
cy.get(`.v-pagination > li:contains('5') button`).click(); cy.restoreLocalStorage();
// wait for page rendering to complete cy.visit(storedURL, {
cy.get(".nc-grid-row").should("have.length", 10); baseUrl: null,
mainPage.getCell("Country", 10).contains("a").should("exist"); });
});
// delete row
mainPage.getPagination(5).click();
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage
.getRow(10)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu().contains("Delete Selected Row").click();
// delete column
cy.get(`th:contains('dummy') .mdi-menu-down`)
.trigger("mouseover")
.click();
cy.get(".nc-column-delete").click();
cy.get("button:contains(Confirm)").click();
cy.toastWait("Update table successful");
mainPage.deleteCreatedViews();
// close table
cy.closeTableTab("Country");
});
it(`Generate default Shared GRID view URL`, () => {
// add row
cy.get(".nc-add-new-row-btn").click({ force: true });
cy.get("#data-table-form-Country > input")
.first()
.click()
.type("a");
cy.contains("Save Row").filter("button").click({ force: true });
cy.toastWait("updated successfully");
// add column
mainPage.addColumn("dummy", "Country");
// visit public view
cy.log(viewURL["rowColUpdate"]);
cy.restoreLocalStorage();
cy.visit(viewURL["rowColUpdate"], {
baseUrl: null,
}); //5
// wait for public view page to load!
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 25);
});
it(`Share GRID view : new row visible`, () => {
// verify row
cy.get(`.v-pagination > li:contains('5') button`).click();
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage.getCell("Country", 10).contains("a").should("exist");
});
it.skip(`Share GRID view : new column visible`, () => { it.skip(`Share GRID view : new column visible`, () => {
// verify column headers // verify column headers
cy.get('[data-col="dummy"]').should("exist"); cy.get('[data-col="dummy"]').should("exist");
});
}); });
});
}; };
/** /**

471
scripts/cypress/integration/common/4f_pg_grid_view_share.js

@ -0,0 +1,471 @@
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { mainPage } from "../../support/page_objects/mainPage";
let storedURL = "";
// 0: all enabled
// 1: field hide
// 2: field sort
// 3: field filter
// 4: default (address table): for view operation validation
// 5: default (country table): for update row/column validation
let viewURL = {};
export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(apiType, dbType)) return;
const generateViewLink = (viewName) => {
// click on share view
// cy.get(".v-navigation-drawer__content > .container")
// .find(".v-list > .v-list-item")
// .contains("Share View")
// .click();
mainPage.shareView().click();
// wait, as URL initially will be /undefined
cy.getActiveModal()
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.should("exist");
// copy link text, visit URL
cy.getActiveModal()
.find(".share-link-box")
.contains("/nc/view/", { timeout: 10000 })
.then(($obj) => {
cy.get("body").type("{esc}");
// viewURL.push($obj.text())
viewURL[viewName] = $obj.text().trim();
});
};
describe(`${apiType.toUpperCase()} api - GRID view (Share)`, () => {
// Run once before test- create project (rest/graphql)
//
before(() => {
// open a table to work on views
//
cy.openTableTab("Address", 25);
cy.saveLocalStorage();
});
beforeEach(() => {
cy.restoreLocalStorage();
});
afterEach(() => {
cy.saveLocalStorage();
});
after(() => {
// close table
// mainPage.deleteCreatedViews()
cy.closeTableTab("Address");
});
// Common routine to create/edit/delete GRID & GALLERY view
// Input: viewType - 'grid'/'gallery'
//
const viewTest = (viewType) => {
it(`Create ${viewType.toUpperCase()} view`, () => {
// create a normal public view
cy.get(`.nc-create-${viewType}-view`).click();
cy.getActiveModal().find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
});
});
it(`Share ${viewType.toUpperCase()} hide, sort, filter & verify`, () => {
cy.get(`.nc-view-item.nc-${viewType}-view-item`)
.contains("Address1")
.click();
mainPage.hideField("Address2");
mainPage.sortField("Address", "Z -> A");
mainPage.filterField("Address", "is like", "Ab");
generateViewLink("combined");
cy.log(viewURL["combined"]);
});
it(`Share GRID view : ensure we have only one link even if shared multiple times`, () => {
// generate view link multiple times
generateViewLink("combined");
generateViewLink("combined");
// verify if only one link exists in table
// cy.get(".v-navigation-drawer__content > .container")
// .find(".v-list > .v-list-item")
// .contains("Share View")
// .parent()
// .find("button.mdi-dots-vertical")
// .click();
mainPage.shareViewList().click();
// cy.getActiveMenu().find(".v-list-item").contains("Views List").click();
cy.get('th:contains("View Link")').should("exist");
cy.get('th:contains("View Link")')
.parent()
.parent()
.next()
.find("tr")
.its("length")
.should("eq", 1)
.then(() => {
// cy.get(".v-overlay__content > .d-flex > .v-icon").click();
// close modal (fix me! add a close button to share view list modal)
cy.get(".v-overlay--active > .v-overlay__scrim").click({
force: true,
});
});
});
it(`Share ${viewType.toUpperCase()} view : Visit URL, Verify title`, () => {
// visit public view
cy.visit(viewURL["combined"], {
baseUrl: null,
});
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 18);
// verify title
cy.get("div.model-name").contains("Address1").should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields hidden/open`, () => {
// verify column headers
cy.get('[data-col="Address"]').should("exist");
cy.get('[data-col="Address2"]').should("not.exist");
cy.get('[data-col="District"]').should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify fields sort/ filter`, () => {
// country column content verification before sort
mainPage
.getCell("Address", 1)
.contains("669 Firozabad Loop")
.should("exist");
mainPage
.getCell("Address", 2)
.contains("48 Maracabo Place")
.should("exist");
mainPage
.getCell("Address", 3)
.contains("44 Najafabad Way")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone`,
`669 Firozabad Loop,,92265,,[object Object],2,,Kanchrapara,`,
`48 Maracabo Place,,1570,,[object Object],2,,Tafuna,`,
`44 Najafabad Way,,61391,,[object Object],2,,Tambaram,`,
`381 Kabul Way,,87272,,[object Object],1,,Pudukkottai,`,
];
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
expect(strCol[0]).to.be.equal(retCol[0]);
expect(strCol[2]).to.be.equal(retCol[2]);
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
}
};
// download & verify
mainPage.downloadAndVerifyCsv(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Disable sort`, () => {
// remove sort and validate
mainPage.clearSort();
mainPage
.getCell("Address", 1)
.contains("217 Botshabelo Place")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Enable sort`, () => {
// Sort menu operations (Country Column, Z->A)
mainPage.sortField("Address", "Z -> A");
mainPage
.getCell("Address", 1)
.contains("669 Firozabad Loop")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : Create Filter`, () => {
// add filter & validate
mainPage.filterField("Address", "is like", "drive");
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 3);
mainPage
.getCell("Address", 1)
.contains("1888 Kabul Drive")
.should("exist");
});
it(`Share ${viewType.toUpperCase()} view : verify download CSV after local filter`, () => {
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`Address,District,PostalCode,Phone,Location,Address => Customer,Address => Staff,City <= Address,Address <=> Staff`,
`1888 Kabul Drive,,20936,,1,,Ife,,`,
`1661 Abha Drive,,14400,,1,,Pudukkottai,,`,
];
// for (let i = 0; i < storedRecords.length; i++) {
// expect(retrievedRecords[i]).to.be.equal(storedRecords[i])
// }
for (let i = 0; i < storedRecords.length; i++) {
let strCol = storedRecords[i].split(",");
let retCol = retrievedRecords[i].split(",");
expect(strCol[0]).to.be.equal(retCol[0]);
expect(strCol[2]).to.be.equal(retCol[2]);
}
};
mainPage.downloadAndVerifyCsv(
`Address_exported_1.csv`,
verifyCsv
);
mainPage.unhideField("LastUpdate");
});
it(`Share ${viewType.toUpperCase()} view : Delete Filter`, () => {
// Remove sort and Validate
mainPage.filterReset();
mainPage
.getCell("Address", 1)
.contains("669 Firozabad Loop")
.should("exist");
});
it(`Share GRID view : Virtual column validation > has many`, () => {
// verify column headers
cy.get('[data-col="Address => Customer"]').should("exist");
cy.get('[data-col="Address => Staff"]').should("exist");
cy.get('[data-col="City <= Address"]').should("exist");
cy.get('[data-col="Address <=> Staff"]').should("exist");
// has many field validation
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-plus")
.should("not.exist");
mainPage
.getCell("Address => Customer", 3)
.click()
.find("button.mdi-arrow-expand")
.click();
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find("button")
.contains("Link to")
.should("not.exist");
cy.getActiveModal()
.find(".child-card")
.contains("2")
.should("exist");
cy.getActiveModal()
.find(".child-card")
.find("button")
.should("not.exist");
cy.get("body").type("{esc}");
});
it(`Share GRID view : Virtual column validation > belongs to`, () => {
// belongs to field validation
mainPage
.getCell("City <= Address", 1)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("City <= Address", 1)
.click()
.find("button.mdi-arrow-expand")
.should("not.exist");
mainPage
.getCell("City <= Address", 1)
.find(".v-chip")
.contains("al-Ayn")
.should("exist");
});
it(`Share GRID view : Virtual column validation > many to many`, () => {
// many-to-many field validation
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-close-thick")
.should("not.exist");
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-plus")
.should("not.exist");
mainPage
.getCell("Address <=> Staff", 1)
.click()
.find("button.mdi-arrow-expand")
.click();
cy.getActiveModal().find("button.mdi-reload").should("exist");
cy.getActiveModal()
.find("button")
.contains("Link to")
.should("not.exist");
cy.get("body").type("{esc}");
});
it(`Delete ${viewType.toUpperCase()} view`, () => {
// go back to base page
cy.visit(storedURL, {
baseUrl: null,
});
// number of view entries should be 2 before we delete
cy.get(".nc-view-item").its("length").should("eq", 2);
cy.get(".nc-view-delete-icon").eq(0).click({ force: true });
cy.toastWait("View deleted successfully");
// confirm if the number of veiw entries is reduced by 1
cy.get(".nc-view-item").its("length").should("eq", 1);
});
};
// below scenario's will be invoked twice, once for rest & then for graphql
viewTest("grid");
});
describe(`${apiType.toUpperCase()} api - Grid view/ row-column update verification`, () => {
before(() => {
// Address table has belongs to, has many & many-to-many
cy.openTableTab("Country", 25);
cy.saveLocalStorage();
// store base URL- to re-visit and delete form view later
cy.url().then((url) => {
storedURL = url;
generateViewLink("rowColUpdate");
});
});
after(() => {
// close table
cy.restoreLocalStorage();
cy.visit(storedURL, {
baseUrl: null,
});
// delete row
mainPage.getPagination(5).click();
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage
.getRow(10)
.find(".mdi-checkbox-blank-outline")
.click({ force: true });
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu().contains("Delete Selected Row").click();
// delete column
cy.get(`th:contains('dummy') .mdi-menu-down`)
.trigger("mouseover")
.click();
cy.get(".nc-column-delete").click();
cy.get("button:contains(Confirm)").click();
cy.toastWait("Update table successful");
mainPage.deleteCreatedViews();
// close table
cy.closeTableTab("Country");
});
it(`Generate default Shared GRID view URL`, () => {
// add row
cy.get(".nc-add-new-row-btn").click({ force: true });
cy.get("#data-table-form-Country > input")
.first()
.click()
.type("a");
cy.contains("Save Row").filter("button").click({ force: true });
cy.toastWait("updated successfully");
// add column
mainPage.addColumn("dummy", "Country");
// visit public view
cy.log(viewURL["rowColUpdate"]);
cy.restoreLocalStorage();
cy.visit(viewURL["rowColUpdate"], {
baseUrl: null,
}); //5
// wait for public view page to load!
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 25);
});
it(`Share GRID view : new row visible`, () => {
// verify row
cy.get(`.v-pagination > li:contains('5') button`).click();
// wait for page rendering to complete
cy.get(".nc-grid-row").should("have.length", 10);
mainPage.getCell("Country", 10).contains("a").should("exist");
});
it.skip(`Share GRID view : new column visible`, () => {
// verify column headers
cy.get('[data-col="dummy"]').should("exist");
});
});
};
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Pranav C Balan <pranavxc@gmail.com>
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

396
scripts/cypress/integration/common/5a_user_role.js

@ -1,205 +1,229 @@
import { loginPage, projectsPage } from "../../support/page_objects/navigation"; import { loginPage, projectsPage } from "../../support/page_objects/navigation";
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
import { import {
roles, isPostgres,
staticProjects, roles,
staticProjects,
} from "../../support/page_objects/projectConstants"; } from "../../support/page_objects/projectConstants";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { import {
_advSettings, _advSettings,
_editSchema, _editSchema,
_editData, _editData,
_editComment, _editComment,
_viewMenu, _viewMenu,
_topRightMenu, _topRightMenu,
disableTableAccess, disableTableAccess,
_accessControl, _accessControl,
} from "../spec/roleValidation.spec"; } from "../spec/roleValidation.spec";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe("Static user creations (different roles)", () => { describe("Static user creations (different roles)", () => {
// beforeEach(() => { before(() => {
// loginPage.signIn(roles.owner.credentials) mainPage.navigationDraw(mainPage.TEAM_N_AUTH).click();
// projectsPage.openProject(getPrimarySuite().basic.name)
// })
before(() => {
mainPage.navigationDraw(mainPage.TEAM_N_AUTH).click();
});
const addUser = (user) => {
it(`RoleType: ${user.name}`, () => {
// for first project, users need to be added explicitly using "New User" button
// for subsequent projects, they will be required to just add to this project
// using ROW count to identify if its former or latter scenario
// 5 users (owner, creator, editor, viewer, commenter) + row header = 6
cy.get(`tr`).then((obj) => {
cy.log(obj.length);
if (obj.length == 6) {
mainPage.addExistingUserToProject(
user.credentials.username,
user.name
);
} else {
mainPage.addNewUserToProject(user.credentials, user.name);
}
});
});
};
addUser(roles.creator);
addUser(roles.editor);
addUser(roles.commenter);
addUser(roles.viewer);
// Access contrl list- configuration
//
it(`Access control list- configuration`, () => {
// open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
// validate if it has 19 entries representing tables & views
cy.get(".nc-acl-table-row").should("have.length", 19);
// disable table & view access
//
disableTableAccess("language", "editor");
disableTableAccess("language", "commenter");
disableTableAccess("language", "viewer");
disableTableAccess("customerlist", "editor");
disableTableAccess("customerlist", "commenter");
disableTableAccess("customerlist", "viewer");
});
});
const roleValidation = (roleType) => {
describe(`User role validation`, () => {
if (roleType != "owner") {
it(`[${roles[roleType].name}] SignIn, Open project`, () => {
cy.log(mainPage.roleURL[roleType]);
cy.visit(mainPage.roleURL[roleType], {
baseUrl: null,
});
// Redirected to new URL, feed details
//
cy.get('input[type="text"]')
.should("exist")
.type(roles[roleType].credentials.username);
cy.get('input[type="password"]').type(
roles[roleType].credentials.password
);
cy.get('button:contains("SIGN")').click();
cy.url({ timeout: 6000 }).should("contain", "#/project");
if (xcdb) {
if ("rest" == type)
projectsPage.openProject(staticProjects.sampleREST.basic.name);
else projectsPage.openProject(staticProjects.sampleGQL.basic.name);
} else {
if ("rest" == type)
projectsPage.openProject(staticProjects.externalREST.basic.name);
else
projectsPage.openProject(staticProjects.externalGQL.basic.name);
}
if (roleType != "creator") {
cy.closeTableTab("Actor");
}
}); });
}
///////////////////////////////////////////////////////
// Test suite
it(`[${roles[roleType].name}] Left navigation menu, New User add`, () => { const addUser = (user) => {
// project configuration settings it(`RoleType: ${user.name}`, () => {
// // for first project, users need to be added explicitly using "New User" button
_advSettings(roleType, false); // for subsequent projects, they will be required to just add to this project
}); // using ROW count to identify if its former or latter scenario
// 5 users (owner, creator, editor, viewer, commenter) + row header = 6
it(`[${roles[roleType].name}] Access control`, () => { cy.get(`tr`).then((obj) => {
// Access control validation cy.log(obj.length);
// if (obj.length == 6) {
_accessControl(roleType, false); mainPage.addExistingUserToProject(
}); user.credentials.username,
user.name
);
} else {
mainPage.addNewUserToProject(
user.credentials,
user.name
);
}
});
});
};
it(`[${roles[roleType].name}] Schema: create table, add/modify/delete column`, () => { addUser(roles.creator);
// Schema related validations addUser(roles.editor);
// - Add/delete table addUser(roles.commenter);
// - Add/Update/delete column addUser(roles.viewer);
//
_editSchema(roleType, false);
});
it(`[${roles[roleType].name}] Data: add/modify/delete row, update cell contents`, () => { // Access contrl list- configuration
// Table data related validations
// - Add/delete/modify row
// //
_editData(roleType, false); it(`Access control list- configuration`, () => {
}); // open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
cy.snip("Meta_Tab3");
// validate if it has 19 entries representing tables & views
if (isPostgres())
cy.get(".nc-acl-table-row").should("have.length", 24);
else cy.get(".nc-acl-table-row").should("have.length", 19);
// disable table & view access
//
disableTableAccess("language", "editor");
disableTableAccess("language", "commenter");
disableTableAccess("language", "viewer");
disableTableAccess("customerlist", "editor");
disableTableAccess("customerlist", "commenter");
disableTableAccess("customerlist", "viewer");
});
});
it(`[${roles[roleType].name}] Comments: view/add`, () => { const roleValidation = (roleType) => {
// read &/ update comment describe(`User role validation`, () => {
// Viewer: only allowed to read if (roleType != "owner") {
// Everyone else: read &/ update it(`[${roles[roleType].name}] SignIn, Open project`, () => {
// cy.log(mainPage.roleURL[roleType]);
if (roleType != "viewer") _editComment(roleType, false); cy.visit(mainPage.roleURL[roleType], {
}); baseUrl: null,
});
it(`[${roles[roleType].name}] Right navigation menu, share view`, () => {
// right navigation menu bar // Redirected to new URL, feed details
// Editor/Viewer/Commenter : can only view 'existing' views //
// Rest: can create/edit cy.get('input[type="text"]')
_viewMenu(roleType, false); .should("exist")
}); .type(roles[roleType].credentials.username);
cy.get('input[type="password"]').type(
it(`[${roles[roleType].name}] Top Right Menu bar`, () => { roles[roleType].credentials.password
// Share button is conditional );
// Rest are static/ mandatory cy.get('button:contains("SIGN")').click();
//
_topRightMenu(roleType, false); cy.url({ timeout: 6000 }).should("contain", "#/project");
});
if (dbType === "xcdb") {
it(`[${roles[roleType].name}] Download files`, () => { if ("rest" == apiType)
// #ID, City, LastUpdate, City => Address, Country <= City, + projectsPage.openProject(
mainPage.hideField("LastUpdate"); staticProjects.sampleREST.basic.name
);
const verifyCsv = (retrievedRecords) => { else
// expected output, statically configured projectsPage.openProject(
let storedRecords = [ staticProjects.sampleGQL.basic.name
`City,City => Address,Country <= City`, );
`A Corua (La Corua),939 Probolinggo Loop,Spain`, } else if (dbType === "mysql") {
`Abha,733 Mandaluyong Place,Saudi Arabia`, if ("rest" == apiType)
`Abu Dhabi,535 Ahmadnagar Manor,United Arab Emirates`, projectsPage.openProject(
`Acua,1789 Saint-Denis Parkway,Mexico`, staticProjects.externalREST.basic.name
]; );
else
for (let i = 0; i < storedRecords.length; i++) { projectsPage.openProject(
// cy.log(retrievedRecords[i]) staticProjects.externalGQL.basic.name
expect(retrievedRecords[i]).to.be.equal(storedRecords[i]); );
} } else if (dbType === "postgres") {
}; if ("rest" == apiType)
projectsPage.openProject(
staticProjects.pgExternalREST.basic.name
);
else
projectsPage.openProject(
staticProjects.pgExternalGQL.basic.name
);
}
if (roleType != "creator") {
cy.closeTableTab("Actor");
}
});
}
///////////////////////////////////////////////////////
// Test suite
it(`[${roles[roleType].name}] Left navigation menu, New User add`, () => {
// project configuration settings
//
_advSettings(roleType, false);
});
it(`[${roles[roleType].name}] Access control`, () => {
// Access control validation
//
_accessControl(roleType, false);
});
it(`[${roles[roleType].name}] Schema: create table, add/modify/delete column`, () => {
// Schema related validations
// - Add/delete table
// - Add/Update/delete column
//
_editSchema(roleType, false);
});
it(`[${roles[roleType].name}] Data: add/modify/delete row, update cell contents`, () => {
// Table data related validations
// - Add/delete/modify row
//
_editData(roleType, false);
});
it(`[${roles[roleType].name}] Comments: view/add`, () => {
// read &/ update comment
// Viewer: only allowed to read
// Everyone else: read &/ update
//
if (roleType != "viewer") _editComment(roleType, false);
});
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, false);
});
it(`[${roles[roleType].name}] Top Right Menu bar`, () => {
// Share button is conditional
// Rest are static/ mandatory
//
_topRightMenu(roleType, false);
});
it(`[${roles[roleType].name}] Download files`, () => {
// #ID, City, LastUpdate, City => Address, Country <= City, +
mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => {
// expected output, statically configured
let storedRecords = [
`City,City => Address,Country <= City`,
`A Corua (La Corua),939 Probolinggo Loop,Spain`,
`Abha,733 Mandaluyong Place,Saudi Arabia`,
`Abu Dhabi,535 Ahmadnagar Manor,United Arab Emirates`,
`Acua,1789 Saint-Denis Parkway,Mexico`,
];
for (let i = 0; i < storedRecords.length; i++) {
// cy.log(retrievedRecords[i])
expect(retrievedRecords[i]).to.be.equal(
storedRecords[i]
);
}
};
// download & verify
mainPage.downloadAndVerifyCsv(`City_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate");
});
});
};
// download & verify // skip owner validation as rest of the cases pretty much cover the same
mainPage.downloadAndVerifyCsv(`City_exported_1.csv`, verifyCsv); // roleValidation('owner')
mainPage.unhideField("LastUpdate"); roleValidation("creator");
}); roleValidation("editor");
}); roleValidation("commenter");
}; roleValidation("viewer");
// skip owner validation as rest of the cases pretty much cover the same
// roleValidation('owner')
roleValidation("creator");
roleValidation("editor");
roleValidation("commenter");
roleValidation("viewer");
}; };
/** /**

234
scripts/cypress/integration/common/5b_preview_role.js

@ -4,123 +4,131 @@
import { loginPage, projectsPage } from "../../support/page_objects/navigation"; import { loginPage, projectsPage } from "../../support/page_objects/navigation";
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { import {
_advSettings, isPostgres,
_editSchema, isTestSuiteActive,
_editData, } from "../../support/page_objects/projectConstants";
_editComment, import {
_viewMenu, _advSettings,
_topRightMenu, _editSchema,
enableTableAccess, _editData,
_accessControl, _editComment,
_viewMenu,
_topRightMenu,
enableTableAccess,
_accessControl,
} from "../spec/roleValidation.spec"; } from "../spec/roleValidation.spec";
export const genTest = (type, xcdb, roleType) => { export const genTest = (apiType, dbType, roleType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
//// Test Suite //// Test Suite
describe("Role preview validations", () => { describe("Role preview validations", () => {
// Sign in/ open project // Sign in/ open project
before(() => { before(() => {
loginPage.loginAndOpenProject(type, xcdb); loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("City", 25); cy.openTableTab("City", 25);
});
after(() => {
cy.get(".nc-preview-reset").click({ force: true });
// cy.wait(20000)
// wait for page rendering to complete
cy.get(".nc-grid-row", { timeout: 25000 }).should(
"have.length",
25
);
// cy.get('.nc-preview-reset:visible').should('not-exist')
// mainPage.navigationDraw(mainPage.ROLE_VIEW).contains('Reset Preview').should('not.exist')
// cy.get('.nc-preview-reset').should('not-exist')
cy.closeTableTab("City");
// open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
// validate if it has 19 entries representing tables & views
if (isPostgres())
cy.get(".nc-acl-table-row").should("have.length", 24);
else cy.get(".nc-acl-table-row").should("have.length", 19);
// restore access
//
enableTableAccess("language", "editor");
enableTableAccess("language", "commenter");
enableTableAccess("language", "viewer");
enableTableAccess("customerlist", "editor");
enableTableAccess("customerlist", "commenter");
enableTableAccess("customerlist", "viewer");
});
const genTestSub = (roleType) => {
it(`Role preview: ${roleType}: Enable preview`, () => {
cy.get(`.nc-preview-${roleType}`).click();
});
it(`Role preview: ${roleType}: Advance settings`, () => {
// project configuration settings
//
_advSettings(roleType, true);
});
it(`Role preview: ${roleType}: Access control`, () => {
// Access control validation
//
_accessControl(roleType, false);
});
it(`Role preview: ${roleType}: Edit data`, () => {
// Table data related validations
// - Add/delete/modify row
//
_editData(roleType, true);
});
it(`Role preview: ${roleType}: Edit comment`, () => {
// read &/ update comment
// Viewer: not allowed to read
// Everyone else: read &/ update
//
_editComment(roleType, true);
});
it(`Role preview: ${roleType}: Preview menu`, () => {
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
_viewMenu(roleType, true);
});
it(`Role preview: ${roleType}: Top Right Menu bar`, () => {
// Share button is conditional
// Rest are static/ mandatory
//
_topRightMenu(roleType, false);
});
it(`Role preview: ${roleType}: Edit Schema`, () => {
// Schema related validations
// - Add/delete table
// - Add/Update/delete column
//
_editSchema(roleType, true);
});
};
genTestSub("editor");
genTestSub("commenter");
genTestSub("viewer");
}); });
after(() => {
cy.get(".nc-preview-reset").click({ force: true });
// cy.wait(20000)
// wait for page rendering to complete
cy.get(".nc-grid-row", { timeout: 25000 }).should("have.length", 25);
// cy.get('.nc-preview-reset:visible').should('not-exist')
// mainPage.navigationDraw(mainPage.ROLE_VIEW).contains('Reset Preview').should('not.exist')
// cy.get('.nc-preview-reset').should('not-exist')
cy.closeTableTab("City");
// open Project metadata tab
//
mainPage.navigationDraw(mainPage.PROJ_METADATA).click();
cy.get(".nc-exp-imp-metadata").dblclick({ force: true });
cy.get(".nc-ui-acl-tab").click({ force: true });
// validate if it has 19 entries representing tables & views
cy.get(".nc-acl-table-row").should("have.length", 19);
// restore access
//
enableTableAccess("language", "editor");
enableTableAccess("language", "commenter");
enableTableAccess("language", "viewer");
enableTableAccess("customerlist", "editor");
enableTableAccess("customerlist", "commenter");
enableTableAccess("customerlist", "viewer");
});
const genTestSub = (roleType) => {
it(`Role preview: ${roleType}: Enable preview`, () => {
cy.get(`.nc-preview-${roleType}`).click();
});
it(`Role preview: ${roleType}: Advance settings`, () => {
// project configuration settings
//
_advSettings(roleType, true);
});
it(`Role preview: ${roleType}: Access control`, () => {
// Access control validation
//
_accessControl(roleType, false);
});
it(`Role preview: ${roleType}: Edit data`, () => {
// Table data related validations
// - Add/delete/modify row
//
_editData(roleType, true);
});
it(`Role preview: ${roleType}: Edit comment`, () => {
// read &/ update comment
// Viewer: not allowed to read
// Everyone else: read &/ update
//
_editComment(roleType, true);
});
it(`Role preview: ${roleType}: Preview menu`, () => {
// right navigation menu bar
// Editor/Viewer/Commenter : can only view 'existing' views
// Rest: can create/edit
_viewMenu(roleType, true);
});
it(`Role preview: ${roleType}: Top Right Menu bar`, () => {
// Share button is conditional
// Rest are static/ mandatory
//
_topRightMenu(roleType, false);
});
it(`Role preview: ${roleType}: Edit Schema`, () => {
// Schema related validations
// - Add/delete table
// - Add/Update/delete column
//
_editSchema(roleType, true);
});
};
genTestSub("editor");
genTestSub("commenter");
genTestSub("viewer");
});
}; };
/** /**

62
scripts/cypress/integration/common/6b_downloadCsv.js

@ -2,44 +2,42 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation"; import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} Upload/ Download CSV`, () => { describe(`${apiType.toUpperCase()} Upload/ Download CSV`, () => {
before(() => { before(() => {
// loginPage.loginAndOpenProject(type) // loginPage.loginAndOpenProject(type)
cy.openTableTab("Country", 25); cy.openTableTab("Country", 25);
cy.screenshot("6b-before"); });
});
after(() => { after(() => {
cy.closeTableTab("Country"); cy.closeTableTab("Country");
cy.screenshot('6b-after') });
});
it("Download verification- base view, default columns", () => { it("Download verification- base view, default columns", () => {
mainPage.hideField("LastUpdate"); mainPage.hideField("LastUpdate");
const verifyCsv = (retrievedRecords) => { const verifyCsv = (retrievedRecords) => {
// expected output, statically configured // expected output, statically configured
let storedRecords = [ let storedRecords = [
`Country,Country => City`, `Country,Country => City`,
`Afghanistan,Kabul`, `Afghanistan,Kabul`,
`Algeria,"Batna,Bchar,Skikda"`, `Algeria,"Batna,Bchar,Skikda"`,
`American Samoa,Tafuna`, `American Samoa,Tafuna`,
`Angola,"Benguela,Namibe"`, `Angola,"Benguela,Namibe"`,
]; ];
for (let i = 0; i < storedRecords.length; i++) { for (let i = 0; i < storedRecords.length - 1; i++) {
cy.log(retrievedRecords[i]); cy.log(retrievedRecords[i]);
expect(retrievedRecords[i]).to.be.equal(storedRecords[i]); expect(retrievedRecords[i]).to.be.equal(storedRecords[i]);
} }
}; };
// download & verify // download & verify
mainPage.downloadAndVerifyCsv(`Country_exported_1.csv`, verifyCsv); mainPage.downloadAndVerifyCsv(`Country_exported_1.csv`, verifyCsv);
mainPage.unhideField("LastUpdate"); mainPage.unhideField("LastUpdate");
});
}); });
});
}; };
/** /**

452
scripts/cypress/integration/common/6c_swagger_api.js

@ -3,225 +3,249 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { roles } from "../../support/page_objects/projectConstants"; import { roles } from "../../support/page_objects/projectConstants";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} : API List - Test preparation`, () => { describe(`${apiType.toUpperCase()} : API List - Test preparation`, () => {
before(() => { before(() => {
loginPage.loginAndOpenProject(type, xcdb); loginPage.loginAndOpenProject(apiType, dbType);
}); });
it("Open project & record swagger URL, AuthToken", () => { it("Open project & record swagger URL, AuthToken", () => {
let authToken = mainPage.getAuthToken(); let authToken = mainPage.getAuthToken();
cy.url().then((url) => { cy.url().then((url) => {
// retrieve project name from URL & use it to construct Swagger URL // retrieve project name from URL & use it to construct Swagger URL
// URL on homepage: http://localhost:3000/#/nc/externalrest_weUO?type=roles&dbalias=&name=Team%20%26%20Auth%20 // URL on homepage: http://localhost:3000/#/nc/externalrest_weUO?type=roles&dbalias=&name=Team%20%26%20Auth%20
// [REST] Swagger URL: http://localhost:8080/nc/externalrest_weUO/db/swagger // [REST] Swagger URL: http://localhost:8080/nc/externalrest_weUO/db/swagger
// [GQL] http://localhost:8080/nc/externalgql_dgwx/v1/graphql // [GQL] http://localhost:8080/nc/externalgql_dgwx/v1/graphql
const projectName = url.split("/")[5].split("?")[0]; const projectName = url.split("/")[5].split("?")[0];
let swaggerURL = ``; let swaggerURL = ``;
if ("rest" == type) { if ("rest" == apiType) {
swaggerURL = `http://localhost:8080/nc/${projectName}/db/swagger`; swaggerURL = `http://localhost:8080/nc/${projectName}/db/swagger`;
} else { } else {
swaggerURL = `http://localhost:8080/nc/${projectName}/v1/graphql`; swaggerURL = `http://localhost:8080/nc/${projectName}/v1/graphql`;
} }
// exchange information between two tests using a file // exchange information between two tests using a file
// https://stackoverflow.com/questions/52050657/what-is-the-best-practice-of-pass-states-between-tests-in-cypress // https://stackoverflow.com/questions/52050657/what-is-the-best-practice-of-pass-states-between-tests-in-cypress
// //
cy.writeFile("shared.json", { cy.writeFile("shared.json", {
SWAGGER_URL: swaggerURL, SWAGGER_URL: swaggerURL,
AUTH_TOKEN: authToken, AUTH_TOKEN: authToken,
});
});
}); });
});
}); });
});
if ("rest" == apiType) {
if ("rest" == type) { describe(`Swagger page, base verification`, () => {
describe(`Swagger page, base verification`, () => { // returns swagger button intended for
// returns swagger button intended for //
// const getSwaggerButton = (tag, idx, desc) => {
const getSwaggerButton = (tag, idx, desc) => { return cy
return cy .get(`#operations-tag-${tag}`)
.get(`#operations-tag-${tag}`) .next()
.next() .find(".opblock")
.find(".opblock") .eq(idx)
.eq(idx) .find(`button:contains(${desc})`);
.find(`button:contains(${desc})`); };
};
let Token;
let Token;
// basic authentication tag verification
// basic authentication tag verification //
// it("Swagger URL access & basic validation", () => {
it("Swagger URL access & basic validation", () => { // retrieve information stored in previous IT block
// retrieve information stored in previous IT block //
// cy.readFile("shared.json").then((jsonPayload) => {
cy.readFile("shared.json").then((jsonPayload) => { let URL = jsonPayload.SWAGGER_URL;
let URL = jsonPayload.SWAGGER_URL; Token = jsonPayload.AUTH_TOKEN;
Token = jsonPayload.AUTH_TOKEN;
cy.visit(URL, {
cy.visit(URL, { baseUrl: null,
baseUrl: null, }).then(() => {
}).then(() => { // wait to allow time for SWAGGER Library loading to finish
// wait to allow time for SWAGGER Library loading to finish cy.log(Token);
cy.log(Token);
// cy.snip("Swagger");
// validate; API order assumed
cy.get("#operations-tag-Authentication", { timeout: 20000 }) // validate; API order assumed
.should("exist") cy.get("#operations-tag-Authentication", {
.next() timeout: 20000,
.find(".opblock") })
.should("has.length", 9); .should("exist")
getSwaggerButton("Authentication", 0, "User login").should("exist"); .next()
getSwaggerButton("Authentication", 1, "User signup").should( .find(".opblock")
"exist" .should("has.length", 9);
); getSwaggerButton(
getSwaggerButton("Authentication", 2, "Password Forgot").should( "Authentication",
"exist" 0,
); "User login"
getSwaggerButton("Authentication", 3, "Email validate link").should( ).should("exist");
"exist" getSwaggerButton(
); "Authentication",
getSwaggerButton( 1,
"Authentication", "User signup"
4, ).should("exist");
"Validate password reset token" getSwaggerButton(
).should("exist"); "Authentication",
getSwaggerButton("Authentication", 5, "Password reset").should( 2,
"exist" "Password Forgot"
); ).should("exist");
getSwaggerButton("Authentication", 6, "User details").should( getSwaggerButton(
"exist" "Authentication",
); 3,
getSwaggerButton("Authentication", 7, "Update user details").should( "Email validate link"
"exist" ).should("exist");
); getSwaggerButton(
getSwaggerButton("Authentication", 8, "Update user details").should( "Authentication",
"exist" 4,
); "Validate password reset token"
}); ).should("exist");
getSwaggerButton(
"Authentication",
5,
"Password reset"
).should("exist");
getSwaggerButton(
"Authentication",
6,
"User details"
).should("exist");
getSwaggerButton(
"Authentication",
7,
"Update user details"
).should("exist");
getSwaggerButton(
"Authentication",
8,
"Update user details"
).should("exist");
});
});
});
it("Authorize success: Valid token", () => {
// authorize button, feed token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type(Token);
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should exist on DOM
cy.get(".auth-container")
.contains("Authorized")
.should("exist");
cy.get(".btn-done").click();
// Authorize button is LOCKED now
cy.get('[class="btn authorize locked"]').should("exist");
});
it("Execute Authentication (valid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: validate email credentials
cy.get(".highlight-code > .microlight")
.contains("email")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Logout post authorization", () => {
// authorize button, logout
cy.get('[class="btn authorize locked"]').click();
cy.get('.auth-btn-wrapper > button:contains("Logout")').click();
cy.get(".btn-done").click();
// Authorize button is UNLOCKED now
cy.get('[class="btn authorize unlocked"]').should("exist");
});
it("Execute Authentication (logout case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Authorize failure: invalid token", () => {
// authorize button, feed *invalid* token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type("xyz");
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should *not* exist on DOM
// TBD: cy.get('.auth-container').contains('Authorized').should('not.exist')
cy.get(".btn-done").click();
// Authorize button should be UNLOCKED now
// TBD: cy.get('[class="btn authorize unlocked"]').should('exist')
});
it("Execute Authentication (invalid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
// clean-up created file (shared.json)
// after(() => {
// cy.exec("del shared.json").then(()=> {
// cy.log("file cleaned up!")
// })
// })
}); });
}); }
it("Authorize success: Valid token", () => {
// authorize button, feed token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type(Token);
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should exist on DOM
cy.get(".auth-container").contains("Authorized").should("exist");
cy.get(".btn-done").click();
// Authorize button is LOCKED now
cy.get('[class="btn authorize locked"]').should("exist");
});
it("Execute Authentication (valid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: validate email credentials
cy.get(".highlight-code > .microlight")
.contains("email")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Logout post authorization", () => {
// authorize button, logout
cy.get('[class="btn authorize locked"]').click();
cy.get('.auth-btn-wrapper > button:contains("Logout")').click();
cy.get(".btn-done").click();
// Authorize button is UNLOCKED now
cy.get('[class="btn authorize unlocked"]').should("exist");
});
it("Execute Authentication (logout case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
it("Authorize failure: invalid token", () => {
// authorize button, feed *invalid* token, click authorize
cy.get('[class="btn authorize unlocked"]').click();
cy.get("input").type("xyz");
cy.get(".auth-btn-wrapper > .authorize").click();
// Response: "Authorized" should *not* exist on DOM
// TBD: cy.get('.auth-container').contains('Authorized').should('not.exist')
cy.get(".btn-done").click();
// Authorize button should be UNLOCKED now
// TBD: cy.get('[class="btn authorize unlocked"]').should('exist')
});
it("Execute Authentication (invalid token case) > GET: User details API", () => {
// Auth> User details API
getSwaggerButton("Authentication", 6, "User details").click();
// "Try it out" button, followed by "Execute"
cy.get(".try-out > .btn").click();
cy.get(".execute-wrapper > .btn").click();
// check response: email credentials shouldnt exist. should display 'guest:true'
cy.get(".highlight-code > .microlight")
.contains("guest")
.should("exist");
cy.get(".highlight-code > .microlight")
.contains("email")
.should("not.exist");
cy.get(".highlight-code > .microlight")
.contains(roles.owner.credentials.username)
.should("not.exist");
// reset operations (clear, cancel, windback User details tab)
cy.get(".btn-clear").click();
cy.get(".try-out > .btn").click();
getSwaggerButton("Authentication", 6, "User details").click();
});
// clean-up created file (shared.json)
// after(() => {
// cy.exec("del shared.json").then(()=> {
// cy.log("file cleaned up!")
// })
// })
});
}
}; };
/** /**

11
scripts/cypress/integration/common/6d_language_validation.js

@ -3,13 +3,13 @@ const { loginPage } = require("../../support/page_objects/navigation");
const { roles } = require("../../support/page_objects/projectConstants"); const { roles } = require("../../support/page_objects/projectConstants");
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`Language support`, () => { describe(`Language support`, () => {
before(() => { before(() => {
//loginPage.signIn(roles.owner.credentials) //loginPage.signIn(roles.owner.credentials)
mainPage.toolBarTopLeft(mainPage.HOME).click(); mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.screenshot("6d-1"); cy.screenshot("Debug 6d-1", { overwrite: true });
}); });
const langVerification = (idx, lang) => { const langVerification = (idx, lang) => {
@ -19,9 +19,12 @@ export const genTest = (type, xcdb) => {
// toggle menu as per index // toggle menu as per index
cy.get(".nc-menu-translate").click(); cy.get(".nc-menu-translate").click();
cy.snipActiveMenu("Menu_Translation");
cy.getActiveMenu().find(".v-list-item").eq(idx).click(); cy.getActiveMenu().find(".v-list-item").eq(idx).click();
cy.screenshot("6d-2"); cy.screenshot("Debug 6d-2", { overwrite: true });
// basic validations // basic validations
// 1. Page title: "My Projects" // 1. Page title: "My Projects"

117
scripts/cypress/integration/common/6e_project_operations.js

@ -2,70 +2,79 @@ import { loginPage } from "../../support/page_objects/navigation";
import { isXcdb, roles } from "../../support/page_objects/projectConstants"; import { isXcdb, roles } from "../../support/page_objects/projectConstants";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
describe(`${type.toUpperCase()} Project operations`, () => { describe(`${apiType.toUpperCase()} Project operations`, () => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
before(() => { before(() => {
loginPage.signIn(roles.owner.credentials); loginPage.signIn(roles.owner.credentials);
}); });
it("Stop Project", () => { it("Stop Project", () => {
//cy.visit('./#/projects') //cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-stop-circle-outline`, { cy.get(`.nc-${apiType}-project-row .mdi-stop-circle-outline`, {
timeout: 10000, timeout: 10000,
}) })
.should("exist") .should("exist")
.last() .last()
.invoke("show") .invoke("show")
.click(); .click();
cy.contains("Submit").closest("button").click(); cy.snipActiveModal("Modal_StopProject");
cy.contains("Submit").closest("button").click();
cy.toastWait("stopped successfully"); cy.toastWait("stopped successfully");
}); });
it("Start Project", () => { it("Start Project", () => {
//cy.visit('./#/projects') //cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-play-circle-outline`, { cy.get(`.nc-${apiType}-project-row .mdi-play-circle-outline`, {
timeout: 10000, timeout: 10000,
}) })
.should("exist") .should("exist")
.last() .last()
.invoke("show") .invoke("show")
.click(); .click();
cy.contains("Submit").closest("button").click(); cy.snipActiveModal("Modal_StartProject");
cy.toastWait("started successfully"); cy.contains("Submit").closest("button").click();
});
it("Restart Project", () => { cy.toastWait("started successfully");
if (!isXcdb()) { });
//cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-restart`, { timeout: 10000 })
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
cy.toastWait("restarted successfully"); it("Restart Project", () => {
} if (!isXcdb()) {
}); //cy.visit('./#/projects')
cy.get(`.nc-${apiType}-project-row .mdi-restart`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.snipActiveModal("Modal_RestartProject");
cy.contains("Submit").closest("button").click();
cy.toastWait("restarted successfully");
}
});
it("Delete Project", () => {
//cy.visit('./#/projects')
cy.get(`.nc-${apiType}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.snipActiveModal("Modal_DeleteProject");
it("Delete Project", () => { cy.contains("Submit").closest("button").click();
//cy.visit('./#/projects')
cy.get(`.nc-${type}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
cy.toastWait("deleted successfully"); cy.toastWait("deleted successfully");
});
}); });
});
}; };
/** /**

10
scripts/cypress/integration/common/6f_attachments.js

@ -2,12 +2,12 @@ import { mainPage } from "../../support/page_objects/mainPage";
import { loginPage } from "../../support/page_objects/navigation"; import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} Columns of type attachment`, () => { describe(`${apiType.toUpperCase()} Columns of type attachment`, () => {
before(() => { before(() => {
loginPage.loginAndOpenProject(type, xcdb); loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Country", 25); cy.openTableTab("Country", 25);
}); });
@ -91,7 +91,7 @@ export const genTest = (type, xcdb) => {
it(`Filter column which contain only attachments, download CSV`, () => { it(`Filter column which contain only attachments, download CSV`, () => {
// come back to main window // come back to main window
loginPage.loginAndOpenProject(type, xcdb); loginPage.loginAndOpenProject(apiType, dbType);
cy.openTableTab("Country", 25); cy.openTableTab("Country", 25);
mainPage.filterField("testAttach", "is not null", null); mainPage.filterField("testAttach", "is not null", null);

207
scripts/cypress/integration/common/6g_base_share.js

@ -3,75 +3,78 @@ import { projectsPage } from "../../support/page_objects/navigation";
import { loginPage } from "../../support/page_objects/navigation"; import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
import { import {
_advSettings, _advSettings,
_editSchema, _editSchema,
_editData, _editData,
_editComment, _editComment,
_viewMenu, _viewMenu,
_topRightMenu, _topRightMenu,
} from "../spec/roleValidation.spec"; } from "../spec/roleValidation.spec";
let linkText = ""; let linkText = "";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
const permissionValidation = (roleType) => { const permissionValidation = (roleType) => {
it(`${roleType}: Visit base shared URL`, () => { it(`${roleType}: Visit base shared URL`, () => {
cy.log(linkText); cy.log(linkText);
// visit URL & wait for page load to complete // visit URL & wait for page load to complete
cy.visit(linkText, { cy.visit(linkText, {
baseUrl: null, baseUrl: null,
}); });
projectsPage.waitHomePageLoad(); projectsPage.waitHomePageLoad();
cy.closeTableTab("Actor"); cy.closeTableTab("Actor");
}); });
it(`${roleType}: Validate access permissions: advance menu`, () => { it(`${roleType}: Validate access permissions: advance menu`, () => {
_advSettings(roleType, false); _advSettings(roleType, false);
}); });
it(`${roleType}: Validate access permissions: edit schema`, () => { it(`${roleType}: Validate access permissions: edit schema`, () => {
_editSchema(roleType, false); _editSchema(roleType, false);
}); });
it(`${roleType}: Validate access permissions: edit data`, () => { it(`${roleType}: Validate access permissions: edit data`, () => {
_editData(roleType, false); _editData(roleType, false);
}); });
it(`${roleType}: Validate access permissions: edit comments`, () => { it(`${roleType}: Validate access permissions: edit comments`, () => {
_editComment(roleType, false); _editComment(roleType, false);
}); });
it(`${roleType}: Validate access permissions: view's menu`, () => { it(`${roleType}: Validate access permissions: view's menu`, () => {
_viewMenu(roleType, false); _viewMenu(roleType, false);
}); });
}; };
describe(`${type.toUpperCase()} Base VIEW share`, () => { describe(`${apiType.toUpperCase()} Base VIEW share`, () => {
it(`Generate base share URL`, () => { it(`Generate base share URL`, () => {
// click SHARE // click SHARE
cy.get(".nc-topright-menu").find(".nc-menu-share").click(); cy.get(".nc-topright-menu").find(".nc-menu-share").click();
// Click on readonly base text cy.snipActiveModal("Modal_BaseShare");
cy.getActiveModal().find(".nc-disable-shared-base").click();
// Click on readonly base text
// Select 'Readonly link' cy.getActiveModal().find(".nc-disable-shared-base").click();
cy.getActiveMenu()
.find(".caption") // Select 'Readonly link'
.contains("Anyone with the link") cy.snipActiveMenu("Menu_ShareLink");
.click(); cy.getActiveMenu()
.find(".caption")
// Copy URL .contains("Anyone with the link")
cy.getActiveModal() .click();
.find(".nc-url")
.then(($obj) => { // Copy URL
cy.log($obj[0]); cy.getActiveModal()
linkText = $obj[0].innerText.trim(); .find(".nc-url")
.then(($obj) => {
const htmlFile = ` cy.log($obj[0]);
linkText = $obj[0].innerText.trim();
const htmlFile = `
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<body> <body>
@ -87,55 +90,63 @@ style="background: transparent; "></iframe>
</body> </body>
</html> </html>
`; `;
cy.writeFile( cy.writeFile(
"scripts/cypress/fixtures/sampleFiles/iFrame.html", "scripts/cypress/fixtures/sampleFiles/iFrame.html",
htmlFile htmlFile
); );
});
}); });
});
permissionValidation("viewer"); permissionValidation("viewer");
it("Update to EDITOR base share link", () => { it("Update to EDITOR base share link", () => {
loginPage.loginAndOpenProject(type, xcdb); loginPage.loginAndOpenProject(apiType, dbType);
// click SHARE // click SHARE
cy.get(".nc-topright-menu").find(".nc-menu-share").click(); cy.get(".nc-topright-menu").find(".nc-menu-share").click();
cy.getActiveModal().find(".nc-shared-base-role").click(); cy.getActiveModal().find(".nc-shared-base-role").click();
cy.getActiveMenu().find('[role="menuitem"]').contains("Editor").click(); cy.getActiveMenu()
}); .find('[role="menuitem"]')
.contains("Editor")
.click();
});
permissionValidation("editor"); permissionValidation("editor");
it("Generate & verify embed HTML IFrame", { baseUrl: null }, () => { it("Generate & verify embed HTML IFrame", { baseUrl: null }, () => {
// open iFrame html // open iFrame html
cy.visit("scripts/cypress/fixtures/sampleFiles/iFrame.html"); cy.visit("scripts/cypress/fixtures/sampleFiles/iFrame.html");
// wait for iFrame to load // wait for iFrame to load
cy.frameLoaded(".nc-embed"); cy.frameLoaded(".nc-embed");
// for GQL- additionally close GQL Client window // for GQL- additionally close GQL Client window
if (type === "graphql") { if (apiType === "graphql") {
cy.iframe().find(`[title="Graphql Client"] > button.mdi-close`).click(); cy.iframe()
} .find(`[title="Graphql Client"] > button.mdi-close`)
.click();
// validation for base menu opitons }
cy.iframe().find(".nc-project-tree").should("exist");
cy.iframe().find(".nc-fields-menu-btn").should("exist"); // validation for base menu opitons
cy.iframe().find(".nc-sort-menu-btn").should("exist"); cy.iframe().find(".nc-project-tree").should("exist");
cy.iframe().find(".nc-filter-menu-btn").should("exist"); cy.iframe().find(".nc-fields-menu-btn").should("exist");
cy.iframe().find(".nc-actions-menu-btn").should("exist"); cy.iframe().find(".nc-sort-menu-btn").should("exist");
cy.iframe().find(".nc-filter-menu-btn").should("exist");
// validate data (row-1) cy.iframe().find(".nc-actions-menu-btn").should("exist");
mainPage
.getIFrameCell("FirstName", 1) // validate data (row-1)
.contains("PENELOPE") mainPage
.should("exist"); .getIFrameCell("FirstName", 1)
mainPage.getIFrameCell("LastName", 1).contains("GUINESS").should("exist"); .contains("PENELOPE")
.should("exist");
mainPage
.getIFrameCell("LastName", 1)
.contains("GUINESS")
.should("exist");
});
}); });
});
}; };
/** /**

538
scripts/cypress/integration/common/7a_create_project_from_excel.js

@ -4,8 +4,8 @@
import { projectsPage } from "../../support/page_objects/navigation"; import { projectsPage } from "../../support/page_objects/navigation";
import { mainPage } from "../../support/page_objects/mainPage"; import { mainPage } from "../../support/page_objects/mainPage";
import { import {
roles, roles,
isTestSuiteActive, isTestSuiteActive,
} from "../../support/page_objects/projectConstants"; } from "../../support/page_objects/projectConstants";
// stores sheet names (table name) // stores sheet names (table name)
@ -21,29 +21,29 @@ let filepath = `sampleFiles/simple.xlsx`;
// let UrlFilePath = `sampleFiles/Financial Sample.xlsx` // let UrlFilePath = `sampleFiles/Financial Sample.xlsx`
let expectedData = { let expectedData = {
0: ["number", "Number"], 0: ["number", "Number"],
1: ["float", "Decimal"], 1: ["float", "Decimal"],
2: ["text", "SingleLineText"], 2: ["text", "SingleLineText"],
}; };
// column names with spaces will be converted to include _ // column names with spaces will be converted to include _
let UrlFileExpectedData = { let UrlFileExpectedData = {
0: ["Segment", "SingleSelect", ["Government"]], 0: ["Segment", "SingleSelect", ["Government"]],
1: ["Country", "SingleSelect", ["Canada"]], 1: ["Country", "SingleSelect", ["Canada"]],
2: ["Product", "SingleSelect", ["Carretera"]], 2: ["Product", "SingleSelect", ["Carretera"]],
3: ["Discount_Band", "SingleSelect", ["None"]], 3: ["Discount_Band", "SingleSelect", ["None"]],
4: ["Units_Sold", "Decimal", [1618.5]], 4: ["Units_Sold", "Decimal", [1618.5]],
5: ["Manufacturing_Price", "Number", [3]], 5: ["Manufacturing_Price", "Number", [3]],
6: ["Sale_Price", "Number", [20]], 6: ["Sale_Price", "Number", [20]],
7: ["Gross_Sales", "Decimal", [32370]], 7: ["Gross_Sales", "Decimal", [32370]],
8: ["Discounts", "Decimal", [0]], 8: ["Discounts", "Decimal", [0]],
9: ["Sales", "Decimal", [32370]], 9: ["Sales", "Decimal", [32370]],
10: ["COGS", "Decimal", [16185]], 10: ["COGS", "Decimal", [16185]],
11: ["Profit", "Decimal", [16185]], 11: ["Profit", "Decimal", [16185]],
12: ["Date", "Date", ["2014-01-01"]], 12: ["Date", "Date", ["2014-01-01"]],
13: ["Month_Number", "Number", [1]], 13: ["Month_Number", "Number", [1]],
14: ["Month_Name", "SingleSelect", ["January"]], 14: ["Month_Name", "SingleSelect", ["January"]],
15: ["Year", "SingleSelect", [2014]], 15: ["Year", "SingleSelect", [2014]],
}; };
// let filepath = `sampleFiles/sample.xlsx` // let filepath = `sampleFiles/sample.xlsx`
@ -63,260 +63,282 @@ let UrlFileExpectedData = {
// 12: ['dateTime', 'DateTime'] // 12: ['dateTime', 'DateTime']
// } // }
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; if (!isTestSuiteActive(apiType, dbType)) return;
describe(`Import from excel`, () => {
before(() => {
cy.task("readSheetList", {
file: `./scripts/cypress/fixtures/${filepath}`,
}).then((rows) => {
cy.log(rows);
sheetList = rows;
});
cy.task("readXlsx", {
file: `./scripts/cypress/fixtures/${filepath}`,
sheet: "Sheet2",
}).then((rows) => {
cy.log(rows);
sheetData = rows;
});
// cy.task('readXlsx', { file: `./scripts/cypress/fixtures/${UrlFilePath}`, sheet: "Sheet1" })
// .then((rows) => {
// cy.log(rows)
// UrlSheetData = rows
// })
});
it("File Upload: Upload excel as template", () => { describe(`Import from excel`, () => {
mainPage.toolBarTopLeft(mainPage.HOME).click(); before(() => {
cy.task("readSheetList", {
file: `./scripts/cypress/fixtures/${filepath}`,
}).then((rows) => {
cy.log(rows);
sheetList = rows;
});
// click on "New Project" cy.task("readXlsx", {
cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click(); file: `./scripts/cypress/fixtures/${filepath}`,
sheet: "Sheet2",
}).then((rows) => {
cy.log(rows);
sheetData = rows;
});
// Subsequent form, select (+ Create) option // cy.task('readXlsx', { file: `./scripts/cypress/fixtures/${UrlFilePath}`, sheet: "Sheet1" })
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({ // .then((rows) => {
force: true, // cy.log(rows)
}); // UrlSheetData = rows
// })
});
cy.get(".nc-excel-import-input").attachFile(filepath); it("File Upload: Upload excel as template", () => {
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist"); mainPage.toolBarTopLeft(mainPage.HOME).click();
});
it("File Upload: Verify pre-load template page", () => { // click on "New Project"
cy.getActiveContentModal() cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click();
.find(".v-expansion-panel")
.then((sheets) => {
for (let i = 0; i < sheets.length; i++) {
// verify if all sheet names are correct
// cy.wrap(sheets[i]).find('.title').then((blk) => {
// cy.log(blk.text().trim())
// expect(blk.text().trim()).to.equal(sheetList[i])
// })
cy.wrap(sheets[i]).contains(sheetList[i]).should("exist"); // Subsequent form, select (+ Create) option
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({
// for each sheet, expand to verify table names & their data types force: true,
cy.wrap(sheets[i]).find(".mdi-chevron-down").click(); });
// wait for 4 DOM rows to become visible, corresponding to 4 column names in excel cy.snipActiveModal("Modal_CreateFromExcel");
// change to avoid static wait
cy.get(".v-data-table").find("tr:visible").should("have.length", 4); cy.get(".nc-excel-import-input").attachFile(filepath);
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist");
cy.get(".v-data-table")
.find("tr:visible")
.then((row) => {
for (let j = 1; j < row.length; j++) {
// column name to match input in excel
cy.wrap(row[j])
.find('[placeholder="Column name"]')
.then((obj) => {
cy.log(obj[0].value);
expect(obj[0].value).to.equal(expectedData[j - 1][0]);
});
// datatype to match expected output
cy.wrap(row[j])
.find("span.caption")
.then((obj) => {
cy.log(obj[0].innerText);
expect(obj[0].innerText).to.equal(expectedData[j - 1][1]);
});
}
});
// unwind
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
}
}); });
});
it("File Upload: Verify loaded data", () => { it("File Upload: Verify pre-load template page", () => {
// create rest/ gql project cy.snip("ExcelImport");
cy.get(".nc-btn-use-template", { timeout: 120000 }).click(); cy.getActiveContentModal()
// if (type == 'rest') { .find(".v-expansion-panel")
// cy.getActiveMenu().find('[role="menuitem"]').contains('REST').click() .then((sheets) => {
// } else { for (let i = 0; i < sheets.length; i++) {
// cy.getActiveMenu().find('[role="menuitem"]').contains('GQL').click() // verify if all sheet names are correct
// } // cy.wrap(sheets[i]).find('.title').then((blk) => {
// cy.log(blk.text().trim())
// wait for loading to be completed // expect(blk.text().trim()).to.equal(sheetList[i])
projectsPage.waitHomePageLoad(); // })
// open sheet & validate contents cy.wrap(sheets[i])
// sheetData contains data read from excel in format .contains(sheetList[i])
// 0: { float: 1.1, number: 1, text: "abc" } .should("exist");
// 1: { float: 1.2, number: 0, text: "def" }
// for each sheet, expand to verify table names & their data types
cy.openTableTab("Sheet2", 2); cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
for (const [key, value] of Object.entries(expectedData)) {
mainPage // wait for 4 DOM rows to become visible, corresponding to 4 column names in excel
.getCell(value[0], 1) // change to avoid static wait
.contains(sheetData[0][value[0]]) cy.get(".v-data-table")
.should("exist"); .find("tr:visible")
mainPage .should("have.length", 4);
.getCell(value[0], 2)
.contains(sheetData[1][value[0]]) cy.get(".v-data-table")
.should("exist"); .find("tr:visible")
} .then((row) => {
cy.closeTableTab("Sheet2"); for (let j = 1; j < row.length; j++) {
// column name to match input in excel
cy.openTableTab("Sheet3", 2); cy.wrap(row[j])
for (const [key, value] of Object.entries(expectedData)) { .find('[placeholder="Column name"]')
mainPage .then((obj) => {
.getCell(value[0], 1) cy.log(obj[0].value);
.contains(sheetData[0][value[0]]) expect(obj[0].value).to.equal(
.should("exist"); expectedData[j - 1][0]
mainPage );
.getCell(value[0], 2) });
.contains(sheetData[1][value[0]])
.should("exist"); // datatype to match expected output
} cy.wrap(row[j])
cy.closeTableTab("Sheet3"); .find("span.caption")
.then((obj) => {
// delete project once all operations are completed cy.log(obj[0].innerText);
mainPage.toolBarTopLeft(mainPage.HOME).click(); expect(obj[0].innerText).to.equal(
cy.get(`.nc-${type}-project-row .mdi-delete-circle-outline`, { expectedData[j - 1][1]
timeout: 10000, );
}) });
.should("exist") }
.last() });
.invoke("show")
.click(); // unwind
cy.contains("Submit").closest("button").click(); cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
}); }
});
});
it("URL: Upload excel as template", () => { it("File Upload: Verify loaded data", () => {
// click on "New Project" // create rest/ gql project
cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click(); cy.get(".nc-btn-use-template", { timeout: 120000 }).click();
// if (type == 'rest') {
// Subsequent form, select (+ Create) option // cy.getActiveMenu().find('[role="menuitem"]').contains('REST').click()
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({ // } else {
force: true, // cy.getActiveMenu().find('[role="menuitem"]').contains('GQL').click()
}); // }
cy.getActiveModal().find(".caption").contains("URL").click(); // wait for loading to be completed
cy.get(".nc-excel-import-tab-item") projectsPage.waitHomePageLoad();
.find('input[type="url"]')
.click() // open sheet & validate contents
.type(URL); // sheetData contains data read from excel in format
cy.get(".nc-excel-import-tab-item") // 0: { float: 1.1, number: 1, text: "abc" }
.find("button") // 1: { float: 1.2, number: 0, text: "def" }
.contains("Load")
.click(); cy.openTableTab("Sheet2", 2);
for (const [key, value] of Object.entries(expectedData)) {
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist"); mainPage
}); .getCell(value[0], 1)
.contains(sheetData[0][value[0]])
.should("exist");
mainPage
.getCell(value[0], 2)
.contains(sheetData[1][value[0]])
.should("exist");
}
cy.closeTableTab("Sheet2");
cy.openTableTab("Sheet3", 2);
for (const [key, value] of Object.entries(expectedData)) {
mainPage
.getCell(value[0], 1)
.contains(sheetData[0][value[0]])
.should("exist");
mainPage
.getCell(value[0], 2)
.contains(sheetData[1][value[0]])
.should("exist");
}
cy.closeTableTab("Sheet3");
// delete project once all operations are completed
mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.get(`.nc-${apiType}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
});
it("URL: Verify pre-load template page", () => { it("URL: Upload excel as template", () => {
cy.getActiveContentModal() // click on "New Project"
.find(".v-expansion-panel") cy.get(":nth-child(5) > .v-btn", { timeout: 20000 }).click();
.then((sheets) => {
for (let i = 0; i < sheets.length; i++) {
// verify if all sheet names are correct
// cy.wrap(sheets[i]).find('.title').then((blk) => {
// cy.log(blk.text().trim())
// expect(blk.text().trim()).to.equal('Sheet1')
// })
cy.wrap(sheets[i]).contains("Sheet1").should("exist"); // Subsequent form, select (+ Create) option
cy.get(".nc-create-project-from-excel", { timeout: 20000 }).click({
// for each sheet, expand to verify table names & their data types force: true,
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
cy.wait(3000).then(() => {
cy.get(".v-data-table")
.find("tr:visible")
.then((row) => {
// verification restricting to 10, as others need to be scrolled back into view
for (let j = 1; j <= 10 /*row.length*/; j++) {
// column name to match input in excel
cy.wrap(row[j])
.find('[placeholder="Column name"]')
.then((obj) => {
cy.log(obj[0].value);
expect(obj[0].value).to.equal(
UrlFileExpectedData[j - 1][0]
);
});
// datatype to match expected output
cy.wrap(row[j])
.find("span.caption")
.then((obj) => {
cy.log(obj[0].innerText);
expect(obj[0].innerText).to.equal(
UrlFileExpectedData[j - 1][1]
);
});
}
});
}); });
// unwind cy.snipActiveModal("Modal_ImportExcelURL");
cy.wrap(sheets[i]).find(".mdi-chevron-down").click(); cy.getActiveModal().find(".caption").contains("URL").click();
} cy.get(".nc-excel-import-tab-item")
.find('input[type="url"]')
.click()
.type(URL);
cy.get(".nc-excel-import-tab-item")
.find("button")
.contains("Load")
.click();
cy.get(".nc-btn-use-template", { timeout: 120000 }).should("exist");
}); });
});
it("URL: Verify loaded data", () => { it("URL: Verify pre-load template page", () => {
// create rest/ gql project cy.getActiveContentModal()
cy.get(".nc-btn-use-template", { timeout: 120000 }).click(); .find(".v-expansion-panel")
.then((sheets) => {
// wait for loading to be completed for (let i = 0; i < sheets.length; i++) {
projectsPage.waitHomePageLoad(); // verify if all sheet names are correct
// cy.wrap(sheets[i]).find('.title').then((blk) => {
// open sheet & validate contents // cy.log(blk.text().trim())
// sheetData contains data read from excel in format // expect(blk.text().trim()).to.equal('Sheet1')
// 0: { float: 1.1, number: 1, text: "abc" } // })
// 1: { float: 1.2, number: 0, text: "def" }
cy.wrap(sheets[i]).contains("Sheet1").should("exist");
cy.openTableTab("Sheet1", 25);
let idx = 0; // for each sheet, expand to verify table names & their data types
for (const [key, value] of Object.entries(UrlFileExpectedData)) { cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
if (UrlFileExpectedData[idx][1] != "Date") cy.wait(3000).then(() => {
mainPage cy.get(".v-data-table")
.getCell(value[0], 1) .find("tr:visible")
.contains(UrlFileExpectedData[idx++][2][0]) .then((row) => {
.should("exist"); // verification restricting to 10, as others need to be scrolled back into view
} for (
cy.closeTableTab("Sheet1"); let j = 1;
}); j <= 10 /*row.length*/;
j++
) {
// column name to match input in excel
cy.wrap(row[j])
.find('[placeholder="Column name"]')
.then((obj) => {
cy.log(obj[0].value);
expect(obj[0].value).to.equal(
UrlFileExpectedData[
j - 1
][0]
);
});
// datatype to match expected output
cy.wrap(row[j])
.find("span.caption")
.then((obj) => {
cy.log(obj[0].innerText);
expect(
obj[0].innerText
).to.equal(
UrlFileExpectedData[
j - 1
][1]
);
});
}
});
});
// unwind
cy.wrap(sheets[i]).find(".mdi-chevron-down").click();
}
});
});
after(() => { it("URL: Verify loaded data", () => {
// delete project once all operations are completed // create rest/ gql project
mainPage.toolBarTopLeft(mainPage.HOME).click(); cy.get(".nc-btn-use-template", { timeout: 120000 }).click();
cy.get(`.nc-${type}-project-row .mdi-delete-circle-outline`, {
timeout: 10000, // wait for loading to be completed
}) projectsPage.waitHomePageLoad();
.should("exist")
.last() // open sheet & validate contents
.invoke("show") // sheetData contains data read from excel in format
.click(); // 0: { float: 1.1, number: 1, text: "abc" }
cy.contains("Submit").closest("button").click(); // 1: { float: 1.2, number: 0, text: "def" }
cy.openTableTab("Sheet1", 25);
let idx = 0;
for (const [key, value] of Object.entries(UrlFileExpectedData)) {
if (UrlFileExpectedData[idx][1] != "Date")
mainPage
.getCell(value[0], 1)
.contains(UrlFileExpectedData[idx++][2][0])
.should("exist");
}
cy.closeTableTab("Sheet1");
});
after(() => {
// delete project once all operations are completed
mainPage.toolBarTopLeft(mainPage.HOME).click();
cy.get(`.nc-${apiType}-project-row .mdi-delete-circle-outline`, {
timeout: 10000,
})
.should("exist")
.last()
.invoke("show")
.click();
cy.contains("Submit").closest("button").click();
});
}); });
});
}; };
// if (typeof require !== 'undefined') XLSX = require('xlsx'); // if (typeof require !== 'undefined') XLSX = require('xlsx');

30
scripts/cypress/integration/test/explicitLogin.js

@ -1,27 +1,27 @@
import { loginPage } from "../../support/page_objects/navigation"; import { loginPage } from "../../support/page_objects/navigation";
import { isTestSuiteActive } from "../../support/page_objects/projectConstants"; import { isTestSuiteActive } from "../../support/page_objects/projectConstants";
export const genTest = (type, xcdb) => { export const genTest = (apiType, dbType) => {
if (!isTestSuiteActive(type, xcdb)) return; // if (!isTestSuiteActive(apiType, dbType)) return;
describe(`${type.toUpperCase()} api - Login & Open project`, () => { describe(`${apiType.toUpperCase()} api - Login & Open project`, () => {
// Run once before test- create project (rest/graphql) // Run once before test- create project (rest/graphql)
// //
before(() => { before(() => {
loginPage.loginAndOpenProject(type, xcdb); loginPage.loginAndOpenProject(apiType, dbType);
// open a table to work on views // open a table to work on views
// //
// cy.openTableTab('City'); // cy.openTableTab('City');
}); });
it(``, () => { it(``, () => {
cy.log("Test-1"); cy.log("Test-1");
});
}); });
});
}; };
// genTest('rest', false) // genTest("rest", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/gqlMisc.js

@ -14,24 +14,24 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t6b.genTest(type, xcdb); t6b.genTest(apiType, dbType);
t6c.genTest(type, xcdb); t6c.genTest(apiType, dbType);
t6d.genTest(type, xcdb); t6d.genTest(apiType, dbType);
t6f.genTest(type, xcdb); t6f.genTest(apiType, dbType);
t6g.genTest(type, xcdb); t6g.genTest(apiType, dbType);
// **deletes created project, hence place it @ end // **deletes created project, hence place it @ end
t6e.genTest(type, xcdb); t6e.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", false); nocoTestSuite("graphql", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

14
scripts/cypress/integration/test/gqlRoles.js

@ -10,19 +10,19 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t5a.genTest(type, xcdb); t5a.genTest(apiType, dbType);
t5b.genTest(type, xcdb); t5b.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", false); nocoTestSuite("graphql", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

32
scripts/cypress/integration/test/gqlTableOps.js

@ -19,28 +19,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
if (0 == executionMode) { if (0 == executionMode) {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t1a.genTest(type, xcdb); t1a.genTest(apiType, dbType);
t1b.genTest(type, xcdb); t1b.genTest(apiType, dbType);
t1c.genTest(type, xcdb); t1c.genTest(apiType, dbType);
t1d.genTest(type, xcdb); t1d.genTest(apiType, dbType);
t1e.genTest(type, xcdb); t1e.genTest(apiType, dbType);
t2a.genTest(type, xcdb); t2a.genTest(apiType, dbType);
t2b.genTest(type, xcdb); t2b.genTest(apiType, dbType);
t3a.genTest(type, xcdb); t3a.genTest(apiType, dbType);
t3b.genTest(type, xcdb); t3b.genTest(apiType, dbType);
t3c.genTest(type, xcdb); t3c.genTest(apiType, dbType);
t3d.genTest(type, xcdb); t3d.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", false); nocoTestSuite("graphql", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/gqlViews.js

@ -14,23 +14,23 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t4a.genTest(type, xcdb); t4a.genTest(apiType, dbType);
t4b.genTest(type, xcdb); t4b.genTest(apiType, dbType);
t4c.genTest(type, xcdb); t4c.genTest(apiType, dbType);
t4d.genTest(type, xcdb); t4d.genTest(apiType, dbType);
t4e.genTest(type, xcdb); t4e.genTest(apiType, dbType);
t4f.genTest(type, xcdb); t4f.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", false); nocoTestSuite("graphql", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

52
scripts/cypress/integration/test/masterSuiteGql.js

@ -26,39 +26,39 @@ let t6e = require("../common/6e_project_operations");
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t00.genTest(type, xcdb); t00.genTest(apiType, dbType);
} }
t1a.genTest(type, xcdb); t1a.genTest(apiType, dbType);
t1b.genTest(type, xcdb); t1b.genTest(apiType, dbType);
// merged with t1b: t1c.genTest(type, xcdb) // merged with t1b: t1c.genTest(apiType, dbType)
t2a.genTest(type, xcdb); t2a.genTest(apiType, dbType);
t2b.genTest(type, xcdb); t2b.genTest(apiType, dbType);
t3a.genTest(type, xcdb); t3a.genTest(apiType, dbType);
t3b.genTest(type, xcdb); t3b.genTest(apiType, dbType);
t3c.genTest(type, xcdb); t3c.genTest(apiType, dbType);
t3d.genTest(type, xcdb); t3d.genTest(apiType, dbType);
t4a.genTest(type, xcdb); t4a.genTest(apiType, dbType);
t4b.genTest(type, xcdb); t4b.genTest(apiType, dbType);
t4c.genTest(type, xcdb); t4c.genTest(apiType, dbType);
t4d.genTest(type, xcdb); t4d.genTest(apiType, dbType);
t4e.genTest(type, xcdb); t4e.genTest(apiType, dbType);
t4f.genTest(type, xcdb); t4f.genTest(apiType, dbType);
t5a.genTest(type, xcdb); t5a.genTest(apiType, dbType);
t5b.genTest(type, xcdb); t5b.genTest(apiType, dbType);
// merged with t1a: t6a.genTest(type, xcdb) // merged with t1a: t6a.genTest(apiType, dbType)
t6c.genTest(type, xcdb); t6c.genTest(apiType, dbType);
t6d.genTest(type, xcdb); t6d.genTest(apiType, dbType);
// **deletes created project, hence place it @ end // **deletes created project, hence place it @ end
t6e.genTest(type, xcdb); t6e.genTest(apiType, dbType);
}; };
// nocoTestSuite('rest', false) // nocoTestSuite('rest', "mysql")
nocoTestSuite("graphql", false); nocoTestSuite("graphql", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

52
scripts/cypress/integration/test/masterSuiteRest.js

@ -26,39 +26,39 @@ let t6e = require("../common/6e_project_operations");
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t00.genTest(type, xcdb); t00.genTest(apiType, dbType);
} }
t1a.genTest(type, xcdb); t1a.genTest(apiType, dbType);
t1b.genTest(type, xcdb); t1b.genTest(apiType, dbType);
// merged with t1b: t1c.genTest(type, xcdb) // merged with t1b: t1c.genTest(apiType, dbType)
t2a.genTest(type, xcdb); t2a.genTest(apiType, dbType);
t2b.genTest(type, xcdb); t2b.genTest(apiType, dbType);
t3a.genTest(type, xcdb); t3a.genTest(apiType, dbType);
t3b.genTest(type, xcdb); t3b.genTest(apiType, dbType);
t3c.genTest(type, xcdb); t3c.genTest(apiType, dbType);
t3d.genTest(type, xcdb); t3d.genTest(apiType, dbType);
t4a.genTest(type, xcdb); t4a.genTest(apiType, dbType);
t4b.genTest(type, xcdb); t4b.genTest(apiType, dbType);
t4c.genTest(type, xcdb); t4c.genTest(apiType, dbType);
t4d.genTest(type, xcdb); t4d.genTest(apiType, dbType);
t4e.genTest(type, xcdb); t4e.genTest(apiType, dbType);
t4f.genTest(type, xcdb); t4f.genTest(apiType, dbType);
t5a.genTest(type, xcdb); t5a.genTest(apiType, dbType);
t5b.genTest(type, xcdb); t5b.genTest(apiType, dbType);
// merged with t1a: t6a.genTest(type, xcdb) // merged with t1a: t6a.genTest(apiType, dbType)
t6c.genTest(type, xcdb); t6c.genTest(apiType, dbType);
t6d.genTest(type, xcdb); t6d.genTest(apiType, dbType);
// **deletes created project, hence place it @ end // **deletes created project, hence place it @ end
t6e.genTest(type, xcdb); t6e.genTest(apiType, dbType);
}; };
nocoTestSuite("rest", false); nocoTestSuite("rest", "mysql");
// nocoTestSuite('graphql', false) // nocoTestSuite('graphql', "mysql")
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

61
scripts/cypress/integration/test/pg-restMisc.js

@ -0,0 +1,61 @@
let t0 = require("./explicitLogin");
let t01 = require("../common/00_pre_configurations");
let t6b = require("../common/6b_downloadCsv");
let t6c = require("../common/6c_swagger_api");
let t6d = require("../common/6d_language_validation");
let t6e = require("../common/6e_project_operations");
let t6f = require("../common/6f_attachments");
let t6g = require("../common/6g_base_share");
let t7a = require("../common/7a_create_project_from_excel");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
// use 0 as mode to execute individual files (debug mode, skip pre-configs)
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(apiType, dbType);
} else {
t01.genTest(apiType, dbType);
}
t6b.genTest(apiType, dbType);
t6d.genTest(apiType, dbType);
t6c.genTest(apiType, dbType);
t6f.genTest(apiType, dbType);
t6g.genTest(apiType, dbType);
// **deletes created project, hence place it @ end
t6e.genTest(apiType, dbType);
// intended to keep this after earlier project deletion
// creates project using excel & deletes it
t7a.genTest(apiType, dbType);
};
nocoTestSuite("rest", "postgres");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

47
scripts/cypress/integration/test/pg-restRoles.js

@ -0,0 +1,47 @@
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");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
// use 0 as mode to execute individual files (debug mode, skip pre-configs)
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(apiType, dbType);
} else {
t01.genTest(apiType, dbType);
}
t5a.genTest(apiType, dbType);
t5b.genTest(apiType, dbType);
};
nocoTestSuite("rest", "postgres");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

65
scripts/cypress/integration/test/pg-restTableOps.js

@ -0,0 +1,65 @@
let t0 = require("./explicitLogin");
let t01 = require("../common/00_pre_configurations");
let t1a = require("../common/1a_table_operations");
let t1b = require("../common/1b_table_column_operations");
let t1c = require("../common/1c_sql_view");
let t1d = require("../common/1d_pg_table_view_drag_drop_reorder");
let t1e = require("../common/1e_pg_meta_sync");
let t2a = require("../common/2a_table_with_belongs_to_colulmn");
let t2b = require("../common/2b_table_with_m2m_column");
let t3a = require("../common/3a_filter_sort_fields_operations");
let t3b = require("../common/3b_formula_column");
let t3c = require("../common/3c_lookup_column");
let t3d = require("../common/3d_rollup_column");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
// use 0 as mode to execute individual files (debug mode, skip pre-configs)
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(apiType, dbType);
} else {
t01.genTest(apiType, dbType);
}
t1a.genTest(apiType, dbType);
t1b.genTest(apiType, dbType);
t1c.genTest(apiType, dbType);
t1d.genTest(apiType, dbType);
t1e.genTest(apiType, dbType);
t2a.genTest(apiType, dbType);
t2b.genTest(apiType, dbType);
t3a.genTest(apiType, dbType);
// t3b.genTest(apiType, dbType);
t3c.genTest(apiType, dbType);
t3d.genTest(apiType, dbType);
};
nocoTestSuite("rest", "postgres");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

55
scripts/cypress/integration/test/pg-restViews.js

@ -0,0 +1,55 @@
let t0 = require("./explicitLogin");
let t01 = require("../common/00_pre_configurations");
let t4a = require("../common/4a_table_view_grid_gallery_form");
let t4b = require("../common/4b_table_view_share");
let t4c = require("../common/4c_form_view_detailed");
let t4d = require("../common/4d_table_view_grid_locked");
let t4e = require("../common/4e_form_view_share");
let t4f = require("../common/4f_pg_grid_view_share");
const {
setCurrentMode,
} = require("../../support/page_objects/projectConstants");
// use 0 as mode to execute individual files (debug mode, skip pre-configs)
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1;
const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(apiType, dbType);
if (0 == executionMode) {
t0.genTest(apiType, dbType);
} else {
t01.genTest(apiType, dbType);
}
t4a.genTest(apiType, dbType);
t4b.genTest(apiType, dbType);
t4c.genTest(apiType, dbType);
t4d.genTest(apiType, dbType);
t4e.genTest(apiType, dbType);
t4f.genTest(apiType, dbType);
};
nocoTestSuite("rest", "postgres");
/**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd
*
* @author Raju Udava <sivadstala@gmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

24
scripts/cypress/integration/test/restMisc.js

@ -15,28 +15,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t6b.genTest(type, xcdb); t6b.genTest(apiType, dbType);
t6d.genTest(type, xcdb); t6d.genTest(apiType, dbType);
t6c.genTest(type, xcdb); t6c.genTest(apiType, dbType);
t6f.genTest(type, xcdb); t6f.genTest(apiType, dbType);
t6g.genTest(type, xcdb); t6g.genTest(apiType, dbType);
// **deletes created project, hence place it @ end // **deletes created project, hence place it @ end
t6e.genTest(type, xcdb); t6e.genTest(apiType, dbType);
// intended to keep this after earlier project deletion // intended to keep this after earlier project deletion
// creates project using excel & deletes it // creates project using excel & deletes it
t7a.genTest(type, xcdb); t7a.genTest(apiType, dbType);
}; };
nocoTestSuite("rest", false); nocoTestSuite("rest", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

14
scripts/cypress/integration/test/restRoles.js

@ -10,19 +10,19 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t5a.genTest(type, xcdb); t5a.genTest(apiType, dbType);
t5b.genTest(type, xcdb); t5b.genTest(apiType, dbType);
}; };
nocoTestSuite("rest", false); nocoTestSuite("rest", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

32
scripts/cypress/integration/test/restTableOps.js

@ -19,28 +19,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t1a.genTest(type, xcdb); t1a.genTest(apiType, dbType);
t1b.genTest(type, xcdb); t1b.genTest(apiType, dbType);
t1c.genTest(type, xcdb); t1c.genTest(apiType, dbType);
t1d.genTest(type, xcdb); t1d.genTest(apiType, dbType);
t1e.genTest(type, xcdb); t1e.genTest(apiType, dbType);
t2a.genTest(type, xcdb); t2a.genTest(apiType, dbType);
t2b.genTest(type, xcdb); t2b.genTest(apiType, dbType);
t3a.genTest(type, xcdb); t3a.genTest(apiType, dbType);
t3b.genTest(type, xcdb); t3b.genTest(apiType, dbType);
t3c.genTest(type, xcdb); t3c.genTest(apiType, dbType);
t3d.genTest(type, xcdb); t3d.genTest(apiType, dbType);
}; };
nocoTestSuite("rest", false); nocoTestSuite("rest", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/restViews.js

@ -14,23 +14,23 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t4a.genTest(type, xcdb); t4a.genTest(apiType, dbType);
t4b.genTest(type, xcdb); t4b.genTest(apiType, dbType);
t4c.genTest(type, xcdb); t4c.genTest(apiType, dbType);
t4d.genTest(type, xcdb); t4d.genTest(apiType, dbType);
t4e.genTest(type, xcdb); t4e.genTest(apiType, dbType);
t4f.genTest(type, xcdb); t4f.genTest(apiType, dbType);
}; };
nocoTestSuite("rest", false); nocoTestSuite("rest", "mysql");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/xcdb-gqlMisc.js

@ -14,24 +14,24 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t6b.genTest(type, xcdb); t6b.genTest(apiType, dbType);
t6c.genTest(type, xcdb); t6c.genTest(apiType, dbType);
t6d.genTest(type, xcdb); t6d.genTest(apiType, dbType);
t6f.genTest(type, xcdb); t6f.genTest(apiType, dbType);
t6g.genTest(type, xcdb); t6g.genTest(apiType, dbType);
// **deletes created project, hence place it @ end // **deletes created project, hence place it @ end
t6e.genTest(type, xcdb); t6e.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", true); nocoTestSuite("graphql", "xcdb");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

14
scripts/cypress/integration/test/xcdb-gqlRoles.js

@ -10,19 +10,19 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t5a.genTest(type, xcdb); t5a.genTest(apiType, dbType);
t5b.genTest(type, xcdb); t5b.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", true); nocoTestSuite("graphql", "xcdb");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

32
scripts/cypress/integration/test/xcdb-gqlTableOps.js

@ -19,28 +19,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t1a.genTest(type, xcdb); t1a.genTest(apiType, dbType);
t1b.genTest(type, xcdb); t1b.genTest(apiType, dbType);
t1c.genTest(type, xcdb); t1c.genTest(apiType, dbType);
t1d.genTest(type, xcdb); t1d.genTest(apiType, dbType);
t1e.genTest(type, xcdb); t1e.genTest(apiType, dbType);
t2a.genTest(type, xcdb); t2a.genTest(apiType, dbType);
t2b.genTest(type, xcdb); t2b.genTest(apiType, dbType);
t3a.genTest(type, xcdb); t3a.genTest(apiType, dbType);
t3b.genTest(type, xcdb); t3b.genTest(apiType, dbType);
t3c.genTest(type, xcdb); t3c.genTest(apiType, dbType);
t3d.genTest(type, xcdb); t3d.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", true); nocoTestSuite("graphql", "xcdb");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

22
scripts/cypress/integration/test/xcdb-gqlViews.js

@ -14,23 +14,23 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t4a.genTest(type, xcdb); t4a.genTest(apiType, dbType);
t4b.genTest(type, xcdb); t4b.genTest(apiType, dbType);
t4c.genTest(type, xcdb); t4c.genTest(apiType, dbType);
t4d.genTest(type, xcdb); t4d.genTest(apiType, dbType);
t4e.genTest(type, xcdb); t4e.genTest(apiType, dbType);
t4f.genTest(type, xcdb); t4f.genTest(apiType, dbType);
}; };
nocoTestSuite("graphql", true); nocoTestSuite("graphql", "xcdb");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

24
scripts/cypress/integration/test/xcdb-restMisc.js

@ -15,28 +15,28 @@ const {
// use 1 mode if noco.db doesnt contain user credentials (full run over GIT) // use 1 mode if noco.db doesnt contain user credentials (full run over GIT)
const executionMode = 1; const executionMode = 1;
const nocoTestSuite = (type, xcdb) => { const nocoTestSuite = (apiType, dbType) => {
setCurrentMode(type, xcdb); setCurrentMode(apiType, dbType);
if (0 == executionMode) { if (0 == executionMode) {
t0.genTest(type, xcdb); t0.genTest(apiType, dbType);
} else { } else {
t01.genTest(type, xcdb); t01.genTest(apiType, dbType);
} }
t6b.genTest(type, xcdb); t6b.genTest(apiType, dbType);
t6d.genTest(type, xcdb); t6d.genTest(apiType, dbType);
t6c.genTest(type, xcdb); t6c.genTest(apiType, dbType);
t6f.genTest(type, xcdb); t6f.genTest(apiType, dbType);
t6g.genTest(type, xcdb); t6g.genTest(apiType, dbType);
// **deletes created project, hence place it @ end // **deletes created project, hence place it @ end
t6e.genTest(type, xcdb); t6e.genTest(apiType, dbType);
// intended to keep this after earlier project deletion // intended to keep this after earlier project deletion
// creates project using excel & deletes it // creates project using excel & deletes it
t7a.genTest(type, xcdb); t7a.genTest(apiType, dbType);
}; };
nocoTestSuite("rest", true); nocoTestSuite("rest", "xcdb");
/** /**
* @copyright Copyright (c) 2021, Xgene Cloud Ltd * @copyright Copyright (c) 2021, Xgene Cloud Ltd

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save