diff --git a/.github/workflows/bats-test.yml b/.github/workflows/bats-test.yml index 1c965c22a6..b0db34f0f7 100644 --- a/.github/workflows/bats-test.yml +++ b/.github/workflows/bats-test.yml @@ -4,6 +4,7 @@ on: push: paths: - 'docker-compose/1_Auto_Upstall/noco.sh' + - '.github/workflows/bats-test.yml' workflow_dispatch: jobs: @@ -18,7 +19,7 @@ jobs: - name: Prepare matrix for test files id: set-matrix run: | - BATS_FILES=$(find docker-compose/setup-script/tests -name '*.bats') + BATS_FILES=$(find docker-compose/1_Auto_Upstall/tests -name '*.bats') MATRIX_JSON=$(echo $BATS_FILES | tr -d '\n' | jq -Rsc 'split(" ")' | tr '"' "'") echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT test: @@ -39,7 +40,7 @@ jobs: - name: Get working directory run: | - WORKING_DIR="$(pwd)/docker-compose/setup-script/tests" + WORKING_DIR="$(pwd)/docker-compose/1_Auto_Upstall/tests" echo "WORKING_DIR=$WORKING_DIR" >> $GITHUB_ENV - name: Run BATS test diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 54137c4fa6..0e5ad521cd 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -4,217 +4,217 @@ name: "CI/CD" on: - push: - branches: [develop] - paths: - - "packages/nc-gui/**" - - "packages/nocodb/**" - - ".github/workflows/ci-cd.yml" - - "tests/playwright/**" - pull_request: - types: [opened, reopened, synchronize, ready_for_review, labeled] - branches: [develop] - paths: - - "packages/nc-gui/**" - - "packages/nocodb/**" - - ".github/workflows/ci-cd.yml" - - ".github/workflows/playwright-test-workflow.yml" - - "tests/playwright/**" + push: + branches: [develop] + paths: + - "packages/nc-gui/**" + - "packages/nocodb/**" + - ".github/workflows/ci-cd.yml" + - "tests/playwright/**" + pull_request: + types: [opened, reopened, synchronize, ready_for_review, labeled] + branches: [develop] + paths: + - "packages/nc-gui/**" + - "packages/nocodb/**" + - ".github/workflows/ci-cd.yml" + - ".github/workflows/playwright-test-workflow.yml" + - "tests/playwright/**" # Triggered manually - workflow_dispatch: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: - validate-swagger-json: - runs-on: ubuntu-20.04 - timeout-minutes: 10 - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 1 + validate-swagger-json: + runs-on: ubuntu-20.04 + timeout-minutes: 10 + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 1 -# enable after fixing all validation errors -# - name: Validate OpenAPI definition -# uses: char0n/swagger-editor-validate@v1 -# with: -# swagger-editor-url: http://localhost/ -# definition-file: packages/nocodb/src/schema/swagger.json + # enable after fixing all validation errors + # - name: Validate OpenAPI definition + # uses: char0n/swagger-editor-validate@v1 + # with: + # swagger-editor-url: http://localhost/ + # definition-file: packages/nocodb/src/schema/swagger.json - - name: Validate Swagger JSON - run: | - if ! jq empty packages/nocodb/src/schema/swagger.json; then - echo "swagger.json file is not valid JSON" - exit 1 - fi - if ! jq empty packages/nocodb/src/schema/swagger-v2.json; then - echo "swaggerv2.json file is not valid JSON" - exit 1 - fi - unit-tests: - runs-on: ubuntu-20.04 - timeout-minutes: 40 - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - steps: - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 8 - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.19.1 - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: remove use-node-version from .npmrc - run: sed -i '/^use-node-version/d' .npmrc - - name: Get pnpm store directory - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - name: Install dependencies for packages - run: pnpm bootstrap - - name: run unit tests - working-directory: ./packages/nocodb - run: pnpm run test:unit - unit-tests-pg: - runs-on: ubuntu-20.04 - timeout-minutes: 40 - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - steps: - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 8 - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.19.1 - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: remove use-node-version from .npmrc - run: sed -i '/^use-node-version/d' .npmrc - - name: Get pnpm store directory - shell: bash - run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 - name: Setup pnpm cache - with: - path: ${{ env.STORE_PATH }} - key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} - restore-keys: | - ${{ runner.os }}-pnpm-store- - - name: Set CI env - run: export CI=true - - name: setup pg - working-directory: ./ - run: docker-compose -f ./tests/playwright/scripts/docker-compose-playwright-pg.yml up -d & - - name: install dependencies - run: pnpm bootstrap - - name: run unit tests - working-directory: ./packages/nocodb - run: pnpm run test:unit:pg + - name: Validate Swagger JSON + run: | + if ! jq empty packages/nocodb/src/schema/swagger.json; then + echo "swagger.json file is not valid JSON" + exit 1 + fi + if ! jq empty packages/nocodb/src/schema/swagger-v2.json; then + echo "swaggerv2.json file is not valid JSON" + exit 1 + fi + unit-tests: + runs-on: ubuntu-20.04 + timeout-minutes: 40 + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + steps: + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.19.1 + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Install dependencies for packages + run: pnpm bootstrap + - name: run unit tests + working-directory: ./packages/nocodb + run: pnpm run test:unit + unit-tests-pg: + runs-on: ubuntu-20.04 + timeout-minutes: 40 + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + steps: + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.19.1 + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + - name: Set CI env + run: export CI=true + - name: setup pg + working-directory: ./ + run: docker-compose -f ./tests/playwright/scripts/docker-compose-playwright-pg.yml up -d & + - name: install dependencies + run: pnpm bootstrap + - name: run unit tests + working-directory: ./packages/nocodb + run: pnpm run test:unit:pg - pre-build-for-playwright: - uses: ./.github/workflows/pre-build-for-playwright.yml + pre-build-for-playwright: + uses: ./.github/workflows/pre-build-for-playwright.yml - playwright-mysql-1: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: mysql - shard: 1 - playwright-mysql-2: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: mysql - shard: 2 - playwright-mysql-3: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: mysql - shard: 3 - playwright-mysql-4: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: mysql - shard: 4 - playwright-sqlite-1: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: sqlite - shard: 1 - playwright-sqlite-2: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: sqlite - shard: 2 - playwright-sqlite-3: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: sqlite - shard: 3 - playwright-sqlite-4: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: sqlite - shard: 4 - playwright-pg-shard-1: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: pg - shard: 1 - playwright-pg-shard-2: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: pg - shard: 2 - playwright-pg-shard-3: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: pg - shard: 3 - playwright-pg-shard-4: - needs: pre-build-for-playwright - if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} - uses: ./.github/workflows/playwright-test-workflow.yml - with: - db: pg - shard: 4 + playwright-mysql-1: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: mysql + shard: 1 + playwright-mysql-2: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: mysql + shard: 2 + playwright-mysql-3: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: mysql + shard: 3 + playwright-mysql-4: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: mysql + shard: 4 + playwright-sqlite-1: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: sqlite + shard: 1 + playwright-sqlite-2: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: sqlite + shard: 2 + playwright-sqlite-3: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: sqlite + shard: 3 + playwright-sqlite-4: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: sqlite + shard: 4 + playwright-pg-shard-1: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: pg + shard: 1 + playwright-pg-shard-2: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: pg + shard: 2 + playwright-pg-shard-3: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: pg + shard: 3 + playwright-pg-shard-4: + needs: pre-build-for-playwright + if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }} + uses: ./.github/workflows/playwright-test-workflow.yml + with: + db: pg + shard: 4 diff --git a/.github/workflows/jest-unit-test.yml b/.github/workflows/jest-unit-test.yml index 25e19f7431..7db2fb4826 100644 --- a/.github/workflows/jest-unit-test.yml +++ b/.github/workflows/jest-unit-test.yml @@ -31,7 +31,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Get pnpm store directory shell: bash timeout-minutes: 1 diff --git a/.github/workflows/playwright-test-workflow.yml b/.github/workflows/playwright-test-workflow.yml index b5f5819d11..20c34d2cf4 100644 --- a/.github/workflows/playwright-test-workflow.yml +++ b/.github/workflows/playwright-test-workflow.yml @@ -4,7 +4,7 @@ on: workflow_call: inputs: shard: - description: 'Shard number' + description: "Shard number" required: true type: string db: @@ -18,8 +18,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 - - name: remove use-node-version from .npmrc - run: sed -i '/^use-node-version/d' .npmrc + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: Setup Node uses: actions/setup-node@v3 with: @@ -27,11 +27,11 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Get pnpm store directory shell: bash run: | - echo "STORE_PATH=/root/setup-pnpm/node_modules/.bin/store/v3" >> $GITHUB_ENV + echo "STORE_PATH=/root/setup-pnpm/node_modules/.bin/store/v3" >> $GITHUB_ENV - uses: actions/cache@v3 name: Setup pnpm cache with: @@ -42,7 +42,7 @@ jobs: - name: setup pg if: ${{ inputs.db == 'pg' || ( inputs.db == 'sqlite' && inputs.shard == '1' ) }} working-directory: ./ - run: | + run: | service postgresql start cd /var/lib/postgresql/ && sudo -u postgres psql -c "SELECT 'dropdb '||datname||'' FROM pg_database WHERE datistemplate = false AND datallowconn = true And datname NOT IN ('postgres')" |grep ' dropdb ' | sudo -u postgres /bin/bash ; cd sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'password';" @@ -113,7 +113,7 @@ jobs: # exit 1 # fi - name: start frontend - working-directory: ./packages/nc-gui/ + working-directory: ./packages/nc-gui/ run: | pnpm run ci:start - name: Install Playwright Browsers @@ -144,32 +144,32 @@ jobs: working-directory: ./tests/playwright run: E2E_DB_TYPE=${{ inputs.db }} node ./scripts/stressTestNewlyAddedTest.js -# # Quick tests (pg on sqlite shard 0 and sqlite on sqlite shard 1) -# - name: Run quick server and tests (pg) -# if: ${{ inputs.db == 'sqlite' && inputs.shard == '1' }} -# working-directory: ./packages/nocodb -# run: | -# kill -9 $(lsof -t -i:8080) -# npm run watch:run:playwright:pg:cyquick > quick_${{ inputs.shard }}_test_backend.log & -# - name: Run quick server and tests (sqlite) -# if: ${{ inputs.db == 'sqlite' && inputs.shard == '2' }} -# working-directory: ./packages/nocodb -# run: | -# kill -9 $(lsof -t -i:8080) -# npm run watch:run:playwright:quick > quick_${{ inputs.shard }}_test_backend.log & -# - name: Wait for backend for sqlite-tests -# if: ${{ inputs.db == 'sqlite' }} -# working-directory: ./tests/playwright -# run: | -# while ! curl --output /dev/null --silent --head --fail http://localhost:8080; do -# printf '.' -# sleep 2 -# done -# timeout-minutes: 1 -# - name: Run quick tests -# if: ${{ inputs.db == 'sqlite' }} -# working-directory: ./tests/playwright -# run: PLAYWRIGHT_HTML_REPORT=playwright-report-quick npm run test:quick + # # Quick tests (pg on sqlite shard 0 and sqlite on sqlite shard 1) + # - name: Run quick server and tests (pg) + # if: ${{ inputs.db == 'sqlite' && inputs.shard == '1' }} + # working-directory: ./packages/nocodb + # run: | + # kill -9 $(lsof -t -i:8080) + # npm run watch:run:playwright:pg:cyquick > quick_${{ inputs.shard }}_test_backend.log & + # - name: Run quick server and tests (sqlite) + # if: ${{ inputs.db == 'sqlite' && inputs.shard == '2' }} + # working-directory: ./packages/nocodb + # run: | + # kill -9 $(lsof -t -i:8080) + # npm run watch:run:playwright:quick > quick_${{ inputs.shard }}_test_backend.log & + # - name: Wait for backend for sqlite-tests + # if: ${{ inputs.db == 'sqlite' }} + # working-directory: ./tests/playwright + # run: | + # while ! curl --output /dev/null --silent --head --fail http://localhost:8080; do + # printf '.' + # sleep 2 + # done + # timeout-minutes: 1 + # - name: Run quick tests + # if: ${{ inputs.db == 'sqlite' }} + # working-directory: ./tests/playwright + # run: PLAYWRIGHT_HTML_REPORT=playwright-report-quick npm run test:quick - uses: actions/upload-artifact@v3 if: ${{ inputs.db == 'sqlite' }} @@ -223,4 +223,4 @@ jobs: # end: artifacts copy SUMMARY='[Artifacts]('${REPORTS_HOST:-http://135.181.48.96}/${path}') [playwright-report]('${REPORTS_HOST:-http://135.181.48.96}/${path}'/playwright-report)' - echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY \ No newline at end of file + echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/pre-build-for-playwright.yml b/.github/workflows/pre-build-for-playwright.yml index bf7e687951..771abaad18 100644 --- a/.github/workflows/pre-build-for-playwright.yml +++ b/.github/workflows/pre-build-for-playwright.yml @@ -2,7 +2,7 @@ name: pre-build-for-playwright on: workflow_call: - + jobs: playwright: runs-on: [self-hosted, v3] @@ -17,13 +17,13 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 - - name: remove use-node-version from .npmrc - run: sed -i '/^use-node-version/d' .npmrc + version: 9 + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: Get pnpm store directory shell: bash run: | - echo "STORE_PATH=/root/setup-pnpm/node_modules/.bin/store/v3" >> $GITHUB_ENV + echo "STORE_PATH=/root/setup-pnpm/node_modules/.bin/store/v3" >> $GITHUB_ENV - uses: actions/cache@v3 name: Setup pnpm cache with: @@ -47,4 +47,3 @@ jobs: zip -r ${FILE} .output || echo "UI build directory does not exists" >&2 echo "uploading ${FILE} to http://65.21.27.147/upload/${FILE}" time curl -T "${FILE}" http://65.21.27.147/upload/${FILE} -n - diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml index d6c991052f..220363223c 100644 --- a/.github/workflows/release-docker.yml +++ b/.github/workflows/release-docker.yml @@ -48,7 +48,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Get Docker Repository id: get-docker-repository run: | @@ -135,6 +135,8 @@ jobs: cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache-new push: true + labels: | + "service=nocodb" tags: | nocodb/${{ steps.get-docker-repository.outputs.DOCKER_REPOSITORY }}:${{ steps.get-docker-repository.outputs.DOCKER_BUILD_TAG }} nocodb/${{ steps.get-docker-repository.outputs.DOCKER_REPOSITORY }}:${{ steps.get-docker-repository.outputs.DOCKER_BUILD_LATEST_TAG }} diff --git a/.github/workflows/release-nightly-dev.yml b/.github/workflows/release-nightly-dev.yml index e4a66f71ce..42b601bef5 100644 --- a/.github/workflows/release-nightly-dev.yml +++ b/.github/workflows/release-nightly-dev.yml @@ -43,29 +43,20 @@ jobs: nightly_build_tag: ${{ steps.tag-step.outputs.NIGHTLY_BUILD_TAG }} is_daily: ${{ steps.tag-step.outputs.IS_DAILY }} current_version: ${{ steps.tag-step.outputs.CURRENT_VERSION }} - # Build frontend and backend and publish to npm - release-npm: - needs: set-tag - uses: ./.github/workflows/release-npm.yml - with: - tag: ${{ needs.set-tag.outputs.nightly_build_tag }} - targetEnv: 'DEV' - secrets: - NPM_TOKEN: "${{ secrets.NPM_TOKEN }}" # Build executables and publish to GitHub - release-executables: - needs: [set-tag, release-npm] - uses: ./.github/workflows/release-timely-executables.yml - with: - tag: ${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.nightly_build_tag }} - secrets: - NC_GITHUB_TOKEN: "${{ secrets.NC_GITHUB_TOKEN }}" +# release-executables: +# needs: [set-tag, release-npm] +# uses: ./.github/workflows/release-timely-executables.yml +# with: +# tag: ${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.nightly_build_tag }} +# secrets: +# NC_GITHUB_TOKEN: "${{ secrets.NC_GITHUB_TOKEN }}" # Build docker image and push to docker hub release-docker: - needs: [set-tag, release-npm] - uses: ./.github/workflows/release-docker.yml + needs: [set-tag] + uses: ./.github/workflows/release-timely-docker.yml with: currentVersion: ${{ needs.set-tag.outputs.current_version }} tag: ${{ needs.set-tag.outputs.nightly_build_tag }} diff --git a/.github/workflows/release-npm.yml b/.github/workflows/release-npm.yml index b5672974b0..a40116d9e4 100644 --- a/.github/workflows/release-npm.yml +++ b/.github/workflows/release-npm.yml @@ -40,7 +40,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Checkout uses: actions/checkout@v3 with: @@ -51,7 +51,7 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18.19.1 - registry-url: 'https://registry.npmjs.org' + registry-url: "https://registry.npmjs.org" - run: | export NODE_OPTIONS="--max_old_space_size=16384" NOCODB_SDK_PKG_NAME=nocodb-sdk @@ -79,10 +79,10 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: signoff: true - branch: 'release/${{ github.event.inputs.tag || inputs.tag }}' + branch: "release/${{ github.event.inputs.tag || inputs.tag }}" delete-branch: true - title: 'Release ${{ github.event.inputs.tag || inputs.tag }}' - labels: 'Bot: Automerge' + title: "Release ${{ github.event.inputs.tag || inputs.tag }}" + labels: "Bot: Automerge" - name: Check outputs if: ${{ github.event.inputs.targetEnv == 'PROD' || inputs.targetEnv == 'PROD' }} run: | diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 37706c21a0..973574ce5d 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -50,22 +50,11 @@ jobs: target_tag: ${{ steps.tag-step.outputs.TARGET_TAG }} current_version: ${{ steps.tag-step.outputs.CURRENT_VERSION }} - # Build, install, publish frontend and backend to npm - release-npm: - 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' }} - needs: [set-tag] - uses: ./.github/workflows/release-npm.yml - with: - tag: ${{ needs.set-tag.outputs.target_tag }} - targetEnv: 'DEV' - secrets: - NPM_TOKEN: "${{ secrets.NPM_TOKEN }}" - # Build docker image and push to docker hub release-docker: 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' }} - needs: [release-npm, set-tag] - uses: ./.github/workflows/release-docker.yml + needs: [set-tag] + uses: ./.github/workflows/release-timely-docker.yml with: currentVersion: ${{ needs.set-tag.outputs.current_version }} tag: ${{ needs.set-tag.outputs.target_tag }} diff --git a/.github/workflows/release-secret-cli.yml b/.github/workflows/release-secret-cli.yml index 47f89b708c..1ea1263b10 100644 --- a/.github/workflows/release-secret-cli.yml +++ b/.github/workflows/release-secret-cli.yml @@ -19,13 +19,13 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Setup Node 18.19.1 # Setup .npmrc file to publish to npm uses: actions/setup-node@v3 with: node-version: 18.19.1 - registry-url: 'https://registry.npmjs.org' + registry-url: "https://registry.npmjs.org" - name: Cache pkg modules id: cache-pkg @@ -68,10 +68,10 @@ jobs: with: node-version: 16 - - name : Install nocodb, other dependencies and build executables + - name: Install nocodb, other dependencies and build executables run: | cd ./packages/nc-secret-mgr - + # install npm dependendencies pnpm i @@ -117,7 +117,6 @@ jobs: runs-on: macos-latest needs: build-and-publish steps: - - uses: actions/download-artifact@master with: name: ${{ github.event.inputs.tag || inputs.tag }} @@ -134,9 +133,8 @@ jobs: path: packages/nc-secret-mgr/mac-dist retention-days: 1 - publish-mac-executables: - needs: [sign-mac-executables,build-and-publish] + needs: [sign-mac-executables, build-and-publish] runs-on: ubuntu-latest steps: - uses: actions/download-artifact@master @@ -153,4 +151,3 @@ jobs: overwrite: true file_glob: true repo_name: nocodb/nc-secret-mgr - diff --git a/.github/workflows/release-timely-docker.yml b/.github/workflows/release-timely-docker.yml new file mode 100644 index 0000000000..db7ec228ef --- /dev/null +++ b/.github/workflows/release-timely-docker.yml @@ -0,0 +1,161 @@ +name: "Release : Docker" + +on: + # Triggered manually + workflow_dispatch: + inputs: + tag: + description: "Docker image tag" + required: true + targetEnv: + description: "Target Environment" + required: true + type: choice + options: + - DEV + - PROD + # Triggered by release-nocodb.yml / release-nightly-dev.yml / release-pr.yml + workflow_call: + inputs: + tag: + description: "Docker image tag" + required: true + type: string + targetEnv: + description: "Target Environment" + required: true + type: string + isDaily: + description: "Is it triggered by daily schedule" + required: false + type: string + currentVersion: + description: "The current NocoDB version" + required: false + type: string + secrets: + DOCKERHUB_USERNAME: + required: true + DOCKERHUB_TOKEN: + required: true + +jobs: + buildx: + runs-on: ubuntu-latest + env: + working-directory: ./packages/nocodb + steps: + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + - name: Get Docker Repository + id: get-docker-repository + run: | + DOCKER_REPOSITORY=nocodb-daily + DOCKER_BUILD_TAG=${{ github.event.inputs.tag || inputs.tag }} + DOCKER_BUILD_LATEST_TAG=latest + if [[ "$DOCKER_BUILD_TAG" =~ "-beta." ]]; then + DOCKER_BUILD_LATEST_TAG=$(echo $DOCKER_BUILD_TAG | awk -F '-beta.' '{print $1}')-beta.latest + fi + if [[ ${{ github.event.inputs.targetEnv || inputs.targetEnv }} == 'DEV' ]]; then + if [[ ${{ github.event.inputs.currentVersion || inputs.currentVersion || 'N/A' }} != 'N/A' ]]; then + DOCKER_BUILD_TAG=${{ github.event.inputs.currentVersion || inputs.currentVersion }}-${{ github.event.inputs.tag || inputs.tag }} + fi + if [[ ${{ inputs.isDaily || 'N' }} == 'Y' ]]; then + DOCKER_REPOSITORY=nocodb-daily + else + DOCKER_REPOSITORY=nocodb-timely + fi + fi + echo "DOCKER_REPOSITORY=${DOCKER_REPOSITORY}" >> $GITHUB_OUTPUT + echo "DOCKER_BUILD_TAG=${DOCKER_BUILD_TAG}" >> $GITHUB_OUTPUT + echo "DOCKER_BUILD_LATEST_TAG=${DOCKER_BUILD_LATEST_TAG}" >> $GITHUB_OUTPUT + echo DOCKER_REPOSITORY: ${DOCKER_REPOSITORY} + echo DOCKER_BUILD_TAG: ${DOCKER_BUILD_TAG} + echo DOCKER_BUILD_LATEST_TAG: ${DOCKER_BUILD_LATEST_TAG} + + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 1 + ref: ${{ github.ref }} + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: 18.19.1 + + - name: install dependencies + run: pnpm bootstrap + + - name: Build gui and sdk + run: | + + pnpm bootstrap && + cd packages/nc-gui && + pnpm run generate + + # copy build to nocodb + rsync -rvzh ./dist/ ../nocodb/docker/nc-gui/ + + + - name: build nocodb + run: | + # build nocodb ( pack nocodb-sdk and nc-gui ) + cd packages/nocodb && + EE=true pnpm exec webpack --config webpack.timely.config.js && + # remove bundled libraries (nocodb-sdk, knex-snowflake) + pnpm uninstall --save-prod nocodb-sdk + + - name: Update version in package.json + run: | + # update package.json + cd packages/nocodb && + jq --arg VERSION "$VERSION" '.version = $VERSION' package.json > tmp.json && + mv tmp.json package.json + env: + VERSION: ${{ steps.get-docker-repository.outputs.DOCKER_BUILD_TAG }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2.1.0 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2.2.1 + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Login to DockerHub + uses: docker/login-action@v2.1.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v3.2.0 + with: + context: ${{ env.working-directory }} + file: ${{ env.working-directory }}/Dockerfile.timely + build-args: NC_VERSION=${{ steps.get-docker-repository.outputs.DOCKER_BUILD_TAG }} + platforms: linux/amd64,linux/arm64 + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new + push: true + tags: | + nocodb/${{ steps.get-docker-repository.outputs.DOCKER_REPOSITORY }}:${{ steps.get-docker-repository.outputs.DOCKER_BUILD_TAG }} + nocodb/${{ steps.get-docker-repository.outputs.DOCKER_REPOSITORY }}:${{ steps.get-docker-repository.outputs.DOCKER_BUILD_LATEST_TAG }} + + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache diff --git a/.github/workflows/sync-to-develop.yml b/.github/workflows/sync-to-develop.yml index 33722572ea..e956fcd2b2 100644 --- a/.github/workflows/sync-to-develop.yml +++ b/.github/workflows/sync-to-develop.yml @@ -1,4 +1,4 @@ -name: 'Sync changes back to develop branch from master' +name: "Sync changes back to develop branch from master" on: # Triggered manually @@ -16,7 +16,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Checkout uses: actions/checkout@v3 with: diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index ef7326cf25..9eb0214ad5 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -5,17 +5,16 @@ name: Backend Unit Tests on: push: - branches: [ "develop" ] + branches: ["develop"] paths: - "packages/nocodb/**" pull_request: - branches: [ "develop" ] + branches: ["develop"] paths: - "packages/nocodb/**" jobs: unit-tests: - runs-on: ubuntu-latest strategy: @@ -27,17 +26,17 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - cache: 'pnpm' - - name: remove use-node-version from .npmrc - run: sed -i '/^use-node-version/d' .npmrc + cache: "pnpm" + - name: remove use-node-version from .npmrc + run: sed -i '/^use-node-version/d' .npmrc - name: install dependencies run: pnpm bootstrap - name: run unit tests working-directory: ./packages/nocodb - run: pnpm run unit-test \ No newline at end of file + run: pnpm run unit-test diff --git a/.github/workflows/update-sdk-path.yml b/.github/workflows/update-sdk-path.yml index 2f8d9725a2..3b31b10bf0 100644 --- a/.github/workflows/update-sdk-path.yml +++ b/.github/workflows/update-sdk-path.yml @@ -12,15 +12,15 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 8 + version: 9 - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 18.19.1 + node-version: 18.19.1 - name: Checkout uses: actions/checkout@v3 with: - fetch-depth: 0 + fetch-depth: 0 - run: | sed -i '/^use-node-version/d' .npmrc pnpm bootstrap @@ -32,10 +32,10 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: signoff: true - branch: 'bot/update-nocodb-sdk-path' + branch: "bot/update-nocodb-sdk-path" delete-branch: true - title: 'Update nocodb-sdk to local path' - labels: 'Bot: Automerge' + title: "Update nocodb-sdk to local path" + labels: "Bot: Automerge" - name: Check outputs run: | echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}" diff --git a/README.md b/README.md index b761a71fa4..339277cbba 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,10 @@ Auto-upstall does the following : 🕊 - 🔒 Automatically setups SSL and also renews it. Needs a domain or subdomain as input while installation. > install.nocodb.com/noco.sh script can be found [here in our github](https://raw.githubusercontent.com/nocodb/nocodb/develop/docker-compose/1_Auto_Upstall/noco.sh) +## One-Click Deployment + +[![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=100) + ## Other Methods @@ -109,6 +113,12 @@ Auto-upstall does the following : 🕊 > When running locally access nocodb by visiting: [http://localhost:8080/dashboard](http://localhost:8080/dashboard) +## Self-Hosting NocoDB + +### Elestio + +[![Deploy on Elestio](https://elest.io/images/logos/deploy-to-elestio-btn.png)](https://elest.io/open-source/nocodb) + # Screenshots ![2](https://github.com/nocodb/nocodb/assets/86527202/a127c05e-2121-4af2-a342-128e0e2d0291) ![3](https://github.com/nocodb/nocodb/assets/86527202/674da952-8a06-4848-a0e8-a7b02d5f5c88) diff --git a/docker-compose/1_Auto_Upstall/tests/expects/install/redis.sh b/docker-compose/1_Auto_Upstall/tests/expects/install/redis.sh index 6cdcaf44a4..f7ac95a23c 100755 --- a/docker-compose/1_Auto_Upstall/tests/expects/install/redis.sh +++ b/docker-compose/1_Auto_Upstall/tests/expects/install/redis.sh @@ -18,6 +18,9 @@ send "Y\r" expect "Choose Community or Enterprise Edition*" send "\r" +expect "Select PostgreSQL or SQLite as your database*" +send "P\r" + expect "Do you want to enabled Redis for caching*" send "Y\r" diff --git a/docker-compose/1_Auto_Upstall/tests/expects/install/scale.sh b/docker-compose/1_Auto_Upstall/tests/expects/install/scale.sh index b0a2064531..1e9d57e13f 100755 --- a/docker-compose/1_Auto_Upstall/tests/expects/install/scale.sh +++ b/docker-compose/1_Auto_Upstall/tests/expects/install/scale.sh @@ -18,6 +18,9 @@ send "Y\r" expect "Choose Community or Enterprise Edition*" send "\r" +expect "Select PostgreSQL or SQLite as your database*" +send "P\r" + expect "Do you want to enabled Redis for caching*" send "Y\r" diff --git a/docker-compose/1_Auto_Upstall/tests/expects/install/watchtower.sh b/docker-compose/1_Auto_Upstall/tests/expects/install/watchtower.sh index fa879ccda6..d02b855612 100755 --- a/docker-compose/1_Auto_Upstall/tests/expects/install/watchtower.sh +++ b/docker-compose/1_Auto_Upstall/tests/expects/install/watchtower.sh @@ -18,6 +18,9 @@ send "Y\r" expect "Choose Community or Enterprise Edition*" send "\r" +expect "Select PostgreSQL or SQLite as your database*" +send "P\r" + expect "Do you want to enabled Redis for caching*" send "\r" diff --git a/packages/nc-gui/components/cell/Checkbox.vue b/packages/nc-gui/components/cell/Checkbox.vue index 569ea6248e..95477815cb 100644 --- a/packages/nc-gui/components/cell/Checkbox.vue +++ b/packages/nc-gui/components/cell/Checkbox.vue @@ -38,13 +38,12 @@ const isSurveyForm = inject(IsSurveyFormInj, ref(false)) const isGrid = inject(IsGridInj, ref(false)) const checkboxMeta = computed(() => { + const icon = extractCheckboxIcon(column?.value?.meta) + return { - icon: { - checked: 'mdi-check-circle-outline', - unchecked: 'mdi-checkbox-blank-circle-outline', - }, color: 'primary', ...parseProp(column?.value?.meta), + icon, } }) diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index 7b4651c01c..bc0f8c6d97 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -381,6 +381,7 @@ const onFocus = () => { v-for="op of options" :key="op.title" :value="op.title" + class="gap-2" :data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`" :class="`nc-select-option-${column.title}-${op.title}`" > @@ -487,6 +488,7 @@ const onFocus = () => { v-for="op of options" :key="op.id || op.title" :value="op.title" + class="gap-2" :data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`" :class="`nc-select-option-${column.title}-${op.title}`" @click.stop diff --git a/packages/nc-gui/components/cell/Rating.vue b/packages/nc-gui/components/cell/Rating.vue index 9b97f7f37f..8aaf4e99ab 100644 --- a/packages/nc-gui/components/cell/Rating.vue +++ b/packages/nc-gui/components/cell/Rating.vue @@ -16,14 +16,12 @@ const rowHeight = inject(RowHeightInj, ref(undefined)) const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const ratingMeta = computed(() => { + const icon = extractRatingIcon(column?.value?.meta) return { - icon: { - full: 'mdi-star', - empty: 'mdi-star-outline', - }, color: '#fcb401', max: 5, ...parseProp(column.value?.meta), + icon, } }) diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index 036308cc48..3a54f4be9d 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -407,6 +407,7 @@ const onFocus = () => { v-for="op of options" :key="op.title" :value="op.title" + class="gap-2" :data-testid="`select-option-${column.title}-${rowIndex}`" :class="`nc-select-option-${column.title}-${op.title}`" @click.stop diff --git a/packages/nc-gui/components/dlg/QuickImport.vue b/packages/nc-gui/components/dlg/QuickImport.vue index 4b873ef404..0ce69d83a0 100644 --- a/packages/nc-gui/components/dlg/QuickImport.vue +++ b/packages/nc-gui/components/dlg/QuickImport.vue @@ -318,9 +318,9 @@ const customReqCbk = (customReqArgs: { file: any; onSuccess: () => void }) => { /** check if the file size exceeds the limit */ const beforeUpload = (file: UploadFile) => { - const exceedLimit = file.size! / 1024 / 1024 > 5 + const exceedLimit = file.size! / 1024 / 1024 > 25 if (exceedLimit) { - message.error(`File ${file.name} is too big. The accepted file size is less than 5MB.`) + message.error(`File ${file.name} is too big. The accepted file size is less than 25MB.`) } return !exceedLimit || Upload.LIST_IGNORE } diff --git a/packages/nc-gui/components/feed/Changelog/index.vue b/packages/nc-gui/components/feed/Changelog/index.vue index 8ee3811e67..832b5dc1ad 100644 --- a/packages/nc-gui/components/feed/Changelog/index.vue +++ b/packages/nc-gui/components/feed/Changelog/index.vue @@ -1,5 +1,9 @@ diff --git a/packages/nc-gui/components/feed/Error.vue b/packages/nc-gui/components/feed/Error.vue index 5bbdcfaa97..ed86a2ad19 100644 --- a/packages/nc-gui/components/feed/Error.vue +++ b/packages/nc-gui/components/feed/Error.vue @@ -1,11 +1,11 @@ diff --git a/packages/nc-gui/components/feed/Recents/Card.vue b/packages/nc-gui/components/feed/Recents/Card.vue index 18867a6e78..e5260f1b20 100644 --- a/packages/nc-gui/components/feed/Recents/Card.vue +++ b/packages/nc-gui/components/feed/Recents/Card.vue @@ -22,6 +22,7 @@ const feedIcon = { Twitter: iconMap.twitter, Youtube: iconMap.youtube, Github: iconMap.githubSolid, + Cloud: iconMap.ncCloud, } const truncate = ref(true) @@ -32,7 +33,7 @@ const expand = () => { truncate.value = false $e('c:nocodb:feed:recents:expand', { title: Title, - type: 'github', + type: source, }) } @@ -61,14 +62,20 @@ const renderedText = computedAsync(async () => { }) const { width } = useWindowSize() + +const handleOpenUrl = (url: string) => { + if (source === 'Cloud') return + + openLink(url) +}