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

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

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

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

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

2
.github/workflows/publish-docs.yml

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

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

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

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

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

28
.github/workflows/release-docker.yml

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

2
.github/workflows/release-draft.yml

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

28
.github/workflows/release-npm.yml

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

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' }} 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' runs-on: 'ubuntu-latest'
steps: steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 1
ref: ${{ github.ref }}
- name: set-tag - name: set-tag
id: tag-step id: tag-step
run: | run: |

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

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

35
.github/workflows/unit-test.yml

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

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

@ -9,21 +9,21 @@ jobs:
release: release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 16.15.0 node-version: 18.14.0
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- run: | - run: |
cd packages/nocodb pnpm bootstrap
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
- name: Create Pull Request - name: Create Pull Request
id: cpr id: cpr

5
.gitignore vendored

@ -84,8 +84,8 @@ mongod
*.sln *.sln
.history .history
/packages/nocodb-legacy/docker/main.js.LICENSE.txt /packages/nocodb/docker/main.js.LICENSE.txt
/packages/nocodb-legacy/noco_log.db /packages/nocodb/noco_log.db
# NC_DBs # NC_DBs
#========= #=========
@ -95,3 +95,4 @@ test_noco.db
# ngrok config # ngrok config
httpbin httpbin
.run/test-debug.run.xml .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"> <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) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-green.svg)](https://conventionalcommits.org)
</div> </div>

36
build-local-docker-image.sh

@ -2,7 +2,7 @@
# script to build local docker image. # script to build local docker image.
# highlevel steps involved # highlevel steps involved
# 1. Stop and remove existing container and image # 1. Stop and remove existing container and image
# 2. Build nocodb-sdk # 2. Install dependencies
# 3. Build nc-gui # 3. Build nc-gui
# 3a. static build of nc-gui # 3a. static build of nc-gui
# 3b. copy nc-gui build to nocodb dir # 3b. copy nc-gui build to nocodb dir
@ -23,41 +23,37 @@ function remove_image() {
docker rmi nocodb-local >/dev/null 2>&1 docker rmi nocodb-local >/dev/null 2>&1
} }
function build_sdk(){ function install_dependencies() {
# build nocodb-sdk # Install all dependencies
cd ${SCRIPT_DIR}/packages/nocodb-sdk cd ${SCRIPT_DIR}
npm ci || ERROR="sdk build failed" pnpm i || ERROR="install_dependencies failed"
npm run build || ERROR="sdk build failed"
} }
function build_gui(){ function build_gui() {
# build nc-gui # build nc-gui
export NODE_OPTIONS="--max_old_space_size=16384" export NODE_OPTIONS="--max_old_space_size=16384"
# generate static build of nc-gui # generate static build of nc-gui
cd ${SCRIPT_DIR}/packages/nc-gui cd ${SCRIPT_DIR}/packages/nc-gui
npm ci || ERROR="gui build failed" pnpm run generate || ERROR="gui build failed"
npm run generate || ERROR="gui build failed"
} }
function copy_gui_artifacts(){ function copy_gui_artifacts() {
# copy nc-gui build to nocodb dir # copy nc-gui build to nocodb dir
rsync -rvzh --delete ./dist/ ${SCRIPT_DIR}/packages/nocodb/docker/nc-gui/ || ERROR="copy_gui_artifacts failed" rsync -rvzh --delete ./dist/ ${SCRIPT_DIR}/packages/nocodb/docker/nc-gui/ || ERROR="copy_gui_artifacts failed"
} }
function package_nocodb(){ function package_nocodb() {
#build nocodb
# build nocodb ( pack nocodb-sdk and nc-gui ) # build nocodb ( pack nocodb-sdk and nc-gui )
cd ${SCRIPT_DIR}/packages/nocodb cd ${SCRIPT_DIR}/packages/nocodb
npm install || 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"
EE=true ./node_modules/.bin/webpack --config webpack.local.config.js || ERROR="package_nocodb failed"
} }
function build_image(){ function build_image() {
# build docker # build docker
docker build . -f Dockerfile.local -t nocodb-local || ERROR="build_image failed" docker build . -f Dockerfile.local -t nocodb-local || ERROR="build_image failed"
} }
function log_message(){ function log_message() {
if [[ ${ERROR} != "" ]]; if [[ ${ERROR} != "" ]];
then then
>&2 echo "build failed, Please check build-local-docker-image.log for more details" >&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 stop_and_remove_container
remove_image remove_image
echo "Info: Building nocodb-sdk" | tee -a ${LOG_FILE} echo "Info: Installing dependencies" | tee -a ${LOG_FILE}
build_sdk 1>> ${LOG_FILE} 2>> ${LOG_FILE} install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE}
echo "Info: Building nc-gui" | tee -a ${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} echo "Info: Copy nc-gui build to nocodb dir" | tee -a ${LOG_FILE}
copy_gui_artifacts 1>> ${LOG_FILE} 2>> ${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} build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE}
fi 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 ```shell
cd packages/nocodb-sdk cd packages/nocodb-sdk
npm install pnpm install
npm run build pnpm run build
``` ```
## 本地运行后端 ## 本地运行后端
```shell ```shell
cd packages/nocodb cd packages/nocodb
npm install pnpm install
npm run watch:run pnpm run watch:run
# 在浏览器中打开 localhost:8080/dashboard # 在浏览器中打开 localhost:8080/dashboard
``` ```
@ -231,14 +231,14 @@ npm run watch:run
```shell ```shell
cd packages/nc-gui cd packages/nc-gui
npm install pnpm install
npm run dev pnpm run dev
# 在浏览器中打开 localhost:3000/dashboard # 在浏览器中打开 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 ```shell
cd packages/nocodb cd packages/nocodb
npm install pnpm install
npm run watch:run pnpm run watch:run
# localhost:8080/dashboard im Browser aufrufen # localhost:8080/dashboard im Browser aufrufen
``` ```
@ -214,8 +214,8 @@ npm run watch:run
```shell ```shell
cd packages/nc-gui cd packages/nc-gui
npm install pnpm install
npm run dev pnpm run dev
# localhost:3000/dashboard iM Browser aufrufen # 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 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 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 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 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", "license": "AGPL-3.0-or-later",
"devDependencies": { "devDependencies": {
"fs": "0.0.1-security", "fs": "0.0.1-security",
"lerna": "^6.4.1", "lerna": "^7.0.2",
"husky": "^8.0.0", "husky": "^8.0.0",
"xlsx": "^0.17.4" "xlsx": "^0.17.4"
}, },
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": "npx lint-staged" "pre-commit": "pnpm dlx lint-staged"
} }
}, },
"lint-staged": { "lint-staged": {
"scripts/playwright/**/*.{ts,tsx,js,json}": [ "scripts/playwright/**/*.{ts,tsx,js,json}": [
"npm run lint:staged:playwright" "pnpm run lint:staged:playwright"
] ]
}, },
"scripts": { "scripts": {
"lint:staged:playwright": "cd ./tests/playwright; npx lint-staged; cd -", "bootstrap": "pnpm --filter=nocodb-sdk install && pnpm --filter=nocodb-sdk run build && pnpm --filter=nocodb --filter=nc-gui --filter=playwright install",
"build:common": "cd ./packages/nocodb-sdk; npm install; npm run build", "start:frontend": "pnpm --filter=nc-gui run dev",
"install:common": "cd packages/nocodb-legacy; npm install ../nocodb-sdk; cd ../nc-gui; npm install ../nocodb-sdk", "start:backend": "pnpm --filter=nocodb run start",
"start:web": "npm run build:common ; cd ./packages/nc-gui; npm install ../nocodb-sdk; npm install; ANT_MESSAGE_DURATION=0.5 npm run dev", "lint:staged:playwright": "cd ./tests/playwright; pnpm dlx lint-staged; cd -",
"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",
"start:mysql": "docker-compose -f ./tests/playwright/scripts/docker-compose-mysql-playwright.yml up -d", "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", "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", "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", "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" "install:local-sdk": "node scripts/installLocalSdk.js"
}, },
"dependencies": { "pnpm": {
"express": "^4.18.1", "overrides": {
"mysql2": "^2.3.3", "vue": "latest",
"pg": "^8.7.3", "typescript": "latest"
"sqlite3": "^5.0.2" }
} }
} }

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

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

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

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

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

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

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

@ -1,5 +1,5 @@
import { dirname, resolve } from 'node:path' 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 Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver' import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite' import Components from 'unplugin-vue-components/vite'
@ -10,7 +10,7 @@ import { FileSystemIconLoader } from 'unplugin-icons/loaders'
import PurgeIcons from 'vite-plugin-purge-icons' 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({ export default defineNuxtConfig({
modules: ['@vueuse/nuxt', 'nuxt-windicss', '@nuxt/image-edge', '@pinia/nuxt'], modules: ['@vueuse/nuxt', 'nuxt-windicss', '@nuxt/image-edge', '@pinia/nuxt'],
@ -103,7 +103,7 @@ export default defineNuxtConfig({
rollupOptions: {}, rollupOptions: {},
}, },
plugins: [ plugins: [
vueI18n({ VueI18nPlugin({
include: [resolve(dirname('./lang/*.json'))], include: [resolve(dirname('./lang/*.json'))],
runtimeOnly: false, 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": { "bugs": {
"url": "https://github.com/nocodb/nocodb/issues" "url": "https://github.com/nocodb/nocodb/issues"
}, },
"engines": {
"node": ">=18"
},
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"web-types": "web-types.json", "web-types": "web-types.json",
"scripts": { "scripts": {
@ -25,10 +28,11 @@
"test": "vitest -c test/vite.config.ts", "test": "vitest -c test/vite.config.ts",
"test:ui": "vitest -c test/vite.config.ts --ui", "test:ui": "vitest -c test/vite.config.ts --ui",
"coverage": "vitest -c test/vite.config.ts run --coverage", "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": "pnpm 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", "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",
"postinstall": "nuxt prepare", "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 &",
"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 &" "preinstall": "npx only-allow pnpm",
"postinstall": "nuxt prepare"
}, },
"dependencies": { "dependencies": {
"@braks/revue-draggable": "^0.4.3", "@braks/revue-draggable": "^0.4.3",
@ -46,7 +50,7 @@
"chart.js": "^4.3.0", "chart.js": "^4.3.0",
"d3-scale": "^4.0.2", "d3-scale": "^4.0.2",
"dagre": "^0.8.5", "dagre": "^0.8.5",
"dayjs": "^1.11.3", "dayjs": "^1.11.9",
"deep-object-diff": "^1.1.9", "deep-object-diff": "^1.1.9",
"emoji-mart-vue-fast": "^15.0.0", "emoji-mart-vue-fast": "^15.0.0",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
@ -60,7 +64,7 @@
"locale-codes": "^1.3.1", "locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"monaco-sql-languages": "^0.11.0", "monaco-sql-languages": "^0.11.0",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "workspace:^",
"papaparse": "^5.3.2", "papaparse": "^5.3.2",
"parse-github-url": "^1.0.2", "parse-github-url": "^1.0.2",
"pinia": "^2.1.4", "pinia": "^2.1.4",
@ -89,29 +93,29 @@
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^0.26.0", "@antfu/eslint-config": "^0.26.0",
"@esbuild-plugins/node-modules-polyfill": "^0.1.4", "@esbuild-plugins/node-modules-polyfill": "^0.2.2",
"@iconify-json/ant-design": "^1.1.3", "@iconify-json/ant-design": "^1.1.9",
"@iconify-json/bi": "^1.1.6", "@iconify-json/bi": "^1.1.18",
"@iconify-json/carbon": "^1.1.2", "@iconify-json/carbon": "^1.1.20",
"@iconify-json/cil": "^1.1.2", "@iconify-json/cil": "^1.1.5",
"@iconify-json/clarity": "^1.1.4", "@iconify-json/clarity": "^1.1.9",
"@iconify-json/eva": "^1.1.2", "@iconify-json/eva": "^1.1.7",
"@iconify-json/ic": "^1.1.7", "@iconify-json/ic": "^1.1.14",
"@iconify-json/ion": "^1.1.8", "@iconify-json/ion": "^1.1.12",
"@iconify-json/la": "^1.1.2", "@iconify-json/la": "^1.1.5",
"@iconify-json/logos": "^1.1.14", "@iconify-json/logos": "^1.1.34",
"@iconify-json/lucide": "^1.1.36", "@iconify-json/lucide": "^1.1.119",
"@iconify-json/material-symbols": "^1.1.8", "@iconify-json/material-symbols": "^1.1.57",
"@iconify-json/mdi": "^1.1.25", "@iconify-json/mdi": "^1.1.54",
"@iconify-json/mi": "^1.1.2", "@iconify-json/mi": "^1.1.5",
"@iconify-json/ph": "^1.1.5", "@iconify-json/ph": "^1.1.6",
"@iconify-json/ri": "^1.1.12", "@iconify-json/ri": "^1.1.12",
"@iconify-json/simple-icons": "^1.1.29", "@iconify-json/simple-icons": "^1.1.67",
"@iconify-json/system-uicons": "^1.1.4", "@iconify-json/system-uicons": "^1.1.9",
"@iconify-json/tabler": "^1.1.59", "@iconify-json/tabler": "^1.1.89",
"@iconify-json/vscode-icons": "^1.1.14", "@iconify-json/vscode-icons": "^1.1.28",
"@intlify/unplugin-vue-i18n": "^0.12.2", "@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/axios": "^0.14.0",
"@types/d3-scale": "^4.0.3", "@types/d3-scale": "^4.0.3",
"@types/dagre": "^0.7.48", "@types/dagre": "^0.7.48",
@ -135,20 +139,20 @@
"@windicss/plugin-animations": "^1.0.9", "@windicss/plugin-animations": "^1.0.9",
"@windicss/plugin-question-mark": "^0.1.1", "@windicss/plugin-question-mark": "^0.1.1",
"@windicss/plugin-scrollbar": "^1.2.3", "@windicss/plugin-scrollbar": "^1.2.3",
"eslint": "^8.22.0", "eslint": "^8.33.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.2.1",
"happy-dom": "^6.0.3", "happy-dom": "^6.0.3",
"nuxt": "^3.6.2", "nuxt": "^3.6.5",
"nuxt-windicss": "^2.5.0", "nuxt-windicss": "^2.6.1",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"sass": "^1.53.0", "sass": "^1.63.4",
"ts-loader": "^9.4.4", "ts-loader": "^9.4.4",
"unplugin-icons": "^0.14.15", "unplugin-icons": "^0.14.15",
"unplugin-vue-components": "^0.22.12", "unplugin-vue-components": "^0.22.12",
"vite-plugin-monaco-editor": "^1.1.0", "vite-plugin-monaco-editor": "^1.1.0",
"vite-plugin-purge-icons": "^0.9.2", "vite-plugin-purge-icons": "^0.9.2",
"vitest": "^0.18.0", "vitest": "^0.30.1",
"windicss": "^3.5.6" "windicss": "^3.5.6"
} }
} }

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

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

2
packages/nc-gui/tsconfig.json

@ -11,7 +11,7 @@
"strictNullChecks": true, "strictNullChecks": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"types": [ "types": [
"@intlify/vite-plugin-vue-i18n/client", "@intlify/unplugin-vue-i18n/messages",
"vue-i18n", "vue-i18n",
"unplugin-icons/types/vue", "unplugin-icons/types/vue",
"nuxt-windicss", "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! Simple installation - takes about three minutes!
## Prerequisites ## 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 ## 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 ### Install nocodb-sdk
```bash ```bash
npm i nocodb-sdk pnpm i nocodb-sdk
``` ```
### Import Api ### 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 ## Clone the repo
```
```bash
git clone https://github.com/nocodb/nocodb git clone https://github.com/nocodb/nocodb
cd nocodb/packages # change directory to the project root
cd nocodb
``` ```
## Build SDK ## Install dependencies
``` ```bash
# build nocodb-sdk # run from the project root
cd nocodb-sdk pnpm i
npm install
npm run build
``` ```
## Build Backend ## Start Frontend
``` ```bash
# build backend - runs on port 8080 # run from the project root
cd ../nocodb pnpm start:frontend
npm install # runs on port 3000
npm run watch:run
``` ```
## Build Frontend ## Start Backend
``` ```bash
# build frontend - runs on port 3000 # run from the project root
cd ../nc-gui pnpm start:backend
npm install # runs on port 8080
npm run dev
``` ```
Any changes made to frontend and backend will be automatically reflected in the browser. 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 ### Setup
```bash ```bash
cd packages/nocodb pnpm --filter=-nocodb install
npm install
# add a .env file # add a .env file
cp tests/unit/.env.sample tests/unit/.env cp tests/unit/.env.sample tests/unit/.env
@ -36,7 +34,7 @@ Configure the following variables
### Run Tests ### Run Tests
``` bash ``` bash
npm run test:unit pnpm run test:unit
``` ```
### Folder Structure ### 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. 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 ```bash
npm install pnpm --filter=playwright install
npx playwright install chromium --with-deps pnpm exec playwright install --with-deps chromium
``` ```
### Run Test Server ### Run Test Server
@ -19,13 +19,13 @@ npx playwright install chromium --with-deps
Start the backend test server (in `packages/nocodb` folder): Start the backend test server (in `packages/nocodb` folder):
```bash ```bash
npm run watch:run:playwright pnpm run watch:run:playwright
``` ```
Start the frontend test server (in `packages/nc-gui` folder): Start the frontend test server (in `packages/nc-gui` folder):
```bash ```bash
NUXT_PAGE_TRANSITION_DISABLE=true npm run dev NUXT_PAGE_TRANSITION_DISABLE=true pnpm run dev
``` ```
### Running all tests ### 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): headless mode(without opening browser):
```bash ```bash
npm run test pnpm run test
``` ```
with browser: with browser:
```bash ```bash
npm run test:debug pnpm run test:debug
``` ```
For setting up mysql(sakila): For setting up mysql(sakila):
@ -67,7 +67,7 @@ test.only('should login', async ({ page }) => {
``` ```
```bash ```bash
npm run test pnpm run test
``` ```
## Concepts ## Concepts
@ -183,7 +183,7 @@ This a method which will reset/clear all the filters. Since this is an action me
```js ```js
async resetFilter() { async resetFilter() {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['DELETE'],
requestUrlPathToMatch: '/api/v1/db/meta/filters/', 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. - Open `Summary` tab in the CI workflow in github actions.
- Scroll down to `Artifacts` section. - 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. - 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. You should see the similar result as below.
``` ```
Node: **v16.14.0** Node: **v18.16.4**
Arch: **arm64** Arch: **arm64**
Platform: **darwin** Platform: **linux**
Docker: **false** Docker: **true**
RootDB: **sqlite3** RootDB: **sqlite3**
PackageVersion: **0.109.7** PackageVersion: **0.111.0**
``` ```
## What is available in free version ? ## 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) ![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": { "bugs": {
"url": "https://github.com/nocodb/nocodb/issues" "url": "https://github.com/nocodb/nocodb/issues"
}, },
"engines": {
"node": ">=18"
},
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"keywords": [], "keywords": [],
"scripts": { "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:main": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
"build:module": "tsc -p tsconfig.module.json && tsc-alias -p tsconfig.module.json", "build:module": "tsc -p tsconfig.module.json && tsc-alias -p tsconfig.module.json",
"fix": "run-s fix:*", "fix": "run-s fix:*",
@ -31,24 +34,25 @@
"test:prettier": "prettier \"src/**/*.ts\" --list-different", "test:prettier": "prettier \"src/**/*.ts\" --list-different",
"test:spelling": "cspell \"{README.md,.github/*.md,src/**/*.ts}\"", "test:spelling": "cspell \"{README.md,.github/*.md,src/**/*.ts}\"",
"watch:build": "tsc -p tsconfig.json -w", "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": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
"jsep": "^1.3.6" "jsep": "^1.3.6"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.0.1", "@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^4.0.1", "@typescript-eslint/parser": "^6.1.0",
"cspell": "^4.1.0", "cspell": "^4.1.0",
"eslint": "^7.8.0", "eslint": "^8.33.0",
"eslint-config-prettier": "^6.11.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2", "eslint-plugin-functional": "^5.0.8",
"eslint-plugin-import": "^2.22.0", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.2.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^2.1.1", "prettier": "^2.8.8",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",
"tsc-alias": "^1.8.7", "tsc-alias": "^1.8.7",
"typescript": "^4.7.4" "typescript": "^4.7.4"
@ -65,4 +69,4 @@
"prettier": { "prettier": {
"singleQuote": true "singleQuote": true
} }
} }

23
packages/nocodb/Dockerfile

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

21
packages/nocodb/Dockerfile.local

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

4
packages/nocodb/README.md

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

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

@ -33,15 +33,17 @@ module.exports = {
}, },
optimization: { optimization: {
minimize: true, //Update this to true or false minimize: true, //Update this to true or false
minimizer: [new TerserPlugin()], minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
},
}),
],
nodeEnv: false, nodeEnv: false,
}, },
externals: [nodeExternals()], externals: [nodeExternals()],
plugins: [ plugins: [new webpack.EnvironmentPlugin(['EE'])],
new webpack.EnvironmentPlugin([
'EE'
]),
],
target: 'node', target: 'node',
node: { node: {
__dirname: false, __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/ 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 WORKDIR /usr/src/app
# install pnpm
RUN corepack enable && corepack prepare pnpm@latest --activate
# Copy application dependency manifests to the container image. # 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 ./
COPY ./docker/main.js ./docker/main.js COPY ./docker/main.js ./docker/main.js
#COPY ./docker/start.sh /usr/src/appEntry/start.sh #COPY ./docker/start.sh /usr/src/appEntry/start.sh
COPY ./docker/start-litestream.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, # install production dependencies,
# reduce node_module size with modclean & removing sqlite deps, # reduce node_module size with modclean & removing sqlite deps,
# package built code into app.tar.gz & add execute permission to start.sh # package built code into app.tar.gz & add execute permission to start.sh
RUN npm ci --production --quiet RUN pnpm install --prod --shamefully-hoist --reporter=silent
RUN npx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**" --run RUN pnpm dlx modclean --patterns="default:*" --ignore="nc-lib-gui/**,dayjs/**,express-status-monitor/**" --run
RUN rm -rf ./node_modules/sqlite3/deps RUN rm -rf ./node_modules/sqlite3/deps
RUN tar -czf ../appEntry/app.tar.gz ./* RUN tar -czf ../appEntry/app.tar.gz ./*
RUN chmod +x /usr/src/appEntry/start.sh RUN chmod +x /usr/src/appEntry/start.sh
FROM alpine:3.18
FROM alpine:3.14
#ENV AWS_ACCESS_KEY_ID= #ENV AWS_ACCESS_KEY_ID=
#ENV AWS_SECRET_ACCESS_KEY= #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": { "bugs": {
"url": "https://github.com/nocodb/nocodb/issues" "url": "https://github.com/nocodb/nocodb/issues"
}, },
"engines": {
"node": ">=18"
},
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"scripts": { "scripts": {
"build": "npm run docker:build", "build": "pnpm run docker:build",
"build:obfuscate": "EE=true webpack --config webpack.config.js", "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\"", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "npm run watch:run", "start": "pnpm run watch:run",
"start:prod": "node docker/main", "start:prod": "node docker/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest", "test": "jest",
@ -45,34 +48,34 @@
"@aws-sdk/client-kafka": "^3.332.0", "@aws-sdk/client-kafka": "^3.332.0",
"@google-cloud/storage": "^5.7.2", "@google-cloud/storage": "^5.7.2",
"@graphql-tools/merge": "^6.0.12", "@graphql-tools/merge": "^6.0.12",
"@jm18457/kafkajs-msk-iam-authentication-mechanism": "^3.1.1", "@jm18457/kafkajs-msk-iam-authentication-mechanism": "^3.1.2",
"@nestjs/bull": "^0.6.3", "@nestjs/bull": "^10.0.1",
"@nestjs/common": "^9.4.0", "@nestjs/common": "^10.2.1",
"@nestjs/config": "^2.3.1", "@nestjs/config": "^3.0.0",
"@nestjs/core": "^9.4.0", "@nestjs/core": "^10.2.1",
"@nestjs/event-emitter": "^1.4.1", "@nestjs/event-emitter": "^2.0.2",
"@nestjs/jwt": "^10.0.3", "@nestjs/jwt": "^10.1.0",
"@nestjs/mapped-types": "*", "@nestjs/mapped-types": "^2.0.2",
"@nestjs/passport": "^9.0.3", "@nestjs/passport": "^10.0.1",
"@nestjs/platform-express": "^9.4.0", "@nestjs/platform-express": "^10.2.1",
"@nestjs/platform-socket.io": "^9.4.0", "@nestjs/platform-socket.io": "^10.2.1",
"@nestjs/serve-static": "^3.0.1", "@nestjs/serve-static": "^4.0.0",
"@nestjs/throttler": "^4.0.0", "@nestjs/throttler": "^4.2.1",
"@nestjs/websockets": "^9.4.0", "@nestjs/websockets": "^10.2.1",
"@sentry/node": "^6.3.5", "@sentry/node": "^6.3.5",
"@techpass/passport-openidconnect": "^0.3.3", "@techpass/passport-openidconnect": "^0.3.3",
"@types/chai": "^4.2.12", "@types/chai": "^4.2.12",
"airtable": "^0.11.3", "airtable": "^0.12.1",
"ajv": "^8.12.0", "ajv": "^8.12.0",
"ajv-formats": "^2.1.1", "ajv-formats": "^2.1.1",
"archiver": "^5.0.2", "archiver": "^5.0.2",
"auto-bind": "^4.0.0", "auto-bind": "^4.0.0",
"aws-kcl": "^2.2.2", "aws-kcl": "^2.2.2",
"aws-sdk": "^2.829.0", "aws-sdk": "^2.1419.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"body-parser": "^1.19.0", "body-parser": "^1.20.1",
"boxen": "^5.0.0", "boxen": "^5.1.0",
"bull": "^4.10.4", "bull": "^4.10.4",
"bullmq": "^1.81.1", "bullmq": "^1.81.1",
"clear": "^0.1.0", "clear": "^0.1.0",
@ -85,12 +88,12 @@
"cron": "^1.8.2", "cron": "^1.8.2",
"crypto-js": "^4.0.0", "crypto-js": "^4.0.0",
"dataloader": "^2.0.0", "dataloader": "^2.0.0",
"dayjs": "^1.8.34", "dayjs": "^1.11.9",
"debug": "^4.2.0", "debug": "^4.2.0",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"ejs": "^3.1.3", "ejs": "^3.1.3",
"emittery": "^0.7.1", "emittery": "^0.7.1",
"express": "^4.17.1", "express": "^4.18.1",
"express-graphql": "^0.11.0", "express-graphql": "^0.11.0",
"extract-zip": "^2.0.1", "extract-zip": "^2.0.1",
"fast-levenshtein": "^2.0.6", "fast-levenshtein": "^2.0.6",
@ -103,8 +106,8 @@
"html-to-json-parser": "^1.1.0", "html-to-json-parser": "^1.1.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
"inflection": "^1.12.0", "inflection": "^1.12.0",
"ioredis": "^5.0.4", "ioredis": "^5.3.2",
"ioredis-mock": "^7.1.0", "ioredis-mock": "^8.8.3",
"is-docker": "^2.2.1", "is-docker": "^2.2.1",
"isomorphic-dompurify": "^0.19.0", "isomorphic-dompurify": "^0.19.0",
"jsep": "^1.3.6", "jsep": "^1.3.6",
@ -112,7 +115,7 @@
"jsonfile": "^6.1.0", "jsonfile": "^6.1.0",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"kafkajs": "^2.2.4", "kafkajs": "^2.2.4",
"knex": "2.2.0", "knex": "2.4.2",
"list-github-dir-content": "^3.0.0", "list-github-dir-content": "^3.0.0",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"lru-cache": "^6.0.0", "lru-cache": "^6.0.0",
@ -122,22 +125,22 @@
"mkdirp": "^2.1.3", "mkdirp": "^2.1.3",
"morgan": "^1.10.0", "morgan": "^1.10.0",
"mssql": "^6.2.0", "mssql": "^6.2.0",
"multer": "^1.4.4", "multer": "^1.4.5-lts.1",
"mysql2": "^3.2.0", "mysql2": "^3.2.0",
"nanoid": "^3.1.20", "nanoid": "^3.1.20",
"nc-help": "0.2.92", "nc-help": "0.3.0",
"nc-lib-gui": "0.111.4", "nc-lib-gui": "0.111.4",
"nc-plugin": "^0.1.3", "nc-plugin": "^0.1.3",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nestjs-kafka": "^1.0.6", "nestjs-kafka": "^1.0.6",
"nestjs-throttler-storage-redis": "^0.3.0", "nestjs-throttler-storage-redis": "^0.3.0",
"nocodb-sdk": "file:../nocodb-sdk", "nocodb-sdk": "workspace:^",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",
"object-hash": "^3.0.0", "object-hash": "^3.0.0",
"object-sizeof": "^2.6.1", "object-sizeof": "^2.6.1",
"os-locale": "^6.0.2", "os-locale": "^6.0.2",
"p-queue": "^6.6.2", "p-queue": "^6.6.2",
"papaparse": "^5.3.1", "papaparse": "^5.4.0",
"parse-database-url": "^0.3.0", "parse-database-url": "^0.3.0",
"passport": "^0.4.1", "passport": "^0.4.1",
"passport-auth-token": "^1.0.1", "passport-auth-token": "^1.0.1",
@ -159,7 +162,7 @@
"socket.io": "^4.4.1", "socket.io": "^4.4.1",
"sql-query-identifier": "^2.5.0", "sql-query-identifier": "^2.5.0",
"sqlite3": "^5.1.6", "sqlite3": "^5.1.6",
"tedious": "^15.0.0", "tedious": "^16.1.0",
"tinycolor2": "^1.4.2", "tinycolor2": "^1.4.2",
"twilio": "^3.55.1", "twilio": "^3.55.1",
"unique-names-generator": "^4.3.1", "unique-names-generator": "^4.3.1",
@ -169,42 +172,42 @@
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "^9.0.0", "@nestjs/cli": "^10.1.10",
"@nestjs/schematics": "^9.0.0", "@nestjs/schematics": "^10.0.1",
"@nestjs/testing": "^9.0.0", "@nestjs/testing": "^10.1.0",
"@nestjsplus/dyn-schematics": "^1.0.12", "@nestjsplus/dyn-schematics": "^1.0.12",
"@types/bull": "^4.10.0", "@types/ejs": "^3.1.2",
"@types/express": "^4.17.13", "@types/express": "^4.17.17",
"@types/jest": "^29.5.0", "@types/jest": "^29.5.2",
"@types/mocha": "^10.0.1", "@types/mocha": "^10.0.1",
"@types/multer": "^1.4.7", "@types/multer": "^1.4.7",
"@types/node": "18.15.11", "@types/node": "20.3.1",
"@types/passport-google-oauth20": "^2.0.11", "@types/passport-google-oauth20": "^2.0.11",
"@types/passport-jwt": "^3.0.8", "@types/passport-jwt": "^3.0.8",
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.12",
"@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^5.0.0", "@typescript-eslint/parser": "^6.1.0",
"chai": "^4.2.0", "chai": "^4.2.0",
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^7.8.0", "eslint": "^8.33.0",
"eslint-config-prettier": "^6.15.0", "eslint-config-prettier": "^8.8.0",
"eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2", "eslint-plugin-functional": "^5.0.8",
"eslint-plugin-import": "^2.25.2", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.2.1",
"jest": "29.5.0", "jest": "29.5.0",
"mocha": "^10.1.0", "mocha": "^10.1.0",
"nodemon": "^2.0.22", "nodemon": "^3.0.1",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"source-map-support": "^0.5.20", "source-map-support": "^0.5.20",
"supertest": "^6.1.3", "supertest": "^6.3.3",
"ts-jest": "29.0.5", "ts-jest": "29.0.5",
"ts-loader": "^9.2.3", "ts-loader": "^9.2.3",
"ts-node": "^10.0.0", "ts-node": "^10.9.1",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^4.7.4", "typescript": "^5.1.3",
"webpack-cli": "^5.0.1" "webpack-cli": "^5.1.4"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": [

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

@ -150,7 +150,7 @@ const resetPgSakilaProject = async ({
); );
if (response.status !== 200) { if (response.status !== 200) {
console.error('Error creating project', response.data); 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 KnexMigratorv2Tans from '../../sql-migrator/lib/KnexMigratorv2Tans';
import SqlMgrv2 from './SqlMgrv2'; import SqlMgrv2 from './SqlMgrv2';
import type Base from '~/models/Base';
import type { Knex } from 'knex'; import type { Knex } from 'knex';
import type { XKnex } from '../../CustomKnex'; import type { XKnex } from '../../CustomKnex';
import Base from '~/models/Base';
import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2'; import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2';
export default class SqlMgrv2Trans extends SqlMgrv2 { 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 (additionalProps) Object.assign(this, additionalProps);
if (offset && offset >= count) { if (offset && offset >= +count) {
this.errors = [ this.errors = [
{ {
message: 'Offset is beyond the total number of rows', 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, '_') .replace(/\W+/g, '_')
.slice(0, 10)}_${child.table_name .slice(0, 10)}_${child.table_name
.replace(/\W+/g, '_') .replace(/\W+/g, '_')
.slice(0, 10)}_${randomID(15)}`; .slice(0, 10)}_${randomID()}`;
return constraintName; return constraintName;
}; };

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

@ -4,7 +4,7 @@ import bcrypt from 'bcryptjs';
import { validatePassword } from 'nocodb-sdk'; import { validatePassword } from 'nocodb-sdk';
import boxen from 'boxen'; import boxen from 'boxen';
import { T } from 'nc-help'; import { T } from 'nc-help';
import { isEmail } from 'validator'; import isEmail from 'validator/lib/isEmail';
import NocoCache from '~/cache/NocoCache'; import NocoCache from '~/cache/NocoCache';
import Noco from '~/Noco'; import Noco from '~/Noco';
import { ProjectUser, User } from '~/models'; 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'; import type { IEventEmitter } from './event-emitter.interface';
export class NestjsEventEmitter implements IEventEmitter { 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 NcToolGui from 'nc-lib-gui';
import { AppModule } from '~/app.module'; 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); const nestApp = await NestFactory.create(AppModule);
await nestApp.init(); await nestApp.init();

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -179,9 +179,8 @@ export interface AttachmentEvent {
type: 'url' | 'file'; type: 'url' | 'file';
} }
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface FormColumnEvent {} export interface FormColumnEvent {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface GridColumnEvent {} export interface GridColumnEvent {}
export interface MetaDiffEvent { 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 { Injectable } from '@nestjs/common';
import { AppEvents, OrgUserRoles, validatePassword } from 'nocodb-sdk'; import { AppEvents, OrgUserRoles, validatePassword } from 'nocodb-sdk';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { isEmail } from 'validator'; import isEmail from 'validator/lib/isEmail';
import { T } from 'nc-help'; import { T } from 'nc-help';
import * as ejs from 'ejs'; import * as ejs from 'ejs';
import bcrypt from 'bcryptjs'; 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 ncModelsOrderUpgrader from './jobs/ncModelsOrderUpgrader';
import ncParentModelTitleUpgrader from './jobs/ncParentModelTitleUpgrader'; import ncParentModelTitleUpgrader from './jobs/ncParentModelTitleUpgrader';
import ncRemoveDuplicatedRelationRows from './jobs/ncRemoveDuplicatedRelationRows'; import ncRemoveDuplicatedRelationRows from './jobs/ncRemoveDuplicatedRelationRows';
import type { DbConfig, NcConfig } from '~/interface/config'; import NcProjectBuilder from './NcProjectBuilder';
import type { XKnex } from '~/db/CustomKnex'; import type { XKnex } from '~/db/CustomKnex';
import type { BaseModelSql } from '~/db/BaseModelSql'; import type { BaseModelSql } from '~/db/BaseModelSql';
import type { MetaService } from '~/meta/meta.service'; import type { MetaService } from '~/meta/meta.service';
import type Noco from '~/Noco'; import type Noco from '~/Noco';
import type NcProjectBuilder from './NcProjectBuilder';
import type { MysqlClient, PgClient, SqlClient } from 'nc-help'; 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 ModelXcMetaFactory from '~/db/sql-mgr/code/models/xc/ModelXcMetaFactory';
import NcConnectionMgr from '~/utils/common/NcConnectionMgr'; 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 { Router } from 'express';
import { GqlApiBuilder } from './gql/GqlApiBuilder'; import { GqlApiBuilder } from './gql/GqlApiBuilder';
import { RestApiBuilder } from './rest/RestApiBuilder'; import { RestApiBuilder } from './rest/RestApiBuilder';
import type Noco from '~/Noco'; import Noco from '~/Noco';
import type { NcConfig } from '~/interface/config'; import { NcConfig } from '~/interface/config';
import { SqlClientFactory } from '~/db/sql-client/lib/SqlClientFactory'; import { SqlClientFactory } from '~/db/sql-client/lib/SqlClientFactory';
export default class NcProjectBuilder { export default class NcProjectBuilder {

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

@ -1,10 +1,10 @@
import { Router } from 'express'; import { Router } from 'express';
import BaseApiBuilder from '../BaseApiBuilder'; import BaseApiBuilder from '../BaseApiBuilder';
import type NcProjectBuilder from '../NcProjectBuilder'; import NcProjectBuilder from '../NcProjectBuilder';
import type { DbConfig, NcConfig } from '~/interface/config';
import type XcMetaMgr from '~/interface/XcMetaMgr'; import type XcMetaMgr from '~/interface/XcMetaMgr';
import type { MetaService } from '~/meta/meta.service'; import { DbConfig, NcConfig } from '~/interface/config';
import type Noco from '~/Noco'; import { MetaService } from '~/meta/meta.service';
import Noco from '~/Noco';
import GqlXcSchemaFactory from '~/db/sql-mgr/code/gql-schema/xc-ts/GqlXcSchemaFactory'; import GqlXcSchemaFactory from '~/db/sql-mgr/code/gql-schema/xc-ts/GqlXcSchemaFactory';
export class GqlApiBuilder extends BaseApiBuilder<Noco> implements XcMetaMgr { 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 autoBind from 'auto-bind';
import BaseApiBuilder from '../BaseApiBuilder'; import BaseApiBuilder from '../BaseApiBuilder';
import NcProjectBuilder from '../NcProjectBuilder';
import type { Router } from 'express'; import type { Router } from 'express';
import type { DbConfig, NcConfig } from '~/interface/config'; import { DbConfig, NcConfig } from '~/interface/config';
import type NcProjectBuilder from '../NcProjectBuilder'; import { MetaService } from '~/meta/meta.service';
import type { MetaService } from '~/meta/meta.service'; import Noco from '~/Noco';
import type Noco from '~/Noco';
import NcHelp from '~/utils/NcHelp'; import NcHelp from '~/utils/NcHelp';
import ExpressXcTsRoutes from '~/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutes'; import ExpressXcTsRoutes from '~/db/sql-mgr/code/routes/xc-ts/ExpressXcTsRoutes';
import SwaggerXc from '~/db/sql-mgr/code/routers/xc-ts/SwaggerXc'; 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 nodeExternals = require('webpack-node-externals');
const webpack = require('webpack'); const webpack = require('webpack');
const CopyPlugin = require('copy-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin');
//
const TerserPlugin = require('terser-webpack-plugin'); const TerserPlugin = require('terser-webpack-plugin');
const { resolveTsAliases } = require('./build-utils/resolveTsAliases'); const { resolveTsAliases } = require('./build-utils/resolveTsAliases');
@ -25,7 +24,13 @@ module.exports = {
optimization: { optimization: {
minimize: true, //Update this to true or false minimize: true, //Update this to true or false
minimizer: [new TerserPlugin()], minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
},
}),
],
nodeEnv: false, nodeEnv: false,
}, },
externals: [nodeExternals()], externals: [nodeExternals()],

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

@ -24,7 +24,13 @@ module.exports = {
optimization: { optimization: {
minimize: true, //Update this to true or false minimize: true, //Update this to true or false
minimizer: [new TerserPlugin()], minimizer: [
new TerserPlugin({
terserOptions: {
keep_classnames: true,
},
}),
],
nodeEnv: false, nodeEnv: false,
}, },
externals: [ 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 guiPath = path.join(__dirname, '..', 'packages', 'nc-gui');
const nocodbPath = path.join(__dirname, '..', 'packages', 'nocodb'); 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) { if (err) {
console.error(`Error installing dependencies and building nocodb-sdk: ${err}`); console.error(`Error installing dependencies and building nocodb-sdk: ${err}`);
return; 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}`); console.log(`Dependencies installed and nocodb-sdk built: ${stdout}`);
const guiPromise = new Promise((resolve, reject) => { 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) { if (err) {
reject(`Error installing dependencies for nc-gui: ${err}`); reject(`Error installing dependencies for nc-gui: ${err}`);
} else { } else {
@ -23,7 +23,7 @@ exec(`cd ${sdkPath} && npm i && npm run build`, (err, stdout, stderr) => {
}); });
const nocodbPromise = new Promise((resolve, reject) => { 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) { if (err) {
reject(`Error installing dependencies for nocodb: ${err}`); reject(`Error installing dependencies for nocodb: ${err}`);
} else { } else {

14
scripts/pkg-executable/package.json

@ -15,12 +15,12 @@
"node_modules/**/*" "node_modules/**/*"
], ],
"targets": [ "targets": [
"node16-linux-arm64", "node18-linux-arm64",
"node16-macos-arm64", "node18-macos-arm64",
"node16-win-arm64", "node18-win-arm64",
"node16-linux-x64", "node18-linux-x64",
"node16-macos-x64", "node18-macos-x64",
"node16-win-x64" "node18-win-x64"
] ]
}, },
"keywords": [], "keywords": [],
@ -28,6 +28,6 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"express": "^4.17.1", "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 = () => { const bumbVersionAndSave = () => {
// upgrade nc-lib-gui version in nocodb // 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 nocodbPackageFilePath = path.join(__dirname, '..', 'packages', 'nocodb', 'package.json')
const nocoLibPackage = JSON.parse(fs.readFileSync(nocodbPackageFilePath)) const nocoLibPackage = JSON.parse(fs.readFileSync(nocodbPackageFilePath))
if (process.env.targetEnv === 'DEV') { 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 = () => { const bumbVersionAndSave = () => {
try { // upgrade nocodb-sdk version in nocodb & nc-gui
// upgrade nocodb-sdk version in nocodb return Promise.all([
execSync(`cd packages/nocodb && npm install --save --save-exact ${nocodbSdkPackage.name}@${nocodbSdkPackage.version}`, {}); replacePackageVersion(path.join(__dirname, '..', 'packages', 'nocodb', 'package.json')),
// upgrade nocodb-sdk version in nc-gui replacePackageVersion(path.join(__dirname, '..', 'packages', 'nc-gui', 'package.json')),
execSync(`cd packages/nc-gui && npm install --save --save-exact ${nocodbSdkPackage.name}@${nocodbSdkPackage.version}`, {}); replacePackageVersion(path.join(__dirname, '..', 'tests', 'playwright', 'package.json')),
} catch (e) { ])
console.log(e.message);
console.log(e.stdout.toString());
}
} }
const dfs = function(dir) { const dfs = function(dir) {
@ -53,8 +63,10 @@ const searchAndReplace = (target) => {
let list = [ let list = [
...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nc-gui'))), ...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nc-gui'))),
...dfs(path.resolve(path.join(__dirname, '..', 'packages', 'nocodb'))), ...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', '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 Promise.all(list.map(d => {
return new Promise((resolve, reject) => { 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", "name": "playwright",
"version": "1.0.0", "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", "main": "index.js",
"engines": {
"node": ">=18"
},
"scripts": { "scripts": {
"test": "TRACE=true npx playwright test --workers=4", "test": "TRACE=true pnpm exec playwright test --workers=4",
"test:fast": "npx playwright test --workers=6", "test:fast": "pnpm exec playwright test --workers=6",
"test:shard:1": "TRACE=true npx playwright test --workers=4 --shard=1/2", "test:shard:1": "TRACE=true pnpm exec playwright test --workers=4 --shard=1/2",
"test:shard:2": "TRACE=true npx playwright test --workers=4 --shard=2/2", "test:shard:2": "TRACE=true pnpm exec playwright test --workers=4 --shard=2/2",
"test:repeat": "TRACE=true npx playwright test --workers=4 --repeat-each=12", "test:repeat": "TRACE=true pnpm exec playwright test --workers=4 --repeat-each=12",
"test:quick": "TRACE=true PW_QUICK_TEST=1 npx playwright test --workers=4", "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 npx playwright test -c playwright.config.ts --headed --project=chromium --retries 0 --timeout 0 --workers 1 --max-failures=1", "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 npx playwright test --trace on -c playwright.config.ts --headed --project=chromium --retries 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": "npx nodemon -e ts -w ./ -x \"npm run test:debug\"", "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 npx playwright test -c playwright.config.ts --headed --project=chromium --retries 0 --timeout 5 --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 pnpm exec 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": "pnpm exec playwright test --workers=2",
"ci:test:shard:1": "npx playwright test --workers=2 --shard=1/2", "ci:test:shard:1": "pnpm exec playwright test --workers=2 --shard=1/2",
"ci:test:shard:2": "npx playwright test --workers=2 --shard=2/2", "ci:test:shard:2": "pnpm exec playwright test --workers=2 --shard=2/2",
"ci:test:mysql": "E2E_DB_TYPE=mysql npx playwright test --workers=2", "ci:test:mysql": "E2E_DB_TYPE=mysql pnpm exec playwright test --workers=2",
"ci:test:pg": "E2E_DB_TYPE=pg npx 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": { "devDependencies": {
"@playwright/test": "1.32.2", "@playwright/test": "1.36.1",
"@typescript-eslint/eslint-plugin": "^4.0.1", "@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^4.0.1", "@typescript-eslint/parser": "^6.1.0",
"axios": "^0.24.0", "axios": "^0.24.0",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"eslint": "^7.8.0", "eslint": "^8.22.0",
"eslint-config-prettier": "^6.15.0", "eslint-config-prettier": "^6.15.0",
"eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2", "eslint-plugin-functional": "^5.0.8",
"eslint-plugin-import": "^2.22.0", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-json": "^3.1.0", "eslint-plugin-json": "^3.1.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.1", "husky": "^8.0.1",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"mysql2": "^2.3.3", "mysql2": "^3.2.0",
"pg": "^8.8.0", "pg": "^8.8.0",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"promised-sqlite3": "^1.2.0" "promised-sqlite3": "^2.1.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"
} }
} }

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

@ -10,7 +10,11 @@ export class AccountLicensePage extends BasePage {
} }
async goto() { 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() { async waitUntilContentLoads() {

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

@ -10,13 +10,17 @@ export class AccountSettingsPage extends BasePage {
this.accountPage = accountPage; this.accountPage = accountPage;
} }
async goto() { async goto(p: { networkValidation: boolean }) {
// await this.rootPage.goto('/#/account/users/settings', { waitUntil: 'networkidle' }); if (p.networkValidation) {
await this.waitForResponse({ return this.waitForResponse({
uiAction: () => this.rootPage.goto('/#/account/users/settings', { waitUntil: 'networkidle' }), uiAction: async () => await this.rootPage.goto('/#/account/users/settings'),
httpMethodsToMatch: ['GET'], httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: `api/v1/app-settings`, requestUrlPathToMatch: `api/v1/app-settings`,
}); });
} else {
await this.rootPage.goto('/#/account/users/settings');
await this.rootPage.waitForTimeout(500);
}
} }
get() { get() {
@ -28,7 +32,10 @@ export class AccountSettingsPage extends BasePage {
} }
async getInviteOnlyCheckboxValue() { 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) { async checkInviteOnlySignupCheckbox(value: boolean) {

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

@ -15,7 +15,11 @@ export class AccountTokenPage extends BasePage {
} }
async goto() { 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() { get() {

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

@ -17,8 +17,21 @@ export class AccountUsersPage extends BasePage {
this.changePasswordPage = new ChangePasswordPage(this.rootPage); this.changePasswordPage = new ChangePasswordPage(this.rootPage);
} }
async goto() { async goto({ waitForResponse = true }: { waitForResponse?: boolean }) {
await this.rootPage.goto('/#/account/users/list', { waitUntil: 'networkidle' }); 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() { get() {
@ -35,7 +48,7 @@ export class AccountUsersPage extends BasePage {
await this.verifyToast({ message: 'Successfully added user' }); await this.verifyToast({ message: 'Successfully added user' });
// http://localhost:3000/#/signup/a5e7bf3a-cbb0-46bc-87f7-c2ae21796707 // 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) { prefixEmail(email: string) {

58
tests/playwright/pages/Base.ts

@ -23,54 +23,32 @@ export default abstract class BasePage {
requestUrlPathToMatch, requestUrlPathToMatch,
// A function that takes the response body and returns true if the response is the one we are looking for // A function that takes the response body and returns true if the response is the one we are looking for
responseJsonMatcher, responseJsonMatcher,
debug = false,
debugKey,
}: { }: {
uiAction: () => Promise<any>; uiAction: () => Promise<any>;
requestUrlPathToMatch: string; requestUrlPathToMatch: string;
httpMethodsToMatch?: string[]; httpMethodsToMatch?: string[];
responseJsonMatcher?: ResponseSelector; responseJsonMatcher?: ResponseSelector;
debug?: boolean;
debugKey?: string;
}) { }) {
const waitForResponsePromise = this.rootPage.waitForResponse(async res => { const [res] = await Promise.all([
let isResJsonMatched = true; this.rootPage.waitForResponse(
if (responseJsonMatcher) { res =>
try { res.url().includes(requestUrlPathToMatch) &&
isResJsonMatched = responseJsonMatcher(await res.json()); res.status() === 200 &&
} catch (e) { httpMethodsToMatch.includes(res.request().method())
return false; ),
} uiAction(),
} ]);
if (debug) { // handle JSON matcher if provided
console.log(`${debugKey},waitForResponse`, { let isResJsonMatched = true;
resUrl: res.request().url(), if (responseJsonMatcher) {
resMethod: res.request().method(), try {
}); isResJsonMatched = responseJsonMatcher(res.json());
console.log(`${debugKey},result`, { } catch {
resUrlResult: res.request().url().includes(requestUrlPathToMatch), isResJsonMatched = false;
resMethodResult: httpMethodsToMatch.includes(res.request().method()),
resJsonResult: isResJsonMatched,
});
} }
}
const found = return isResJsonMatched;
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()]);
} }
async attachFile({ filePickUIAction, filePath }: { filePickUIAction: Promise<any>; filePath: string[] }) { 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({ 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', requestUrlPathToMatch: 'api/v1/db/meta/views',
httpMethodsToMatch: ['PATCH'], httpMethodsToMatch: ['PATCH'],
}); });
@ -346,7 +346,7 @@ export class ColumnPageObject extends BasePage {
async save({ isUpdated }: { isUpdated?: boolean } = {}) { async save({ isUpdated }: { isUpdated?: boolean } = {}) {
await this.waitForResponse({ 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/', requestUrlPathToMatch: 'api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'], httpMethodsToMatch: ['GET'],
responseJsonMatcher: json => json['pageInfo'], responseJsonMatcher: json => json['pageInfo'],

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

@ -94,6 +94,7 @@ export class GridPage extends BasePage {
index, index,
columnHeader, columnHeader,
}); });
await this.rootPage.waitForTimeout(500);
await cell.locator('input').fill(value); 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() { async save() {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: '/visibility-rules', requestUrlPathToMatch: '/visibility-rules',
}); });

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

@ -250,7 +250,7 @@ export class TreeViewPage extends BasePage {
} }
await this.waitForResponse({ await this.waitForResponse({
uiAction: () => this.rootPage.getByRole('button', { name: 'Confirm' }).click(), uiAction: async () => await this.rootPage.getByRole('button', { name: 'Confirm' }).click(),
httpMethodsToMatch: ['POST'], httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: `/api/v1/db/meta/duplicate/`, 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() { async save() {
const saveAction = () => this.saveButton.click(); const saveAction = async () => await this.saveButton.click();
await this.waitForResponse({ await this.waitForResponse({
uiAction: saveAction, uiAction: saveAction,
@ -148,8 +148,10 @@ export class WebhookFormPage extends BasePage {
async configureHeader({ key, value }: { key: string; value: string }) { async configureHeader({ key, value }: { key: string; value: string }) {
// hardcode "Content-type: application/json" // hardcode "Content-type: application/json"
await this.get().locator(`.ant-tabs-tab-btn:has-text("Headers")`).click(); 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.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 // kludge, as the dropdown is not visible even after scroll into view
await this.rootPage.locator('.ant-select-dropdown:visible').hover(); 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(); return await this.get({ index, columnHeader }).locator('.nc-cell').click();
} }
async isChecked({ index, columnHeader }: { index?: number; columnHeader: string }) { // async isChecked({ index, columnHeader }: { index?: number; columnHeader: string }) {
return await this.get({ index, columnHeader }).locator('.nc-cell-hover-show').isVisible(); // return await this.get({ index, columnHeader }).locator('.nc-cell-hover-show').isVisible();
} // }
async verifyChecked({ index, columnHeader }: { index?: number; columnHeader: string }) { async verifyChecked({ index, columnHeader }: { index?: number; columnHeader: string }) {
await expect(this.get({ index, columnHeader }).locator('.nc-cell-hover-show')).not.toBeVisible(); 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 }) { async select({ index, columnHeader, rating }: { index?: number; columnHeader: string; rating: number }) {
await this.get({ index, columnHeader }).scrollIntoViewIfNeeded(); await this.get({ index, columnHeader }).scrollIntoViewIfNeeded();
await this.waitForResponse({ 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'], httpMethodsToMatch: ['POST', 'PATCH'],
requestUrlPathToMatch: 'api/v1/db/data/noco/', 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 } = {}) { async toggleShowSystemFields({ isLocallySaved }: { isLocallySaved?: boolean } = {}) {
await this.toolbar.clickFields(); await this.toolbar.clickFields();
await this.waitForResponse({ 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/', requestUrlPathToMatch: isLocallySaved ? '/api/v1/db/public/' : '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'], 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); await this.rootPage.waitForTimeout(350);
} else { } else {
await this.waitForResponse({ await this.waitForResponse({
uiAction: () => uiAction: async () =>
this.rootPage await this.rootPage
.locator('div.ant-select-dropdown.nc-dropdown-toolbar-field-list') .locator('div.ant-select-dropdown.nc-dropdown-toolbar-field-list')
.locator(`div[label="${title}"]:visible`) .locator(`div[label="${title}"]:visible`)
.click(), .click(),
@ -171,8 +171,8 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350); await this.rootPage.waitForTimeout(350);
} else { } else {
await this.waitForResponse({ await this.waitForResponse({
uiAction: () => uiAction: async () =>
this.rootPage await this.rootPage
.locator('.nc-dropdown-filter-comp-op') .locator('.nc-dropdown-filter-comp-op')
.locator(`.ant-select-item:has-text("${operation}")`) .locator(`.ant-select-item:has-text("${operation}")`)
.first() .first()
@ -199,8 +199,8 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350); await this.rootPage.waitForTimeout(350);
} else { } else {
await this.waitForResponse({ await this.waitForResponse({
uiAction: () => uiAction: async () =>
this.rootPage await this.rootPage
.locator('.nc-dropdown-filter-comp-sub-op') .locator('.nc-dropdown-filter-comp-sub-op')
.locator(`.ant-select-item:has-text("${subOperation}")`) .locator(`.ant-select-item:has-text("${subOperation}")`)
.first() .first()
@ -246,7 +246,8 @@ export class ToolbarFilterPage extends BasePage {
await this.rootPage.waitForTimeout(350); await this.rootPage.waitForTimeout(350);
} else { } else {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: locallySaved ? `/api/v1/db/public/` : `/api/v1/db/data/noco/`, 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); await this.rootPage.waitForTimeout(350);
} else { } else {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['GET'],
requestUrlPathToMatch: locallySaved ? `/api/v1/db/public/` : `/api/v1/db/data/noco/`, requestUrlPathToMatch: locallySaved ? `/api/v1/db/public/` : `/api/v1/db/data/noco/`,
}); });
@ -348,7 +349,7 @@ export class ToolbarFilterPage extends BasePage {
await this.toolbar.clickFilter(); await this.toolbar.clickFilter();
if (networkValidation) { if (networkValidation) {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['DELETE'],
requestUrlPathToMatch: '/api/v1/db/meta/filters/', requestUrlPathToMatch: '/api/v1/db/meta/filters/',
}); });
@ -361,7 +362,7 @@ export class ToolbarFilterPage extends BasePage {
async remove({ networkValidation = true }: { networkValidation?: boolean } = {}) { async remove({ networkValidation = true }: { networkValidation?: boolean } = {}) {
if (networkValidation) { if (networkValidation) {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['DELETE'],
requestUrlPathToMatch: '/api/v1/db/meta/filters/', 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() { async openDetailedTab() {
await this.btn_details.click(); await this.btn_details.click();
await this.rootPage.waitForTimeout(500);
} }
async openDataTab() { async openDataTab() {

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

@ -61,7 +61,10 @@ export class DashboardPage extends BasePage {
this.project = project; this.project = project;
this.tablesSideBar = rootPage.locator('.nc-treeview-container'); this.tablesSideBar = rootPage.locator('.nc-treeview-container');
this.workspaceMenuLink = rootPage.getByTestId('nc-project-menu'); 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.tabBar = rootPage.locator('.nc-tab-bar');
this.treeView = new TreeViewPage(this, project); this.treeView = new TreeViewPage(this, project);
this.grid = new GridPage(this); 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}`; return `nc_test_${parallelId}_${email}`;
} }
goto() { async goto() {
return this.rootPage.goto('/#/signin'); return this.rootPage.goto('/#/signin');
} }

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

@ -136,34 +136,33 @@ export class ProjectsPage extends BasePage {
let project: any; 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`, { .locator(`.ant-table-cell`, {
hasText: title, hasText: title,
}) })
.click(); .click();
await Promise.all([ await 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;
}),
openProjectUiAction,
]);
const dashboard = new DashboardPage(this.rootPage, project); 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() { async submit() {
await this.waitForResponse({ 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'], httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: '/rows', requestUrlPathToMatch: '/rows',
}); });

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

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

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

Loading…
Cancel
Save