Browse Source

Merge branch 'develop' into geodata-prototyping-restart

pull/4140/head
flisowna 2 years ago
parent
commit
710b25039c
  1. 822
      .github/workflows/ci-cd.yml
  2. 127
      .github/workflows/playwright-test-workflow.yml
  3. 2
      package.json
  4. 12
      packages/nc-cli/package-lock.json
  5. 7
      packages/nc-gui/components/cell/DatePicker.vue
  6. 9
      packages/nc-gui/components/cell/DateTimePicker.vue
  7. 7
      packages/nc-gui/components/cell/TimePicker.vue
  8. 7
      packages/nc-gui/components/cell/YearPicker.vue
  9. 2
      packages/nc-gui/components/cell/attachment/Carousel.vue
  10. 7
      packages/nc-gui/components/cell/attachment/index.vue
  11. 5
      packages/nc-gui/components/cell/attachment/utils.ts
  12. 14
      packages/nc-gui/components/dashboard/TreeView.vue
  13. 4
      packages/nc-gui/components/erd/Flow.vue
  14. 33
      packages/nc-gui/components/erd/RelationEdge.vue
  15. 9
      packages/nc-gui/components/smartsheet/Cell.vue
  16. 7
      packages/nc-gui/components/smartsheet/Form.vue
  17. 4
      packages/nc-gui/components/smartsheet/Grid.vue
  18. 21
      packages/nc-gui/components/smartsheet/sidebar/index.vue
  19. 10
      packages/nc-gui/composables/useApi/index.ts
  20. 2
      packages/nc-gui/composables/useColumn.ts
  21. 14
      packages/nc-gui/composables/useGlobal/state.ts
  22. 3
      packages/nc-gui/composables/useProject.ts
  23. 16
      packages/nc-gui/composables/useViewData.ts
  24. 2
      packages/nc-gui/composables/useViewFilters.ts
  25. 2
      packages/nc-gui/lib/constants.ts
  26. 26
      packages/nc-gui/nuxt.config.ts
  27. 97
      packages/nc-gui/package-lock.json
  28. 7
      packages/nc-gui/package.json
  29. 0
      packages/nc-gui/tests/playwright/.env.example
  30. 0
      packages/nc-gui/tests/playwright/.eslintrc.json
  31. 0
      packages/nc-gui/tests/playwright/.gitignore
  32. 0
      packages/nc-gui/tests/playwright/.lintstagedrc.json
  33. 0
      packages/nc-gui/tests/playwright/.prettierignore
  34. 0
      packages/nc-gui/tests/playwright/.prettierrc.js
  35. 79
      packages/nc-gui/tests/playwright/README.md
  36. 0
      packages/nc-gui/tests/playwright/constants/index.ts
  37. 110
      packages/nc-gui/tests/playwright/fixtures/expectedBaseDownloadData.txt
  38. 110
      packages/nc-gui/tests/playwright/fixtures/expectedBaseDownloadDataPg.txt
  39. 0
      packages/nc-gui/tests/playwright/fixtures/expectedData.txt
  40. 19
      packages/nc-gui/tests/playwright/fixtures/expectedDataSqlite.txt
  41. 0
      packages/nc-gui/tests/playwright/fixtures/sampleFiles/1.json
  42. 0
      packages/nc-gui/tests/playwright/fixtures/sampleFiles/2.json
  43. 0
      packages/nc-gui/tests/playwright/fixtures/sampleFiles/3.json
  44. 0
      packages/nc-gui/tests/playwright/fixtures/sampleFiles/4.json
  45. 0
      packages/nc-gui/tests/playwright/fixtures/sampleFiles/5.json
  46. 0
      packages/nc-gui/tests/playwright/fixtures/sampleFiles/6.json
  47. 0
      packages/nc-gui/tests/playwright/fixtures/sampleFiles/simple.xlsx
  48. 0
      packages/nc-gui/tests/playwright/fixtures/template.spec.ts
  49. 267
      packages/nc-gui/tests/playwright/package-lock.json
  50. 13
      packages/nc-gui/tests/playwright/package.json
  51. 0
      packages/nc-gui/tests/playwright/pages/Base.ts
  52. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/ExpandedForm/index.ts
  53. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Form/index.ts
  54. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Gallery/index.ts
  55. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/LTAR/ChildList.ts
  56. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/LTAR/LinkRecord.ts
  57. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/SelectOptionColumn.ts
  58. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/index.ts
  59. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Grid/index.ts
  60. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Import/Airtable.ts
  61. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Import/ImportTemplate.ts
  62. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Kanban/index.ts
  63. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Acl.ts
  64. 15
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/AppStore.ts
  65. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Audit.ts
  66. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Erd.ts
  67. 25
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Metadata.ts
  68. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Miscellaneous.ts
  69. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Teams.ts
  70. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/Settings/index.ts
  71. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/SurveyForm/index.ts
  72. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/TreeView.ts
  73. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/ViewSidebar/index.ts
  74. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/WebhookForm/index.ts
  75. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/AttachmentCell.ts
  76. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/CheckboxCell.ts
  77. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/RatingCell.ts
  78. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/SelectOptionCell.ts
  79. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/index.ts
  80. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/ProjectMenu/index.ts
  81. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Actions/Erd.ts
  82. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Actions/index.ts
  83. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/AddEditKanbanStack.ts
  84. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Fields.ts
  85. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts
  86. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/ShareView.ts
  87. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Sort.ts
  88. 0
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/StackBy.ts
  89. 5
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/ViewMenu.ts
  90. 4
      packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/index.ts
  91. 2
      packages/nc-gui/tests/playwright/pages/Dashboard/commonBase/Erd.ts
  92. 3
      packages/nc-gui/tests/playwright/pages/Dashboard/index.ts
  93. 0
      packages/nc-gui/tests/playwright/pages/LoginPage/index.ts
  94. 20
      packages/nc-gui/tests/playwright/pages/ProjectsPage/index.ts
  95. 0
      packages/nc-gui/tests/playwright/pages/SharedForm/index.ts
  96. 0
      packages/nc-gui/tests/playwright/pages/SignupPage/index.ts
  97. 0
      packages/nc-gui/tests/playwright/playwright.config.ts
  98. 4
      packages/nc-gui/tests/playwright/quickTests/commonTest.ts
  99. 0
      packages/nc-gui/tests/playwright/quickTests/quickTests.spec.ts
  100. 2
      packages/nc-gui/tests/playwright/scripts/docker-compose-mysql-playwright.yml
  101. Some files were not shown because too many files have changed in this diff Show More

822
.github/workflows/ci-cd.yml

@ -25,651 +25,6 @@ concurrency:
cancel-in-progress: true
jobs:
cypress-restTableOps-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/restTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-restTableOps-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-restViews-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/restViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-restViews-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-restRoles-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/restRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-restRoles-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-restMisc-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/restMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-restMisc-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-xcdb-restTableOps-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:xcdb-api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restTableOps.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-xcdb-restTableOps-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-xcdb-restViews-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:xcdb-api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restViews.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-xcdb-restViews-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-xcdb-restRoles-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:xcdb-api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restRoles.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-xcdb-restRoles-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-xcdb-restMisc-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:xcdb-api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/xcdb-restMisc.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-xcdb-restMisc-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restTableOps-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
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/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-pg-restTableOps-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restViews-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
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/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-pg-restViews-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restRoles-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
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/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-pg-restRoles-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cypress-pg-restMisc-run-cache:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
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/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-pg-restMisc-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cy-quick-sqlite:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
cp ./scripts/cypress/fixtures/quickTest/noco_0_91_7.db ./packages/nocodb/noco.db
npm run start:api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/quickTest.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cy-quick-sqlite-snapshots
path: scripts/cypress/screenshots
retention-days: 2
cy-quick-pg:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
docker-compose -f ./scripts/cypress/docker-compose-pg-cy-quick.yml up -d
npm run start:api:cache:pg:cyquick
npm run start:web
spec: "./scripts/cypress/integration/test/quickTest.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cy-quick-pg-snapshots
path: scripts/cypress/screenshots
retention-days: 2
unit-tests:
runs-on: ubuntu-20.04
timeout-minutes: 30
@ -711,144 +66,39 @@ jobs:
- name: run unit tests
working-directory: ./packages/nocodb
run: npm run test:unit
cypress-db-independent:
runs-on: ubuntu-20.04
timeout-minutes: 30
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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@v4
with:
start: |
npm run start:api:cache
npm run start:web
docker-compose -f ./scripts/cypress/docker-compose-cypress.yml up -d
spec: "./scripts/cypress/integration/test/db-independent.js"
wait-on: "http://localhost:8080, http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png"
wait-on-timeout: 1200
config-file: scripts/cypress/cypress.json
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-restMisc-run-cache-snapshots
path: scripts/cypress/screenshots
retention-days: 2
playwright:
runs-on: ubuntu-20.04
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
# Reference: https://github.com/pierotofy/set-swap-space/blob/master/action.yml
- name: Set 5gb swap
shell: bash
# Delete the swap file, allocate a new one, and activate it
run: |
export SWAP_FILE=$(swapon --show=NAME | tail -n 1)
sudo swapoff $SWAP_FILE
sudo rm $SWAP_FILE
sudo fallocate -l 5G $SWAP_FILE
sudo chmod 600 $SWAP_FILE
sudo mkswap $SWAP_FILE
sudo swapon $SWAP_FILE
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
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: install dependencies nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm install
- name: build nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm run build
- name: Install dependencies
working-directory: ./packages/nocodb
run: npm install
- name: setup mysql
working-directory: ./
run: docker-compose -f ./scripts/playwright/scripts/docker-compose-playwright.yml up -d &
- name: run frontend
run: npm run start:web &
- name: Run backend
working-directory: ./packages/nocodb
run: npm run watch:run:playwright > mysql_test_backend.log &
- name: Cache playwright npm modules
uses: actions/cache@v3
id: playwright-cache
with:
path: |
**/playwright/node_modules
key: cache-playwright-${{ hashFiles('**/playwright/package-lock.json') }}
- name: Install dependencies
if: steps.playwright-cache.outputs.cache-hit != 'true'
working-directory: ./scripts/playwright
run: npm install
- name: Install Playwright Browsers
working-directory: ./scripts/playwright
run: npx playwright install chromium --with-deps
- name: Wait for frontend
run: |
while ! curl --output /dev/null --silent --head --fail http://localhost:3000/_nuxt/assets/img/icons/512x512-trans.png; do
printf '.'
sleep 2
done
- name: Wait for backend
run: |
while ! curl --output /dev/null --silent --head --fail http://localhost:8080; do
printf '.'
sleep 2
done
- name: Run Playwright tests
working-directory: ./scripts/playwright
run: npm run ci:test:mysql
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: ./scripts/playwright/playwright-report/
retention-days: 2
- uses: actions/upload-artifact@v3
if: always()
with:
name: backend logs
path: ./packages/nocodb/mysql_test_backend.log
retention-days: 2
playwright-mysql-1:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
uses: ./.github/workflows/playwright-test-workflow.yml
with:
db: mysql
shard: 1
playwright-mysql-2:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
uses: ./.github/workflows/playwright-test-workflow.yml
with:
db: mysql
shard: 2
playwright-sqlite-1:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
uses: ./.github/workflows/playwright-test-workflow.yml
with:
db: sqlite
shard: 1
playwright-sqlite-2:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
uses: ./.github/workflows/playwright-test-workflow.yml
with:
db: sqlite
shard: 2
playwright-pg-shard-1:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
uses: ./.github/workflows/playwright-test-workflow.yml
with:
db: pg
shard: 1
playwright-pg-shard-2:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
uses: ./.github/workflows/playwright-test-workflow.yml
with:
db: pg
shard: 2

127
.github/workflows/playwright-test-workflow.yml

@ -0,0 +1,127 @@
name: Playwright test reusable workflow
on:
workflow_call:
inputs:
shard:
description: 'Shard number'
required: true
type: string
db:
required: true
type: string
jobs:
playwright:
runs-on: ubuntu-20.04
steps:
# Reference: https://github.com/pierotofy/set-swap-space/blob/master/action.yml
- name: Set 5gb swap
shell: bash
# Delete the swap file, allocate a new one, and activate it
run: |
export SWAP_FILE=$(swapon --show=NAME | tail -n 1)
sudo swapoff $SWAP_FILE
sudo rm $SWAP_FILE
sudo fallocate -l 5G $SWAP_FILE
sudo chmod 600 $SWAP_FILE
sudo mkswap $SWAP_FILE
sudo swapon $SWAP_FILE
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
- name: Cache node modules
uses: actions/cache@v3
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: install dependencies nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm install
- name: build nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm run build
- name: setup mysql
if: ${{ inputs.db == 'mysql' }}
working-directory: ./
run: docker-compose -f ./packages/nc-gui/tests/playwright/scripts/docker-compose-mysql-playwright.yml up -d &
- name: setup pg
if: ${{ inputs.db == 'pg' }}
working-directory: ./
run: docker-compose -f ./packages/nc-gui/tests/playwright/scripts/docker-compose-playwright-pg.yml up -d &
- name: setup pg for quick tests
if: ${{ inputs.db == 'sqlite' && inputs.shard == '1' }}
working-directory: ./
run: docker-compose -f ./packages/nc-gui/tests/playwright/scripts/docker-compose-pg-pw-quick.yml up -d &
- name: run frontend
working-directory: ./packages/nc-gui
run: npm run ci:run
- name: Run backend
working-directory: ./packages/nocodb
run: npm run ci:run &
- name: Cache playwright npm modules
uses: actions/cache@v3
id: playwright-cache
with:
path: |
**/playwright/node_modules
key: cache-nc-playwright-${{ hashFiles('**/playwright/package-lock.json') }}
- name: Install dependencies
if: steps.playwright-cache.outputs.cache-hit != 'true'
working-directory: ./packages/nc-gui/tests/playwright
run: npm install
- name: Install Playwright Browsers
working-directory: ./packages/nc-gui/tests/playwright
run: npx playwright install chromium --with-deps
- name: Wait for backend
run: |
while ! curl --output /dev/null --silent --head --fail http://localhost:8080; do
printf '.'
sleep 2
done
- name: Run Playwright tests
working-directory: ./packages/nc-gui/tests/playwright
run: E2E_DB_TYPE=${{ inputs.db }} npm run ci:test:shard:${{ inputs.shard }}
# Quick tests (pg on sqlite shard 0 and sqlite on sqlite shard 1)
- name: Run quick server and tests (pg)
if: ${{ inputs.db == 'sqlite' && inputs.shard == '1' }}
working-directory: ./packages/nocodb
run: |
kill -9 $(lsof -t -i:8080)
npm run watch:run:playwright:pg:cyquick &
cd ../nc-gui/tests/playwright
npm run test:quick
- name: Run quick server and tests (sqlite)
if: ${{ inputs.db == 'sqlite' && inputs.shard == '2' }}
working-directory: ./packages/nocodb
run: |
kill -9 $(lsof -t -i:8080)
npm run watch:run:playwright:quick &
cd ../nc-gui/tests/playwright
npm run test:quick
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report-${{ inputs.db }}-${{ inputs.shard }}
path: ./packages/nc-gui/tests/playwright/playwright-report/
retention-days: 2
- uses: actions/upload-artifact@v3
if: always()
with:
name: backend-logs-${{ inputs.db }}-${{ inputs.shard }}
path: ./packages/nocodb/mysql_test_backend.log
retention-days: 2

2
package.json

@ -36,7 +36,7 @@
]
},
"scripts": {
"lint:staged:playwright": "cd scripts/playwright; npx lint-staged; cd ..",
"lint:staged:playwright": "cd packages/nc-gui/tests/playwright; npx lint-staged; cd -",
"build:common": "cd ./packages/nocodb-sdk; npm install; npm run build",
"install:common": "cd ./packages/nocodb; npm install ../nocodb-sdk; cd ../nc-gui; npm install ../nocodb-sdk",
"start:api": "npm run build:common ; cd ./packages/nocodb; npm install ../nocodb-sdk; npm install; NC_DISABLE_CACHE=true NC_DISABLE_TELE=true npm run watch:run:cypress",

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

@ -9008,9 +9008,9 @@
}
},
"node_modules/loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
"integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
"dev": true,
"dependencies": {
"big.js": "^5.2.2",
@ -22415,9 +22415,9 @@
"dev": true
},
"loader-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.3.tgz",
"integrity": "sha512-THWqIsn8QRnvLl0shHYVBN9syumU8pYWEHPTmkiVGd+7K5eFNVSY6AJhRvgGF70gg1Dz+l/k8WicvFCxdEs60A==",
"dev": true,
"requires": {
"big.js": "^5.2.2",

7
packages/nc-gui/components/cell/DatePicker.vue

@ -4,9 +4,10 @@ import { ColumnInj, ReadonlyInj, computed, inject, ref, watch } from '#imports'
interface Props {
modelValue?: string | null
isPk?: boolean
}
const { modelValue } = defineProps<Props>()
const { modelValue, isPk } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
@ -65,10 +66,10 @@ const placeholder = computed(() => (isDateInvalid ? 'Invalid date' : ''))
class="!w-full !px-0 !border-none"
:format="dateFormat"
:placeholder="placeholder"
:allow-clear="!readOnly"
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:dropdown-class-name="`${randomClass} nc-picker-date`"
:open="readOnly ? false : open"
:open="readOnly || (localState && isPk) ? false : open"
@click="open = !open"
>
<template #suffixIcon></template>

9
packages/nc-gui/components/cell/DateTimePicker.vue

@ -4,9 +4,10 @@ import { ReadonlyInj, inject, ref, useProject, watch } from '#imports'
interface Props {
modelValue?: string | null
isPk?: boolean
}
const { modelValue } = defineProps<Props>()
const { modelValue, isPk } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
@ -65,11 +66,11 @@ watch(
class="!w-full !px-0 !border-none"
format="YYYY-MM-DD HH:mm"
:placeholder="isDateInvalid ? 'Invalid date' : ''"
:allow-clear="!readOnly"
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:dropdown-class-name="`${randomClass} nc-picker-datetime`"
:open="readOnly ? false : open"
:disabled="readOnly"
:open="readOnly || (localState && isPk) ? false : open"
:disabled="readOnly || (localState && isPk)"
@click="open = !open"
@ok="open = !open"
>

7
packages/nc-gui/components/cell/TimePicker.vue

@ -4,9 +4,10 @@ import { ReadonlyInj, inject, onClickOutside, useProject, watch } from '#imports
interface Props {
modelValue?: string | null | undefined
isPk?: boolean
}
const { modelValue } = defineProps<Props>()
const { modelValue, isPk } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
@ -76,9 +77,9 @@ watch(
format="HH:mm"
class="!w-full !px-0 !border-none"
:placeholder="isTimeInvalid ? 'Invalid time' : ''"
:allow-clear="!readOnly"
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:open="readOnly ? false : open"
:open="readOnly || (localState && isPk) ? false : open"
:popup-class-name="`${randomClass} nc-picker-time`"
@click="open = !open"
@ok="open = !open"

7
packages/nc-gui/components/cell/YearPicker.vue

@ -4,9 +4,10 @@ import { ReadonlyInj, computed, inject, onClickOutside, ref, watch } from '#impo
interface Props {
modelValue?: number | string | null
isPk?: boolean
}
const { modelValue } = defineProps<Props>()
const { modelValue, isPk = false } = defineProps<Props>()
const emit = defineEmits(['update:modelValue'])
@ -63,9 +64,9 @@ const placeholder = computed(() => (isYearInvalid ? 'Invalid year' : ''))
:bordered="false"
class="!w-full !px-0 !border-none"
:placeholder="placeholder"
:allow-clear="!readOnly"
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:open="readOnly ? false : open"
:open="readOnly || (localState && isPk) ? false : open"
:dropdown-class-name="`${randomClass} nc-picker-year`"
@click="open = !open"
@change="open = !open"

2
packages/nc-gui/components/cell/attachment/Carousel.vue

@ -47,7 +47,7 @@ onClickOutside(carouselRef, () => {
</script>
<template>
<general-overlay v-model="selectedImage" z-index="1001">
<general-overlay v-model="selectedImage" :z-index="1001">
<template v-if="selectedImage">
<div class="overflow-hidden p-12 text-center relative">
<div class="text-white group absolute top-5 right-5">

7
packages/nc-gui/components/cell/attachment/index.vue

@ -152,7 +152,8 @@ watch(
:target="currentCellRef"
class="nc-attachment-cell-dropzone text-white text-lg ring ring-accent ring-opacity-100 bg-gray-700/75 flex items-center justify-center gap-2 backdrop-blur-xl"
>
<MaterialSymbolsFileCopyOutline class="text-accent" /> Drop here
<MaterialSymbolsFileCopyOutline class="text-accent" />
Drop here
</general-overlay>
</template>
@ -166,7 +167,7 @@ watch(
<MdiReload v-if="isLoading" :class="{ 'animate-infinite animate-spin': isLoading }" />
<a-tooltip v-else placement="bottom">
<template #title> Click or drop a file into cell </template>
<template #title> Click or drop a file into cell</template>
<div class="flex items-center gap-2">
<MaterialSymbolsAttachFile
@ -225,7 +226,7 @@ watch(
<MdiReload v-if="isLoading" :class="{ 'animate-infinite animate-spin': isLoading }" />
<a-tooltip v-else placement="bottom">
<template #title> View attachments </template>
<template #title> View attachments</template>
<MdiArrowExpand
class="transform dark:(!text-white) group-hover:(!text-accent scale-120) text-gray-500 text-[0.75rem]"

5
packages/nc-gui/components/cell/attachment/utils.ts

@ -66,12 +66,13 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
function removeFile(i: number) {
if (isPublic.value) {
storedFiles.value.splice(i, 1)
attachments.value.splice(i, 1)
updateModelValue(storedFiles.value.map((stored) => stored.file))
updateModelValue(storedFiles.value)
} else {
attachments.value.splice(i, 1)
updateModelValue(attachments.value)
updateModelValue(JSON.stringify(attachments.value))
}
}

14
packages/nc-gui/components/dashboard/TreeView.vue

@ -1,7 +1,9 @@
<script setup lang="ts">
import type { TableType } from 'nocodb-sdk'
import type { Input } from 'ant-design-vue'
import Sortable from 'sortablejs'
import GithubButton from 'vue-github-button'
import type { VNodeRef } from '#imports'
import {
Empty,
computed,
@ -39,7 +41,7 @@ let key = $ref(0)
const menuRef = $ref<HTMLLIElement>()
const filterQuery = $ref('')
let filterQuery = $ref('')
const activeTable = computed(() => ([TabType.TABLE, TabType.VIEW].includes(activeTab.value?.type) ? activeTab.value.title : null))
@ -207,6 +209,13 @@ function openTableCreateDialog() {
close(1000)
}
}
const searchInputRef: VNodeRef = (vnode: typeof Input) => vnode?.$el?.focus()
const onSearchCloseIconClick = () => {
filterQuery = ''
toggleSearchActive(false)
}
</script>
<template>
@ -217,6 +226,7 @@ function openTableCreateDialog() {
<Transition name="slide-left" mode="out-in">
<a-input
v-if="searchActive"
:ref="searchInputRef"
v-model:value="filterQuery"
class="flex-1 rounded"
:placeholder="$t('placeholder.searchProjectTree')"
@ -230,7 +240,7 @@ function openTableCreateDialog() {
</Transition>
<Transition name="layout" mode="out-in">
<MdiClose v-if="searchActive" class="text-lg mx-1 mt-0.5" @click="toggleSearchActive(false)" />
<MdiClose v-if="searchActive" class="text-lg mx-1 mt-0.5" @click="onSearchCloseIconClick" />
<IcRoundSearch v-else class="text-lg text-primary mx-1 mt-0.5" @click="toggleSearchActive(true)" />
</Transition>
</div>

4
packages/nc-gui/components/erd/Flow.vue

@ -94,10 +94,6 @@ onScopeDispose($destroy)
</template>
<style>
.vue-flow__edges {
z-index: 1000 !important;
}
.vue-flow__controls-zoomin {
@apply rounded-t;
}

33
packages/nc-gui/components/erd/RelationEdge.vue

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { EdgeProps, Position } from '@vue-flow/core'
import { EdgeText, getBezierPath } from '@vue-flow/core'
import { EdgeLabelRenderer, getBezierPath } from '@vue-flow/core'
import type { CSSProperties } from '@vue/runtime-dom'
import type { EdgeData } from './utils'
import { computed, toRef } from '#imports'
@ -92,26 +92,27 @@ export default {
<path class="opacity-0" :stroke-width="showSkeleton ? baseStroke * 12 : baseStroke * 8" fill="none" :d="edgePath[0]" />
<Transition name="layout">
<EdgeText
v-if="data.label?.length && data.label.length > 0"
:key="`edge-text-${id}.${showSkeleton}`"
class="color-transition"
<EdgeLabelRenderer>
<div
:style="{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${edgePath[1]}px,${edgePath[2]}px)`,
color: 'white',
fontSize: `${showSkeleton ? baseStroke * 2 : baseStroke / 2}rem`,
backgroundColor: data.color,
borderRadius: '0.25rem',
padding: '0.25rem 0.5rem',
}"
class="nodrag nopan color-transition z-1000"
:class="[
selected || isHovering ? 'opacity-100' : 'opacity-0 !pointer-events-none',
showSkeleton ? '!text-6xl' : '!text-xs',
`nc-erd-table-label-${data.label.toLowerCase().replace(' ', '-').replace('\(', '').replace(')', '')}`,
]"
:x="edgePath[1]"
:y="edgePath[2]"
:label="showSkeleton ? data.simpleLabel : data.label"
:label-style="{ fill: 'white', fontSize: `${showSkeleton ? baseStroke * 2 : baseStroke / 2}rem` }"
:label-show-bg="true"
:label-bg-style="{ fill: data.color }"
:label-bg-padding="[8, 6]"
:label-bg-border-radius="2"
/>
</Transition>
>
{{ showSkeleton ? data.simpleLabel : data.label }}
</div>
</EdgeLabelRenderer>
<template v-if="!showSkeleton">
<rect

9
packages/nc-gui/components/smartsheet/Cell.vue

@ -92,6 +92,7 @@ const {
isPhoneNumber,
isAutoSaved,
isManualSaved,
isPrimaryKey,
} = useColumn(column)
const vModel = computed({
@ -138,10 +139,10 @@ const syncAndNavigate = (dir: NavigateDir, e: KeyboardEvent) => {
<LazyCellAttachment v-else-if="isAttachment" v-model="vModel" :row-index="props.rowIndex" />
<LazyCellSingleSelect v-else-if="isSingleSelect" v-model="vModel" :row-index="props.rowIndex" />
<LazyCellMultiSelect v-else-if="isMultiSelect" v-model="vModel" :row-index="props.rowIndex" />
<LazyCellDatePicker v-else-if="isDate" v-model="vModel" />
<LazyCellYearPicker v-else-if="isYear" v-model="vModel" />
<LazyCellDateTimePicker v-else-if="isDateTime" v-model="vModel" />
<LazyCellTimePicker v-else-if="isTime" v-model="vModel" />
<LazyCellDatePicker v-else-if="isDate" v-model="vModel" :is-pk="isPrimaryKey" />
<LazyCellYearPicker v-else-if="isYear" v-model="vModel" :is-pk="isPrimaryKey" />
<LazyCellDateTimePicker v-else-if="isDateTime" v-model="vModel" :is-pk="isPrimaryKey" />
<LazyCellTimePicker v-else-if="isTime" v-model="vModel" :is-pk="isPrimaryKey" />
<LazyCellRating v-else-if="isRating" v-model="vModel" />
<LazyCellDuration v-else-if="isDuration" v-model="vModel" />
<LazyCellEmail v-else-if="isEmail" v-model="vModel" />

7
packages/nc-gui/components/smartsheet/Form.vue

@ -170,15 +170,14 @@ function onMoveCallback(event: any) {
function onMove(event: any) {
const { newIndex, element, oldIndex } = event.added || event.moved || event.removed
if (shouldSkipColumn(element)) {
return
}
if (event.added) {
element.show = true
}
if (event.removed) {
if (shouldSkipColumn(element)) {
return
}
element.show = false
saveOrUpdate(element, oldIndex)
} else {

4
packages/nc-gui/components/smartsheet/Grid.vue

@ -383,8 +383,8 @@ const saveOrUpdateRecords = async (args: { metaValue?: TableType; viewMetaValue?
currentRow.rowMeta.changed = false
for (const field of (args.metaValue || meta.value)?.columns ?? []) {
if (isVirtualCol(field)) continue
if (currentRow.row[field.title!] !== currentRow.oldRow[field.title!]) {
await updateOrSaveRow(currentRow, field.title!, args)
if (field.title! in currentRow.row && currentRow.row[field.title!] !== currentRow.oldRow[field.title!]) {
await updateOrSaveRow(currentRow, field.title!, {}, args)
}
}
}

21
packages/nc-gui/components/smartsheet/sidebar/index.vue

@ -21,8 +21,18 @@ const meta = inject(MetaInj, ref())
const activeView = inject(ActiveViewInj, ref())
const { activeTab } = useTabs()
const { views, loadViews, isLoading } = useViews(meta)
const { lastOpenedViewMap } = useProject()
const setLastOpenedViewId = (viewId?: string) => {
if (viewId && activeTab.value?.id) {
lastOpenedViewMap.value[activeTab.value?.id] = viewId
}
}
const { isUIAllowed } = useUIPermission()
const router = useRouter()
@ -43,10 +53,14 @@ const sidebar = ref()
watch(
[views, () => route.params.viewTitle],
([nextViews, viewTitle]) => {
const lastOpenedViewId = activeTab.value?.id && lastOpenedViewMap.value[activeTab.value?.id]
const lastOpenedView = nextViews.find((v) => v.id === lastOpenedViewId)
if (viewTitle) {
let view = nextViews.find((v) => v.title === viewTitle)
if (view) {
activeView.value = view
setLastOpenedViewId(activeView.value?.id)
} else {
/** search with view id and if found replace with title */
view = nextViews.find((v) => v.id === viewTitle)
@ -58,6 +72,13 @@ watch(
})
}
}
} else if (lastOpenedView) {
/** if active view is not found, set it to last opened view */
router.replace({
params: {
viewTitle: lastOpenedView.title,
},
})
} else {
if (nextViews?.length && activeView.value !== nextViews[0]) {
activeView.value = nextViews[0]

10
packages/nc-gui/composables/useApi/index.ts

@ -3,14 +3,16 @@ import { Api } from 'nocodb-sdk'
import type { Ref } from 'vue'
import type { CreateApiOptions, UseApiProps, UseApiReturn } from './types'
import { addAxiosInterceptors } from './interceptors'
import { BASE_URL, createEventHook, extractSdkResponseErrorMsg, ref, unref, useCounter, useGlobal, useNuxtApp } from '#imports'
import { BASE_FALLBACK_URL, createEventHook, extractSdkResponseErrorMsg, ref, unref, useCounter, useNuxtApp } from '#imports'
export function createApiInstance<SecurityDataType = any>({ baseURL = BASE_URL }: CreateApiOptions = {}): Api<SecurityDataType> {
const { appInfo } = $(useGlobal())
export function createApiInstance<SecurityDataType = any>({
baseURL = BASE_FALLBACK_URL,
}: CreateApiOptions = {}): Api<SecurityDataType> {
const config = useRuntimeConfig()
return addAxiosInterceptors(
new Api<SecurityDataType>({
baseURL: baseURL ?? appInfo.ncSiteUrl,
baseURL: config.public.ncBackendUrl || baseURL,
}),
)
}

2
packages/nc-gui/composables/useColumn.ts

@ -63,6 +63,7 @@ export function useColumn(column: Ref<ColumnType | undefined>) {
)
const isManualSaved = computed(() => [UITypes.Currency].includes(uiDatatype.value))
const isPrimary = computed(() => column.value?.pv)
const isPrimaryKey = computed(() => !!column.value?.pk)
return {
abstractType,
@ -95,5 +96,6 @@ export function useColumn(column: Ref<ColumnType | undefined>) {
isPercent,
isPhoneNumber,
isSpecificDBType,
isPrimaryKey,
}
}

14
packages/nc-gui/composables/useGlobal/state.ts

@ -1,7 +1,17 @@
import { useStorage } from '@vueuse/core'
import type { JwtPayload } from 'jwt-decode'
import type { AppInfo, State, StoredState } from './types'
import { BASE_URL, computed, ref, toRefs, useCounter, useJwt, useNuxtApp, usePreferredLanguages, useTimestamp } from '#imports'
import {
BASE_FALLBACK_URL,
computed,
ref,
toRefs,
useCounter,
useJwt,
useNuxtApp,
usePreferredLanguages,
useTimestamp,
} from '#imports'
import type { Language, User } from '~/lib'
export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
@ -75,7 +85,7 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
})
const appInfo = ref<AppInfo>({
ncSiteUrl: BASE_URL,
ncSiteUrl: BASE_FALLBACK_URL,
authType: 'jwt',
connectToExternalDB: false,
defaultLimit: 0,

3
packages/nc-gui/composables/useProject.ts

@ -39,6 +39,8 @@ const [setup, use] = useInjectionState(() => {
const projectMetaInfo = ref<ProjectMetaInfo | undefined>()
const lastOpenedViewMap = ref<Record<string, string>>({})
const projectId = computed(() => route.params.projectId as string)
// todo: refactor path param name and variable name
@ -165,6 +167,7 @@ const [setup, use] = useInjectionState(() => {
projectLoadedHook: projectLoadedHook.on,
reset,
isLoading,
lastOpenedViewMap,
}
}, 'useProject')

16
packages/nc-gui/composables/useViewData.ts

@ -241,14 +241,17 @@ export function useViewData(
}
}
// inside this method use metaValue and viewMetaValue to refer meta
// since sometimes we need to pass old metas
async function updateRowProperty(
toUpdate: Row,
property: string,
{ metaValue = meta.value, viewMetaValue = viewMeta.value }: { metaValue?: TableType; viewMetaValue?: ViewType } = {},
) {
if (toUpdate.rowMeta) toUpdate.rowMeta.saving = true
try {
const id = extractPkFromRow(toUpdate.row, meta.value?.columns as ColumnType[])
const id = extractPkFromRow(toUpdate.row, metaValue?.columns as ColumnType[])
const updatedRowData = await $api.dbViewRow.update(
NOCO,
@ -257,7 +260,8 @@ export function useViewData(
viewMetaValue?.id as string,
id,
{
[property]: toUpdate.row[property],
// if value is undefined treat it as null
[property]: toUpdate.row[property] ?? null,
},
// todo:
// {
@ -289,13 +293,19 @@ export function useViewData(
ltarState?: Record<string, any>,
args: { metaValue?: TableType; viewMetaValue?: ViewType } = {},
) {
// update changed status
if (row.rowMeta) row.rowMeta.changed = false
// if new row and save is in progress then wait until the save is complete
await until(() => !(row.rowMeta?.new && row.rowMeta?.saving)).toMatch((v) => v)
if (row.rowMeta.new) {
return await insertRow(row, formattedData.value.indexOf(row), ltarState, args)
} else {
await updateRowProperty(row, property!, args)
// if the field name is missing skip update
if (property) {
await updateRowProperty(row, property, args)
}
}
}

2
packages/nc-gui/composables/useViewFilters.ts

@ -40,7 +40,7 @@ export function useViewFilters(
const _filters = ref<Filter[]>([])
const nestedMode = computed(() => isPublic.value || !isUIAllowed('filte rSync') || !isUIAllowed('filterChildrenRead'))
const nestedMode = computed(() => isPublic.value || !isUIAllowed('filterSync') || !isUIAllowed('filterChildrenRead'))
const tabMeta = inject(TabMetaInj, ref({ filterState: new Map(), sortsState: new Map() } as TabItem))

2
packages/nc-gui/lib/constants.ts

@ -4,7 +4,7 @@ export const NOCO = 'noco'
export const SYSTEM_COLUMNS = ['id', 'title', 'created_at', 'updated_at']
export const BASE_URL = import.meta.env.NC_BACKEND_URL || (process.env.NODE_ENV === 'production' ? '..' : 'http://localhost:8080')
export const BASE_FALLBACK_URL = process.env.NODE_ENV === 'production' ? '..' : 'http://localhost:8080'
/**
* Each permission value means the following
* `*` - which is wildcard, means all permissions are allowed

26
packages/nc-gui/nuxt.config.ts

@ -14,14 +14,18 @@ export default defineNuxtConfig({
ssr: false,
app: {
pageTransition: {
name: 'page',
mode: 'out-in',
},
layoutTransition: {
name: 'layout',
mode: 'out-in',
},
pageTransition: process.env.NUXT_PAGE_TRANSITION_DISABLE
? false
: {
name: 'page',
mode: 'out-in',
},
layoutTransition: process.env.NUXT_PAGE_TRANSITION_DISABLE
? false
: {
name: 'layout',
mode: 'out-in',
},
/** In production build we need to load assets using relative path, to achieve the result we are using cdnURL */
cdnURL: process.env.NODE_ENV === 'production' ? '.' : undefined,
@ -35,6 +39,12 @@ export default defineNuxtConfig({
'~/assets/style.scss',
],
runtimeConfig: {
public: {
ncBackendUrl: '',
},
},
meta: {
title: 'NocoDB',
link: [

97
packages/nc-gui/package-lock.json generated

@ -9,8 +9,8 @@
"license": "AGPL-3.0-or-later",
"dependencies": {
"@ckpack/vue-color": "^1.2.0",
"@vue-flow/additional-components": "^1.1.0",
"@vue-flow/core": "^1.1.3",
"@vue-flow/additional-components": "^1.2.0",
"@vue-flow/core": "^1.3.0",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",
@ -90,7 +90,7 @@
}
},
"../nocodb-sdk": {
"version": "0.98.3",
"version": "0.98.4",
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^0.21.1",
@ -2960,6 +2960,33 @@
"@types/node": "*"
}
},
"node_modules/@types/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA=="
},
"node_modules/@types/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==",
"dependencies": {
"@types/d3-color": "*"
}
},
"node_modules/@types/d3-selection": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.3.tgz",
"integrity": "sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA=="
},
"node_modules/@types/d3-zoom": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz",
"integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==",
"dependencies": {
"@types/d3-interpolate": "*",
"@types/d3-selection": "*"
}
},
"node_modules/@types/dagre": {
"version": "0.7.48",
"resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.48.tgz",
@ -3357,18 +3384,24 @@
}
},
"node_modules/@vue-flow/additional-components": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@vue-flow/additional-components/-/additional-components-1.1.0.tgz",
"integrity": "sha512-uWz/xieBI80UwcIolnFkGojgKZwr46nspLMpz1oZuzCN09kqd7ZK2VgZSS04r7j8aWNNanioun2AvDXr+vg8vg==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@vue-flow/additional-components/-/additional-components-1.2.0.tgz",
"integrity": "sha512-a5F2y0WdPxaxTAcN7mSYVZ6A2kDSxenp+YwMt/2ldFRmCIP4jCbXEsTZfcpUe5zhlehfbyTTYbEw03w3YW24aA==",
"dependencies": {
"@types/d3-selection": "^3.0.3",
"@types/d3-zoom": "^3.0.1",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0"
},
"peerDependencies": {
"@vue-flow/core": "^1.0.0",
"vue": "^3.2.37"
}
},
"node_modules/@vue-flow/core": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@vue-flow/core/-/core-1.1.3.tgz",
"integrity": "sha512-MuJjWLexkZ5RiMY/LmuyRZXiXKo8ttaKSPk02RYP8SoWVj6Kr0XglWh6FJdQE0bQhqpwsXBka+4EQrI4B/ueSw==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@vue-flow/core/-/core-1.3.0.tgz",
"integrity": "sha512-hitjBy8RTw8gixcgJ9sjfZWyI6KNyKp4ffxTz/O4ZN/7TMwunEdc3cFHuU7R6J1OEhZ+HnlMRGrXmzXiIfdJow==",
"dependencies": {
"@vueuse/core": "^9.3.0",
"d3-drag": "^3.0.0",
@ -19454,6 +19487,33 @@
"@types/node": "*"
}
},
"@types/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA=="
},
"@types/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==",
"requires": {
"@types/d3-color": "*"
}
},
"@types/d3-selection": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.3.tgz",
"integrity": "sha512-Mw5cf6nlW1MlefpD9zrshZ+DAWL4IQ5LnWfRheW6xwsdaWOb6IRRu2H7XPAQcyXEx1D7XQWgdoKR83ui1/HlEA=="
},
"@types/d3-zoom": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.1.tgz",
"integrity": "sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==",
"requires": {
"@types/d3-interpolate": "*",
"@types/d3-selection": "*"
}
},
"@types/dagre": {
"version": "0.7.48",
"resolved": "https://registry.npmjs.org/@types/dagre/-/dagre-0.7.48.tgz",
@ -19752,15 +19812,20 @@
}
},
"@vue-flow/additional-components": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@vue-flow/additional-components/-/additional-components-1.1.0.tgz",
"integrity": "sha512-uWz/xieBI80UwcIolnFkGojgKZwr46nspLMpz1oZuzCN09kqd7ZK2VgZSS04r7j8aWNNanioun2AvDXr+vg8vg==",
"requires": {}
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@vue-flow/additional-components/-/additional-components-1.2.0.tgz",
"integrity": "sha512-a5F2y0WdPxaxTAcN7mSYVZ6A2kDSxenp+YwMt/2ldFRmCIP4jCbXEsTZfcpUe5zhlehfbyTTYbEw03w3YW24aA==",
"requires": {
"@types/d3-selection": "^3.0.3",
"@types/d3-zoom": "^3.0.1",
"d3-selection": "^3.0.0",
"d3-zoom": "^3.0.0"
}
},
"@vue-flow/core": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@vue-flow/core/-/core-1.1.3.tgz",
"integrity": "sha512-MuJjWLexkZ5RiMY/LmuyRZXiXKo8ttaKSPk02RYP8SoWVj6Kr0XglWh6FJdQE0bQhqpwsXBka+4EQrI4B/ueSw==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@vue-flow/core/-/core-1.3.0.tgz",
"integrity": "sha512-hitjBy8RTw8gixcgJ9sjfZWyI6KNyKp4ffxTz/O4ZN/7TMwunEdc3cFHuU7R6J1OEhZ+HnlMRGrXmzXiIfdJow==",
"requires": {
"@vueuse/core": "^9.3.0",
"d3-drag": "^3.0.0",

7
packages/nc-gui/package.json

@ -27,12 +27,13 @@
"coverage": "vitest -c test/vite.config.ts run --coverage",
"build:copy": "npm run generate; rm -rf ../nc-lib-gui/lib/dist/; rsync -rvzh ./dist/ ../nc-lib-gui/lib/dist/",
"build:copy:publish": "npm run generate; rm -rf ../nc-lib-gui/lib/dist/; rsync -rvzh ./dist/ ../nc-lib-gui/lib/dist/; npm publish ../nc-lib-gui",
"postinstall": "node scripts/updateNuxtRouting.js"
"postinstall": "node scripts/updateNuxtRouting.js",
"ci:run": "export NODE_OPTIONS=\"--max_old_space_size=16384\"; npm install; NUXT_PAGE_TRANSITION_DISABLE=true npm run build; NUXT_PUBLIC_NC_BACKEND_URL=http://localhost:8080 npm run start &"
},
"dependencies": {
"@ckpack/vue-color": "^1.2.0",
"@vue-flow/additional-components": "^1.1.0",
"@vue-flow/core": "^1.1.3",
"@vue-flow/additional-components": "^1.2.0",
"@vue-flow/core": "^1.3.0",
"@vuelidate/core": "^2.0.0-alpha.44",
"@vuelidate/validators": "^2.0.0-alpha.31",
"@vueuse/core": "^9.0.2",

0
scripts/playwright/.env.example → packages/nc-gui/tests/playwright/.env.example

0
scripts/playwright/.eslintrc.json → packages/nc-gui/tests/playwright/.eslintrc.json

0
scripts/playwright/.gitignore → packages/nc-gui/tests/playwright/.gitignore vendored

0
scripts/playwright/.lintstagedrc.json → packages/nc-gui/tests/playwright/.lintstagedrc.json

0
scripts/playwright/.prettierignore → packages/nc-gui/tests/playwright/.prettierignore

0
scripts/playwright/.prettierrc.js → packages/nc-gui/tests/playwright/.prettierrc.js

79
packages/nc-gui/tests/playwright/README.md

@ -0,0 +1,79 @@
# Playwright E2E tests
## Setup
Make sure to install the dependencies(in the playwright folder):
```bash
npm install
npx playwright install chromium --with-deps
```
## Run Test Server
Start the backend test server (in `packages/nocodb` folder):
```bash
npm run watch:run:playwright:quick
```
Start the frontend test server (in `packages/nc-gui` folder):
```bash
NUXT_PAGE_TRANSITION_DISABLE=true npm run dev
```
## Running Tests
### Running all tests
For selecting db type, rename `.env.example` to `.env` and set `E2E_DEV_DB_TYPE` to `sqlite`(default), `mysql` or `pg`.
```bash
npm run test
```
### Running individual tests
Add `.only` to the test you want to run:
```js
test.only('should login', async ({ page }) => {
// ...
})
```
```bash
npm run test
```
## Developing tests
### WebStorm
In Webstorm, you can use the `test-debug` run action to run the tests.
Add `.only` to the test you want to run. This will open the test in a chromium session and you can also add break points.
i.e `test.only('should login', async ({ page }) => {`
### VSCode
In VSCode, use this [https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chromium](extension).
It will have run button beside each test in the file.
### Page Objects
Page object is a class which has methods to interact with a page/component. Methods should be thin and should not do a whole lot. They should also be reusable.
All the action methods i.e click of a page object is also responsible for waiting till the action is completed. This can be done by waiting on an API call or some ui change.
Do not add any logic to the tests. Instead, create a page object for the page you are testing.
All the selection, UI actions and assertions should be in the page object.
Page objects should be in `packages/nc-gui/tests/playwright/pages` folder.
### Verify if tests are not flaky
Add `.only` to the added test and run `npm run test:repeat`. This will run the test multiple times and should show if the test is flaky.

0
scripts/playwright/constants/index.ts → packages/nc-gui/tests/playwright/constants/index.ts

110
packages/nc-gui/tests/playwright/fixtures/expectedBaseDownloadData.txt

@ -0,0 +1,110 @@
Country,City List
Afghanistan,Kabul
Algeria,"Batna, Bchar, Skikda"
American Samoa,Tafuna
Angola,"Benguela, Namibe"
Anguilla,South Hill
Argentina,"Almirante Brown, Avellaneda, Baha Blanca, Crdoba, Escobar, Ezeiza, La Plata, Merlo, Quilmes, San Miguel de Tucumn, Santa F, Tandil, Vicente Lpez"
Armenia,Yerevan
Australia,Woodridge
Austria,"Graz, Linz, Salzburg"
Azerbaijan,"Baku, Sumqayit"
Bahrain,al-Manama
Bangladesh,"Dhaka, Jamalpur, Tangail"
Belarus,"Mogiljov, Molodetno"
Bolivia,"El Alto, Sucre"
Brazil,"Alvorada, Angra dos Reis, Anpolis, Aparecida de Goinia, Araatuba, Bag, Belm, Blumenau, Boa Vista, Braslia, Goinia, Guaruj, guas Lindas de Gois, Ibirit, Juazeiro do Norte, Juiz de Fora, Luzinia, Maring, Po, Poos de Caldas, Rio Claro, Santa Brbara dOeste, Santo Andr, So Bernardo do Campo, So Leopoldo"
Brunei,Bandar Seri Begawan
Bulgaria,"Ruse, Stara Zagora"
Cambodia,"Battambang, Phnom Penh"
Cameroon,"Bamenda, Yaound"
Canada,"Gatineau, Halifax, Lethbridge, London, Oshawa, Richmond Hill, Vancouver"
Chad,NDjamna
Chile,"Antofagasta, Coquimbo, Rancagua"
China,"Baicheng, Baiyin, Binzhou, Changzhou, Datong, Daxian, Dongying, Emeishan, Enshi, Ezhou, Fuyu, Fuzhou, Haining, Hami, Hohhot, Huaian, Jinchang, Jining, Jinzhou, Junan, Korla, Laiwu, Laohekou, Lengshuijiang, Leshan"
Colombia,"Buenaventura, Dos Quebradas, Florencia, Pereira, Sincelejo, Sogamoso"
"Congo, The Democratic Republic of the","Lubumbashi, Mwene-Ditu"
Czech Republic,Olomouc
Dominican Republic,"La Romana, San Felipe de Puerto Plata, Santiago de los Caballeros"
Ecuador,"Loja, Portoviejo, Robamba"
Egypt,"Bilbays, Idfu, Mit Ghamr, Qalyub, Sawhaj, Shubra al-Khayma"
Estonia,Tartu
Ethiopia,Addis Abeba
Faroe Islands,Trshavn
Finland,Oulu
France,"Brest, Le Mans, Toulon, Toulouse"
French Guiana,Cayenne
French Polynesia,"Faaa, Papeete"
Gambia,Banjul
Germany,"Duisburg, Erlangen, Halle/Saale, Mannheim, Saarbrcken, Siegen, Witten"
Greece,"Athenai, Patras"
Greenland,Nuuk
Holy See (Vatican City State),Citt del Vaticano
Hong Kong,Kowloon and New Kowloon
Hungary,Szkesfehrvr
India,"Adoni, Ahmadnagar, Allappuzha (Alleppey), Ambattur, Amroha, Balurghat, Berhampore (Baharampur), Bhavnagar, Bhilwara, Bhimavaram, Bhopal, Bhusawal, Bijapur, Chandrapur, Chapra, Dhule (Dhulia), Etawah, Firozabad, Gandhinagar, Gulbarga, Haldia, Halisahar, Hoshiarpur, Hubli-Dharwad, Jaipur"
Indonesia,"Cianjur, Ciomas, Ciparay, Gorontalo, Jakarta, Lhokseumawe, Madiun, Pangkal Pinang, Pemalang, Pontianak, Probolinggo, Purwakarta, Surakarta, Tegal"
Iran,"Arak, Esfahan, Kermanshah, Najafabad, Qomsheh, Shahr-e Kord, Sirjan, Tabriz"
Iraq,Mosul
Israel,"Ashdod, Ashqelon, Bat Yam, Tel Aviv-Jaffa"
Italy,"Alessandria, Bergamo, Brescia, Brindisi, Livorno, Syrakusa, Udine"
Japan,"Akishima, Fukuyama, Higashiosaka, Hino, Hiroshima, Isesaki, Iwaki, Iwakuni, Iwatsuki, Izumisano, Kakamigahara, Kamakura, Kanazawa, Koriyama, Kurashiki, Kuwana, Matsue, Miyakonojo, Nagareyama, Okayama, Okinawa, Omiya, Onomichi, Otsu, Sagamihara"
Kazakstan,"Pavlodar, Zhezqazghan"
Kenya,"Kisumu, Nyeri"
Kuwait,Jalib al-Shuyukh
Latvia,"Daugavpils, Liepaja"
Liechtenstein,Vaduz
Lithuania,Vilnius
Madagascar,Mahajanga
Malawi,Lilongwe
Malaysia,"Ipoh, Kuching, Sungai Petani"
Mexico,"Acua, Allende, Atlixco, Carmen, Celaya, Coacalco de Berriozbal, Coatzacoalcos, Cuauhtmoc, Cuautla, Cuernavaca, El Fuerte, Guadalajara, Hidalgo, Huejutla de Reyes, Huixquilucan, Jos Azueta, Jurez, La Paz, Matamoros, Mexicali, Monclova, Nezahualcyotl, Pachuca de Soto, Salamanca, San Felipe del Progreso"
Moldova,Chisinau
Morocco,"Beni-Mellal, Nador, Sal"
Mozambique,"Beira, Naala-Porto, Tete"
Myanmar,"Monywa, Myingyan"
Nauru,Yangor
Nepal,Birgunj
Netherlands,"Amersfoort, Apeldoorn, Ede, Emmen, s-Hertogenbosch"
New Zealand,Hamilton
Nigeria,"Benin City, Deba Habe, Effon-Alaiye, Ife, Ikerre, Ilorin, Kaduna, Ogbomosho, Ondo, Owo, Oyo, Sokoto, Zaria"
North Korea,Pyongyang
Oman,"Masqat, Salala"
Pakistan,"Dadu, Mandi Bahauddin, Mardan, Okara, Shikarpur"
Paraguay,"Asuncin, Ciudad del Este, San Lorenzo"
Peru,"Callao, Hunuco, Lima, Sullana"
Philippines,"Baybay, Bayugan, Bislig, Cabuyao, Cavite, Davao, Gingoog, Hagonoy, Iligan, Imus, Lapu-Lapu, Mandaluyong, Ozamis, Santa Rosa, Taguig, Talavera, Tanauan, Tanza, Tarlac, Tuguegarao"
Poland,"Bydgoszcz, Czestochowa, Jastrzebie-Zdrj, Kalisz, Lublin, Plock, Tychy, Wroclaw"
Puerto Rico,"Arecibo, Ponce"
Romania,"Botosani, Bucuresti"
Runion,Saint-Denis
Russian Federation,"Atinsk, Balaiha, Dzerzinsk, Elista, Ivanovo, Jaroslavl, Jelets, Kaliningrad, Kamyin, Kirovo-Tepetsk, Kolpino, Korolev, Kurgan, Kursk, Lipetsk, Ljubertsy, Maikop, Moscow, Nabereznyje Telny, Niznekamsk, Novoterkassk, Pjatigorsk, Serpuhov, Smolensk, Syktyvkar"
Saint Vincent and the Grenadines,Kingstown
Saudi Arabia,"Abha, al-Hawiya, al-Qatif, Jedda, Tabuk"
Senegal,Ziguinchor
Slovakia,Bratislava
South Africa,"Boksburg, Botshabelo, Chatsworth, Johannesburg, Kimberley, Klerksdorp, Newcastle, Paarl, Rustenburg, Soshanguve, Springs"
South Korea,"Cheju, Kimchon, Naju, Tonghae, Uijongbu"
Spain,"A Corua (La Corua), Donostia-San Sebastin, Gijn, Ourense (Orense), Santiago de Compostela"
Sri Lanka,Jaffna
Sudan,"al-Qadarif, Omdurman"
Sweden,Malm
Switzerland,"Basel, Bern, Lausanne"
Taiwan,"Changhwa, Chiayi, Chungho, Fengshan, Hsichuh, Lungtan, Nantou, Tanshui, Touliu, Tsaotun"
Tanzania,"Mwanza, Tabora, Zanzibar"
Thailand,"Nakhon Sawan, Pak Kret, Songkhla"
Tonga,Nukualofa
Tunisia,Sousse
Turkey,"Adana, Balikesir, Batman, Denizli, Eskisehir, Gaziantep, Inegl, Kilis, Ktahya, Osmaniye, Sivas, Sultanbeyli, Tarsus, Tokat, Usak"
Turkmenistan,Ashgabat
Tuvalu,Funafuti
Ukraine,"Kamjanets-Podilskyi, Konotop, Mukateve, ostka, Simferopol, Sumy"
United Arab Emirates,"Abu Dhabi, al-Ayn, Sharja"
United Kingdom,"Bradford, Dundee, London, Southampton, Southend-on-Sea, Southport, Stockport, York"
United States,"Akron, Arlington, Augusta-Richmond County, Aurora, Bellevue, Brockton, Cape Coral, Citrus Heights, Clarksville, Compton, Dallas, Dayton, El Monte, Fontana, Garden Grove, Garland, Grand Prairie, Greensboro, Joliet, Kansas City, Lancaster, Laredo, Lincoln, Manchester, Memphis"
Venezuela,"Barcelona, Caracas, Cuman, Maracabo, Ocumare del Tuy, Valencia, Valle de la Pascua"
Vietnam,"Cam Ranh, Haiphong, Hanoi, Nam Dinh, Nha Trang, Vinh"
"Virgin Islands, U.S.",Charlotte Amalie
Yemen,"Aden, Hodeida, Sanaa, Taizz"
Yugoslavia,"Kragujevac, Novi Sad"
Zambia,Kitwe

110
packages/nc-gui/tests/playwright/fixtures/expectedBaseDownloadDataPg.txt

@ -0,0 +1,110 @@
Country,City List
Afghanistan,Kabul
Algeria,"Batna, Bchar, Skikda"
American Samoa,Tafuna
Angola,"Benguela, Namibe"
Anguilla,South Hill
Argentina,"Almirante Brown, Avellaneda, Baha Blanca, Crdoba, Escobar, Ezeiza, La Plata, Merlo, Quilmes, San Miguel de Tucumn, Santa F, Tandil, Vicente Lpez"
Armenia,Yerevan
Australia,Woodridge
Austria,"Graz, Linz, Salzburg"
Azerbaijan,"Baku, Sumqayit"
Bahrain,al-Manama
Bangladesh,"Dhaka, Jamalpur, Tangail"
Belarus,"Mogiljov, Molodetno"
Bolivia,"El Alto, Sucre"
Brazil,"Alvorada, Angra dos Reis, Anpolis, Aparecida de Goinia, Araatuba, Bag, Belm, Blumenau, Boa Vista, Braslia, Goinia, Guaruj, guas Lindas de Gois, Ibirit, Juazeiro do Norte, Juiz de Fora, Luzinia, Maring, Po, Poos de Caldas, Rio Claro, Santa Brbara dOeste, Santo Andr, So Bernardo do Campo, So Leopoldo"
Brunei,Bandar Seri Begawan
Bulgaria,"Ruse, Stara Zagora"
Cambodia,"Battambang, Phnom Penh"
Cameroon,"Bamenda, Yaound"
Canada,"Gatineau, Halifax, Lethbridge, London, Oshawa, Richmond Hill, Vancouver"
Chad,NDjamna
Chile,"Antofagasta, Coquimbo, Rancagua"
China,"Baicheng, Baiyin, Binzhou, Changzhou, Datong, Daxian, Dongying, Emeishan, Enshi, Ezhou, Fuyu, Fuzhou, Haining, Hami, Hohhot, Huaian, Jinchang, Jining, Jinzhou, Junan, Korla, Laiwu, Laohekou, Lengshuijiang, Leshan"
Colombia,"Buenaventura, Dos Quebradas, Florencia, Pereira, Sincelejo, Sogamoso"
"Congo, The Democratic Republic of the","Lubumbashi, Mwene-Ditu"
Czech Republic,Olomouc
Dominican Republic,"La Romana, San Felipe de Puerto Plata, Santiago de los Caballeros"
Ecuador,"Loja, Portoviejo, Robamba"
Egypt,"Bilbays, Idfu, Mit Ghamr, Qalyub, Sawhaj, Shubra al-Khayma"
Estonia,Tartu
Ethiopia,Addis Abeba
Faroe Islands,Trshavn
Finland,Oulu
France,"Brest, Le Mans, Toulon, Toulouse"
French Guiana,Cayenne
French Polynesia,"Faaa, Papeete"
Gambia,Banjul
Germany,"Duisburg, Erlangen, Halle/Saale, Mannheim, Saarbrcken, Siegen, Witten"
Greece,"Athenai, Patras"
Greenland,Nuuk
Holy See (Vatican City State),Citt del Vaticano
Hong Kong,Kowloon and New Kowloon
Hungary,Szkesfehrvr
India,"Adoni, Ahmadnagar, Allappuzha (Alleppey), Ambattur, Amroha, Balurghat, Berhampore (Baharampur), Bhavnagar, Bhilwara, Bhimavaram, Bhopal, Bhusawal, Bijapur, Chandrapur, Chapra, Dhule (Dhulia), Etawah, Firozabad, Gandhinagar, Gulbarga, Haldia, Halisahar, Hoshiarpur, Hubli-Dharwad, Jaipur"
Indonesia,"Cianjur, Ciomas, Ciparay, Gorontalo, Jakarta, Lhokseumawe, Madiun, Pangkal Pinang, Pemalang, Pontianak, Probolinggo, Purwakarta, Surakarta, Tegal"
Iran,"Arak, Esfahan, Kermanshah, Najafabad, Qomsheh, Shahr-e Kord, Sirjan, Tabriz"
Iraq,Mosul
Israel,"Ashdod, Ashqelon, Bat Yam, Tel Aviv-Jaffa"
Italy,"Alessandria, Bergamo, Brescia, Brindisi, Livorno, Syrakusa, Udine"
Japan,"Akishima, Fukuyama, Higashiosaka, Hino, Hiroshima, Isesaki, Iwaki, Iwakuni, Iwatsuki, Izumisano, Kakamigahara, Kamakura, Kanazawa, Koriyama, Kurashiki, Kuwana, Matsue, Miyakonojo, Nagareyama, Okayama, Okinawa, Omiya, Onomichi, Otsu, Sagamihara"
Kazakstan,"Pavlodar, Zhezqazghan"
Kenya,"Kisumu, Nyeri"
Kuwait,Jalib al-Shuyukh
Latvia,"Daugavpils, Liepaja"
Liechtenstein,Vaduz
Lithuania,Vilnius
Madagascar,Mahajanga
Malawi,Lilongwe
Malaysia,"Ipoh, Kuching, Sungai Petani"
Mexico,"Acua, Allende, Atlixco, Carmen, Celaya, Coacalco de Berriozbal, Coatzacoalcos, Cuauhtmoc, Cuautla, Cuernavaca, El Fuerte, Guadalajara, Hidalgo, Huejutla de Reyes, Huixquilucan, Jos Azueta, Jurez, La Paz, Matamoros, Mexicali, Monclova, Nezahualcyotl, Pachuca de Soto, Salamanca, San Felipe del Progreso"
Moldova,Chisinau
Morocco,"Beni-Mellal, Nador, Sal"
Mozambique,"Beira, Naala-Porto, Tete"
Myanmar,"Monywa, Myingyan"
Nauru,Yangor
Nepal,Birgunj
Netherlands,"Amersfoort, Apeldoorn, Ede, Emmen, s-Hertogenbosch"
New Zealand,Hamilton
Nigeria,"Benin City, Deba Habe, Effon-Alaiye, Ife, Ikerre, Ilorin, Kaduna, Ogbomosho, Ondo, Owo, Oyo, Sokoto, Zaria"
North Korea,Pyongyang
Oman,"Masqat, Salala"
Pakistan,"Dadu, Mandi Bahauddin, Mardan, Okara, Shikarpur"
Paraguay,"Asuncin, Ciudad del Este, San Lorenzo"
Peru,"Callao, Hunuco, Lima, Sullana"
Philippines,"Baybay, Bayugan, Bislig, Cabuyao, Cavite, Davao, Gingoog, Hagonoy, Iligan, Imus, Lapu-Lapu, Mandaluyong, Ozamis, Santa Rosa, Taguig, Talavera, Tanauan, Tanza, Tarlac, Tuguegarao"
Poland,"Bydgoszcz, Czestochowa, Jastrzebie-Zdrj, Kalisz, Lublin, Plock, Tychy, Wroclaw"
Puerto Rico,"Arecibo, Ponce"
Romania,"Botosani, Bucuresti"
Runion,Saint-Denis
Russian Federation,"Atinsk, Balaiha, Dzerzinsk, Elista, Ivanovo, Jaroslavl, Jelets, Kaliningrad, Kamyin, Kirovo-Tepetsk, Kolpino, Korolev, Kurgan, Kursk, Lipetsk, Ljubertsy, Maikop, Moscow, Nabereznyje Telny, Niznekamsk, Novoterkassk, Pjatigorsk, Serpuhov, Smolensk, Syktyvkar"
Saint Vincent and the Grenadines,Kingstown
Saudi Arabia,"Abha, al-Hawiya, al-Qatif, Jedda, Tabuk"
Senegal,Ziguinchor
Slovakia,Bratislava
South Africa,"Boksburg, Botshabelo, Chatsworth, Johannesburg, Kimberley, Klerksdorp, Newcastle, Paarl, Rustenburg, Soshanguve, Springs"
South Korea,"Cheju, Kimchon, Naju, Tonghae, Uijongbu"
Spain,"A Corua (La Corua), Donostia-San Sebastin, Gijn, Ourense (Orense), Santiago de Compostela"
Sri Lanka,Jaffna
Sudan,"al-Qadarif, Omdurman"
Sweden,Malm
Switzerland,"Basel, Bern, Lausanne"
Taiwan,"Changhwa, Chiayi, Chungho, Fengshan, Hsichuh, Lungtan, Nantou, Tanshui, Touliu, Tsaotun"
Tanzania,"Mwanza, Tabora, Zanzibar"
Thailand,"Nakhon Sawan, Pak Kret, Songkhla"
Tonga,Nukualofa
Tunisia,Sousse
Turkey,"Adana, Balikesir, Batman, Denizli, Eskisehir, Gaziantep, Inegl, Kilis, Ktahya, Osmaniye, Sivas, Sultanbeyli, Tarsus, Tokat, Usak"
Turkmenistan,Ashgabat
Tuvalu,Funafuti
Ukraine,"Kamjanets-Podilskyi, Konotop, Mukateve, ostka, Simferopol, Sumy"
United Arab Emirates,"Abu Dhabi, al-Ayn, Sharja"
United Kingdom,"Bradford, Dundee, London, Southampton, Southend-on-Sea, Southport, Stockport, York"
United States,"Akron, Arlington, Augusta-Richmond County, Aurora, Bellevue, Brockton, Cape Coral, Citrus Heights, Clarksville, Compton, Dallas, Dayton, El Monte, Fontana, Garden Grove, Garland, Grand Prairie, Greensboro, Joliet, Kansas City, Lancaster, Laredo, Lincoln, Manchester, Memphis"
Venezuela,"Barcelona, Caracas, Cuman, Maracabo, Ocumare del Tuy, Valencia, Valle de la Pascua"
Vietnam,"Cam Ranh, Haiphong, Hanoi, Nam Dinh, Nha Trang, Vinh"
"Virgin Islands, U.S.",Charlotte Amalie
Yemen,"Aden, Hodeida, Sanaa, Taizz"
Yugoslavia,"Kragujevac, Novi Sad"
Zambia,Kitwe

0
scripts/playwright/fixtures/expectedData.txt → packages/nc-gui/tests/playwright/fixtures/expectedData.txt

19
packages/nc-gui/tests/playwright/fixtures/expectedDataSqlite.txt

@ -0,0 +1,19 @@
Address,District,PostalCode,Phone,Customer List,Staff List,City,Staff List1
1013 Tabuk Boulevard," ",96203," ",2,,Kanchrapara,
1168 Najafabad Parkway," ",40301," ",1,,Kabul,
1294 Firozabad Drive," ",70618," ",2,,Pingxiang,
1342 Abha Boulevard," ",10714," ",2,,Bucuresti,
1368 Maracabo Boulevard," ",32716," ",2,,South Hill,
1427 Tabuk Place," ",31342," ",2,,Cape Coral,
1519 Santiago de los Caballeros Loop," ",22025," ",2,,Mwene-Ditu,
1661 Abha Drive," ",14400," ",1,,Pudukkottai,
17 Kabul Boulevard," ",38594," ",1,,Nagareyama,
1838 Tabriz Lane," ",1195," ",1,,Dhaka,
1888 Kabul Drive," ",20936," ",1,,Ife,
1892 Nabereznyje Telny Lane," ",28396," ",2,,Tafuna,
1993 Tabuk Lane," ",64221," ",2,,Tambaram,
217 Botshabelo Place," ",49521," ",2,,Davao,
381 Kabul Way," ",87272," ",2,,Hsichuh,
44 Najafabad Way," ",61391," ",2,,Donostia-San Sebastin,
48 Maracabo Place," ",1570," ",1,,Talavera,
669 Firozabad Loop," ",92265," ",1,,al-Ayn,

0
scripts/playwright/fixtures/sampleFiles/1.json → packages/nc-gui/tests/playwright/fixtures/sampleFiles/1.json

0
scripts/playwright/fixtures/sampleFiles/2.json → packages/nc-gui/tests/playwright/fixtures/sampleFiles/2.json

0
scripts/playwright/fixtures/sampleFiles/3.json → packages/nc-gui/tests/playwright/fixtures/sampleFiles/3.json

0
scripts/playwright/fixtures/sampleFiles/4.json → packages/nc-gui/tests/playwright/fixtures/sampleFiles/4.json

0
scripts/playwright/fixtures/sampleFiles/5.json → packages/nc-gui/tests/playwright/fixtures/sampleFiles/5.json

0
scripts/playwright/fixtures/sampleFiles/6.json → packages/nc-gui/tests/playwright/fixtures/sampleFiles/6.json

0
scripts/playwright/fixtures/sampleFiles/simple.xlsx → packages/nc-gui/tests/playwright/fixtures/sampleFiles/simple.xlsx

0
scripts/playwright/fixtures/template.spec.ts → packages/nc-gui/tests/playwright/fixtures/template.spec.ts

267
scripts/playwright/package-lock.json → packages/nc-gui/tests/playwright/package-lock.json generated

@ -29,6 +29,7 @@
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"mysql2": "^2.3.3",
"pg": "^8.8.0",
"prettier": "^2.7.1",
"promised-sqlite3": "^1.2.0"
}
@ -841,6 +842,15 @@
"node": ">=8"
}
},
"node_modules/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==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -3628,6 +3638,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/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==",
"dev": true
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -3686,6 +3702,87 @@
"node": ">=8"
}
},
"node_modules/pg": {
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz",
"integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==",
"dev": true,
"dependencies": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
"pg-connection-string": "^2.5.0",
"pg-pool": "^3.5.2",
"pg-protocol": "^1.5.0",
"pg-types": "^2.1.0",
"pgpass": "1.x"
},
"engines": {
"node": ">= 8.0.0"
},
"peerDependencies": {
"pg-native": ">=3.0.1"
},
"peerDependenciesMeta": {
"pg-native": {
"optional": true
}
}
},
"node_modules/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==",
"dev": true
},
"node_modules/pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"dev": true,
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pg-pool": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz",
"integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==",
"dev": true,
"peerDependencies": {
"pg": ">=8.0"
}
},
"node_modules/pg-protocol": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==",
"dev": true
},
"node_modules/pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"dev": true,
"dependencies": {
"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"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pgpass": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"dev": true,
"dependencies": {
"split2": "^4.1.0"
}
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@ -3722,6 +3819,45 @@
"node": ">=14"
}
},
"node_modules/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==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/postgres-bytea": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/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==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/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==",
"dev": true,
"dependencies": {
"xtend": "^4.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@ -4273,6 +4409,15 @@
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/split2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
"integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
"dev": true,
"engines": {
"node": ">= 10.x"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@ -4797,6 +4942,15 @@
"node": ">=0.8"
}
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true,
"engines": {
"node": ">=0.4"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@ -5394,6 +5548,12 @@
"fill-range": "^7.0.1"
}
},
"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==",
"dev": true
},
"bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -7459,6 +7619,12 @@
"aggregate-error": "^3.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==",
"dev": true
},
"parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@ -7502,6 +7668,68 @@
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"dev": true
},
"pg": {
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz",
"integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==",
"dev": true,
"requires": {
"buffer-writer": "2.0.0",
"packet-reader": "1.0.0",
"pg-connection-string": "^2.5.0",
"pg-pool": "^3.5.2",
"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==",
"dev": true
},
"pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"dev": true
},
"pg-pool": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz",
"integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==",
"dev": true,
"requires": {}
},
"pg-protocol": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==",
"dev": true
},
"pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"dev": true,
"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==",
"dev": true,
"requires": {
"split2": "^4.1.0"
}
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@ -7520,6 +7748,33 @@
"integrity": "sha512-9EmeXDncC2Pmp/z+teoVYlvmPWUC6ejSSYZUln7YaP89Z6lpAaiaAnqroUt/BoLo8tn7WYShcfaCh+xofZa44Q==",
"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==",
"dev": true
},
"postgres-bytea": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
"dev": true
},
"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==",
"dev": true
},
"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==",
"dev": true,
"requires": {
"xtend": "^4.0.0"
}
},
"prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@ -7917,6 +8172,12 @@
"is-fullwidth-code-point": "^3.0.0"
}
},
"split2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
"integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
"dev": true
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@ -8320,6 +8581,12 @@
"word": "~0.3.0"
}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

13
scripts/playwright/package.json → packages/nc-gui/tests/playwright/package.json

@ -5,11 +5,17 @@
"main": "index.js",
"scripts": {
"test": "TRACE=true npx playwright test --workers=4",
"test:repeat": "TRACE=true npx playwright test --workers=4 --repeat-each=10",
"test:shard:1": "TRACE=true npx playwright test --workers=4 --shard=1/2",
"test:shard:2": "TRACE=true npx playwright test --workers=4 --shard=2/2",
"test:repeat": "TRACE=true npx playwright test --workers=4 --repeat-each=12",
"test:quick": "TRACE=true PW_QUICK_TEST=1 npx playwright test --workers=4",
"test:debug": "./startPlayWrightServer.sh; PW_TEST_REUSE_CONTEXT=1 PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:31000/ PWDEBUG=console npx playwright test -c playwright.config.ts --headed --project=chromium --retries 0 --timeout 0 --workers 1 --max-failures=1",
"test:debug:quick:sqlite": "./startPlayWrightServer.sh; PW_QUICK_TEST=1 PW_TEST_REUSE_CONTEXT=1 PW_TEST_CONNECT_WS_ENDPOINT=ws://127.0.0.1:31000/ PWDEBUG=console npx playwright test -c playwright.config.ts --headed --project=chromium --retries 0 --timeout 5 --workers 1 --max-failures=1",
"ci:test:mysql": "E2E_DB_TYPE=mysql npx playwright test --workers=2"
"ci:test": "npx playwright test --workers=2",
"ci:test:shard:1": "npx playwright test --workers=2 --shard=1/2",
"ci:test:shard:2": "npx playwright test --workers=2 --shard=2/2",
"ci:test:mysql": "E2E_DB_TYPE=mysql npx playwright test --workers=2",
"ci:test:pg": "E2E_DB_TYPE=pg npx playwright test --workers=2"
},
"keywords": [],
"author": "",
@ -25,11 +31,12 @@
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"mysql2": "^2.3.3",
"pg": "^8.8.0",
"prettier": "^2.7.1",
"promised-sqlite3": "^1.2.0"
},

0
scripts/playwright/pages/Base.ts → packages/nc-gui/tests/playwright/pages/Base.ts

0
scripts/playwright/pages/Dashboard/ExpandedForm/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/ExpandedForm/index.ts

0
scripts/playwright/pages/Dashboard/Form/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Form/index.ts

0
scripts/playwright/pages/Dashboard/Gallery/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Gallery/index.ts

0
scripts/playwright/pages/Dashboard/Grid/Column/LTAR/ChildList.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/LTAR/ChildList.ts

0
scripts/playwright/pages/Dashboard/Grid/Column/LTAR/LinkRecord.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/LTAR/LinkRecord.ts

0
scripts/playwright/pages/Dashboard/Grid/Column/SelectOptionColumn.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/SelectOptionColumn.ts

0
scripts/playwright/pages/Dashboard/Grid/Column/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Grid/Column/index.ts

0
scripts/playwright/pages/Dashboard/Grid/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Grid/index.ts

0
scripts/playwright/pages/Dashboard/Import/Airtable.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Import/Airtable.ts

0
scripts/playwright/pages/Dashboard/Import/ImportTemplate.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Import/ImportTemplate.ts

0
scripts/playwright/pages/Dashboard/Kanban/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Kanban/index.ts

0
scripts/playwright/pages/Dashboard/Settings/Acl.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Acl.ts

15
scripts/playwright/pages/Dashboard/Settings/AppStore.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/AppStore.ts

@ -17,6 +17,21 @@ export class AppStoreSettingsPage extends BasePage {
async install({ name }: { name: string }) {
const card = await this.settings.get().locator(`.nc-app-store-card-${name}`);
await card.click();
// todo: Hack to solve the issue when if the test installing a plugin fails, the next test will fail because the plugin is already installed
let appAlreadyInstalled = true;
for (let i = 0; i < 5; i++) {
if (await card.locator('.nc-app-store-card-install').isVisible()) {
appAlreadyInstalled = false;
break;
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
if (appAlreadyInstalled) {
await this.uninstall({ name });
}
await card.locator('.nc-app-store-card-install').click();
}

0
scripts/playwright/pages/Dashboard/Settings/Audit.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Audit.ts

0
scripts/playwright/pages/Dashboard/Settings/Erd.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Erd.ts

25
scripts/playwright/pages/Dashboard/Settings/Metadata.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Metadata.ts

@ -31,18 +31,17 @@ export class MetaDataPage extends BasePage {
}
async verifyRow({ index, model, state }: { index: number; model: string; state: string }) {
await expect
.poll(async () => {
return await this.get()
.locator(`tr.ant-table-row`)
.nth(index)
.locator(`td.ant-table-cell`)
.nth(0)
.textContent();
})
.toContain(model);
await expect(
await this.get().locator(`tr.ant-table-row`).nth(index).locator(`td.ant-table-cell`).nth(1).textContent()
).toContain(state);
await expect(this.get().locator(`tr.ant-table-row`).nth(index).locator(`td.ant-table-cell`).nth(0)).toHaveText(
model,
{
ignoreCase: true,
}
);
await expect(this.get().locator(`tr.ant-table-row`).nth(index).locator(`td.ant-table-cell`).nth(1)).toHaveText(
state,
{
ignoreCase: true,
}
);
}
}

0
scripts/playwright/pages/Dashboard/Settings/Miscellaneous.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Miscellaneous.ts

0
scripts/playwright/pages/Dashboard/Settings/Teams.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/Teams.ts

0
scripts/playwright/pages/Dashboard/Settings/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/Settings/index.ts

0
scripts/playwright/pages/Dashboard/SurveyForm/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/SurveyForm/index.ts

0
scripts/playwright/pages/Dashboard/TreeView.ts → packages/nc-gui/tests/playwright/pages/Dashboard/TreeView.ts

0
scripts/playwright/pages/Dashboard/ViewSidebar/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/ViewSidebar/index.ts

0
scripts/playwright/pages/Dashboard/WebhookForm/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/WebhookForm/index.ts

0
scripts/playwright/pages/Dashboard/common/Cell/AttachmentCell.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/AttachmentCell.ts

0
scripts/playwright/pages/Dashboard/common/Cell/CheckboxCell.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/CheckboxCell.ts

0
scripts/playwright/pages/Dashboard/common/Cell/RatingCell.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/RatingCell.ts

0
scripts/playwright/pages/Dashboard/common/Cell/SelectOptionCell.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/SelectOptionCell.ts

0
scripts/playwright/pages/Dashboard/common/Cell/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Cell/index.ts

0
scripts/playwright/pages/Dashboard/common/ProjectMenu/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/ProjectMenu/index.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/Actions/Erd.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Actions/Erd.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/Actions/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Actions/index.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/AddEditKanbanStack.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/AddEditKanbanStack.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/Fields.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Fields.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/Filter.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/ShareView.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/ShareView.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/Sort.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/Sort.ts

0
scripts/playwright/pages/Dashboard/common/Toolbar/StackBy.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/StackBy.ts

5
scripts/playwright/pages/Dashboard/common/Toolbar/ViewMenu.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/ViewMenu.ts

@ -55,7 +55,8 @@ export class ToolbarViewMenuPage extends BasePage {
// Get API Snippet
// ERD View
async click({ menu, subMenu }: { menu: string; subMenu?: string }) {
// todo: Move verification out of the click method
async click({ menu, subMenu, verificationInfo }: { menu: string; subMenu?: string; verificationInfo?: any }) {
await this.viewsMenuBtn.click();
await this.get().locator(`.ant-dropdown-menu-title-content:has-text("${menu}")`).first().click();
if (subMenu) {
@ -65,7 +66,7 @@ export class ToolbarViewMenuPage extends BasePage {
downloadLocator: await this.rootPage
.locator(`.ant-dropdown-menu-title-content:has-text("${subMenu}")`)
.last(),
expectedDataFile: './fixtures/expectedBaseDownloadData.txt',
expectedDataFile: verificationInfo?.verificationFile ?? './fixtures/expectedBaseDownloadData.txt',
});
} else {
await this.rootPage.locator(`.ant-dropdown-menu-title-content:has-text("${subMenu}")`).last().click();

4
scripts/playwright/pages/Dashboard/common/Toolbar/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/common/Toolbar/index.ts

@ -94,7 +94,7 @@ export class ToolbarPage extends BasePage {
await this.get().locator(`.nc-toolbar-btn.nc-add-new-row-btn`).click();
}
async clickDownload(type: string, verificationFile: string) {
async clickDownload(type: string, verificationFile = 'expectedData.txt') {
await this.get().locator(`.nc-toolbar-btn.nc-actions-menu-btn`).click();
const [download] = await Promise.all([
@ -111,7 +111,7 @@ export class ToolbarPage extends BasePage {
await download.saveAs('./output/at.txt');
// verify downloaded content against expected content
const expectedData = fs.readFileSync('./fixtures/expectedData.txt', 'utf8');
const expectedData = fs.readFileSync(`./fixtures/${verificationFile}`, 'utf8');
const file = fs.readFileSync('./output/at.txt', 'utf8');
await expect(file).toEqual(expectedData);
}

2
scripts/playwright/pages/Dashboard/commonBase/Erd.ts → packages/nc-gui/tests/playwright/pages/Dashboard/commonBase/Erd.ts

@ -89,7 +89,7 @@ export abstract class ErdBasePage extends BasePage {
}
async verifyJunctionTableLabel({ tableTitle, tableName }: { tableName: string; tableTitle: string }) {
await await this.vueFlow().locator(`.nc-erd-table-label-${tableTitle}-${tableName}`).locator('text').waitFor({
await this.vueFlow().locator(`.nc-erd-table-label-${tableTitle}-${tableName}`).waitFor({
state: 'visible',
});
}

3
scripts/playwright/pages/Dashboard/index.ts → packages/nc-gui/tests/playwright/pages/Dashboard/index.ts

@ -79,6 +79,9 @@ export class DashboardPage extends BasePage {
}
async clickHome() {
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
await this.rootPage.locator('[data-cy="nc-noco-brand-icon"]').click();
const projectsPage = new ProjectsPage(this.rootPage);
await projectsPage.waitToBeRendered();

0
scripts/playwright/pages/LoginPage/index.ts → packages/nc-gui/tests/playwright/pages/LoginPage/index.ts

20
scripts/playwright/pages/ProjectsPage/index.ts → packages/nc-gui/tests/playwright/pages/ProjectsPage/index.ts

@ -9,7 +9,7 @@ export class ProjectsPage extends BasePage {
prefixTitle(title: string) {
const parallelId = process.env.TEST_PARALLEL_INDEX ?? '0';
return `${title}${parallelId}`;
return `nc_test_${parallelId}_${title}`;
}
get() {
@ -31,15 +31,24 @@ export class ProjectsPage extends BasePage {
await this.rootPage.locator('.nc-new-project-menu').click();
const createProjectMenu = await this.rootPage.locator('.nc-dropdown-create-project');
if (type === 'xcdb') {
await createProjectMenu.locator(`.ant-dropdown-menu-title-content`).nth(0).click();
} else {
await createProjectMenu.locator(`.ant-dropdown-menu-title-content`).nth(1).click();
}
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
await this.rootPage.locator(`.nc-metadb-project-name`).waitFor();
await this.rootPage.locator(`input.nc-metadb-project-name`).fill(name);
await this.rootPage.locator(`input.nc-metadb-project-name`).press('Enter');
await this.rootPage.waitForTimeout(2000);
await this.rootPage.locator(`button:has-text("Create")`).click({
delay: 2000,
});
// fix me! wait for page to be rendered completely
await this.rootPage.waitForTimeout(2000);
@ -78,6 +87,9 @@ export class ProjectsPage extends BasePage {
withoutPrefix?: boolean;
waitForAuthTab?: boolean;
}) {
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
if (!withoutPrefix) title = this.prefixTitle(title);
let project: any;
@ -144,6 +156,10 @@ export class ProjectsPage extends BasePage {
has: project.locator(`td.ant-table-cell:has-text("${title}")`),
});
await projRow.locator('.nc-action-btn').nth(0).click();
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
await project.locator('input.nc-metadb-project-name').fill(newTitle);
// press enter to save
const submitAction = project.locator('input.nc-metadb-project-name').press('Enter');

0
scripts/playwright/pages/SharedForm/index.ts → packages/nc-gui/tests/playwright/pages/SharedForm/index.ts

0
scripts/playwright/pages/SignupPage/index.ts → packages/nc-gui/tests/playwright/pages/SignupPage/index.ts

0
scripts/playwright/playwright.config.ts → packages/nc-gui/tests/playwright/playwright.config.ts

4
scripts/playwright/quickTests/commonTest.ts → packages/nc-gui/tests/playwright/quickTests/commonTest.ts

@ -1,7 +1,7 @@
import { DashboardPage } from '../pages/Dashboard';
import { ProjectsPage } from '../pages/ProjectsPage';
import { NcContext } from '../setup';
import { isMysql } from '../setup/db';
import { isMysql, isPg } from '../setup/db';
// normal fields
const recordCells = {
@ -103,7 +103,7 @@ const quickVerify = async ({
await dashboard.grid.cell.verifyVirtualCell({
index: cellIndex,
columnHeader: 'Actor',
value: isMysql(context) ? ['Actor1'] : recordsVirtualCells.Actor,
value: isMysql(context) || isPg(context) ? ['Actor1'] : recordsVirtualCells.Actor,
});
// Status (from Actor)

0
scripts/playwright/quickTests/quickTests.spec.ts → packages/nc-gui/tests/playwright/quickTests/quickTests.spec.ts

2
scripts/playwright/scripts/docker-compose-playwright.yml → packages/nc-gui/tests/playwright/scripts/docker-compose-mysql-playwright.yml

@ -11,4 +11,4 @@ services:
environment:
MYSQL_ROOT_PASSWORD: password
volumes:
- ../../../packages/nocodb/tests/mysql-sakila-db:/docker-entrypoint-initdb.d
- ../../../../../packages/nocodb/tests/mysql-sakila-db:/docker-entrypoint-initdb.d

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

Loading…
Cancel
Save