diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 584eb1e37d..388cb7c8a6 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -119,11 +119,18 @@ jobs: shard: 2 playwright-mysql-3: needs: pre-build-for-playwright - if: ${{ always() && ( 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 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 }} @@ -144,7 +151,14 @@ jobs: uses: ./.github/workflows/playwright-test-workflow.yml with: db: sqlite - shard: 3 + 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 }} @@ -161,8 +175,15 @@ jobs: shard: 2 playwright-pg-shard-3: needs: pre-build-for-playwright - if: ${{ always() && ( 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 + 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: 3 \ No newline at end of file + shard: 4 \ No newline at end of file diff --git a/.github/workflows/playwright-test-workflow.yml b/.github/workflows/playwright-test-workflow.yml index 6c9e95acef..f753fec7f8 100644 --- a/.github/workflows/playwright-test-workflow.yml +++ b/.github/workflows/playwright-test-workflow.yml @@ -17,32 +17,30 @@ jobs: timeout-minutes: 100 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v3 + - name: Check node,pnpm Installation and set Path + shell: bash + working-directory: scripts/self-hosted-gh-runner + timeout-minutes: 1 + run: | + ./node-pnpm-check.sh + echo "make sure below mentioned versions are expected versions" + echo "If you are expecting the node and pnpm versions to be updated. Please update the node-pnpm-check.sh script" + env - name: Setup Node + if: ${{ env.SETUP_NODE != 'false' }} uses: actions/setup-node@v3 with: - node-version: 18.14.0 + node-version: ${{ env.NC_REQ_NODE_V }} - name: Setup pnpm + if: ${{ env.SETUP_PNPM != 'false' }} uses: pnpm/action-setup@v2 with: - version: 8 + version: ${{ env.NC_REQ_PNPM_V }} - name: Get pnpm store directory shell: bash run: | - echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - name: check if npm cache is needed - shell: bash - run: | - IS_NPM_CACHE_DOWNLOAD_REQUIRED="/cache-marker-v1.txt" - # update the above file name to force the cache ex: /cache-marker-v2.txt. - if [[ ! -f ${PRE_REQ_CHECK_FILE_PATH} ]]; - then - echo "IS_NPM_CACHE_DOWNLOAD_REQUIRED is true" - IS_NPM_CACHE_DOWNLOAD_REQUIRED="true" - else - IS_NPM_CACHE_DOWNLOAD_REQUIRED="false" - fi - echo "IS_NPM_CACHE_DOWNLOAD_REQUIRED=${IS_NPM_CACHE_DOWNLOAD_REQUIRED}" >> $GITHUB_ENV + echo "STORE_PATH=/root/setup-pnpm/node_modules/.bin/store/v3" >> $GITHUB_ENV - uses: actions/cache@v3 if: env.IS_NPM_CACHE_DOWNLOAD_REQUIRED == 'true' name: Setup pnpm cache @@ -233,6 +231,6 @@ jobs: cp -r ./tests/playwright/playwright-report ${target_dir}/ || echo "playwright reports directory does not exists" >> ${target_dir}/playwright-report/index.html cp ./packages/nocodb/*_test_backend.log ${target_dir}/ || echo "backend logs file does not exists" >> ${target_dir}/index.html # end: artifacts copy - SUMMARY='[Artifacts]('${REPORTS_HOST}/${path}') - [playwright-report]('${REPORTS_HOST}/${path}'/playwright-report)' + 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 diff --git a/.github/workflows/pre-build-for-playwright.yml b/.github/workflows/pre-build-for-playwright.yml index c952d58963..079137dfff 100644 --- a/.github/workflows/pre-build-for-playwright.yml +++ b/.github/workflows/pre-build-for-playwright.yml @@ -16,27 +16,25 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + - name: Check node,pnpm Installation and set Path + shell: bash + working-directory: scripts/self-hosted-gh-runner + timeout-minutes: 1 + run: | + ./node-pnpm-check.sh + echo "make sure below mentioned versions are expected versions" + echo "If you are expecting the node and pnpm versions to be updated. Please update the node-pnpm-check.sh script" + env - name: Setup Node + if: ${{ env.SETUP_NODE != 'false' }} uses: actions/setup-node@v3 with: - node-version: 18.14.0 + node-version: ${{ env.NC_REQ_NODE_V }} - name: Setup pnpm + if: ${{ env.SETUP_PNPM != 'false' }} uses: pnpm/action-setup@v2 with: - version: 8 - - name: check if npm cache is needed - shell: bash - run: | - PRE_REQ_CHECK_FILE_PATH="/cache-marker-v1.txt" - # update the above file name to force the cache ex: /cache-marker-v2.txt. - if [[ ! -f ${PRE_REQ_CHECK_FILE_PATH} ]]; - then - echo "IS_NPM_CACHE_DOWNLOAD_REQUIRED is true" - IS_NPM_CACHE_DOWNLOAD_REQUIRED="true" - else - IS_NPM_CACHE_DOWNLOAD_REQUIRED="false" - fi - echo "IS_NPM_CACHE_DOWNLOAD_REQUIRED=${IS_NPM_CACHE_DOWNLOAD_REQUIRED}" >> $GITHUB_ENV + version: ${{ env.NC_REQ_PNPM_V }} - name: Get pnpm store directory shell: bash run: | diff --git a/.github/workflows/publish-api-docs.yml b/.github/workflows/publish-api-docs.yml index 76925bf3ac..ebf714d7ec 100644 --- a/.github/workflows/publish-api-docs.yml +++ b/.github/workflows/publish-api-docs.yml @@ -18,26 +18,50 @@ jobs: with: fetch-depth: 0 - - name: Pushes swagger file to src + - name: Pushes swagger file to data-apis-v1 uses: dmnemec/copy_file_to_another_repo_action@1b29cbd9a323185f20b175dc6d5f8f31be5c0658 env: API_TOKEN_GITHUB: ${{ secrets.GH_TOKEN }} with: source_file: 'packages/nocodb/src/schema/swagger.json' destination_repo: 'nocodb/noco-apis-doc' - destination_folder: 'src' + destination_folder: 'data-apis-v1' user_email: 'oof1lab@gmail.com' user_name: 'o1lab' commit_message: 'Autorelease from github.com/nocodb/nocodb' - - name: Pushes swagger file to meta-src + - name: Pushes swagger file to data-apis-v2 uses: dmnemec/copy_file_to_another_repo_action@1b29cbd9a323185f20b175dc6d5f8f31be5c0658 env: API_TOKEN_GITHUB: ${{ secrets.GH_TOKEN }} with: source_file: 'packages/nocodb/src/schema/swagger.json' destination_repo: 'nocodb/noco-apis-doc' - destination_folder: 'meta-src' + destination_folder: 'data-apis-v2' + user_email: 'oof1lab@gmail.com' + user_name: 'o1lab' + commit_message: 'Autorelease from github.com/nocodb/nocodb' + + - name: Pushes swagger file to meta-apis-v1 + uses: dmnemec/copy_file_to_another_repo_action@1b29cbd9a323185f20b175dc6d5f8f31be5c0658 + env: + API_TOKEN_GITHUB: ${{ secrets.GH_TOKEN }} + with: + source_file: 'packages/nocodb/src/schema/swagger.json' + destination_repo: 'nocodb/noco-apis-doc' + destination_folder: 'meta-apis-v1' + user_email: 'oof1lab@gmail.com' + user_name: 'o1lab' + commit_message: 'Autorelease from github.com/nocodb/nocodb' + + - name: Pushes swagger file to meta-apis-v2 + uses: dmnemec/copy_file_to_another_repo_action@1b29cbd9a323185f20b175dc6d5f8f31be5c0658 + env: + API_TOKEN_GITHUB: ${{ secrets.GH_TOKEN }} + with: + source_file: 'packages/nocodb/src/schema/swagger-v2.json' + destination_repo: 'nocodb/noco-apis-doc' + destination_folder: 'meta-apis-v2' user_email: 'oof1lab@gmail.com' user_name: 'o1lab' commit_message: 'Autorelease from github.com/nocodb/nocodb' diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml index efac03f6ff..bf8ccc2322 100644 --- a/.github/workflows/release-docker.yml +++ b/.github/workflows/release-docker.yml @@ -90,10 +90,7 @@ jobs: if: ${{ github.event.inputs.targetEnv == 'DEV' || inputs.targetEnv == 'DEV' }} run: | export NODE_OPTIONS="--max_old_space_size=16384" - NOCODB_SDK_PKG_NAME=nocodb-sdk - if [[ "${{ github.event.inputs.targetEnv == 'DEV' || inputs.targetEnv == 'DEV' }}" ]]; then - NOCODB_SDK_PKG_NAME=nocodb-sdk-daily - fi + NOCODB_SDK_PKG_NAME=nocodb-sdk-daily 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 && @@ -104,6 +101,7 @@ jobs: - name: Build nocodb and docker files run: | + pnpm install --ignore-scripts --no-frozen-lockfile pnpm run docker:build working-directory: ${{ env.working-directory }} diff --git a/.github/workflows/release-npm.yml b/.github/workflows/release-npm.yml index fff4f57678..d2b25a696c 100644 --- a/.github/workflows/release-npm.yml +++ b/.github/workflows/release-npm.yml @@ -55,9 +55,11 @@ jobs: - run: | export NODE_OPTIONS="--max_old_space_size=16384" NOCODB_SDK_PKG_NAME=nocodb-sdk - if [[ "${{ github.event.inputs.targetEnv == 'DEV' || inputs.targetEnv == 'DEV' }}" ]]; then + # If targetEnv is DEV, then use nocodb-sdk-daily package + if [[ ${{ github.event.inputs.targetEnv || inputs.targetEnv }} == 'DEV' ]]; then NOCODB_SDK_PKG_NAME=nocodb-sdk-daily fi + echo $NOCODB_SDK_PKG_NAME 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 && pnpm --filter=${NOCODB_SDK_PKG_NAME} publish --no-git-checks && sleep 90 && diff --git a/README.md b/README.md index 844253d45e..6ac3a9a388 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart spreadshe

- + [![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) @@ -210,22 +210,22 @@ Access Dashboard using: [http://localhost:8080/dashboard](http://localhost:8080/ # Table of Contents - [Quick try](#quick-try) - - [NPX](#npx) - - [Node Application](#node-application) - - [Docker](#docker) - - [Docker Compose](#docker-compose) + - [NPX](#npx) + - [Node Application](#node-application) + - [Docker](#docker) + - [Docker Compose](#docker-compose) - [GUI](#gui) - [Join Our Community](#join-our-community) - [Screenshots](#screenshots) - [Table of Contents](#table-of-contents) - [Features](#features) - - [Rich Spreadsheet Interface](#rich-spreadsheet-interface) - - [App Store for Workflow Automations](#app-store-for-workflow-automations) - - [Programmatic Access](#programmatic-access) - - [Sync Schema](#sync-schema) - - [Audit](#audit) + - [Rich Spreadsheet Interface](#rich-spreadsheet-interface) + - [App Store for Workflow Automations](#app-store-for-workflow-automations) + - [Programmatic Access](#programmatic-access) + - [Sync Schema](#sync-schema) + - [Audit](#audit) - [Production Setup](#production-setup) - - [Environment variables](#environment-variables) + - [Environment variables](#environment-variables) - [Development Setup](#development-setup) - [Contributing](#contributing) - [Why are we building this?](#why-are-we-building-this) @@ -305,4 +305,4 @@ Thank you for your contributions! We appreciate all the contributions from the c - + \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index db8953bed0..2fd791a798 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -3,5 +3,5 @@ ### Reporting a Vulnerability Please report (suspected) security vulnerabilities to security@nocodb.com -- You will receive a response from us within 3 working days. -- If the issue is confirmed, we will release a patch as soon as possible depending on complexity but historically within a few days. \ No newline at end of file +- You will receive a response from us within 7 working days. +- If the issue is confirmed, we will release a patch as soon as possible depending on complexity but historically within a few days. diff --git a/charts/nocodb/templates/deployment.yaml b/charts/nocodb/templates/deployment.yaml index 582d365df8..785b0adf0f 100644 --- a/charts/nocodb/templates/deployment.yaml +++ b/charts/nocodb/templates/deployment.yaml @@ -33,9 +33,11 @@ spec: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.storage.enabled }} volumeMounts: - name: {{ include "nocodb.fullname" . }} mountPath: /usr/app/data + {{- end }} envFrom: - configMapRef: name: {{ include "nocodb.fullname" . }} @@ -67,7 +69,9 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- if .Values.storage.enabled }} volumes: - name: {{ include "nocodb.fullname" . }} persistentVolumeClaim: claimName: {{ include "nocodb.fullname" . }} + {{- end }} diff --git a/charts/nocodb/templates/pvc.yaml b/charts/nocodb/templates/pvc.yaml index 092a1b0439..369480f057 100644 --- a/charts/nocodb/templates/pvc.yaml +++ b/charts/nocodb/templates/pvc.yaml @@ -1,3 +1,4 @@ +{{ if .Values.storage.enabled }} apiVersion: v1 kind: PersistentVolumeClaim metadata: @@ -12,3 +13,4 @@ spec: accessModes: {{- default (toYaml .Values.storage.accessModes) "- ReadWriteMany" | nindent 4 }} volumeMode: Filesystem +{{ end }} diff --git a/charts/nocodb/values.yaml b/charts/nocodb/values.yaml index 881e31cdbb..ad84527338 100644 --- a/charts/nocodb/values.yaml +++ b/charts/nocodb/values.yaml @@ -86,6 +86,10 @@ extraSecretEnvs: NC_DB: "mysql2://mysql:3306?u=nocodb&p=secretPass&d=nocodb" storage: + # If disabled, another persistent storage should be configured for attachments to work. + # We recommend setting NC_S3_BUCKET_NAME and other NC_S3* environment variables. + # Refer documentation for more details. + enabled: true size: 3Gi storageClassName: "" diff --git a/docker-compose/sqlite/nocodb/noco.db b/docker-compose/sqlite/nocodb/noco.db new file mode 100644 index 0000000000..3283348219 Binary files /dev/null and b/docker-compose/sqlite/nocodb/noco.db differ diff --git a/packages/nc-gui/assets/img/brand/nocodb.png b/packages/nc-gui/assets/img/brand/nocodb.png new file mode 100644 index 0000000000..188ed5e198 Binary files /dev/null and b/packages/nc-gui/assets/img/brand/nocodb.png differ diff --git a/packages/nc-gui/assets/img/fieldPlaceholder.svg b/packages/nc-gui/assets/img/fieldPlaceholder.svg new file mode 100644 index 0000000000..7fc8286651 --- /dev/null +++ b/packages/nc-gui/assets/img/fieldPlaceholder.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/add-data-source.svg b/packages/nc-gui/assets/nc-icons/add-data-source.svg new file mode 100644 index 0000000000..6ea287bc88 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/add-data-source.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/bt-solid.svg b/packages/nc-gui/assets/nc-icons/bt-solid.svg new file mode 100644 index 0000000000..d5a0e362c2 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/bt-solid.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/comment_here.svg b/packages/nc-gui/assets/nc-icons/comment_here.svg new file mode 100644 index 0000000000..1b413ad9ea --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/comment_here.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/nc-gui/assets/nc-icons/commentor.svg b/packages/nc-gui/assets/nc-icons/commentor.svg new file mode 100644 index 0000000000..fee40f383d --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/commentor.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/creator.svg b/packages/nc-gui/assets/nc-icons/creator.svg new file mode 100644 index 0000000000..954e553b38 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/creator.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/download.svg b/packages/nc-gui/assets/nc-icons/download.svg index 2692f7d8fb..2403b35d0e 100644 --- a/packages/nc-gui/assets/nc-icons/download.svg +++ b/packages/nc-gui/assets/nc-icons/download.svg @@ -1,5 +1,5 @@ - + diff --git a/packages/nc-gui/assets/nc-icons/editor.svg b/packages/nc-gui/assets/nc-icons/editor.svg new file mode 100644 index 0000000000..e9190dd7b9 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/editor.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/fields.svg b/packages/nc-gui/assets/nc-icons/fields.svg index ad389d64e0..1922eb13a1 100644 --- a/packages/nc-gui/assets/nc-icons/fields.svg +++ b/packages/nc-gui/assets/nc-icons/fields.svg @@ -1,8 +1,8 @@ - - - - - - + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/filter.svg b/packages/nc-gui/assets/nc-icons/filter.svg index 0369fd2c1b..4779e17a99 100644 --- a/packages/nc-gui/assets/nc-icons/filter.svg +++ b/packages/nc-gui/assets/nc-icons/filter.svg @@ -1,3 +1,3 @@ - + diff --git a/packages/nc-gui/assets/nc-icons/group.svg b/packages/nc-gui/assets/nc-icons/group.svg index 3f57b18319..3d0c09d23f 100644 --- a/packages/nc-gui/assets/nc-icons/group.svg +++ b/packages/nc-gui/assets/nc-icons/group.svg @@ -1,5 +1,5 @@ - - - + + + diff --git a/packages/nc-gui/assets/nc-icons/hm-solid.svg b/packages/nc-gui/assets/nc-icons/hm-solid.svg new file mode 100644 index 0000000000..efe6772786 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/hm-solid.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/lookup.svg b/packages/nc-gui/assets/nc-icons/lookup.svg new file mode 100644 index 0000000000..8a5c0dba2b --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/lookup.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/mm-solid.svg b/packages/nc-gui/assets/nc-icons/mm-solid.svg new file mode 100644 index 0000000000..eaa045334a --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/mm-solid.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/no-access.svg b/packages/nc-gui/assets/nc-icons/no-access.svg new file mode 100644 index 0000000000..0f301628e0 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/no-access.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/owner.svg b/packages/nc-gui/assets/nc-icons/owner.svg new file mode 100644 index 0000000000..effffd02de --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/owner.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/project.svg b/packages/nc-gui/assets/nc-icons/project.svg new file mode 100644 index 0000000000..92fb62f59c --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/project.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/record.svg b/packages/nc-gui/assets/nc-icons/record.svg new file mode 100644 index 0000000000..7515f62243 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/record.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/nc-icons/super-admin.svg b/packages/nc-gui/assets/nc-icons/super-admin.svg new file mode 100644 index 0000000000..45cdf43031 --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/super-admin.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/nc-gui/assets/nc-icons/users.svg b/packages/nc-gui/assets/nc-icons/users.svg index 60c1c870fb..2e75180b88 100644 --- a/packages/nc-gui/assets/nc-icons/users.svg +++ b/packages/nc-gui/assets/nc-icons/users.svg @@ -1,6 +1,6 @@ - - - - + + + + diff --git a/packages/nc-gui/assets/nc-icons/viewer.svg b/packages/nc-gui/assets/nc-icons/viewer.svg new file mode 100644 index 0000000000..c2ad9a442f --- /dev/null +++ b/packages/nc-gui/assets/nc-icons/viewer.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index d75eef04f3..c317f29f0c 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -53,6 +53,14 @@ main { @apply !rounded-lg !py-2 !px-3 mb-1; } +.mobile { + .nc-scrollbar-md, nc-scrollbar-dark-md, nc-scrollbar-dark-md, nc-scrollbar-sm-dark, nc-scrollbar-x-md { + &::-webkit-scrollbar { + width: 0px; + } + } +} + .nc-scrollbar-md { overflow-y: scroll; overflow-x: hidden; @@ -185,7 +193,7 @@ a { } } -.nc-project-menu-item { +.nc-base-menu-item { @apply cursor-pointer flex items-center gap-2 py-2 after:(content-[''] absolute top-0 left-0 bottom-0 right-0 w-full h-full bg-current opacity-0 transition transition-opacity duration-100) hover:(after:(opacity-5)); // &:hover { @@ -434,9 +442,6 @@ a { @apply !shadow-none rounded ring-1 ring-red-600; } -.ant-modal { - @apply !top-[30px]; -} .ant-modal-content { @apply !p-6; border-radius: 1rem; @@ -598,7 +603,7 @@ input[type='number'] { } .nc-sidebar-node { - @apply !xs:(min-h-12 max-h-12 hover:bg-gray-50 ml-1.5); + @apply !xs:(min-h-12 max-h-12 hover:bg-gray-50 ml-1.5 w-[calc(100%-8px)]); .nc-emoji { @apply xs:(text-lg); diff --git a/packages/nc-gui/components.d.ts b/packages/nc-gui/components.d.ts index 142768f672..57affe1553 100644 --- a/packages/nc-gui/components.d.ts +++ b/packages/nc-gui/components.d.ts @@ -52,7 +52,6 @@ declare module '@vue/runtime-core' { APagination: typeof import('ant-design-vue/es')['Pagination'] APopover: typeof import('ant-design-vue/es')['Popover'] ARadio: typeof import('ant-design-vue/es')['Radio'] - ARadioButton: typeof import('ant-design-vue/es')['RadioButton'] ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup'] ARate: typeof import('ant-design-vue/es')['Rate'] ARow: typeof import('ant-design-vue/es')['Row'] @@ -81,7 +80,6 @@ declare module '@vue/runtime-core' { CilFullscreenExit: typeof import('~icons/cil/fullscreen-exit')['default'] ClaritySuccessLine: typeof import('~icons/clarity/success-line')['default'] IcBaselineMoreVert: typeof import('~icons/ic/baseline-more-vert')['default'] - Icon: typeof import('~icons/ic/on')['default'] IcOutlineInsertDriveFile: typeof import('~icons/ic/outline-insert-drive-file')['default'] IcRoundEdit: typeof import('~icons/ic/round-edit')['default'] IcRoundKeyboardArrowDown: typeof import('~icons/ic/round-keyboard-arrow-down')['default'] @@ -93,6 +91,7 @@ declare module '@vue/runtime-core' { MaterialSymbolsChevronRightRounded: typeof import('~icons/material-symbols/chevron-right-rounded')['default'] MaterialSymbolsCloseRounded: typeof import('~icons/material-symbols/close-rounded')['default'] MaterialSymbolsDarkModeOutline: typeof import('~icons/material-symbols/dark-mode-outline')['default'] + MaterialSymbolsDeleteOutlineRounded: typeof import('~icons/material-symbols/delete-outline-rounded')['default'] MaterialSymbolsFileCopyOutline: typeof import('~icons/material-symbols/file-copy-outline')['default'] MaterialSymbolsKeyboardArrowDownRounded: typeof import('~icons/material-symbols/keyboard-arrow-down-rounded')['default'] MaterialSymbolsKeyboardReturn: typeof import('~icons/material-symbols/keyboard-return')['default'] @@ -105,12 +104,9 @@ declare module '@vue/runtime-core' { MaterialSymbolsVisibility: typeof import('~icons/material-symbols/visibility')['default'] MaterialSymbolsVisibilityOff: typeof import('~icons/material-symbols/visibility-off')['default'] MaterialSymbolsWarning: typeof import('~icons/material-symbols/warning')['default'] - MdiAccordionUp: typeof import('~icons/mdi/accordion-up')['default'] MdiAccount: typeof import('~icons/mdi/account')['default'] MdiAccountCircleOutline: typeof import('~icons/mdi/account-circle-outline')['default'] - MdiAccountCircleOutlines: typeof import('~icons/mdi/account-circle-outlines')['default'] MdiAccountSupervisorOutline: typeof import('~icons/mdi/account-supervisor-outline')['default'] - MdiAlpha: typeof import('~icons/mdi/alpha')['default'] MdiAppleKeyboardShift: typeof import('~icons/mdi/apple-keyboard-shift')['default'] MdiArrowDownDropCircle: typeof import('~icons/mdi/arrow-down-drop-circle')['default'] MdiArrowDownDropCircleOutline: typeof import('~icons/mdi/arrow-down-drop-circle-outline')['default'] @@ -121,9 +117,7 @@ declare module '@vue/runtime-core' { MdiCardsHeart: typeof import('~icons/mdi/cards-heart')['default'] MdiCellphoneMessage: typeof import('~icons/mdi/cellphone-message')['default'] MdiChat: typeof import('~icons/mdi/chat')['default'] - MdiChatProcessingOutline: typeof import('~icons/mdi/chat-processing-outline')['default'] MdiCheck: typeof import('~icons/mdi/check')['default'] - MdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] MdiChevronLeft: typeof import('~icons/mdi/chevron-left')['default'] MdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] MdiChevronUp: typeof import('~icons/mdi/chevron-up')['default'] @@ -134,6 +128,7 @@ declare module '@vue/runtime-core' { MdiCurrencyUsd: typeof import('~icons/mdi/currency-usd')['default'] MdiDiscord: typeof import('~icons/mdi/discord')['default'] MdiDotsHorizontal: typeof import('~icons/mdi/dots-horizontal')['default'] + MdiDotsVertical: typeof import('~icons/mdi/dots-vertical')['default'] MdiEye: typeof import('~icons/mdi/eye')['default'] MdiFileDocumentMultipleOutline: typeof import('~icons/mdi/file-document-multiple-outline')['default'] MdiFileDocumentOutline: typeof import('~icons/mdi/file-document-outline')['default'] @@ -151,12 +146,10 @@ declare module '@vue/runtime-core' { MdiMessageOutline: typeof import('~icons/mdi/message-outline')['default'] MdiMicrosoftTeams: typeof import('~icons/mdi/microsoft-teams')['default'] MdiMoonFull: typeof import('~icons/mdi/moon-full')['default'] - MdiMoreVert: typeof import('~icons/mdi/more-vert')['default'] MdiPlus: typeof import('~icons/mdi/plus')['default'] MdiReload: typeof import('~icons/mdi/reload')['default'] MdiRocketLaunchOutline: typeof import('~icons/mdi/rocket-launch-outline')['default'] MdiScriptTextOutline: typeof import('~icons/mdi/script-text-outline')['default'] - MdiShieldKeyOutline: typeof import('~icons/mdi/shield-key-outline')['default'] MdiSlack: typeof import('~icons/mdi/slack')['default'] MdiStar: typeof import('~icons/mdi/star')['default'] MdiStarOutline: typeof import('~icons/mdi/star-outline')['default'] @@ -168,9 +161,7 @@ declare module '@vue/runtime-core' { MdiWhatsapp: typeof import('~icons/mdi/whatsapp')['default'] MiCircleWarning: typeof import('~icons/mi/circle-warning')['default'] NcIconsInbox: typeof import('~icons/nc-icons/inbox')['default'] - PhLink: typeof import('~icons/ph/link')['default'] PhMagnifyingGlassBold: typeof import('~icons/ph/magnifying-glass-bold')['default'] - PhTriangleFill: typeof import('~icons/ph/triangle-fill')['default'] RiExternalLinkLine: typeof import('~icons/ri/external-link-line')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/packages/nc-gui/components/account/License.vue b/packages/nc-gui/components/account/License.vue index 795fb16e8c..e4d780bc17 100644 --- a/packages/nc-gui/components/account/License.vue +++ b/packages/nc-gui/components/account/License.vue @@ -5,6 +5,8 @@ import { extractSdkResponseErrorMsg, useApi, useGlobal } from '#imports' const { api, isLoading } = useApi() +const { t } = useI18n() + const { $e } = useNuxtApp() const { loadAppInfo } = useGlobal() @@ -22,7 +24,7 @@ const loadLicense = async () => { const setLicense = async () => { try { await api.orgLicense.set({ key: key.value }) - message.success('License key updated') + message.success(t('success.licenseKeyUpdated')) await loadAppInfo() } catch (e: any) { message.error(await extractSdkResponseErrorMsg(e)) @@ -35,14 +37,14 @@ loadLicense() diff --git a/packages/nc-gui/components/account/Profile.vue b/packages/nc-gui/components/account/Profile.vue index a1b338c0ca..c695c6813e 100644 --- a/packages/nc-gui/components/account/Profile.vue +++ b/packages/nc-gui/components/account/Profile.vue @@ -1,6 +1,8 @@ diff --git a/packages/nc-gui/components/account/Token.vue b/packages/nc-gui/components/account/Token.vue index 5088da9269..4e665c30ab 100644 --- a/packages/nc-gui/components/account/Token.vue +++ b/packages/nc-gui/components/account/Token.vue @@ -2,7 +2,7 @@ import type { VNodeRef } from '@vue/runtime-core' import { message } from 'ant-design-vue' import type { ApiTokenType, RequestParams } from 'nocodb-sdk' -import { extractSdkResponseErrorMsg, ref, useApi, useCopy, useNuxtApp } from '#imports' +import { extractSdkResponseErrorMsg, isEeUI, ref, useApi, useCopy, useNuxtApp } from '#imports' const { api, isLoading } = useApi() @@ -29,7 +29,7 @@ const showNewTokenModal = ref(false) const currentLimit = ref(10) -const defaultTokenName = 'Untitled token' +const defaultTokenName = t('labels.untitledToken') const selectedTokenData = ref({ description: defaultTokenName, @@ -147,9 +147,9 @@ const selectInputOnMount: VNodeRef = (el) => const errorMessage = computed(() => { const tokenLength = selectedTokenData.value.description?.length if (!tokenLength) { - return 'Token name should not be empty' + return t('msg.info.tokenNameNotEmpty') } else if (tokenLength > 255) { - return 'Token name should not be more than 255 characters' + return t('msg.info.tokenNameMaxLength') } }) @@ -160,39 +160,54 @@ const handleCancel = () => { diff --git a/packages/nc-gui/components/cell/Email.vue b/packages/nc-gui/components/cell/Email.vue index 434dd0a1fc..385fecb852 100644 --- a/packages/nc-gui/components/cell/Email.vue +++ b/packages/nc-gui/components/cell/Email.vue @@ -71,7 +71,7 @@ watch( :ref="focus" v-model="vModel" class="w-full outline-none text-sm px-1 py-2" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" @blur="editEnabled = false" @keydown.down.stop @keydown.left.stop @@ -84,7 +84,7 @@ watch( @mousedown.stop /> - NULL + {{ $t('general.null') }} !isExpandedFormOpen.value && !isEditColumn.value class="outline-none px-1 border-none w-full h-full text-sm" type="number" step="0.1" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" @blur="editEnabled = false" @keydown.down.stop @keydown.left.stop @@ -63,7 +63,7 @@ const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value @selectstart.capture.stop @mousedown.stop /> - NULL + {{ $t('general.null') }} {{ vModel }} diff --git a/packages/nc-gui/components/cell/Integer.vue b/packages/nc-gui/components/cell/Integer.vue index 477232670a..5c0bf8944a 100644 --- a/packages/nc-gui/components/cell/Integer.vue +++ b/packages/nc-gui/components/cell/Integer.vue @@ -87,8 +87,11 @@ function onKeyDown(e: any) { v-model="vModel" class="outline-none py-2 px-1 border-none w-full h-full text-sm" type="number" + :class="{ + 'pl-2': isExpandedFormOpen, + }" style="letter-spacing: 0.06rem" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" @blur="editEnabled = false" @keydown="onKeyDown" @keydown.down.stop @@ -99,7 +102,7 @@ function onKeyDown(e: any) { @selectstart.capture.stop @mousedown.stop /> - NULL + {{ $t('general.null') }} {{ displayValue }} diff --git a/packages/nc-gui/components/cell/Json.vue b/packages/nc-gui/components/cell/Json.vue index 1206b4b5b2..18326296f9 100644 --- a/packages/nc-gui/components/cell/Json.vue +++ b/packages/nc-gui/components/cell/Json.vue @@ -1,10 +1,12 @@ diff --git a/packages/nc-gui/components/cell/MultiSelect.vue b/packages/nc-gui/components/cell/MultiSelect.vue index ae68ab7aad..7a64c35a1a 100644 --- a/packages/nc-gui/components/cell/MultiSelect.vue +++ b/packages/nc-gui/components/cell/MultiSelect.vue @@ -23,9 +23,9 @@ import { onMounted, reactive, ref, + useBase, useEventListener, useMetas, - useProject, useRoles, useSelectedCellKeyupListener, watch, @@ -43,6 +43,8 @@ const { modelValue, disableOptionCreation } = defineProps() const emit = defineEmits(['update:modelValue']) +const { isMobileMode } = useGlobal() + const column = inject(ColumnInj)! const readOnly = inject(ReadonlyInj)! @@ -81,7 +83,7 @@ const { getMeta } = useMetas() const { isUIAllowed } = useRoles() -const { isPg, isMysql } = useProject() +const { isPg, isMysql } = useBase() // a variable to keep newly created options value // temporary until it's add the option to column meta @@ -133,7 +135,7 @@ const vModel = computed({ const selectedTitles = computed(() => modelValue ? typeof modelValue === 'string' - ? isMysql(column.value.base_id) + ? isMysql(column.value.source_id) ? modelValue.split(',').sort((a, b) => { const opa = options.value.find((el) => el.title === a) const opb = options.value.find((el) => el.title === b) @@ -142,8 +144,8 @@ const selectedTitles = computed(() => } return 0 }) - : modelValue.split(',') - : modelValue + : modelValue.split(',').map((el) => el.trim()) + : modelValue.map((el) => el.trim()) : [], ) @@ -247,7 +249,7 @@ async function addIfMissingAndSave() { // todo: refactor and avoid repetition if (updatedColMeta.cdf) { // Postgres returns default value wrapped with single quotes & casted with type so we have to get value between single quotes to keep it unified for all databases - if (isPg(column.value.base_id)) { + if (isPg(column.value.source_id)) { updatedColMeta.cdf = updatedColMeta.cdf.substring( updatedColMeta.cdf.indexOf(`'`) + 1, updatedColMeta.cdf.lastIndexOf(`'`), @@ -255,7 +257,7 @@ async function addIfMissingAndSave() { } // Mysql escapes single quotes with backslash so we keep quotes but others have to unescaped - if (!isMysql(column.value.base_id)) { + if (!isMysql(column.value.source_id) && !isPg(column.value.source_id)) { updatedColMeta.cdf = updatedColMeta.cdf.replace(/''/g, "'") } } @@ -321,6 +323,8 @@ const handleClose = (e: MouseEvent) => { !aselect.value.$el.contains(e.target) && !document.querySelector('.nc-dropdown-multi-select-cell.active')?.contains(e.target as Node) ) { + // loose focus when clicked outside + isEditable.value = false isOpen.value = false } } @@ -378,10 +382,10 @@ const selectedOpts = computed(() => { v-model:value="vModel" mode="multiple" class="w-full overflow-hidden" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" :bordered="false" clear-icon - show-search + :show-search="!isMobileMode" :show-arrow="editAllowed && !(readOnly || isLockedMode)" :open="isOpen && editAllowed" :disabled="readOnly || !editAllowed || isLockedMode" @@ -390,6 +394,9 @@ const selectedOpts = computed(() => { @search="search" @keydown.stop > + {
- Create new option named {{ searchVal }} + {{ $t('msg.selectOption.createNewOptionNamed') }} {{ searchVal }}
diff --git a/packages/nc-gui/components/cell/Percent.vue b/packages/nc-gui/components/cell/Percent.vue index 5fec5b0412..55b6188e56 100644 --- a/packages/nc-gui/components/cell/Percent.vue +++ b/packages/nc-gui/components/cell/Percent.vue @@ -42,7 +42,7 @@ const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value class="w-full !text-sm !border-none !outline-none focus:ring-0 text-base p-1" :class="{ '!px-2': editEnabled }" type="number" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" @blur="editEnabled = false" @keydown.down.stop @keydown.left.stop @@ -54,6 +54,6 @@ const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value @selectstart.capture.stop @mousedown.stop /> - NULL + {{ $t('general.null') }} {{ vModel }} diff --git a/packages/nc-gui/components/cell/PhoneNumber.vue b/packages/nc-gui/components/cell/PhoneNumber.vue index 42f2f37f25..24c3c8ef36 100644 --- a/packages/nc-gui/components/cell/PhoneNumber.vue +++ b/packages/nc-gui/components/cell/PhoneNumber.vue @@ -15,6 +15,8 @@ const rowHeight = inject(RowHeightInj, ref(undefined)) const { showNull } = useGlobal() +const { t } = useI18n() + const editEnabled = inject(EditModeInj)! const isEditColumn = inject(EditColumnInj, ref(false)) @@ -46,7 +48,7 @@ watch( () => editEnabled.value, () => { if (parseProp(column.value.meta)?.validate && !editEnabled.value && localState.value && !isMobilePhone(localState.value)) { - message.error('Invalid Phone Number') + message.error(t('msg.invalidPhoneNumber')) localState.value = undefined return } @@ -61,7 +63,7 @@ watch( :ref="focus" v-model="vModel" class="w-full outline-none text-sm px-1 py-2" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" @blur="editEnabled = false" @keydown.down.stop @keydown.left.stop @@ -74,7 +76,7 @@ watch( @mousedown.stop /> - NULL + {{ $t('general.null') }} diff --git a/packages/nc-gui/components/cell/SingleSelect.vue b/packages/nc-gui/components/cell/SingleSelect.vue index 4e357d1cb2..6d132cf0b0 100644 --- a/packages/nc-gui/components/cell/SingleSelect.vue +++ b/packages/nc-gui/components/cell/SingleSelect.vue @@ -20,8 +20,8 @@ import { inject, isDrawerOrModalExist, ref, + useBase, useEventListener, - useProject, useRoles, useSelectedCellKeyupListener, watch, @@ -37,6 +37,8 @@ const { modelValue, disableOptionCreation } = defineProps() const emit = defineEmits(['update:modelValue']) +const { isMobileMode } = useGlobal() + const column = inject(ColumnInj)! const readOnly = inject(ReadonlyInj)! @@ -71,7 +73,7 @@ const { getMeta } = useMetas() const { isUIAllowed } = useRoles() -const { isPg, isMysql } = useProject() +const { isPg, isMysql } = useBase() // a variable to keep newly created option value // temporary until it's add the option to column meta @@ -102,7 +104,7 @@ const hasEditRoles = computed(() => isUIAllowed('dataEdit')) const editAllowed = computed(() => (hasEditRoles.value || isForm.value) && active.value) const vModel = computed({ - get: () => tempSelectedOptState.value ?? modelValue, + get: () => tempSelectedOptState.value ?? modelValue?.trim(), set: (val) => { if (val && isNewOptionCreateEnabled.value && (options.value ?? []).every((op) => op.title !== val)) { tempSelectedOptState.value = val @@ -175,7 +177,7 @@ async function addIfMissingAndSave() { // todo: refactor and avoid repetition if (updatedColMeta.cdf) { // Postgres returns default value wrapped with single quotes & casted with type so we have to get value between single quotes to keep it unified for all databases - if (isPg(column.value.base_id)) { + if (isPg(column.value.source_id)) { updatedColMeta.cdf = updatedColMeta.cdf.substring( updatedColMeta.cdf.indexOf(`'`) + 1, updatedColMeta.cdf.lastIndexOf(`'`), @@ -183,7 +185,7 @@ async function addIfMissingAndSave() { } // Mysql escapes single quotes with backslash so we keep quotes but others have to unescaped - if (!isMysql(column.value.base_id)) { + if (!isMysql(column.value.source_id) && !isPg(column.value.source_id)) { updatedColMeta.cdf = updatedColMeta.cdf.replace(/''/g, "'") } } @@ -202,6 +204,8 @@ async function addIfMissingAndSave() { } const search = () => { + if (isMobileMode.value) return + searchVal.value = aselect.value?.$el?.querySelector('.ant-select-selection-search-input')?.value } @@ -217,6 +221,7 @@ const onKeydown = (e: KeyboardEvent) => { const onSelect = () => { isOpen.value = false + isEditable.value = false } const cellClickHook = inject(CellClickHookInj, null) @@ -284,16 +289,16 @@ const selectedOpt = computed(() => { v-else ref="aselect" v-model:value="vModel" - class="w-full overflow-hidden" + class="w-full overflow-hidden xs:min-h-12" :class="{ 'caret-transparent': !hasEditRoles }" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" :allow-clear="!column.rqd && editAllowed" :bordered="false" :open="isOpen && editAllowed" :disabled="readOnly || !editAllowed || isLockedMode" :show-arrow="hasEditRoles && !(readOnly || isLockedMode) && active && vModel === null" :dropdown-class-name="`nc-dropdown-single-select-cell ${isOpen && active ? 'active' : ''}`" - :show-search="isOpen && active" + :show-search="!isMobileMode && isOpen && active" @select="onSelect" @keydown="onKeydown($event)" @search="search" @@ -324,7 +329,7 @@ const selectedOpt = computed(() => {
- Create new option named {{ searchVal }} + {{ $t('msg.selectOption.createNewOptionNamed') }} {{ searchVal }}
diff --git a/packages/nc-gui/components/cell/Text.vue b/packages/nc-gui/components/cell/Text.vue index 9fc0b9209e..e3ec8698a6 100644 --- a/packages/nc-gui/components/cell/Text.vue +++ b/packages/nc-gui/components/cell/Text.vue @@ -33,7 +33,10 @@ const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value :ref="focus" v-model="vModel" class="h-full w-full outline-none p-2 bg-transparent" - :placeholder="isEditColumn ? '(Optional)' : ''" + :placeholder="isEditColumn ? $t('labels.optional') : ''" + :class="{ + 'px-1': isExpandedFormOpen, + }" @blur="editEnabled = false" @keydown.down.stop @keydown.left.stop @@ -46,7 +49,7 @@ const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value @mousedown.stop /> - NULL + {{ $t('general.null') }} diff --git a/packages/nc-gui/components/cell/TextArea.vue b/packages/nc-gui/components/cell/TextArea.vue index 0ebd53ae86..6cf430bd22 100644 --- a/packages/nc-gui/components/cell/TextArea.vue +++ b/packages/nc-gui/components/cell/TextArea.vue @@ -28,6 +28,8 @@ const isEditColumn = inject(EditColumnInj, ref(false)) const rowHeight = inject(RowHeightInj, ref(1 as const)) +const isForm = inject(IsFormInj, ref(false)) + const { showNull } = useGlobal() const vModel = useVModel(props, 'modelValue', emits, { defaultValue: '' }) @@ -68,10 +70,11 @@ onClickOutside(inputWrapperRef, (e) => {