Browse Source

Merge pull request #5903 from nocodb/feat/pnpm

feat: pnpm
pull/6315/head
աɨռɢӄաօռɢ 1 year ago committed by GitHub
parent
commit
c05e3cdd95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 78
      .github/workflows/ci-cd.yml
  2. 64
      .github/workflows/playwright-test-workflow.yml
  3. 2
      .github/workflows/publish-blog.yml
  4. 2
      .github/workflows/publish-dev-docs.yml
  5. 2
      .github/workflows/publish-docs.yml
  6. 2
      .github/workflows/publish-noco-i18n.yml
  7. 2
      .github/workflows/publish-prev-docs.yml
  8. 28
      .github/workflows/release-docker.yml
  9. 2
      .github/workflows/release-draft.yml
  10. 22
      .github/workflows/release-executables.yml
  11. 28
      .github/workflows/release-npm.yml
  12. 5
      .github/workflows/release-pr.yml
  13. 2
      .github/workflows/release-timely-executables.yml
  14. 35
      .github/workflows/unit-test.yml
  15. 12
      .github/workflows/update-sdk-path.yml
  16. 5
      .gitignore
  17. 3
      .npmrc
  18. 2
      README.md
  19. 36
      build-local-docker-image.sh
  20. 14
      markdown/readme/languages/chinese.md
  21. 8
      markdown/readme/languages/german.md
  22. 2
      markdown/readme/languages/portuguese.md
  23. 2
      markdown/readme/languages/spanish.md
  24. 17866
      package-lock.json
  25. 33
      package.json
  26. 2
      packages/nc-gui/components/account/ResetPassword.vue
  27. 2
      packages/nc-gui/components/general/MiniSidebar.vue
  28. 2
      packages/nc-gui/layouts/base.vue
  29. 6
      packages/nc-gui/nuxt.config.ts
  30. 29694
      packages/nc-gui/package-lock.json
  31. 74
      packages/nc-gui/package.json
  32. 4
      packages/nc-gui/test/vite.config.ts
  33. 2
      packages/nc-gui/tsconfig.json
  34. 2
      packages/noco-docs/docs/020.getting-started/010.installation.md
  35. 2
      packages/noco-docs/docs/040.developer-resources/030.sdk.md
  36. 38
      packages/noco-docs/docs/050.engineering/030.development-setup.md
  37. 6
      packages/noco-docs/docs/050.engineering/040.unit-testing.md
  38. 20
      packages/noco-docs/docs/050.engineering/050.playwright.md
  39. 8
      packages/noco-docs/docs/060.FAQs.md
  40. 1
      packages/noco-docs/versioned_docs/version-0.109.7/050.engineering/030.development-setup.md
  41. 7630
      packages/nocodb-sdk/package-lock.json
  42. 26
      packages/nocodb-sdk/package.json
  43. 23
      packages/nocodb/Dockerfile
  44. 21
      packages/nocodb/Dockerfile.local
  45. 4
      packages/nocodb/README.md
  46. 14
      packages/nocodb/docker/webpack.config.js
  47. 23
      packages/nocodb/litestream/Dockerfile
  48. 35076
      packages/nocodb/package-lock.json
  49. 105
      packages/nocodb/package.json
  50. 2
      packages/nocodb/src/controllers/test/TestResetService/resetPgSakilaProject.ts
  51. 2
      packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2Trans.ts
  52. 2
      packages/nocodb/src/helpers/PagedResponse.ts
  53. 2
      packages/nocodb/src/helpers/columnHelpers.ts
  54. 2
      packages/nocodb/src/helpers/initAdminFromEnv.ts
  55. 2
      packages/nocodb/src/modules/event-emitter/nestjs-event-emitter.ts
  56. 3
      packages/nocodb/src/nocobuild.ts
  57. 4
      packages/nocodb/src/run/docker.ts
  58. 4
      packages/nocodb/src/run/dockerEntry.ts
  59. 4
      packages/nocodb/src/run/dockerRunMysql.ts
  60. 4
      packages/nocodb/src/run/dockerRunPG.ts
  61. 4
      packages/nocodb/src/run/dockerRunPG_CyQuick.ts
  62. 5
      packages/nocodb/src/run/local.ts
  63. 4
      packages/nocodb/src/run/testDocker.ts
  64. 3
      packages/nocodb/src/services/app-hooks/interfaces.ts
  65. 2
      packages/nocodb/src/services/users/users.service.ts
  66. 4
      packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts
  67. 4
      packages/nocodb/src/version-upgrader/v1-legacy/NcProjectBuilder.ts
  68. 8
      packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts
  69. 8
      packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts
  70. 9
      packages/nocodb/webpack.config.js
  71. 8
      packages/nocodb/webpack.local.config.js
  72. 23728
      pnpm-lock.yaml
  73. 5
      pnpm-workspace.yaml
  74. 6
      scripts/installLocalSdk.js
  75. 14
      scripts/pkg-executable/package.json
  76. 2
      scripts/upgradeNcGui.js
  77. 32
      scripts/upgradeNocodbSdk.js
  78. 2
      tests/playwright/.lintstagedrc.json
  79. 10705
      tests/playwright/package-lock.json
  80. 89
      tests/playwright/package.json
  81. 6
      tests/playwright/pages/Account/License.ts
  82. 23
      tests/playwright/pages/Account/Settings.ts
  83. 6
      tests/playwright/pages/Account/Token.ts
  84. 19
      tests/playwright/pages/Account/Users.ts
  85. 58
      tests/playwright/pages/Base.ts
  86. 4
      tests/playwright/pages/Dashboard/Grid/Column/index.ts
  87. 1
      tests/playwright/pages/Dashboard/Grid/index.ts
  88. 2
      tests/playwright/pages/Dashboard/Settings/Acl.ts
  89. 2
      tests/playwright/pages/Dashboard/TreeView.ts
  90. 4
      tests/playwright/pages/Dashboard/WebhookForm/index.ts
  91. 6
      tests/playwright/pages/Dashboard/common/Cell/CheckboxCell.ts
  92. 2
      tests/playwright/pages/Dashboard/common/Cell/RatingCell.ts
  93. 2
      tests/playwright/pages/Dashboard/common/Toolbar/Fields.ts
  94. 21
      tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts
  95. 1
      tests/playwright/pages/Dashboard/common/Topbar/index.ts
  96. 5
      tests/playwright/pages/Dashboard/index.ts
  97. 2
      tests/playwright/pages/LoginPage/index.ts
  98. 45
      tests/playwright/pages/ProjectsPage/index.ts
  99. 2
      tests/playwright/pages/SharedForm/index.ts
  100. 4
      tests/playwright/pages/SigninPage/index.ts
  101. Some files were not shown because too many files have changed in this diff Show More

78
.github/workflows/ci-cd.yml

@ -33,65 +33,62 @@ jobs:
timeout-minutes: 40
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
node-version: 18.14.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
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
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:main
- name: Install dependencies
working-directory: ./packages/nocodb
run: npm install
${{ runner.os }}-pnpm-store-
- name: Install dependencies for packages
run: pnpm bootstrap
- name: run unit tests
working-directory: ./packages/nocodb
run: npm run test:unit
run: pnpm run test:unit
unit-tests-pg:
runs-on: ubuntu-20.04
timeout-minutes: 40
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
node-version: 18.14.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
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
${{ runner.os }}-pnpm-store-
- name: Set CI env
run: export CI=true
- name: Set NC Edition
@ -99,18 +96,11 @@ jobs:
- name: setup pg
working-directory: ./
run: docker-compose -f ./tests/playwright/scripts/docker-compose-playwright-pg.yml up -d &
- 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:main
- name: Install dependencies
working-directory: ./packages/nocodb
run: npm install
- name: install dependencies
run: pnpm bootstrap
- name: run unit tests
working-directory: ./packages/nocodb
run: npm run test:unit:pg
run: pnpm run test:unit:pg
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

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

@ -16,25 +16,27 @@ jobs:
runs-on: [self-hosted, v2]
timeout-minutes: 100
steps:
- name: Checkout
uses: actions/checkout@v3
- 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
node-version: 18.14.0
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-v2-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
version: 8
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-v2-build-${{ env.cache-name }}-
${{ runner.os }}-v2-build-
${{ runner.os }}-v2
${{ runner.os }}-pnpm-store-
- name: setup pg
if: ${{ inputs.db == 'pg' || ( inputs.db == 'sqlite' && inputs.shard == '1' ) }}
working-directory: ./
@ -55,12 +57,8 @@ jobs:
run: export CI=true
- name: Set NC Edition
run: export EE=true
- 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
run: pnpm bootstrap
- name: Setup mysql
if: ${{ inputs.db == 'mysql' }}
working-directory: ./packages/nocodb/tests/mysql-sakila-db
@ -82,42 +80,26 @@ jobs:
sudo -u postgres psql -U postgres -f 01-cy-quick.sql
- name: run frontend
working-directory: ./packages/nc-gui
run: npm run ci:run
run: pnpm run ci:run
timeout-minutes: 20
- name: Run backend
if: ${{ inputs.db == 'sqlite' }}
working-directory: ./packages/nocodb
run: |
npm install
npm run watch:run:playwright &> ${{ inputs.db }}_${{ inputs.shard }}_test_backend.log &
pnpm run watch:run:playwright &> ${{ inputs.db }}_${{ inputs.shard }}_test_backend.log &
- name: Run backend:mysql
if: ${{ inputs.db == 'mysql' }}
working-directory: ./packages/nocodb
run: |
npm install
npm run watch:run:playwright:mysql &> ${{ inputs.db }}_${{ inputs.shard }}_test_backend.log &
pnpm run watch:run:playwright:mysql &> ${{ inputs.db }}_${{ inputs.shard }}_test_backend.log &
- name: Run backend:pg
if: ${{ inputs.db == 'pg' }}
working-directory: ./packages/nocodb
run: |
npm install
npm run watch:run:playwright:pg &> ${{ inputs.db }}_${{ inputs.shard }}_test_backend.log &
- name: Cache playwright npm modules
uses: actions/cache@v3
id: playwright-cache
with:
path: |
**/tests/playwright/node_modules
key: cache-v2-nc-playwright-${{ hashFiles('**/tests/playwright/package-lock.json') }}
restore-keys: |
cache-v2-nc-playwright-
- name: Install dependencies
if: steps.playwright-cache.outputs.cache-hit != 'true'
working-directory: ./tests/playwright
run: npm install
pnpm run watch:run:playwright:pg &> ${{ inputs.db }}_${{ inputs.shard }}_test_backend.log &
- name: Install Playwright Browsers
working-directory: ./tests/playwright
run: npx playwright install chromium --with-deps
run: pnpm exec playwright install --with-deps chromium
- name: Wait for backend
run: |
while ! curl --output /dev/null --silent --head --fail http://localhost:8080; do

2
.github/workflows/publish-blog.yml

@ -17,7 +17,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Build blogs
run: |
cd packages/noco-blog

2
.github/workflows/publish-dev-docs.yml

@ -20,7 +20,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Build docs
run: |
cd packages/noco-docs

2
.github/workflows/publish-docs.yml

@ -19,7 +19,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Build docs
run: |
cd packages/noco-docs

2
.github/workflows/publish-noco-i18n.yml

@ -19,7 +19,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Build noco-i18n
run: |
cd packages/noco-i18n

2
.github/workflows/publish-prev-docs.yml

@ -19,7 +19,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Build prev docs
run: |
cd packages/noco-docs-prev

28
.github/workflows/release-docker.yml

@ -45,6 +45,10 @@ jobs:
env:
working-directory: ./packages/nocodb
steps:
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Get Docker Repository
id: get-docker-repository
run: |
@ -80,31 +84,27 @@ jobs:
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: 16.15.0
node-version: 18.14.0
- name: upgrade packages for nightly build or pr build
if: ${{ github.event.inputs.targetEnv == 'DEV' || inputs.targetEnv == 'DEV' }}
run: |
export NODE_OPTIONS="--max_old_space_size=16384"
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} node scripts/bumpNocodbSdkVersion.js
cd packages/nocodb-sdk
npm install && npm run build
cd ../..
NOCODB_SDK_PKG_NAME=nocodb-sdk
if [[ "${{ github.event.inputs.targetEnv == 'DEV' || inputs.targetEnv == 'DEV' }}" ]]; then
NOCODB_SDK_PKG_NAME=nocodb-sdk-daily
fi
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} node scripts/bumpNocodbSdkVersion.js &&
pnpm --filter=${NOCODB_SDK_PKG_NAME} install --ignore-scripts --no-frozen-lockfile && pnpm --filter=${NOCODB_SDK_PKG_NAME} run build &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNocodbSdk.js &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} node scripts/bumpNcGuiVersion.js &&
cd packages/nc-gui
npm install
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} npm run build:copy
cd ../..
pnpm --filter=nc-gui install --ignore-scripts --no-frozen-lockfile &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} pnpm --filter=nc-gui run build:copy &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNcGui.js
- uses: bahmutov/npm-install@v1
with:
working-directory: ${{ env.working-directory }}
- name: Build nocodb and docker files
run: |
npm run docker:build
pnpm run docker:build
working-directory: ${{ env.working-directory }}
- name: Set up QEMU

2
.github/workflows/release-draft.yml

@ -70,5 +70,5 @@ jobs:
})
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GITHUB_TOKEN }} --draft --tags ${{ github.event.inputs.tag || inputs.tag }}..${{ github.event.inputs.prev_tag || inputs.prev_tag }}"

22
.github/workflows/release-executables.yml

@ -22,19 +22,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cache node modules
id: cache-npm
uses: actions/cache@v3
env:
cache-name: cache-node-modules
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
${{ runner.os }}-pnpm-store-
- name: Cache pkg modules
id: cache-pkg
@ -64,7 +62,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name : Install nocodb, other dependencies and build executables
run: |

28
.github/workflows/release-npm.yml

@ -37,32 +37,36 @@ jobs:
env:
working-directory: ./packages/nocodb
steps:
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.ref }}
- name: NPM Setup and Publish with 16.15.0
- name: pnpm Setup and Publish with 18.14.0
# Setup .npmrc file to publish to npm
uses: actions/setup-node@v3
with:
node-version: 16.15.0
node-version: 18.14.0
registry-url: 'https://registry.npmjs.org'
- run: |
export NODE_OPTIONS="--max_old_space_size=16384"
NOCODB_SDK_PKG_NAME=nocodb-sdk
if [[ "${{ github.event.inputs.targetEnv == 'DEV' || inputs.targetEnv == 'DEV' }}" ]]; then
NOCODB_SDK_PKG_NAME=nocodb-sdk-daily
fi
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} node scripts/bumpNocodbSdkVersion.js &&
cd packages/nocodb-sdk &&
npm ci && npm run build && npm publish &&
cd ../.. &&
sleep 60 &&
pnpm --filter=${NOCODB_SDK_PKG_NAME} install --ignore-scripts --no-frozen-lockfile && pnpm --filter=${NOCODB_SDK_PKG_NAME} run build && pnpm --filter=${NOCODB_SDK_PKG_NAME} publish --no-git-checks &&
sleep 90 &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNocodbSdk.js &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} node scripts/bumpNcGuiVersion.js &&
cd packages/nc-gui &&
npm ci &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} npm run build:copy:publish &&
cd ../.. &&
sleep 60 &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNcGui.js && cd packages/nocodb && npm install && npm run obfuscate:build:publish
pnpm --filter=nc-gui install --ignore-scripts --no-frozen-lockfile &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} targetVersion=${{ github.event.inputs.tag || inputs.tag }} pnpm --filter=nc-gui run build:copy:publish --no-git-checks &&
sleep 90 &&
targetEnv=${{ github.event.inputs.targetEnv || inputs.targetEnv }} node scripts/upgradeNcGui.js && cd packages/nocodb && pnpm run obfuscate:build:publish --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create Pull Request

5
.github/workflows/release-pr.yml

@ -24,6 +24,11 @@ jobs:
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' && github.event.pull_request.draft == false && github.base_ref == 'develop' && github.event.action != 'closed' }}
runs-on: 'ubuntu-latest'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 1
ref: ${{ github.ref }}
- name: set-tag
id: tag-step
run: |

2
.github/workflows/release-timely-executables.yml

@ -64,7 +64,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 18
- name: Update nocodb-timely
env:

35
.github/workflows/unit-test.yml

@ -20,25 +20,22 @@ jobs:
strategy:
matrix:
node-version: [16.x]
node-version: [18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: install dependencies nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm ci
- name: build nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm run build:main
- name: install dependencies nocodb
working-directory: ./packages/nocodb
run: npm ci
- name: run unit tests
working-directory: ./packages/nocodb
run: npm run unit-test
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: install dependencies
run: pnpm bootstrap
- name: run unit tests
working-directory: ./packages/nocodb
run: pnpm run unit-test

12
.github/workflows/update-sdk-path.yml

@ -9,21 +9,21 @@ jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
node-version: 18.14.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- run: |
cd packages/nocodb
npm install --save --save-exact nocodb-sdk@file:../nocodb-sdk
cd ../..
cd packages/nc-gui
npm install --save --save-exact nocodb-sdk@file:../nocodb-sdk
pnpm bootstrap
- name: Create Pull Request
id: cpr

5
.gitignore vendored

@ -84,8 +84,8 @@ mongod
*.sln
.history
/packages/nocodb-legacy/docker/main.js.LICENSE.txt
/packages/nocodb-legacy/noco_log.db
/packages/nocodb/docker/main.js.LICENSE.txt
/packages/nocodb/noco_log.db
# NC_DBs
#=========
@ -95,3 +95,4 @@ test_noco.db
# ngrok config
httpbin
.run/test-debug.run.xml

3
.npmrc

@ -0,0 +1,3 @@
engine-strict=true
shamefully-hoist=true
use-node-version=18.14.0

2
README.md

@ -15,7 +15,7 @@ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart spreadshe
<div align="center">
[![Node version](https://img.shields.io/badge/node-%3E%3D%2016.14.0-brightgreen)](http://nodejs.org/download/)
[![Node version](https://img.shields.io/badge/node-%3E%3D%2018.14.0-brightgreen)](http://nodejs.org/download/)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-green.svg)](https://conventionalcommits.org)
</div>

36
build-local-docker-image.sh

@ -2,7 +2,7 @@
# script to build local docker image.
# highlevel steps involved
# 1. Stop and remove existing container and image
# 2. Build nocodb-sdk
# 2. Install dependencies
# 3. Build nc-gui
# 3a. static build of nc-gui
# 3b. copy nc-gui build to nocodb dir
@ -23,41 +23,37 @@ function remove_image() {
docker rmi nocodb-local >/dev/null 2>&1
}
function build_sdk(){
# build nocodb-sdk
cd ${SCRIPT_DIR}/packages/nocodb-sdk
npm ci || ERROR="sdk build failed"
npm run build || ERROR="sdk build failed"
function install_dependencies() {
# Install all dependencies
cd ${SCRIPT_DIR}
pnpm i || ERROR="install_dependencies failed"
}
function build_gui(){
function build_gui() {
# build nc-gui
export NODE_OPTIONS="--max_old_space_size=16384"
# generate static build of nc-gui
cd ${SCRIPT_DIR}/packages/nc-gui
npm ci || ERROR="gui build failed"
npm run generate || ERROR="gui build failed"
pnpm run generate || ERROR="gui build failed"
}
function copy_gui_artifacts(){
function copy_gui_artifacts() {
# copy nc-gui build to nocodb dir
rsync -rvzh --delete ./dist/ ${SCRIPT_DIR}/packages/nocodb/docker/nc-gui/ || ERROR="copy_gui_artifacts failed"
}
function package_nocodb(){
#build nocodb
function package_nocodb() {
# build nocodb ( pack nocodb-sdk and nc-gui )
cd ${SCRIPT_DIR}/packages/nocodb
npm install || ERROR="package_nocodb failed"
EE=true ./node_modules/.bin/webpack --config webpack.local.config.js || ERROR="package_nocodb failed"
EE=true ${SCRIPT_DIR}/node_modules/.bin/webpack --config ${SCRIPT_DIR}/packages/nocodb/webpack.local.config.js || ERROR="package_nocodb failed"
}
function build_image(){
function build_image() {
# build docker
docker build . -f Dockerfile.local -t nocodb-local || ERROR="build_image failed"
}
function log_message(){
function log_message() {
if [[ ${ERROR} != "" ]];
then
>&2 echo "build failed, Please check build-local-docker-image.log for more details"
@ -73,11 +69,11 @@ echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE
stop_and_remove_container
remove_image
echo "Info: Building nocodb-sdk" | tee -a ${LOG_FILE}
build_sdk 1>> ${LOG_FILE} 2>> ${LOG_FILE}
echo "Info: Installing dependencies" | tee -a ${LOG_FILE}
install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE}
echo "Info: Building nc-gui" | tee -a ${LOG_FILE}
build_gui 1>> ${LOG_FILE} 2>> ${LOG_FILE}
build_gui 1>> ${LOG_FILE} 2>> ${LOG_FILE}
echo "Info: Copy nc-gui build to nocodb dir" | tee -a ${LOG_FILE}
copy_gui_artifacts 1>> ${LOG_FILE} 2>> ${LOG_FILE}
@ -90,4 +86,4 @@ if [[ ${ERROR} == "" ]]; then
build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE}
fi
log_message | tee -a ${LOG_FILE}
log_message | tee -a ${LOG_FILE}

14
markdown/readme/languages/chinese.md

@ -215,15 +215,15 @@ cd nocodb
```shell
cd packages/nocodb-sdk
npm install
npm run build
pnpm install
pnpm run build
```
## 本地运行后端
```shell
cd packages/nocodb
npm install
npm run watch:run
pnpm install
pnpm run watch:run
# 在浏览器中打开 localhost:8080/dashboard
```
@ -231,14 +231,14 @@ npm run watch:run
```shell
cd packages/nc-gui
npm install
npm run dev
pnpm install
pnpm run dev
# 在浏览器中打开 localhost:3000/dashboard
```
修改代码后会自动重新启动。
> nocodb/packages/nocodb 包括 nc-lib-gui,它是 npm 源中托管的 nc-gui 的预构建版本。如果您只想修改后端,则可以在本地启动后端后在浏览器中访问 localhost:8000/dashboard
> nocodb/packages/nocodb 包括 nc-lib-gui,它是 pnpm 源中托管的 nc-gui 的预构建版本。如果您只想修改后端,则可以在本地启动后端后在浏览器中访问 localhost:8000/dashboard
# 贡献

8
markdown/readme/languages/german.md

@ -205,8 +205,8 @@ cd nocodb
```shell
cd packages/nocodb
npm install
npm run watch:run
pnpm install
pnpm run watch:run
# localhost:8080/dashboard im Browser aufrufen
```
@ -214,8 +214,8 @@ npm run watch:run
```shell
cd packages/nc-gui
npm install
npm run dev
pnpm install
pnpm run dev
# localhost:3000/dashboard iM Browser aufrufen
```

2
markdown/readme/languages/portuguese.md

@ -49,7 +49,7 @@ docker run -d --name nocodb -p 8080:8080 nocodb/nocodb:latest
docker run -d -p 8080:8080 --name nocodb -v "$(pwd)"/nocodb:/usr/app/data/ nocodb/nocodb:latest
```
### Usando npm.
### Usando npx.
```
npx create-nocodb-app

2
markdown/readme/languages/spanish.md

@ -49,7 +49,7 @@ docker run -d --name nocodb -p 8080:8080 nocodb/nocodb:latest
docker run -d -p 8080:8080 --name nocodb -v "$(pwd)"/nocodb:/usr/app/data/ nocodb/nocodb:latest
```
### Usando npm.
### Usando npx.
```
npx create-nocodb-app

17866
package-lock.json generated

File diff suppressed because it is too large Load Diff

33
package.json

@ -17,42 +17,37 @@
"license": "AGPL-3.0-or-later",
"devDependencies": {
"fs": "0.0.1-security",
"lerna": "^6.4.1",
"lerna": "^7.0.2",
"husky": "^8.0.0",
"xlsx": "^0.17.4"
},
"husky": {
"hooks": {
"pre-commit": "npx lint-staged"
"pre-commit": "pnpm dlx lint-staged"
}
},
"lint-staged": {
"scripts/playwright/**/*.{ts,tsx,js,json}": [
"npm run lint:staged:playwright"
"pnpm run lint:staged:playwright"
]
},
"scripts": {
"lint:staged:playwright": "cd ./tests/playwright; npx lint-staged; cd -",
"build:common": "cd ./packages/nocodb-sdk; npm install; npm run build",
"install:common": "cd packages/nocodb-legacy; npm install ../nocodb-sdk; cd ../nc-gui; npm install ../nocodb-sdk",
"start:web": "npm run build:common ; cd ./packages/nc-gui; npm install ../nocodb-sdk; npm install; ANT_MESSAGE_DURATION=0.5 npm run dev",
"test:travis": "git log --pretty=format:'%h' -n 1 --skip 1 | xargs lerna run test:travis --since",
"lerna:install": "git log --pretty=format:'%h' -n 1 --skip 1 | xargs lerna bootstrap --ignore nc-cli --since",
"updated:xc-migrator": "lerna run publish --scope xc-migrator && lerna run xc && lerna publish && npm install -f xc-cli",
"doc": "lerna run doc",
"install:local:dep": "cd packages/nc-lib-gui;npm uninstall -S xc-lib;rm package-lock.json; npm i ../../../xc-lib-private; cd ../xc-instant;npm uninstall -S xc-lib xc-lib-gui;npm i ../../../xc-lib-private;npm i ../xc-lib-gui",
"install:npm:dep": "cd packages/nc-lib-gui;npm uninstall -S xc-lib; npm i -S xc-lib@latest; cd ../xc-instant;npm uninstall -S xc-lib xc-lib-gui;npm i -S xc-lib@latest xc-lib-gui@latest;npm i ../xc-lib-gui",
"prepare": "husky install",
"bootstrap": "pnpm --filter=nocodb-sdk install && pnpm --filter=nocodb-sdk run build && pnpm --filter=nocodb --filter=nc-gui --filter=playwright install",
"start:frontend": "pnpm --filter=nc-gui run dev",
"start:backend": "pnpm --filter=nocodb run start",
"lint:staged:playwright": "cd ./tests/playwright; pnpm dlx lint-staged; cd -",
"start:mysql": "docker-compose -f ./tests/playwright/scripts/docker-compose-mysql-playwright.yml up -d",
"stop:mysql": "docker-compose -f ./tests/playwright/scripts/docker-compose-mysql-playwright.yml down",
"start:pg": "docker-compose -f ./tests/playwright/scripts/docker-compose-pg.yml up -d",
"stop:pg": "docker-compose -f ./tests/playwright/scripts/docker-compose-pg.yml down",
"prepare": "husky install",
"preinstall": "npx only-allow pnpm",
"install:local-sdk": "node scripts/installLocalSdk.js"
},
"dependencies": {
"express": "^4.18.1",
"mysql2": "^2.3.3",
"pg": "^8.7.3",
"sqlite3": "^5.0.2"
"pnpm": {
"overrides": {
"vue": "latest",
"typescript": "latest"
}
}
}

2
packages/nc-gui/components/account/ResetPassword.vue

@ -56,7 +56,7 @@ const passwordChange = async () => {
await signOut()
navigateTo('/signin')
await navigateTo('/signin')
}
const resetError = () => {

2
packages/nc-gui/components/general/MiniSidebar.vue

@ -13,7 +13,7 @@ const email = computed(() => user.value?.email ?? '---')
const logout = async () => {
await signOut(false)
navigateTo('/signin')
await navigateTo('/signin')
}
</script>

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

@ -15,7 +15,7 @@ const sidebar = ref<HTMLDivElement>()
const logout = async () => {
await signOut(false)
navigateTo('/signin')
await navigateTo('/signin')
}
const { hooks } = useNuxtApp()

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

@ -1,5 +1,5 @@
import { dirname, resolve } from 'node:path'
import vueI18n from '@intlify/unplugin-vue-i18n/vite'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite'
@ -10,7 +10,7 @@ import { FileSystemIconLoader } from 'unplugin-icons/loaders'
import PurgeIcons from 'vite-plugin-purge-icons'
// https://v3.nuxtjs.org/api/configuration/nuxt.config
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: ['@vueuse/nuxt', 'nuxt-windicss', '@nuxt/image-edge', '@pinia/nuxt'],
@ -103,7 +103,7 @@ export default defineNuxtConfig({
rollupOptions: {},
},
plugins: [
vueI18n({
VueI18nPlugin({
include: [resolve(dirname('./lang/*.json'))],
runtimeOnly: false,
}),

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

File diff suppressed because it is too large Load Diff

74
packages/nc-gui/package.json

@ -14,6 +14,9 @@
"bugs": {
"url": "https://github.com/nocodb/nocodb/issues"
},
"engines": {
"node": ">=18"
},
"license": "AGPL-3.0-or-later",
"web-types": "web-types.json",
"scripts": {
@ -25,10 +28,11 @@
"test": "vitest -c test/vite.config.ts",
"test:ui": "vitest -c test/vite.config.ts --ui",
"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": "nuxt prepare",
"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 &"
"build:copy": "pnpm run generate; rm -rf ../nc-lib-gui/lib/dist/; rsync -rvzh ./dist/ ../nc-lib-gui/lib/dist/",
"build:copy:publish": "pnpm run generate; rm -rf ../nc-lib-gui/lib/dist/; rsync -rvzh ./dist/ ../nc-lib-gui/lib/dist/; pnpm publish ../nc-lib-gui",
"ci:run": "export NODE_OPTIONS=\"--max_old_space_size=16384\"; pnpm install; pnpm run build; NUXT_PAGE_TRANSITION_DISABLE=true NUXT_PUBLIC_NC_BACKEND_URL=http://localhost:8080 pnpm run start &",
"preinstall": "npx only-allow pnpm",
"postinstall": "nuxt prepare"
},
"dependencies": {
"@braks/revue-draggable": "^0.4.3",
@ -46,7 +50,7 @@
"chart.js": "^4.3.0",
"d3-scale": "^4.0.2",
"dagre": "^0.8.5",
"dayjs": "^1.11.3",
"dayjs": "^1.11.9",
"deep-object-diff": "^1.1.9",
"emoji-mart-vue-fast": "^15.0.0",
"file-saver": "^2.0.5",
@ -60,7 +64,7 @@
"locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0",
"monaco-sql-languages": "^0.11.0",
"nocodb-sdk": "file:../nocodb-sdk",
"nocodb-sdk": "workspace:^",
"papaparse": "^5.3.2",
"parse-github-url": "^1.0.2",
"pinia": "^2.1.4",
@ -89,29 +93,29 @@
},
"devDependencies": {
"@antfu/eslint-config": "^0.26.0",
"@esbuild-plugins/node-modules-polyfill": "^0.1.4",
"@iconify-json/ant-design": "^1.1.3",
"@iconify-json/bi": "^1.1.6",
"@iconify-json/carbon": "^1.1.2",
"@iconify-json/cil": "^1.1.2",
"@iconify-json/clarity": "^1.1.4",
"@iconify-json/eva": "^1.1.2",
"@iconify-json/ic": "^1.1.7",
"@iconify-json/ion": "^1.1.8",
"@iconify-json/la": "^1.1.2",
"@iconify-json/logos": "^1.1.14",
"@iconify-json/lucide": "^1.1.36",
"@iconify-json/material-symbols": "^1.1.8",
"@iconify-json/mdi": "^1.1.25",
"@iconify-json/mi": "^1.1.2",
"@iconify-json/ph": "^1.1.5",
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@iconify-json/ant-design": "^1.1.9",
"@iconify-json/bi": "^1.1.18",
"@iconify-json/carbon": "^1.1.20",
"@iconify-json/cil": "^1.1.5",
"@iconify-json/clarity": "^1.1.9",
"@iconify-json/eva": "^1.1.7",
"@iconify-json/ic": "^1.1.14",
"@iconify-json/ion": "^1.1.12",
"@iconify-json/la": "^1.1.5",
"@iconify-json/logos": "^1.1.34",
"@iconify-json/lucide": "^1.1.119",
"@iconify-json/material-symbols": "^1.1.57",
"@iconify-json/mdi": "^1.1.54",
"@iconify-json/mi": "^1.1.5",
"@iconify-json/ph": "^1.1.6",
"@iconify-json/ri": "^1.1.12",
"@iconify-json/simple-icons": "^1.1.29",
"@iconify-json/system-uicons": "^1.1.4",
"@iconify-json/tabler": "^1.1.59",
"@iconify-json/vscode-icons": "^1.1.14",
"@iconify-json/simple-icons": "^1.1.67",
"@iconify-json/system-uicons": "^1.1.9",
"@iconify-json/tabler": "^1.1.89",
"@iconify-json/vscode-icons": "^1.1.28",
"@intlify/unplugin-vue-i18n": "^0.12.2",
"@nuxt/image-edge": "^1.0.0-27657146.da85542",
"@nuxt/image-edge": "^1.0.0-rc.1-28217290.de85e17",
"@types/axios": "^0.14.0",
"@types/d3-scale": "^4.0.3",
"@types/dagre": "^0.7.48",
@ -135,20 +139,20 @@
"@windicss/plugin-animations": "^1.0.9",
"@windicss/plugin-question-mark": "^0.1.1",
"@windicss/plugin-scrollbar": "^1.2.3",
"eslint": "^8.22.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"happy-dom": "^6.0.3",
"nuxt": "^3.6.2",
"nuxt-windicss": "^2.5.0",
"nuxt": "^3.6.5",
"nuxt-windicss": "^2.6.1",
"prettier": "^2.7.1",
"sass": "^1.53.0",
"sass": "^1.63.4",
"ts-loader": "^9.4.4",
"unplugin-icons": "^0.14.15",
"unplugin-vue-components": "^0.22.12",
"vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-purge-icons": "^0.9.2",
"vitest": "^0.18.0",
"vitest": "^0.30.1",
"windicss": "^3.5.6"
}
}
}

4
packages/nc-gui/test/vite.config.ts

@ -1,7 +1,7 @@
/// <reference types="vitest" />
import path from 'path'
import vueI18n from '@intlify/vite-plugin-vue-i18n'
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'
import Icons from 'unplugin-icons/vite'
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
@ -9,7 +9,7 @@ import Vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
Vue(),
vueI18n({
VueI18nPlugin({
include: path.resolve(__dirname, '../lang'),
}),
Icons({

2
packages/nc-gui/tsconfig.json

@ -11,7 +11,7 @@
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"types": [
"@intlify/vite-plugin-vue-i18n/client",
"@intlify/unplugin-vue-i18n/messages",
"vue-i18n",
"unplugin-icons/types/vue",
"nuxt-windicss",

2
packages/noco-docs/docs/020.getting-started/010.installation.md

@ -8,7 +8,7 @@ import TabItem from '@theme/TabItem';
Simple installation - takes about three minutes!
## Prerequisites
- [Docker](https://www.docker.com/get-started) or [Node.js](https://nodejs.org/en/download) ( > v16.x )
- [Docker](https://www.docker.com/get-started) or [Node.js](https://nodejs.org/en/download) ( > v18.x )
## Quick try

2
packages/noco-docs/docs/040.developer-resources/030.sdk.md

@ -16,7 +16,7 @@ The NocoDB SDK requires authorization token. If you haven't created one, please
### Install nocodb-sdk
```bash
npm i nocodb-sdk
pnpm i nocodb-sdk
```
### Import Api

38
packages/noco-docs/docs/050.engineering/030.development-setup.md

@ -4,36 +4,34 @@ description: "How to set-up your development environment"
---
## Clone the repo
```
```bash
git clone https://github.com/nocodb/nocodb
cd nocodb/packages
# change directory to the project root
cd nocodb
```
## Build SDK
## Install dependencies
```
# build nocodb-sdk
cd nocodb-sdk
npm install
npm run build
```bash
# run from the project root
pnpm i
```
## Build Backend
## Start Frontend
```
# build backend - runs on port 8080
cd ../nocodb
npm install
npm run watch:run
```bash
# run from the project root
pnpm start:frontend
# runs on port 3000
```
## Build Frontend
## Start Backend
```
# build frontend - runs on port 3000
cd ../nc-gui
npm install
npm run dev
```bash
# run from the project root
pnpm start:backend
# runs on port 8080
```
Any changes made to frontend and backend will be automatically reflected in the browser.

6
packages/noco-docs/docs/050.engineering/040.unit-testing.md

@ -16,9 +16,7 @@ description: "Overview to Unit Testing"
### Setup
```bash
cd packages/nocodb
npm install
pnpm --filter=-nocodb install
# add a .env file
cp tests/unit/.env.sample tests/unit/.env
@ -36,7 +34,7 @@ Configure the following variables
### Run Tests
``` bash
npm run test:unit
pnpm run test:unit
```
### Folder Structure

20
packages/noco-docs/docs/050.engineering/050.playwright.md

@ -7,11 +7,11 @@ description: "Overview to playwright based e2e tests"
All the tests reside in `tests/playwright` folder.
Make sure to install the dependencies(in the playwright folder):
Make sure to install the dependencies (in the playwright folder):
```bash
npm install
npx playwright install chromium --with-deps
pnpm --filter=playwright install
pnpm exec playwright install --with-deps chromium
```
### Run Test Server
@ -19,13 +19,13 @@ npx playwright install chromium --with-deps
Start the backend test server (in `packages/nocodb` folder):
```bash
npm run watch:run:playwright
pnpm run watch:run:playwright
```
Start the frontend test server (in `packages/nc-gui` folder):
```bash
NUXT_PAGE_TRANSITION_DISABLE=true npm run dev
NUXT_PAGE_TRANSITION_DISABLE=true pnpm run dev
```
### Running all tests
@ -35,13 +35,13 @@ For selecting db type, rename `.env.example` to `.env` and set `E2E_DEV_DB_TYPE`
headless mode(without opening browser):
```bash
npm run test
pnpm run test
```
with browser:
```bash
npm run test:debug
pnpm run test:debug
```
For setting up mysql(sakila):
@ -67,7 +67,7 @@ test.only('should login', async ({ page }) => {
```
```bash
npm run test
pnpm run test
```
## Concepts
@ -183,7 +183,7 @@ This a method which will reset/clear all the filters. Since this is an action me
```js
async resetFilter() {
await this.waitForResponse({
uiAction: () => this.get().locator('.nc-filter-item-remove-btn').click(),
uiAction: async () => await this.get().locator('.nc-filter-item-remove-btn').click(),
httpMethodsToMatch: ['DELETE'],
requestUrlPathToMatch: '/api/v1/db/meta/filters/',
});
@ -215,4 +215,4 @@ async verifyFilter({ title }: { title: string }) {
- Open `Summary` tab in the CI workflow in github actions.
- Scroll down to `Artifacts` section.
- Access reports which suffixed with the db type and shard number(corresponding to the CI workerflow name). i.e `playwright-report-mysql-2` is for `playwright-mysql-2` workflow.
- Download it and run `npm install -D @playwright/test && npx playwright show-report ./` inside the downloaded folder.
- Download it and run `pnpm install -D @playwright/test && npx playwright show-report ./` inside the downloaded folder.

8
packages/noco-docs/docs/060.FAQs.md

@ -25,12 +25,12 @@ description: 'General FAQs'
You should see the similar result as below.
```
Node: **v16.14.0**
Node: **v18.16.4**
Arch: **arm64**
Platform: **darwin**
Docker: **false**
Platform: **linux**
Docker: **true**
RootDB: **sqlite3**
PackageVersion: **0.109.7**
PackageVersion: **0.111.0**
```
## What is available in free version ?

1
packages/noco-docs/versioned_docs/version-0.109.7/050.engineering/030.development-setup.md vendored

@ -58,4 +58,3 @@ Double click twice on empty space between `View list` & `Share` button to the le
![Screenshot 2023-05-23 at 8 35 14 PM](https://github.com/nocodb/nocodb/assets/86527202/fe2765fa-5796-4d26-8c12-e71b8226872e)

7630
packages/nocodb-sdk/package-lock.json generated

File diff suppressed because it is too large Load Diff

26
packages/nocodb-sdk/package.json

@ -17,10 +17,13 @@
"bugs": {
"url": "https://github.com/nocodb/nocodb/issues"
},
"engines": {
"node": ">=18"
},
"license": "AGPL-3.0-or-later",
"keywords": [],
"scripts": {
"build": "npm run generate:sdk && run-p build:*",
"build": "pnpm generate:sdk && run-p build:*",
"build:main": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
"build:module": "tsc -p tsconfig.module.json && tsc-alias -p tsconfig.module.json",
"fix": "run-s fix:*",
@ -31,24 +34,25 @@
"test:prettier": "prettier \"src/**/*.ts\" --list-different",
"test:spelling": "cspell \"{README.md,.github/*.md,src/**/*.ts}\"",
"watch:build": "tsc -p tsconfig.json -w",
"generate:sdk": "npx --yes swagger-typescript-api@10.0.3 -r -p ../nocodb/src/schema/swagger.json -o ./src/lib/ --axios --unwrap-response-data --module-name-first-tag --type-suffix=Type --templates ../../scripts/sdk/templates"
"generate:sdk": "pnpm dlx swagger-typescript-api@10.0.3 -r -p ../nocodb/src/schema/swagger.json -o ./src/lib/ --axios --unwrap-response-data --module-name-first-tag --type-suffix=Type --templates ../../scripts/sdk/templates",
"preinstall": "npx only-allow pnpm"
},
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"cspell": "^4.1.0",
"eslint": "^7.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.8.0",
"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-functional": "^5.0.8",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.2.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.1",
"prettier": "^2.8.8",
"rimraf": "^5.0.1",
"tsc-alias": "^1.8.7",
"typescript": "^4.7.4"
@ -65,4 +69,4 @@
"prettier": {
"singleQuote": true
}
}
}

23
packages/nocodb/Dockerfile

@ -1,7 +1,7 @@
###########
# Litestream Builder
###########
FROM golang:alpine3.14 as lt-builder
FROM golang:alpine3.18 as lt-builder
WORKDIR /usr/src/
@ -18,26 +18,31 @@ RUN cp $GOPATH/bin/litestream /usr/src/lt
###########
# Builder
###########
FROM node:16.17.0-alpine3.15 as builder
FROM node:18.12.1-alpine as builder
WORKDIR /usr/src/app
# install node-gyp dependencies
RUN apk add --no-cache python3 make g++
# install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate
# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm ci on every code change.
COPY ./package*.json ./
COPY ./package.json ./package.json
COPY ./docker/main.js ./docker/main.js
#COPY ./docker/start.sh /usr/src/appEntry/start.sh
COPY ./docker/start-litestream.sh /usr/src/appEntry/start.sh
COPY src/public/ ./docker/public/
# for pnpm to generate a flat node_modules without symlinks
# so that modclean could work as expected
RUN echo "node-linker=hoisted" > .npmrc
# install production dependencies,
# reduce node_module size with modclean & removing sqlite deps,
# package built code into app.tar.gz & add execute permission to start.sh
RUN npm ci --omit=dev --quiet \
&& npx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**,@azure/msal-node/dist/**" --run \
RUN pnpm install --prod --shamefully-hoist \
&& pnpm dlx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**,@azure/msal-node/dist/**" --run \
&& rm -rf ./node_modules/sqlite3/deps \
&& tar -czf ../appEntry/app.tar.gz ./* \
&& chmod +x /usr/src/appEntry/start.sh
@ -45,7 +50,7 @@ RUN npm ci --omit=dev --quiet \
##########
# Runner
##########
FROM alpine:3.15
FROM alpine:3.18
WORKDIR /usr/src/app
ENV NC_DOCKER 0.6
@ -59,7 +64,7 @@ RUN apk --update --no-cache add \
dumb-init
# Copy litestream binary build
COPY --from=lt-builder /usr/src/lt /usr/src/appEntry/litestream
COPY --from=lt-builder /usr/src/lt /usr/src/appEntry/litestream
# Copy packaged production code & main entry file
COPY --from=builder /usr/src/appEntry/ /usr/src/appEntry/

21
packages/nocodb/Dockerfile.local

@ -1,27 +1,32 @@
###########
# Builder
###########
FROM node:16.17.0-alpine3.15 as builder
FROM node:18.12.1-alpine as builder
WORKDIR /usr/src/app
# install node-gyp dependencies
RUN apk add --no-cache python3 make g++
# install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate
# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm ci on every code change.
COPY ./package*.json ./
COPY ./package.json ./package.json
COPY ./docker/nc-gui/ ./docker/nc-gui/
COPY ./docker/main.js ./docker/index.js
COPY ./docker/start-local.sh /usr/src/appEntry/start.sh
COPY src/public/ ./docker/public/
# for pnpm to generate a flat node_modules without symlinks
# so that modclean could work as expected
RUN echo "node-linker=hoisted" > .npmrc
# install production dependencies,
# reduce node_module size with modclean & removing sqlite deps,
# package built code into app.tar.gz & add execute permission to start.sh
RUN npm uninstall --save nocodb-sdk
RUN npm ci --omit=dev --quiet \
&& npx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**,@azure/msal-node/dist/**" --run \
RUN pnpm uninstall nocodb-sdk
RUN pnpm install --prod --shamefully-hoist --reporter=silent \
&& pnpm dlx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**,@azure/msal-node/dist/**" --run \
&& rm -rf ./node_modules/sqlite3/deps \
&& tar -czf ../appEntry/app.tar.gz ./* \
&& chmod +x /usr/src/appEntry/start.sh
@ -29,7 +34,7 @@ RUN npm ci --omit=dev --quiet \
##########
# Runner
##########
FROM alpine:3.15
FROM alpine:3.18
WORKDIR /usr/src/app
ENV NC_DOCKER 0.6

4
packages/nocodb/README.md

@ -85,8 +85,8 @@ We provide a simple NodeJS Application for getting started.
```bash
git clone https://github.com/nocodb/nocodb-seed
cd nocodb-seed
npm install
npm start
pnpm install
pnpm start
```
## Docker

14
packages/nocodb/docker/webpack.config.js

@ -33,15 +33,17 @@ module.exports = {
},
optimization: {
minimize: true, //Update this to true or false
minimizer: [new TerserPlugin()],
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
},
}),
],
nodeEnv: false,
},
externals: [nodeExternals()],
plugins: [
new webpack.EnvironmentPlugin([
'EE'
]),
],
plugins: [new webpack.EnvironmentPlugin(['EE'])],
target: 'node',
node: {
__dirname: false,

23
packages/nocodb/litestream/Dockerfile

@ -1,4 +1,4 @@
FROM golang:alpine3.14 as lt
FROM golang:alpine3.18 as lt
WORKDIR /usr/src/
@ -12,29 +12,32 @@ RUN cp $GOPATH/bin/litestream /usr/src/lt
FROM node:12 as builder
FROM node:18.12.1-alpine as builder
WORKDIR /usr/src/app
# install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate
# Copy application dependency manifests to the container image.
# A wildcard is used to ensure both package.json AND package-lock.json are copied.
# Copying this separately prevents re-running npm ci on every code change.
COPY ./package*.json ./
COPY ./docker/main.js ./docker/main.js
#COPY ./docker/start.sh /usr/src/appEntry/start.sh
COPY ./docker/start-litestream.sh /usr/src/appEntry/start.sh
# for pnpm to generate a flat node_modules without symlinks
# so that modclean could work as expected
RUN echo "node-linker=hoisted" > .npmrc
# install production dependencies,
# reduce node_module size with modclean & removing sqlite deps,
# package built code into app.tar.gz & add execute permission to start.sh
RUN npm ci --production --quiet
RUN npx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**" --run
RUN pnpm install --prod --shamefully-hoist --reporter=silent
RUN pnpm dlx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**" --run
RUN rm -rf ./node_modules/sqlite3/deps
RUN tar -czf ../appEntry/app.tar.gz ./*
RUN chmod +x /usr/src/appEntry/start.sh
FROM alpine:3.14
FROM alpine:3.18
#ENV AWS_ACCESS_KEY_ID=
#ENV AWS_SECRET_ACCESS_KEY=

35076
packages/nocodb/package-lock.json generated

File diff suppressed because it is too large Load Diff

105
packages/nocodb/package.json

@ -15,13 +15,16 @@
"bugs": {
"url": "https://github.com/nocodb/nocodb/issues"
},
"engines": {
"node": ">=18"
},
"license": "AGPL-3.0-or-later",
"scripts": {
"build": "npm run docker:build",
"build": "pnpm run docker:build",
"build:obfuscate": "EE=true webpack --config webpack.config.js",
"obfuscate:build:publish": "npm run build:obfuscate && npm publish .",
"obfuscate:build:publish": "pnpm run build:obfuscate && pnpm publish .",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "npm run watch:run",
"start": "pnpm run watch:run",
"start:prod": "node docker/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
@ -45,34 +48,34 @@
"@aws-sdk/client-kafka": "^3.332.0",
"@google-cloud/storage": "^5.7.2",
"@graphql-tools/merge": "^6.0.12",
"@jm18457/kafkajs-msk-iam-authentication-mechanism": "^3.1.1",
"@nestjs/bull": "^0.6.3",
"@nestjs/common": "^9.4.0",
"@nestjs/config": "^2.3.1",
"@nestjs/core": "^9.4.0",
"@nestjs/event-emitter": "^1.4.1",
"@nestjs/jwt": "^10.0.3",
"@nestjs/mapped-types": "*",
"@nestjs/passport": "^9.0.3",
"@nestjs/platform-express": "^9.4.0",
"@nestjs/platform-socket.io": "^9.4.0",
"@nestjs/serve-static": "^3.0.1",
"@nestjs/throttler": "^4.0.0",
"@nestjs/websockets": "^9.4.0",
"@jm18457/kafkajs-msk-iam-authentication-mechanism": "^3.1.2",
"@nestjs/bull": "^10.0.1",
"@nestjs/common": "^10.2.1",
"@nestjs/config": "^3.0.0",
"@nestjs/core": "^10.2.1",
"@nestjs/event-emitter": "^2.0.2",
"@nestjs/jwt": "^10.1.0",
"@nestjs/mapped-types": "^2.0.2",
"@nestjs/passport": "^10.0.1",
"@nestjs/platform-express": "^10.2.1",
"@nestjs/platform-socket.io": "^10.2.1",
"@nestjs/serve-static": "^4.0.0",
"@nestjs/throttler": "^4.2.1",
"@nestjs/websockets": "^10.2.1",
"@sentry/node": "^6.3.5",
"@techpass/passport-openidconnect": "^0.3.3",
"@types/chai": "^4.2.12",
"airtable": "^0.11.3",
"airtable": "^0.12.1",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"archiver": "^5.0.2",
"auto-bind": "^4.0.0",
"aws-kcl": "^2.2.2",
"aws-sdk": "^2.829.0",
"aws-sdk": "^2.1419.0",
"axios": "^0.21.1",
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"boxen": "^5.0.0",
"body-parser": "^1.20.1",
"boxen": "^5.1.0",
"bull": "^4.10.4",
"bullmq": "^1.81.1",
"clear": "^0.1.0",
@ -85,12 +88,12 @@
"cron": "^1.8.2",
"crypto-js": "^4.0.0",
"dataloader": "^2.0.0",
"dayjs": "^1.8.34",
"dayjs": "^1.11.9",
"debug": "^4.2.0",
"dotenv": "^8.2.0",
"ejs": "^3.1.3",
"emittery": "^0.7.1",
"express": "^4.17.1",
"express": "^4.18.1",
"express-graphql": "^0.11.0",
"extract-zip": "^2.0.1",
"fast-levenshtein": "^2.0.6",
@ -103,8 +106,8 @@
"html-to-json-parser": "^1.1.0",
"import-fresh": "^3.2.1",
"inflection": "^1.12.0",
"ioredis": "^5.0.4",
"ioredis-mock": "^7.1.0",
"ioredis": "^5.3.2",
"ioredis-mock": "^8.8.3",
"is-docker": "^2.2.1",
"isomorphic-dompurify": "^0.19.0",
"jsep": "^1.3.6",
@ -112,7 +115,7 @@
"jsonfile": "^6.1.0",
"jsonwebtoken": "^9.0.0",
"kafkajs": "^2.2.4",
"knex": "2.2.0",
"knex": "2.4.2",
"list-github-dir-content": "^3.0.0",
"lodash": "^4.17.19",
"lru-cache": "^6.0.0",
@ -122,22 +125,22 @@
"mkdirp": "^2.1.3",
"morgan": "^1.10.0",
"mssql": "^6.2.0",
"multer": "^1.4.4",
"multer": "^1.4.5-lts.1",
"mysql2": "^3.2.0",
"nanoid": "^3.1.20",
"nc-help": "0.2.92",
"nc-help": "0.3.0",
"nc-lib-gui": "0.111.4",
"nc-plugin": "^0.1.3",
"ncp": "^2.0.0",
"nestjs-kafka": "^1.0.6",
"nestjs-throttler-storage-redis": "^0.3.0",
"nocodb-sdk": "file:../nocodb-sdk",
"nocodb-sdk": "workspace:^",
"nodemailer": "^6.4.10",
"object-hash": "^3.0.0",
"object-sizeof": "^2.6.1",
"os-locale": "^6.0.2",
"p-queue": "^6.6.2",
"papaparse": "^5.3.1",
"papaparse": "^5.4.0",
"parse-database-url": "^0.3.0",
"passport": "^0.4.1",
"passport-auth-token": "^1.0.1",
@ -159,7 +162,7 @@
"socket.io": "^4.4.1",
"sql-query-identifier": "^2.5.0",
"sqlite3": "^5.1.6",
"tedious": "^15.0.0",
"tedious": "^16.1.0",
"tinycolor2": "^1.4.2",
"twilio": "^3.55.1",
"unique-names-generator": "^4.3.1",
@ -169,42 +172,42 @@
"xlsx": "^0.18.5"
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
"@nestjs/schematics": "^9.0.0",
"@nestjs/testing": "^9.0.0",
"@nestjs/cli": "^10.1.10",
"@nestjs/schematics": "^10.0.1",
"@nestjs/testing": "^10.1.0",
"@nestjsplus/dyn-schematics": "^1.0.12",
"@types/bull": "^4.10.0",
"@types/express": "^4.17.13",
"@types/jest": "^29.5.0",
"@types/ejs": "^3.1.2",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
"@types/mocha": "^10.0.1",
"@types/multer": "^1.4.7",
"@types/node": "18.15.11",
"@types/node": "20.3.1",
"@types/passport-google-oauth20": "^2.0.11",
"@types/passport-jwt": "^3.0.8",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"chai": "^4.2.0",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
"eslint": "^7.8.0",
"eslint-config-prettier": "^6.15.0",
"eslint": "^8.33.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-functional": "^5.0.8",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.2.1",
"jest": "29.5.0",
"mocha": "^10.1.0",
"nodemon": "^2.0.22",
"nodemon": "^3.0.1",
"prettier": "^2.7.1",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"supertest": "^6.3.3",
"ts-jest": "29.0.5",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0",
"typescript": "^4.7.4",
"webpack-cli": "^5.0.1"
"typescript": "^5.1.3",
"webpack-cli": "^5.1.4"
},
"jest": {
"moduleFileExtensions": [

2
packages/nocodb/src/controllers/test/TestResetService/resetPgSakilaProject.ts

@ -150,7 +150,7 @@ const resetPgSakilaProject = async ({
);
if (response.status !== 200) {
console.error('Error creating project', response.data);
throw new Error('Error creating project', response.data);
throw new Error(response.data);
}
};

2
packages/nocodb/src/db/sql-mgr/v2/SqlMgrv2Trans.ts

@ -1,8 +1,8 @@
import KnexMigratorv2Tans from '../../sql-migrator/lib/KnexMigratorv2Tans';
import SqlMgrv2 from './SqlMgrv2';
import type Base from '~/models/Base';
import type { Knex } from 'knex';
import type { XKnex } from '../../CustomKnex';
import Base from '~/models/Base';
import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2';
export default class SqlMgrv2Trans extends SqlMgrv2 {

2
packages/nocodb/src/helpers/PagedResponse.ts

@ -34,7 +34,7 @@ export class PagedResponseImpl<T> {
if (additionalProps) Object.assign(this, additionalProps);
if (offset && offset >= count) {
if (offset && offset >= +count) {
this.errors = [
{
message: 'Offset is beyond the total number of rows',

2
packages/nocodb/src/helpers/columnHelpers.ts

@ -215,7 +215,7 @@ export const generateFkName = (parent: TableType, child: TableType) => {
.replace(/\W+/g, '_')
.slice(0, 10)}_${child.table_name
.replace(/\W+/g, '_')
.slice(0, 10)}_${randomID(15)}`;
.slice(0, 10)}_${randomID()}`;
return constraintName;
};

2
packages/nocodb/src/helpers/initAdminFromEnv.ts

@ -4,7 +4,7 @@ import bcrypt from 'bcryptjs';
import { validatePassword } from 'nocodb-sdk';
import boxen from 'boxen';
import { T } from 'nc-help';
import { isEmail } from 'validator';
import isEmail from 'validator/lib/isEmail';
import NocoCache from '~/cache/NocoCache';
import Noco from '~/Noco';
import { ProjectUser, User } from '~/models';

2
packages/nocodb/src/modules/event-emitter/nestjs-event-emitter.ts

@ -1,4 +1,4 @@
import type { EventEmitter2 } from '@nestjs/event-emitter';
import { EventEmitter2 } from '@nestjs/event-emitter';
import type { IEventEmitter } from './event-emitter.interface';
export class NestjsEventEmitter implements IEventEmitter {

3
packages/nocodb/src/nocobuild.ts

@ -3,7 +3,8 @@ import express from 'express';
import NcToolGui from 'nc-lib-gui';
import { AppModule } from '~/app.module';
export default async function (app = express()) {
export default async function (app) {
if (!app) app = express();
const nestApp = await NestFactory.create(AppModule);
await nestApp.init();

4
packages/nocodb/src/run/docker.ts

@ -1,7 +1,11 @@
import dns from 'node:dns';
import cors from 'cors';
import express from 'express';
import Noco from '~/Noco';
// ref: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
dns.setDefaultResultOrder('ipv4first');
const server = express();
server.enable('trust proxy');
server.disable('etag');

4
packages/nocodb/src/run/dockerEntry.ts

@ -1,7 +1,11 @@
import dns from 'node:dns';
import express from 'express';
import cors from 'cors';
import Noco from '~/Noco';
// ref: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
dns.setDefaultResultOrder('ipv4first');
const server = express();
server.enable('trust proxy');
server.use(cors());

4
packages/nocodb/src/run/dockerRunMysql.ts

@ -1,7 +1,11 @@
import dns from 'node:dns';
import cors from 'cors';
import express from 'express';
import Noco from '~/Noco';
// ref: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
dns.setDefaultResultOrder('ipv4first');
const server = express();
server.enable('trust proxy');
server.disable('etag');

4
packages/nocodb/src/run/dockerRunPG.ts

@ -1,7 +1,11 @@
import dns from 'node:dns';
import cors from 'cors';
import express from 'express';
import Noco from '~/Noco';
// ref: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
dns.setDefaultResultOrder('ipv4first');
const server = express();
server.enable('trust proxy');
server.disable('etag');

4
packages/nocodb/src/run/dockerRunPG_CyQuick.ts

@ -1,7 +1,11 @@
import dns from 'node:dns';
import cors from 'cors';
import express from 'express';
import Noco from '~/Noco';
// ref: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
dns.setDefaultResultOrder('ipv4first');
const server = express();
server.enable('trust proxy');
server.disable('etag');

5
packages/nocodb/src/run/local.ts

@ -1,9 +1,12 @@
import dns from 'node:dns';
import path from 'path';
import cors from 'cors';
import express from 'express';
import Noco from '~/Noco';
// ref: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
dns.setDefaultResultOrder('ipv4first');
const server = express();
server.enable('trust proxy');
server.use(cors());

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

@ -1,3 +1,4 @@
import dns from 'node:dns';
import axios from 'axios';
import cors from 'cors';
import express from 'express';
@ -6,6 +7,9 @@ import { User } from '~/models';
process.env.NC_VERSION = '0009044';
// ref: https://github.com/nodejs/node/issues/40702#issuecomment-1103623246
dns.setDefaultResultOrder('ipv4first');
const server = express();
server.enable('trust proxy');
server.disable('etag');

3
packages/nocodb/src/services/app-hooks/interfaces.ts

@ -179,9 +179,8 @@ export interface AttachmentEvent {
type: 'url' | 'file';
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface FormColumnEvent {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface GridColumnEvent {}
export interface MetaDiffEvent {

2
packages/nocodb/src/services/users/users.service.ts

@ -2,7 +2,7 @@ import { promisify } from 'util';
import { Injectable } from '@nestjs/common';
import { AppEvents, OrgUserRoles, validatePassword } from 'nocodb-sdk';
import { v4 as uuidv4 } from 'uuid';
import { isEmail } from 'validator';
import isEmail from 'validator/lib/isEmail';
import { T } from 'nc-help';
import * as ejs from 'ejs';
import bcrypt from 'bcryptjs';

4
packages/nocodb/src/version-upgrader/v1-legacy/BaseApiBuilder.ts

@ -4,13 +4,13 @@ import inflection from 'inflection';
import ncModelsOrderUpgrader from './jobs/ncModelsOrderUpgrader';
import ncParentModelTitleUpgrader from './jobs/ncParentModelTitleUpgrader';
import ncRemoveDuplicatedRelationRows from './jobs/ncRemoveDuplicatedRelationRows';
import type { DbConfig, NcConfig } from '~/interface/config';
import NcProjectBuilder from './NcProjectBuilder';
import type { XKnex } from '~/db/CustomKnex';
import type { BaseModelSql } from '~/db/BaseModelSql';
import type { MetaService } from '~/meta/meta.service';
import type Noco from '~/Noco';
import type NcProjectBuilder from './NcProjectBuilder';
import type { MysqlClient, PgClient, SqlClient } from 'nc-help';
import { DbConfig, NcConfig } from '~/interface/config';
import ModelXcMetaFactory from '~/db/sql-mgr/code/models/xc/ModelXcMetaFactory';
import NcConnectionMgr from '~/utils/common/NcConnectionMgr';

4
packages/nocodb/src/version-upgrader/v1-legacy/NcProjectBuilder.ts

@ -1,8 +1,8 @@
import { Router } from 'express';
import { GqlApiBuilder } from './gql/GqlApiBuilder';
import { RestApiBuilder } from './rest/RestApiBuilder';
import type Noco from '~/Noco';
import type { NcConfig } from '~/interface/config';
import Noco from '~/Noco';
import { NcConfig } from '~/interface/config';
import { SqlClientFactory } from '~/db/sql-client/lib/SqlClientFactory';
export default class NcProjectBuilder {

8
packages/nocodb/src/version-upgrader/v1-legacy/gql/GqlApiBuilder.ts

@ -1,10 +1,10 @@
import { Router } from 'express';
import BaseApiBuilder from '../BaseApiBuilder';
import type NcProjectBuilder from '../NcProjectBuilder';
import type { DbConfig, NcConfig } from '~/interface/config';
import NcProjectBuilder from '../NcProjectBuilder';
import type XcMetaMgr from '~/interface/XcMetaMgr';
import type { MetaService } from '~/meta/meta.service';
import type Noco from '~/Noco';
import { DbConfig, NcConfig } from '~/interface/config';
import { MetaService } from '~/meta/meta.service';
import Noco from '~/Noco';
import GqlXcSchemaFactory from '~/db/sql-mgr/code/gql-schema/xc-ts/GqlXcSchemaFactory';
export class GqlApiBuilder extends BaseApiBuilder<Noco> implements XcMetaMgr {

8
packages/nocodb/src/version-upgrader/v1-legacy/rest/RestApiBuilder.ts

@ -1,10 +1,10 @@
import autoBind from 'auto-bind';
import BaseApiBuilder from '../BaseApiBuilder';
import NcProjectBuilder from '../NcProjectBuilder';
import type { Router } from 'express';
import type { DbConfig, NcConfig } from '~/interface/config';
import type NcProjectBuilder from '../NcProjectBuilder';
import type { MetaService } from '~/meta/meta.service';
import type Noco from '~/Noco';
import { DbConfig, NcConfig } from '~/interface/config';
import { MetaService } from '~/meta/meta.service';
import Noco from '~/Noco';
import NcHelp from '~/utils/NcHelp';
import ExpressXcTsRoutes from '~/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutes';
import SwaggerXc from '~/db/sql-mgr/code/routers/xc-ts/SwaggerXc';

9
packages/nocodb/webpack.config.js

@ -2,7 +2,6 @@ const path = require('path');
const nodeExternals = require('webpack-node-externals');
const webpack = require('webpack');
const CopyPlugin = require('copy-webpack-plugin');
//
const TerserPlugin = require('terser-webpack-plugin');
const { resolveTsAliases } = require('./build-utils/resolveTsAliases');
@ -25,7 +24,13 @@ module.exports = {
optimization: {
minimize: true, //Update this to true or false
minimizer: [new TerserPlugin()],
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
},
}),
],
nodeEnv: false,
},
externals: [nodeExternals()],

8
packages/nocodb/webpack.local.config.js

@ -24,7 +24,13 @@ module.exports = {
optimization: {
minimize: true, //Update this to true or false
minimizer: [new TerserPlugin()],
minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
},
}),
],
nodeEnv: false,
},
externals: [

23728
pnpm-lock.yaml

File diff suppressed because it is too large Load Diff

5
pnpm-workspace.yaml

@ -0,0 +1,5 @@
packages:
- 'packages/nocodb-sdk'
- 'packages/nc-gui'
- 'packages/nocodb'
- 'tests/playwright'

6
scripts/installLocalSdk.js

@ -4,7 +4,7 @@ const sdkPath = path.join(__dirname, '..', 'packages', 'nocodb-sdk');
const guiPath = path.join(__dirname, '..', 'packages', 'nc-gui');
const nocodbPath = path.join(__dirname, '..', 'packages', 'nocodb');
exec(`cd ${sdkPath} && npm i && npm run build`, (err, stdout, stderr) => {
exec(`cd ${sdkPath} && pnpm i && npm run build`, (err, stdout, stderr) => {
if (err) {
console.error(`Error installing dependencies and building nocodb-sdk: ${err}`);
return;
@ -13,7 +13,7 @@ exec(`cd ${sdkPath} && npm i && npm run build`, (err, stdout, stderr) => {
console.log(`Dependencies installed and nocodb-sdk built: ${stdout}`);
const guiPromise = new Promise((resolve, reject) => {
exec(`cd ${guiPath} && npm i ${sdkPath}`, (err, stdout, stderr) => {
exec(`cd ${guiPath} && pnpm i ${sdkPath}`, (err, stdout, stderr) => {
if (err) {
reject(`Error installing dependencies for nc-gui: ${err}`);
} else {
@ -23,7 +23,7 @@ exec(`cd ${sdkPath} && npm i && npm run build`, (err, stdout, stderr) => {
});
const nocodbPromise = new Promise((resolve, reject) => {
exec(`cd ${nocodbPath} && npm i ${sdkPath}`, (err, stdout, stderr) => {
exec(`cd ${nocodbPath} && pnpm i ${sdkPath}`, (err, stdout, stderr) => {
if (err) {
reject(`Error installing dependencies for nocodb: ${err}`);
} else {

14
scripts/pkg-executable/package.json

@ -15,12 +15,12 @@
"node_modules/**/*"
],
"targets": [
"node16-linux-arm64",
"node16-macos-arm64",
"node16-win-arm64",
"node16-linux-x64",
"node16-macos-x64",
"node16-win-x64"
"node18-linux-arm64",
"node18-macos-arm64",
"node18-win-arm64",
"node18-linux-x64",
"node18-macos-x64",
"node18-win-x64"
]
},
"keywords": [],
@ -28,6 +28,6 @@
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"nocodb": "0.97.0"
"nocodb": "0.111.0"
}
}

2
scripts/upgradeNcGui.js

@ -22,7 +22,7 @@ const replacePackageName = (filePath) => {
const bumbVersionAndSave = () => {
// upgrade nc-lib-gui version in nocodb
execSync(`cd packages/nocodb && npm install --save --save-exact ${ncLibPackage.name}@${ncLibPackage.version}`, {});
execSync(`pnpm --filter=nocodb install --ignore-scripts ${ncLibPackage.name}@${ncLibPackage.version}`, {});
const nocodbPackageFilePath = path.join(__dirname, '..', 'packages', 'nocodb', 'package.json')
const nocoLibPackage = JSON.parse(fs.readFileSync(nocodbPackageFilePath))
if (process.env.targetEnv === 'DEV') {

32
scripts/upgradeNocodbSdk.js

@ -18,16 +18,26 @@ const replacePackageName = (filePath) => {
})
}
const replacePackageVersion = (filePath) => {
return new Promise((resolve, reject) => {
return fs.readFile(filePath, 'utf8', function (err, data) {
if (err) return reject(err)
var result = data.replace(/workspace:\^/g, nocodbSdkPackage.version);
return fs.writeFile(filePath, result, 'utf8', function (err) {
if (err) return reject(err)
return resolve()
});
});
})
}
const bumbVersionAndSave = () => {
try {
// upgrade nocodb-sdk version in nocodb
execSync(`cd packages/nocodb && npm install --save --save-exact ${nocodbSdkPackage.name}@${nocodbSdkPackage.version}`, {});
// upgrade nocodb-sdk version in nc-gui
execSync(`cd packages/nc-gui && npm install --save --save-exact ${nocodbSdkPackage.name}@${nocodbSdkPackage.version}`, {});
} catch (e) {
console.log(e.message);
console.log(e.stdout.toString());
}
// upgrade nocodb-sdk version in nocodb & nc-gui
return Promise.all([
replacePackageVersion(path.join(__dirname, '..', 'packages', 'nocodb', 'package.json')),
replacePackageVersion(path.join(__dirname, '..', 'packages', 'nc-gui', 'package.json')),
replacePackageVersion(path.join(__dirname, '..', 'tests', 'playwright', 'package.json')),
])
}
const dfs = function(dir) {
@ -53,8 +63,10 @@ const searchAndReplace = (target) => {
let list = [
...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nc-gui'))),
...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nocodb'))),
...dfs(path.resolve(path.join(__dirname, '..', 'tests', 'playwright'))),
path.join(__dirname, '..', 'packages', 'nc-gui', 'package.json'),
path.join(__dirname, '..', 'packages', 'nocodb', 'package.json')
path.join(__dirname, '..', 'packages', 'nocodb', 'package.json'),
path.join(__dirname, '..', 'tests', 'playwright', 'package.json'),
]
return Promise.all(list.map(d => {
return new Promise((resolve, reject) => {

2
tests/playwright/.lintstagedrc.json

@ -1,3 +1,3 @@
{
"**/*.{ts,tsx,js,json}": "npx eslint --fix"
"**/*.{ts,tsx,js,json}": "pnpm exec eslint --fix"
}

10705
tests/playwright/package-lock.json generated

File diff suppressed because it is too large Load Diff

89
tests/playwright/package.json

@ -1,55 +1,70 @@
{
"name": "playwright",
"version": "1.0.0",
"description": "",
"description": "NocoDB playwright",
"private": true,
"author": {
"name": "NocoDB",
"url": "https://nocodb.com/"
},
"homepage": "https://github.com/nocodb/nocodb",
"repository": {
"type": "git",
"url": "https://github.com/nocodb/nocodb.git"
},
"bugs": {
"url": "https://github.com/nocodb/nocodb/issues"
},
"license": "AGPL-3.0-or-later",
"main": "index.js",
"engines": {
"node": ">=18"
},
"scripts": {
"test": "TRACE=true npx playwright test --workers=4",
"test:fast": "npx playwright test --workers=6",
"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:intelliJ": "TRACE=true PWDEBUG=console npx playwright test --trace on -c playwright.config.ts --headed --project=chromium --retries 0 --workers 1 --max-failures=1",
"test:debug:watch": "npx nodemon -e ts -w ./ -x \"npm run test:debug\"",
"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": "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"
"test": "TRACE=true pnpm exec playwright test --workers=4",
"test:fast": "pnpm exec playwright test --workers=6",
"test:shard:1": "TRACE=true pnpm exec playwright test --workers=4 --shard=1/2",
"test:shard:2": "TRACE=true pnpm exec playwright test --workers=4 --shard=2/2",
"test:repeat": "TRACE=true pnpm exec playwright test --workers=4 --repeat-each=12",
"test:quick": "TRACE=true PW_QUICK_TEST=1 pnpm exec 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 pnpm exec playwright test -c playwright.config.ts --headed --project=chromium --retries 0 --timeout 0 --workers 1 --max-failures=1",
"test:debug:intelliJ": "TRACE=true PWDEBUG=console pnpm exec playwright test --trace on -c playwright.config.ts --headed --project=chromium --retries 0 --workers 1 --max-failures=1",
"test:debug:watch": "pnpm dlx nodemon -e ts -w ./ -x \"pnpm run test:debug\"",
"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 pnpm exec playwright test -c playwright.config.ts --headed --project=chromium --retries 0 --timeout 5 --workers 1 --max-failures=1",
"ci:test": "pnpm exec playwright test --workers=2",
"ci:test:shard:1": "pnpm exec playwright test --workers=2 --shard=1/2",
"ci:test:shard:2": "pnpm exec playwright test --workers=2 --shard=2/2",
"ci:test:mysql": "E2E_DB_TYPE=mysql pnpm exec playwright test --workers=2",
"ci:test:pg": "E2E_DB_TYPE=pg pnpm exec playwright test --workers=2",
"preinstall": "npx only-allow pnpm"
},
"dependencies": {
"body-parser": "^1.20.1",
"dayjs": "^1.11.9",
"express": "^4.18.1",
"knex": "^2.4.2",
"nocodb-sdk": "workspace:^",
"sqlite3": "^5.1.6",
"xlsx": "^0.18.5"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "1.32.2",
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"@playwright/test": "1.36.1",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"axios": "^0.24.0",
"dotenv": "^16.0.3",
"eslint": "^7.8.0",
"eslint": "^8.22.0",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-functional": "^5.0.8",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"mysql2": "^2.3.3",
"mysql2": "^3.2.0",
"pg": "^8.8.0",
"prettier": "^2.7.1",
"promised-sqlite3": "^1.2.0"
},
"dependencies": {
"body-parser": "^1.20.1",
"dayjs": "^1.11.7",
"express": "^4.18.2",
"knex": "^2.4.2",
"nocodb-sdk": "file:../../packages/nocodb-sdk",
"sqlite3": "^5.1.6",
"xlsx": "^0.18.5"
"promised-sqlite3": "^2.1.0"
}
}

6
tests/playwright/pages/Account/License.ts

@ -10,7 +10,11 @@ export class AccountLicensePage extends BasePage {
}
async goto() {
await this.rootPage.goto('/#/account/license', { waitUntil: 'networkidle' });
return this.waitForResponse({
uiAction: async () => await this.rootPage.goto('/#/account/license'),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: `api/v1/license`,
});
}
async waitUntilContentLoads() {

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

@ -10,13 +10,17 @@ export class AccountSettingsPage extends BasePage {
this.accountPage = accountPage;
}
async goto() {
// await this.rootPage.goto('/#/account/users/settings', { waitUntil: 'networkidle' });
await this.waitForResponse({
uiAction: () => this.rootPage.goto('/#/account/users/settings', { waitUntil: 'networkidle' }),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: `api/v1/app-settings`,
});
async goto(p: { networkValidation: boolean }) {
if (p.networkValidation) {
return this.waitForResponse({
uiAction: async () => await this.rootPage.goto('/#/account/users/settings'),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: `api/v1/app-settings`,
});
} else {
await this.rootPage.goto('/#/account/users/settings');
await this.rootPage.waitForTimeout(500);
}
}
get() {
@ -28,7 +32,10 @@ export class AccountSettingsPage extends BasePage {
}
async getInviteOnlyCheckboxValue() {
return this.get().locator(`.nc-invite-only-signup-checkbox`).isChecked();
// allow time for the checkbox to be rendered
await this.rootPage.waitForTimeout(1000);
return this.get().locator(`.nc-invite-only-signup-checkbox`).isChecked({ timeout: 1000 });
}
async checkInviteOnlySignupCheckbox(value: boolean) {

6
tests/playwright/pages/Account/Token.ts

@ -15,7 +15,11 @@ export class AccountTokenPage extends BasePage {
}
async goto() {
await this.rootPage.goto('/#/account/tokens', { waitUntil: 'networkidle' });
return this.waitForResponse({
uiAction: async () => await this.rootPage.goto('/#/account/tokens'),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: `api/v1/tokens`,
});
}
get() {

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

@ -17,8 +17,21 @@ export class AccountUsersPage extends BasePage {
this.changePasswordPage = new ChangePasswordPage(this.rootPage);
}
async goto() {
await this.rootPage.goto('/#/account/users/list', { waitUntil: 'networkidle' });
async goto({ waitForResponse = true }: { waitForResponse?: boolean }) {
if (waitForResponse) {
return this.waitForResponse({
uiAction: async () => await this.rootPage.goto('/#/account/users'),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: `api/v1/users`,
});
} else {
await this.rootPage.waitForTimeout(1000);
return this.rootPage.goto('/#/account/users');
}
}
async waitUntilContentLoads() {
return this.rootPage.waitForResponse(resp => resp.url().includes('api/v1/users') && resp.status() === 200);
}
get() {
@ -35,7 +48,7 @@ export class AccountUsersPage extends BasePage {
await this.verifyToast({ message: 'Successfully added user' });
// http://localhost:3000/#/signup/a5e7bf3a-cbb0-46bc-87f7-c2ae21796707
return (await this.inviteUserModal.locator(`.ant-alert-message`).innerText()).slice(0, 67);
return (await this.inviteUserModal.locator(`.ant-alert-message`).innerText()).split('\n')[0];
}
prefixEmail(email: string) {

58
tests/playwright/pages/Base.ts

@ -23,54 +23,32 @@ export default abstract class BasePage {
requestUrlPathToMatch,
// A function that takes the response body and returns true if the response is the one we are looking for
responseJsonMatcher,
debug = false,
debugKey,
}: {
uiAction: () => Promise<any>;
requestUrlPathToMatch: string;
httpMethodsToMatch?: string[];
responseJsonMatcher?: ResponseSelector;
debug?: boolean;
debugKey?: string;
}) {
const waitForResponsePromise = this.rootPage.waitForResponse(async res => {
let isResJsonMatched = true;
if (responseJsonMatcher) {
try {
isResJsonMatched = responseJsonMatcher(await res.json());
} catch (e) {
return false;
}
}
const [res] = await Promise.all([
this.rootPage.waitForResponse(
res =>
res.url().includes(requestUrlPathToMatch) &&
res.status() === 200 &&
httpMethodsToMatch.includes(res.request().method())
),
uiAction(),
]);
if (debug) {
console.log(`${debugKey},waitForResponse`, {
resUrl: res.request().url(),
resMethod: res.request().method(),
});
console.log(`${debugKey},result`, {
resUrlResult: res.request().url().includes(requestUrlPathToMatch),
resMethodResult: httpMethodsToMatch.includes(res.request().method()),
resJsonResult: isResJsonMatched,
});
// handle JSON matcher if provided
let isResJsonMatched = true;
if (responseJsonMatcher) {
try {
isResJsonMatched = responseJsonMatcher(res.json());
} catch {
isResJsonMatched = false;
}
const found =
res.request().url().includes(requestUrlPathToMatch) &&
httpMethodsToMatch.includes(res.request().method()) &&
isResJsonMatched;
return found;
});
const uiActionWithDelay = async () => {
// Create a promise that resolves after a delay
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
// Returning a promise that resolves with the result after the a delay
await delay(100);
return await uiAction();
};
await Promise.all([waitForResponsePromise, uiActionWithDelay()]);
}
return isResJsonMatched;
}
async attachFile({ filePickUIAction, filePath }: { filePickUIAction: Promise<any>; filePath: string[] }) {

4
tests/playwright/pages/Dashboard/Grid/Column/index.ts

@ -336,7 +336,7 @@ export class ColumnPageObject extends BasePage {
}
await this.waitForResponse({
uiAction: () => this.rootPage.locator('li[role="menuitem"]:has-text("Hide Field"):visible').click(),
uiAction: async () => await this.rootPage.locator('li[role="menuitem"]:has-text("Hide Field"):visible').click(),
requestUrlPathToMatch: 'api/v1/db/meta/views',
httpMethodsToMatch: ['PATCH'],
});
@ -346,7 +346,7 @@ export class ColumnPageObject extends BasePage {
async save({ isUpdated }: { isUpdated?: boolean } = {}) {
await this.waitForResponse({
uiAction: () => this.get().locator('button:has-text("Save")').click(),
uiAction: async () => await this.get().locator('button:has-text("Save")').click(),
requestUrlPathToMatch: 'api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
responseJsonMatcher: json => json['pageInfo'],

1
tests/playwright/pages/Dashboard/Grid/index.ts

@ -94,6 +94,7 @@ export class GridPage extends BasePage {
index,
columnHeader,
});
await this.rootPage.waitForTimeout(500);
await cell.locator('input').fill(value);
}

2
tests/playwright/pages/Dashboard/Settings/Acl.ts

@ -19,7 +19,7 @@ export class AclPage extends BasePage {
async save() {
await this.waitForResponse({
uiAction: () => this.get().locator(`button:has-text("Save")`).click(),
uiAction: async() => await this.get().locator(`button:has-text("Save")`).click(),
httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: '/visibility-rules',
});

2
tests/playwright/pages/Dashboard/TreeView.ts

@ -250,7 +250,7 @@ export class TreeViewPage extends BasePage {
}
await this.waitForResponse({
uiAction: () => this.rootPage.getByRole('button', { name: 'Confirm' }).click(),
uiAction: async () => await this.rootPage.getByRole('button', { name: 'Confirm' }).click(),
httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: `/api/v1/db/meta/duplicate/`,
});

4
tests/playwright/pages/Dashboard/WebhookForm/index.ts

@ -100,7 +100,7 @@ export class WebhookFormPage extends BasePage {
}
async save() {
const saveAction = () => this.saveButton.click();
const saveAction = async () => await this.saveButton.click();
await this.waitForResponse({
uiAction: saveAction,
@ -148,8 +148,10 @@ export class WebhookFormPage extends BasePage {
async configureHeader({ key, value }: { key: string; value: string }) {
// hardcode "Content-type: application/json"
await this.get().locator(`.ant-tabs-tab-btn:has-text("Headers")`).click();
await this.rootPage.waitForTimeout(500);
await this.get().locator('.nc-input-hook-header-key').click();
await this.rootPage.waitForTimeout(500);
// kludge, as the dropdown is not visible even after scroll into view
await this.rootPage.locator('.ant-select-dropdown:visible').hover();

6
tests/playwright/pages/Dashboard/common/Cell/CheckboxCell.ts

@ -18,9 +18,9 @@ export class CheckboxCellPageObject extends BasePage {
return await this.get({ index, columnHeader }).locator('.nc-cell').click();
}
async isChecked({ index, columnHeader }: { index?: number; columnHeader: string }) {
return await this.get({ index, columnHeader }).locator('.nc-cell-hover-show').isVisible();
}
// async isChecked({ index, columnHeader }: { index?: number; columnHeader: string }) {
// return await this.get({ index, columnHeader }).locator('.nc-cell-hover-show').isVisible();
// }
async verifyChecked({ index, columnHeader }: { index?: number; columnHeader: string }) {
await expect(this.get({ index, columnHeader }).locator('.nc-cell-hover-show')).not.toBeVisible();

2
tests/playwright/pages/Dashboard/common/Cell/RatingCell.ts

@ -17,7 +17,7 @@ export class RatingCellPageObject extends BasePage {
async select({ index, columnHeader, rating }: { index?: number; columnHeader: string; rating: number }) {
await this.get({ index, columnHeader }).scrollIntoViewIfNeeded();
await this.waitForResponse({
uiAction: () => this.get({ index, columnHeader }).locator('.ant-rate-star > div').nth(rating).click(),
uiAction: async () => await this.get({ index, columnHeader }).locator('.ant-rate-star > div').nth(rating).click(),
httpMethodsToMatch: ['POST', 'PATCH'],
requestUrlPathToMatch: 'api/v1/db/data/noco/',
});

2
tests/playwright/pages/Dashboard/common/Toolbar/Fields.ts

@ -88,7 +88,7 @@ export class ToolbarFieldsPage extends BasePage {
async toggleShowSystemFields({ isLocallySaved }: { isLocallySaved?: boolean } = {}) {
await this.toolbar.clickFields();
await this.waitForResponse({
uiAction: () => this.get().locator(`.nc-fields-show-system-fields`).click(),
uiAction: async () => await this.get().locator(`.nc-fields-show-system-fields`).click(),
requestUrlPathToMatch: isLocallySaved ? '/api/v1/db/public/' : '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
});

21
tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts

@ -145,8 +145,8 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350);
} else {
await this.waitForResponse({
uiAction: () =>
this.rootPage
uiAction: async () =>
await this.rootPage
.locator('div.ant-select-dropdown.nc-dropdown-toolbar-field-list')
.locator(`div[label="${title}"]:visible`)
.click(),
@ -171,8 +171,8 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350);
} else {
await this.waitForResponse({
uiAction: () =>
this.rootPage
uiAction: async () =>
await this.rootPage
.locator('.nc-dropdown-filter-comp-op')
.locator(`.ant-select-item:has-text("${operation}")`)
.first()
@ -199,8 +199,8 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350);
} else {
await this.waitForResponse({
uiAction: () =>
this.rootPage
uiAction: async () =>
await this.rootPage
.locator('.nc-dropdown-filter-comp-sub-op')
.locator(`.ant-select-item:has-text("${subOperation}")`)
.first()
@ -246,7 +246,8 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350);
} else {
await this.waitForResponse({
uiAction: () => this.rootPage.locator(`.ant-picker-cell-inner:has-text("${value}")`).click(),
uiAction: async () =>
await this.rootPage.locator(`.ant-picker-cell-inner:has-text("${value}")`).click(),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: locallySaved ? `/api/v1/db/public/` : `/api/v1/db/data/noco/`,
});
@ -274,7 +275,7 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350);
} else {
await this.waitForResponse({
uiAction: () => this.get().locator('.nc-filter-value-select').locator('input').fill(value),
uiAction: async () => await this.get().locator('.nc-filter-value-select').locator('input').fill(value),
httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: locallySaved ? `/api/v1/db/public/` : `/api/v1/db/data/noco/`,
});
@ -348,7 +349,7 @@ export class ToolbarFilterPage extends BasePage {
await this.toolbar.clickFilter();
if (networkValidation) {
await this.waitForResponse({
uiAction: () => this.get().locator('.nc-filter-item-remove-btn').click(),
uiAction: async () => await this.get().locator('.nc-filter-item-remove-btn').click(),
httpMethodsToMatch: ['DELETE'],
requestUrlPathToMatch: '/api/v1/db/meta/filters/',
});
@ -361,7 +362,7 @@ export class ToolbarFilterPage extends BasePage {
async remove({ networkValidation = true }: { networkValidation?: boolean } = {}) {
if (networkValidation) {
await this.waitForResponse({
uiAction: () => this.get().locator('.nc-filter-item-remove-btn').click(),
uiAction: async () => await this.get().locator('.nc-filter-item-remove-btn').click(),
httpMethodsToMatch: ['DELETE'],
requestUrlPathToMatch: '/api/v1/db/meta/filters/',
});

1
tests/playwright/pages/Dashboard/common/Topbar/index.ts

@ -69,6 +69,7 @@ export class TopbarPage extends BasePage {
async openDetailedTab() {
await this.btn_details.click();
await this.rootPage.waitForTimeout(500);
}
async openDataTab() {

5
tests/playwright/pages/Dashboard/index.ts

@ -61,7 +61,10 @@ export class DashboardPage extends BasePage {
this.project = project;
this.tablesSideBar = rootPage.locator('.nc-treeview-container');
this.workspaceMenuLink = rootPage.getByTestId('nc-project-menu');
this.projectMenuLink = rootPage.locator(`.project-title-node:has-text("${project.title}")`).locator('.nc-icon.ant-dropdown-trigger').first();
this.projectMenuLink = rootPage
.locator(`.project-title-node:has-text("${project.title}")`)
.locator('.nc-icon.ant-dropdown-trigger')
.first();
this.tabBar = rootPage.locator('.nc-tab-bar');
this.treeView = new TreeViewPage(this, project);
this.grid = new GridPage(this);

2
tests/playwright/pages/LoginPage/index.ts

@ -11,7 +11,7 @@ export class LoginPage extends BasePage {
return `nc_test_${parallelId}_${email}`;
}
goto() {
async goto() {
return this.rootPage.goto('/#/signin');
}

45
tests/playwright/pages/ProjectsPage/index.ts

@ -136,34 +136,33 @@ export class ProjectsPage extends BasePage {
let project: any;
const openProjectUiAction = this.get()
const responsePromise = this.rootPage.waitForResponse(async res => {
let json: any = {};
try {
json = await res.json();
} catch (e) {
return false;
}
const isRequiredResponse =
res.request().url().includes('/api/v1/db/meta/projects') &&
['GET'].includes(res.request().method()) &&
json?.title === title;
if (isRequiredResponse) {
project = json;
}
return isRequiredResponse;
});
await this.get()
.locator(`.ant-table-cell`, {
hasText: title,
})
.click();
await Promise.all([
this.rootPage.waitForResponse(async res => {
let json: any = {};
try {
json = await res.json();
} catch (e) {
return false;
}
const isRequiredResponse =
res.request().url().includes('/api/v1/db/meta/projects') &&
['GET'].includes(res.request().method()) &&
json?.title === title;
if (isRequiredResponse) {
project = json;
}
return isRequiredResponse;
}),
openProjectUiAction,
]);
await responsePromise;
const dashboard = new DashboardPage(this.rootPage, project);

2
tests/playwright/pages/SharedForm/index.ts

@ -16,7 +16,7 @@ export class SharedFormPage extends BasePage {
async submit() {
await this.waitForResponse({
uiAction: () => this.get().getByTestId('shared-form-submit-button').click(),
uiAction: async () => await this.get().getByTestId('shared-form-submit-button').click(),
httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: '/rows',
});

4
tests/playwright/pages/SigninPage/index.ts

@ -16,8 +16,8 @@ export class SigninPage extends BasePage {
return `nc_test_${parallelId}_${email}`;
}
goto() {
return this.rootPage.goto('/#/signin/', { waitUntil: 'networkidle' });
async goto() {
return this.rootPage.goto('/#/signin/');
}
get() {

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

Loading…
Cancel
Save