Browse Source

Merge branch 'develop' into qr-scanner-integration-3-2022-12-20

pull/4898/head
Daniel Spaude 2 years ago
parent
commit
53f6019550
No known key found for this signature in database
GPG Key ID: 654A3D1FA4F35FFE
  1. 2
      .github/workflows/pr-to-master.yml
  2. 98
      .github/workflows/release-executables.yml
  3. 21
      .github/workflows/release-nightly-dev.yml
  4. 4
      .github/workflows/release-npm.yml
  5. 76
      .github/workflows/release-pr.yml
  6. 4
      .github/workflows/update-sdk-path.yml
  7. 2
      charts/nocodb/.gitignore
  8. 23
      charts/nocodb/.helmignore
  9. 12
      charts/nocodb/Chart.yaml
  10. 22
      charts/nocodb/templates/NOTES.txt
  11. 82
      charts/nocodb/templates/_helpers.tpl
  12. 13
      charts/nocodb/templates/configmap.yaml
  13. 73
      charts/nocodb/templates/deployment.yaml
  14. 28
      charts/nocodb/templates/hpa.yaml
  15. 61
      charts/nocodb/templates/ingress.yaml
  16. 14
      charts/nocodb/templates/pvc.yaml
  17. 13
      charts/nocodb/templates/secret.yaml
  18. 15
      charts/nocodb/templates/service.yaml
  19. 12
      charts/nocodb/templates/serviceaccount.yaml
  20. 15
      charts/nocodb/templates/tests/test-connection.yaml
  21. 98
      charts/nocodb/values.yaml
  22. 27
      markdown/readme/languages/korean.md
  23. 2
      packages/nc-gui/components.d.ts
  24. 2
      packages/nc-gui/components/account/UserList.vue
  25. 2
      packages/nc-gui/components/cell/Checkbox.vue
  26. 13
      packages/nc-gui/components/cell/Currency.vue
  27. 8
      packages/nc-gui/components/cell/Json.vue
  28. 37
      packages/nc-gui/components/cell/MultiSelect.vue
  29. 13
      packages/nc-gui/components/cell/Percent.vue
  30. 39
      packages/nc-gui/components/cell/SingleSelect.vue
  31. 16
      packages/nc-gui/components/dashboard/settings/Modal.vue
  32. 3
      packages/nc-gui/components/shared-view/Grid.vue
  33. 11
      packages/nc-gui/components/smartsheet/Gallery.vue
  34. 8
      packages/nc-gui/components/smartsheet/Grid.vue
  35. 60
      packages/nc-gui/components/smartsheet/Kanban.vue
  36. 2
      packages/nc-gui/components/smartsheet/column/LookupOptions.vue
  37. 2
      packages/nc-gui/components/smartsheet/column/RollupOptions.vue
  38. 155
      packages/nc-gui/components/smartsheet/column/SelectOptions.vue
  39. 2
      packages/nc-gui/components/smartsheet/expanded-form/Header.vue
  40. 33
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  41. 51
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  42. 45
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  43. 13
      packages/nc-gui/components/smartsheet/toolbar/ShareView.vue
  44. 3
      packages/nc-gui/components/virtual-cell/Formula.vue
  45. 4
      packages/nc-gui/composables/useApi/interceptors.ts
  46. 2
      packages/nc-gui/composables/useGlobal/actions.ts
  47. 15
      packages/nc-gui/composables/useKanbanViewStore.ts
  48. 3
      packages/nc-gui/composables/useMultiSelect/index.ts
  49. 13
      packages/nc-gui/composables/useSharedFormViewStore.ts
  50. 42
      packages/nc-gui/composables/useSharedView.ts
  51. 4
      packages/nc-gui/composables/useTable.ts
  52. 61
      packages/nc-gui/composables/useViewData.ts
  53. 8
      packages/nc-gui/lang/ar.json
  54. 8
      packages/nc-gui/lang/bn_IN.json
  55. 8
      packages/nc-gui/lang/cs.json
  56. 8
      packages/nc-gui/lang/da.json
  57. 11
      packages/nc-gui/lang/de.json
  58. 8
      packages/nc-gui/lang/en.json
  59. 8
      packages/nc-gui/lang/es.json
  60. 194
      packages/nc-gui/lang/eu.json
  61. 8
      packages/nc-gui/lang/fa.json
  62. 8
      packages/nc-gui/lang/fi.json
  63. 136
      packages/nc-gui/lang/fr.json
  64. 8
      packages/nc-gui/lang/he.json
  65. 8
      packages/nc-gui/lang/hi.json
  66. 8
      packages/nc-gui/lang/hr.json
  67. 8
      packages/nc-gui/lang/id.json
  68. 8
      packages/nc-gui/lang/it.json
  69. 8
      packages/nc-gui/lang/ja.json
  70. 8
      packages/nc-gui/lang/ko.json
  71. 8
      packages/nc-gui/lang/lv.json
  72. 8
      packages/nc-gui/lang/nl.json
  73. 8
      packages/nc-gui/lang/no.json
  74. 8
      packages/nc-gui/lang/pl.json
  75. 8
      packages/nc-gui/lang/pt.json
  76. 8
      packages/nc-gui/lang/pt_BR.json
  77. 8
      packages/nc-gui/lang/ru.json
  78. 8
      packages/nc-gui/lang/sk.json
  79. 8
      packages/nc-gui/lang/sl.json
  80. 8
      packages/nc-gui/lang/sv.json
  81. 8
      packages/nc-gui/lang/th.json
  82. 8
      packages/nc-gui/lang/tr.json
  83. 8
      packages/nc-gui/lang/uk.json
  84. 8
      packages/nc-gui/lang/vi.json
  85. 8
      packages/nc-gui/lang/zh-Hans.json
  86. 8
      packages/nc-gui/lang/zh-Hant.json
  87. 7
      packages/nc-gui/layouts/shared-view.vue
  88. 4
      packages/nc-gui/nuxt.config.ts
  89. 28
      packages/nc-gui/package-lock.json
  90. 8
      packages/nc-gui/pages/[projectType]/form/[viewId]/index/index.vue
  91. 50
      packages/nc-gui/utils/filterUtils.ts
  92. 4
      packages/nc-gui/utils/parsers/parserHelpers.ts
  93. 2
      packages/nc-lib-gui/package.json
  94. 24
      packages/nc-plugin/package-lock.json
  95. 4
      packages/noco-docs/content/en/developer-resources/rest-apis.md
  96. 27
      packages/noco-docs/content/en/setup-and-usages/account-settings.md
  97. 17
      packages/nocodb-sdk/package-lock.json
  98. 2
      packages/nocodb-sdk/package.json
  99. 20
      packages/nocodb-sdk/src/lib/Api.ts
  100. 17
      packages/nocodb-sdk/src/lib/formulaHelpers.ts
  101. Some files were not shown because too many files have changed in this diff Show More

2
.github/workflows/pr-to-master.yml

@ -55,7 +55,7 @@ jobs:
echo "Pull Request URL - ${{ steps.cpr.outputs.pr_url }}"
- name: automerge
if: ${{ github.event.inputs.targetEnv == 'PROD' || inputs.targetEnv == 'PROD' }}
uses: "pascalgn/automerge-action@v0.14.3"
uses: "pascalgn/automerge-action@v0.15.5"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PULL_REQUEST: "${{ steps.cpr.outputs.pr_number }}"

98
.github/workflows/release-executables.yml

@ -21,14 +21,6 @@ jobs:
build-executables:
runs-on: ubuntu-latest
steps:
# Get the latest draft release for asset upload url
- uses: cardinalby/git-get-release-action@v1
id: get_release
env:
GITHUB_TOKEN: ${{ secrets.NC_GITHUB_TOKEN }}
with:
latest: 1
draft: true
- uses: actions/checkout@v3
- name: Cache node modules
id: cache-npm
@ -107,54 +99,25 @@ jobs:
mv ./dist/Noco-macos-arm64 ./mac-dist/
mv ./dist/Noco-macos-x64 ./mac-dist/
- name: Upload win-arm64 build to asset
- name: Upload executables to asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: ./scripts/pkg-executable/dist/Noco-win-arm64.exe
asset_name: Noco-win-arm64.exe
asset_content_type: application/octet-stream
- name: Upload win-x64 build to asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: ./scripts/pkg-executable/dist/Noco-win-x64.exe
asset_name: Noco-win-x64.exe
asset_content_type: application/octet-stream
- name: Upload linux-arm64 build to asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: ./scripts/pkg-executable/dist/Noco-linux-arm64
asset_name: Noco-linux-arm64
asset_content_type: application/octet-stream
- name: Upload linux-x64 build to asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: ./scripts/pkg-executable/dist/Noco-linux-x64
asset_name: Noco-linux-x64
asset_content_type: application/octet-stream
draft: true
tag_name: ${{ github.event.inputs.tag || inputs.tag }}
files: |
./scripts/pkg-executable/dist/Noco-win-arm64.exe
./scripts/pkg-executable/dist/Noco-win-x64.exe
./scripts/pkg-executable/dist/Noco-linux-arm64
./scripts/pkg-executable/dist/Noco-linux-x64
- uses: actions/upload-artifact@master
with:
name: ${{ github.event.inputs.tag || inputs.tag }}
path: scripts/pkg-executable/mac-dist
retention-days: 1
outputs:
upload_url: ${{ steps.get_release.outputs.upload_url }}
sign-mac-executables:
runs-on: macos-latest
needs: build-executables
@ -205,40 +168,17 @@ jobs:
id: compress
- name: Upload macos-x64 build to asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.build-executables.outputs.upload_url }}
asset_path: ./scripts/pkg-executable/mac-dist/Noco-macos-x64
asset_name: Noco-macos-x64
asset_content_type: application/octet-stream
- name: Upload macos-arm64 build to asset
uses: actions/upload-release-asset@v1
- name: Upload macos executable to asset
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.build-executables.outputs.upload_url }}
asset_path: ./scripts/pkg-executable/mac-dist/Noco-macos-arm64
asset_name: Noco-macos-arm64
asset_content_type: application/octet-stream
- name: Upload macos compressed build(for homebrew) to asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.build-executables.outputs.upload_url }}
asset_path: ./scripts/pkg-executable/mac-dist/nocodb.tar.gz
asset_name: nocodb.tar.gz
asset_content_type: application/octet-stream
draft: true
tag_name: ${{ github.event.inputs.tag || inputs.tag }}
files: |
./scripts/pkg-executable/mac-dist/Noco-macos-x64
./scripts/pkg-executable/mac-dist/Noco-macos-arm64
./scripts/pkg-executable/mac-dist/nocodb.tar.gz
- name: Generate Homebrew Formula class and push
run: |
@ -267,7 +207,3 @@ jobs:
git commit ./Formula/nocodb.rb -m "Automatic publish"
git push

21
.github/workflows/release-nightly-dev.yml

@ -12,6 +12,11 @@ jobs:
set-tag:
runs-on: 'ubuntu-latest'
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 1
ref: ${{ github.ref }}
- name: set-tag
id: tag-step
run: |
@ -21,7 +26,7 @@ jobs:
TAG_NAME=${CURRENT_DATE}-${CURRENT_TIME}
IS_DAILY='Y'
# Get current version
CURRENT_VERSION=$(curl -fs https://docs.nocodb.com/releases | grep article | grep div | grep h2 | grep 'id\="[^"]*' -o | cut -c 5-)
CURRENT_VERSION=$(cat ./packages/nocodb/package.json | jq -r ".version")
# Set the tag
if [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then
IS_DAILY='N'
@ -49,13 +54,13 @@ jobs:
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:

4
.github/workflows/release-npm.yml

@ -68,7 +68,7 @@ jobs:
- name: Create Pull Request
if: ${{ github.event.inputs.targetEnv == 'PROD' || inputs.targetEnv == 'PROD' }}
id: cpr
uses: peter-evans/create-pull-request@v3
uses: peter-evans/create-pull-request@v4.2.3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -84,7 +84,7 @@ jobs:
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- name: automerge
if: ${{ github.event.inputs.targetEnv == 'PROD' || inputs.targetEnv == 'PROD' }}
uses: "pascalgn/automerge-action@v0.14.3"
uses: "pascalgn/automerge-action@v0.15.5"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PULL_REQUEST: "${{ steps.cpr.outputs.pull-request-number }}"

76
.github/workflows/release-pr.yml

@ -33,7 +33,7 @@ jobs:
# Get current PR number
PR_NUMBER=${{github.event.number}}
# Get current version
CURRENT_VERSION=$(curl -fs https://docs.nocodb.com/releases | grep article | grep div | grep h2 | grep 'id\="[^"]*' -o | cut -c 5-)
CURRENT_VERSION=$(curl -fs https://docs.nocodb.com/releases | grep article | grep div | grep h2 | grep 'id\="[^"]*' -o | cut -c 5- | cut -d\: -f1)
# Construct tag name
TAG_NAME=pr-${PR_NUMBER}-${CURRENT_DATE}-${CURRENT_TIME}
echo "TARGET_TAG=${TAG_NAME}" >> $GITHUB_OUTPUT
@ -72,14 +72,14 @@ jobs:
DOCKERHUB_TOKEN: "${{ secrets.DOCKERHUB_TOKEN }}"
# Build executables and publish to GitHub
release-executables:
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, release-npm]
uses: ./.github/workflows/release-timely-executables.yml
with:
tag: ${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}
secrets:
NC_GITHUB_TOKEN: "${{ secrets.NC_GITHUB_TOKEN }}"
# release-executables:
# 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, release-npm]
# uses: ./.github/workflows/release-timely-executables.yml
# with:
# tag: ${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}
# secrets:
# NC_GITHUB_TOKEN: "${{ secrets.NC_GITHUB_TOKEN }}"
# Add a comment for PR docker build
leave-comment:
@ -132,40 +132,40 @@ jobs:
retention-days: 2
# Add a comment for PR executable build
leave-executable-comment:
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'
needs: [release-executables, set-tag]
steps:
- uses: peter-evans/commit-comment@v2
with:
body: |
### Run Executables
# leave-executable-comment:
# 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'
# needs: [release-executables, set-tag]
# steps:
# - uses: peter-evans/commit-comment@v2
# with:
# body: |
# ### Run Executables
#### MacOS
# #### MacOS
```bash
mkdir -p ./${{ needs.set-tag.outputs.current_version }}/${{ needs.set-tag.outputs.target_tag }} && cd "$_" \
&& curl http://dl.nocodb.com/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}/Noco-macos-arm64 -o noco -L \
&& chmod +x noco \
&& ./noco
```
#### Linux
# ```bash
# mkdir -p ./${{ needs.set-tag.outputs.current_version }}/${{ needs.set-tag.outputs.target_tag }} && cd "$_" \
# && curl http://dl.nocodb.com/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}/Noco-macos-arm64 -o noco -L \
# && chmod +x noco \
# && ./noco
# ```
# #### Linux
```bash
mkdir -p ./${{ needs.set-tag.outputs.current_version }}/${{ needs.set-tag.outputs.target_tag }} && cd "$_" \
&& curl http://dl.nocodb.com/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}/Noco-linux-x64 -o noco -L \
&& chmod +x noco \
&& ./noco
```
#### Windows
# ```bash
# mkdir -p ./${{ needs.set-tag.outputs.current_version }}/${{ needs.set-tag.outputs.target_tag }} && cd "$_" \
# && curl http://dl.nocodb.com/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}/Noco-linux-x64 -o noco -L \
# && chmod +x noco \
# && ./noco
# ```
# #### Windows
```bash
iwr http://dl.nocodb.com/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}/Noco-win-arm64.exe
.\Noco-win-arm64.exe
```
# ```bash
# iwr http://dl.nocodb.com/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }}/Noco-win-arm64.exe
# .\Noco-win-arm64.exe
# ```
For executables visit [here](https://github.com/nocodb/nocodb-timely/releases/tag/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }})
# For executables visit [here](https://github.com/nocodb/nocodb-timely/releases/tag/${{ needs.set-tag.outputs.current_version }}-${{ needs.set-tag.outputs.target_tag }})
# delete the uffizzi preview created off of this PR
delete-uffizzi-preview:

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

@ -27,7 +27,7 @@ jobs:
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v3
uses: peter-evans/create-pull-request@v4.2.3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -41,7 +41,7 @@ jobs:
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- name: automerge
uses: "pascalgn/automerge-action@v0.14.3"
uses: "pascalgn/automerge-action@v0.15.5"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
PULL_REQUEST: "${{ steps.cpr.outputs.pull-request-number }}"

2
charts/nocodb/.gitignore vendored

@ -0,0 +1,2 @@
charts/
Chart.lock

23
charts/nocodb/.helmignore

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

12
charts/nocodb/Chart.yaml

@ -0,0 +1,12 @@
apiVersion: v2
appVersion: 0.100.2
dependencies:
- condition: postgresql.enabled
name: postgresql
repository: https://charts.bitnami.com/bitnami
version: ~11.6.6
description: A Helm chart for Kubernetes
maintainers: []
name: nocodb
type: application
version: 0.3.0

22
charts/nocodb/templates/NOTES.txt

@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "nocodb.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "nocodb.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "nocodb.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "nocodb.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

82
charts/nocodb/templates/_helpers.tpl

@ -0,0 +1,82 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "nocodb.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "nocodb.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "nocodb.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "nocodb.labels" -}}
helm.sh/chart: {{ include "nocodb.chart" . }}
{{ include "nocodb.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "nocodb.selectorLabels" -}}
app.kubernetes.io/name: {{ include "nocodb.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "nocodb.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "nocodb.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{- define "postgresHost" -}}
{{- printf "%s-postgresql" .Release.Name }}
{{- end }}
{{- define "postgresDatabase" -}}
{{- .Values.postgresql.auth.database }}
{{- end }}
{{- define "postgresUsername" -}}
{{- .Values.postgresql.auth.username }}
{{- end }}
{{- define "postgresPassword" -}}
{{- .Values.postgresql.auth.password }}
{{- end }}
{{- define "databaseUri" -}}
{{- printf "pg://%s:5432?u=%s&p=%s&d=%s" (include "postgresHost" .) (include "postgresUsername" .) (include "postgresPassword" .) (include "postgresDatabase" .) }}
{{- end }}

13
charts/nocodb/templates/configmap.yaml

@ -0,0 +1,13 @@
{{- if .Values.extraEnvs }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "nocodb.fullname" . }}
labels:
{{- include "nocodb.labels" . | nindent 4 }}
data:
{{- range $key, $value := .Values.extraEnvs }}
{{ $key }}: |-
{{- $value | nindent 4 }}
{{- end }}
{{- end }}

73
charts/nocodb/templates/deployment.yaml

@ -0,0 +1,73 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "nocodb.fullname" . }}
labels:
{{- include "nocodb.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "nocodb.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "nocodb.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "nocodb.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
volumeMounts:
- name: {{ include "nocodb.fullname" . }}
mountPath: /usr/app/data
envFrom:
- configMapRef:
name: {{ include "nocodb.fullname" . }}
- secretRef:
name: {{ include "nocodb.fullname" . }}
ports:
- name: http
containerPort: 8080
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: {{ include "nocodb.fullname" . }}
persistentVolumeClaim:
claimName: {{ include "nocodb.fullname" . }}

28
charts/nocodb/templates/hpa.yaml

@ -0,0 +1,28 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "nocodb.fullname" . }}
labels:
{{- include "nocodb.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "nocodb.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

61
charts/nocodb/templates/ingress.yaml

@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "nocodb.fullname" . -}}
{{- $svcPort := .Values.ingress.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "nocodb.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

14
charts/nocodb/templates/pvc.yaml

@ -0,0 +1,14 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "nocodb.fullname" . }}
labels:
{{- include "nocodb.selectorLabels" . | nindent 8 }}
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: {{ .Values.storage.size }}
storageClassName: {{ .Values.storage.storageClassName }}
volumeMode: Filesystem

13
charts/nocodb/templates/secret.yaml

@ -0,0 +1,13 @@
{{- if .Values.extraSecretEnvs }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "nocodb.fullname" . }}
labels:
{{- include "nocodb.labels" . | nindent 4 }}
data:
NC_DB: {{ include "databaseUri" . | b64enc}}
{{- range $key, $value := .Values.extraSecretEnvs }}
{{ $key }}: '{{ $value | b64enc }}'
{{- end }}
{{- end }}

15
charts/nocodb/templates/service.yaml

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "nocodb.fullname" . }}
labels:
{{- include "nocodb.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "nocodb.selectorLabels" . | nindent 4 }}

12
charts/nocodb/templates/serviceaccount.yaml

@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "nocodb.serviceAccountName" . }}
labels:
{{- include "nocodb.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

15
charts/nocodb/templates/tests/test-connection.yaml

@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "nocodb.fullname" . }}-test-connection"
labels:
{{- include "nocodb.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "nocodb.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

98
charts/nocodb/values.yaml

@ -0,0 +1,98 @@
# Default values for nocodb.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: nocodb/nocodb
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: false
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 8080
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
extraEnvs:
NC_PUBLIC_URL: https:/nocodb.local.org
extraSecretEnvs:
NC_AUTH_JWT_SECRET: secretString
storage:
size: 3Gi
storageClassName: ""
postgresql:
enabled: false
auth:
database: nocodb
username: nocodb
password: secretPass
persistence:
size: 8Gi

27
markdown/readme/languages/korean.md

@ -6,7 +6,7 @@
</h1>
<p align="center">
MySQL, PostgreSQL, SQL Server, SQLite, MariaDB를 똑똑한 스프레드시트로 바꿔줍니다.
MySQL, PostgreSQL, SQL Server, SQLite, MariaDB를 스마트 스프레드시트로 바꿔줍니다.
</p>
<div align="center">
@ -32,7 +32,7 @@ MySQL, PostgreSQL, SQL Server, SQLite, MariaDB를 똑똑한 스프레드시트
<a href="https://www.producthunt.com/posts/nocodb?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-nocodb" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=297536&theme=dark" alt="NocoDB - The Open Source Airtable alternative | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
</p>
# 바로 써보기
# 빠른 시도
### Docker 사용
@ -65,7 +65,7 @@ npm start
### GUI
대시보드 접근하기 : [http://localhost:8080/dashboard](http://localhost:8080/dashboard)
대시보드 접근 : [http://localhost:8080/dashboard](http://localhost:8080/dashboard)
# 커뮤니티 가입
@ -114,18 +114,17 @@ npm start
# 기능
### 스프레드시트같은 인터페이스
### 스프레드시트 인터페이스
- ⚡ 정말 쉬운 검색, 정렬, 필터링, 열 숨기기
- ⚡ 뷰 만들기: 그리드, 갤러리, 칸반, 간트 차트, 양식
- ⚡ 뷰 공유하기: 완전 공개, 패스워드 걸고 공개
- ⚡ 개인화하거나 잠글 수 있는 뷰
- ⚡ 이미지를 자신의 공간에 업로드 (S3, Minio, GCP, Azure, Digitalocean, Linode, OVH, Backblaze 등)
- ⚡ 역할 부여: 소유자, 작성자, 편집자, 보기 전용, 의견 제시만, 원하는 대로
- ⚡ 접근 통제: 데이터베이스, 테이블 및 열 수준까지도 상세한 통제 가능
- ⚡ 기본 오퍼레이션: 테이블, 칼럼, 로우 CRUD
- ⚡ 필드 오퍼레이션: 정렬, 필터, 칼럼 보기/숨기기
- ⚡ 뷰 타입: 그리드, 갤러리, 칸반, 간트 차트, 양식(Form)
- ⚡ 공유: 공개 / 비공개 뷰 (비밀 번호 설정)
- ⚡ 다양한 셀 타입: ID, LinkToAnotherRecord, Lookup, Rollup, SingleLine Text, Attachment, Currency, Formula 등
- ⚡ 역할에 따른 접근 제한: 다양한 수준의 세분화된 액세스 제어
### 워크플로 자동화를 위한 앱스토어
크게 채팅, 이메일, 저장소 세 가지 카테고리에 대한 통합을 제공합니다. 자세한 사항은 <a href="https://docs.nocodb.com/setup-and-usages/app-store" target="_blank">App Store</a> 를 참고하세요.
- ⚡ 채팅: MS 팀즈, 슬랙, 디스코드, 매터모스트
- ⚡ 이메일: SMTP, SES, MailChimp
- ⚡ SMS: Twilio
@ -188,12 +187,12 @@ docker-compose up -d
여기서 확인해주세요.
[환경변수 ](https://docs.nocodb.com/getting-started/installation#environment-variables)
# 개발 환경에 설치하기
# 개발 환경에 설치
여기서 확인해주세요.
[개발 환경에 설치하는 법](https://docs.nocodb.com/engineering/development-setup)
# 기여하기
# 기여
여기서 확인해주세요.
[기여 가이드라인](https://github.com/nocodb/nocodb/blob/master/.github/CONTRIBUTING.md).

2
packages/nc-gui/components.d.ts vendored

@ -126,6 +126,7 @@ declare module '@vue/runtime-core' {
MdiArrowDownDropCircleOutline: typeof import('~icons/mdi/arrow-down-drop-circle-outline')['default']
MdiArrowExpand: typeof import('~icons/mdi/arrow-expand')['default']
MdiArrowLeftBold: typeof import('~icons/mdi/arrow-left-bold')['default']
MdiArrowULeftBottom: typeof import('~icons/mdi/arrow-u-left-bottom')['default']
MdiAt: typeof import('~icons/mdi/at')['default']
MdiBackburger: typeof import('~icons/mdi/backburger')['default']
MdiBookOpenOutline: typeof import('~icons/mdi/book-open-outline')['default']
@ -139,6 +140,7 @@ declare module '@vue/runtime-core' {
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']
MdiClose: typeof import('~icons/mdi/close')['default']
MdiCloseBox: typeof import('~icons/mdi/close-box')['default']
MdiCloseCircle: typeof import('~icons/mdi/close-circle')['default']

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

@ -71,7 +71,7 @@ const deleteUser = async (userId: string) => {
Modal.confirm({
title: 'Are you sure you want to delete this user?',
type: 'warn',
content: 'On deleting, user will remove from organization and any sync source(Airtable) created by user will get removed',
content: 'Upon deletion, the user will be removed from the installation.',
onOk: async () => {
try {
await api.orgUsers.delete(userId)

2
packages/nc-gui/components/cell/Checkbox.vue

@ -65,7 +65,7 @@ useSelectedCellKeyupListener(active, (e) => {
<div
class="flex cursor-pointer"
:class="{
'justify-center': !isForm && !readOnly,
'justify-center': !isForm,
'w-full': isForm,
'nc-cell-hover-show': !vModel && !readOnly,
'opacity-0': readOnly && !vModel,

13
packages/nc-gui/components/cell/Currency.vue

@ -14,7 +14,18 @@ const column = inject(ColumnInj)!
const editEnabled = inject(EditModeInj)!
const vModel = useVModel(props, 'modelValue', emit)
const _vModel = useVModel(props, 'modelValue', emit)
const vModel = computed({
get: () => _vModel.value,
set: (value: unknown) => {
if (value === '') {
_vModel.value = null
} else {
_vModel.value = value as number
}
},
})
const lastSaved = ref()

8
packages/nc-gui/components/cell/Json.vue

@ -123,8 +123,8 @@ useSelectedCellKeyupListener(active, (e) => {
<template>
<component :is="isExpanded ? AModal : 'div'" v-model:visible="isExpanded" :closable="false" centered :footer="null">
<div v-if="editEnabled && !readonly" class="flex flex-col w-full">
<div class="flex flex-row justify-between pt-1 pb-2">
<div v-if="editEnabled && !readonly" class="flex flex-col w-full" @mousedown.stop @mouseup.stop @click.stop>
<div class="flex flex-row justify-between pt-1 pb-2" @mousedown.stop>
<a-button type="text" size="small" @click="isExpanded = !isExpanded">
<CilFullscreenExit v-if="isExpanded" class="h-2.5" />
@ -134,8 +134,8 @@ useSelectedCellKeyupListener(active, (e) => {
<div v-if="!isForm || isExpanded" class="flex flex-row">
<a-button type="text" size="small" :onclick="clear"><div class="text-xs">Cancel</div></a-button>
<a-button type="primary" size="small" :disabled="!!error || localValue === vModel">
<div class="text-xs" @click="onSave">Save</div>
<a-button type="primary" size="small" :disabled="!!error || localValue === vModel" @click="onSave">
<div class="text-xs">Save</div>
</a-button>
</div>
</div>

37
packages/nc-gui/components/cell/MultiSelect.vue

@ -19,6 +19,7 @@ import {
useEventListener,
useMetas,
useProject,
useRoles,
useSelectedCellKeyupListener,
watch,
} from '#imports'
@ -57,6 +58,8 @@ const { $api } = useNuxtApp()
const { getMeta } = useMetas()
const { hasRole } = useRoles()
const { isPg, isMysql } = useProject()
// a variable to keep newly created options value
@ -80,6 +83,10 @@ const isOptionMissing = computed(() => {
return (options.value ?? []).every((op) => op.title !== searchVal.value)
})
const hasEditRoles = computed(() => hasRole('owner', true) || hasRole('creator', true) || hasRole('editor', true))
const editAllowed = computed(() => hasEditRoles.value && (active.value || editable.value))
const vModel = computed({
get: () => {
const selected = selectedIds.value.reduce((acc, id) => {
@ -154,10 +161,12 @@ watch(
)
watch(isOpen, (n, _o) => {
if (!n) {
aselect.value?.$el?.querySelector('input')?.blur()
} else {
aselect.value?.$el?.querySelector('input')?.focus()
if (editAllowed.value) {
if (!n) {
aselect.value?.$el?.querySelector('input')?.blur()
} else {
aselect.value?.$el?.querySelector('input')?.focus()
}
}
})
@ -167,7 +176,7 @@ useSelectedCellKeyupListener(active, (e) => {
isOpen.value = false
break
case 'Enter':
if (active.value && !isOpen.value) {
if (editAllowed.value && active.value && !isOpen.value) {
isOpen.value = true
}
break
@ -179,6 +188,10 @@ useSelectedCellKeyupListener(active, (e) => {
// skip
break
default:
if (!editAllowed.value) {
e.preventDefault()
break
}
// toggle only if char key pressed
if (!(e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) && e.key?.length === 1) {
e.stopPropagation()
@ -272,14 +285,14 @@ const onTagClick = (e: Event, onClose: Function) => {
:bordered="false"
clear-icon
show-search
:show-arrow="!readOnly"
:show-arrow="hasEditRoles && !readOnly && (editable || (active && vModel.length === 0))"
:open="isOpen && (active || editable)"
:disabled="readOnly"
:class="{ '!ml-[-8px]': readOnly }"
:class="{ '!ml-[-8px]': readOnly, 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-multi-select-cell ${isOpen ? 'active' : ''}`"
@search="search"
@keydown.stop
@click="isOpen = (active || editable) && !isOpen"
@click="isOpen = editAllowed && !isOpen"
>
<a-select-option
v-for="op of options"
@ -303,7 +316,11 @@ const onTagClick = (e: Event, onClose: Function) => {
</a-tag>
</a-select-option>
<a-select-option v-if="searchVal && isOptionMissing && !isPublic" :key="searchVal" :value="searchVal">
<a-select-option
v-if="searchVal && isOptionMissing && !isPublic && (hasRole('owner', true) || hasRole('creator', true))"
:key="searchVal"
:value="searchVal"
>
<div class="flex gap-2 text-gray-500 items-center h-full">
<MdiPlusThick class="min-w-4" />
<div class="text-xs whitespace-normal">
@ -318,7 +335,7 @@ const onTagClick = (e: Event, onClose: Function) => {
class="rounded-tag nc-selected-option"
:style="{ display: 'flex', alignItems: 'center' }"
:color="options.find((el) => el.title === val)?.color"
:closable="(active || editable) && (vModel.length > 1 || !column?.rqd)"
:closable="editAllowed && (active || editable) && (vModel.length > 1 || !column?.rqd)"
:close-icon="h(MdiCloseCircle, { class: ['ms-close-icon'] })"
@click="onTagClick($event, onClose)"
@close="onClose"

13
packages/nc-gui/components/cell/Percent.vue

@ -12,7 +12,18 @@ const emits = defineEmits(['update:modelValue'])
const editEnabled = inject(EditModeInj)
const vModel = useVModel(props, 'modelValue', emits)
const _vModel = useVModel(props, 'modelValue', emits)
const vModel = computed({
get: () => _vModel.value,
set: (value) => {
if (value === '') {
_vModel.value = null
} else {
_vModel.value = value
}
},
})
const focus: VNodeRef = (el) => {
;(el as HTMLInputElement)?.focus()

39
packages/nc-gui/components/cell/SingleSelect.vue

@ -14,6 +14,7 @@ import {
extractSdkResponseErrorMsg,
inject,
ref,
useRoles,
useSelectedCellKeyupListener,
watch,
} from '#imports'
@ -49,6 +50,8 @@ const searchVal = ref()
const { getMeta } = useMetas()
const { hasRole } = useRoles()
const { isPg, isMysql } = useProject()
// a variable to keep newly created option value
@ -73,6 +76,10 @@ const isOptionMissing = computed(() => {
return (options.value ?? []).every((op) => op.title !== searchVal.value)
})
const hasEditRoles = computed(() => hasRole('owner', true) || hasRole('creator', true) || hasRole('editor', true))
const editAllowed = computed(() => hasEditRoles.value && (active.value || editable.value))
const vModel = computed({
get: () => tempSelectedOptState.value ?? modelValue,
set: (val) => {
@ -87,10 +94,12 @@ const vModel = computed({
})
watch(isOpen, (n, _o) => {
if (!n) {
aselect.value?.$el?.querySelector('input')?.blur()
} else {
aselect.value?.$el?.querySelector('input')?.focus()
if (editAllowed.value) {
if (!n) {
aselect.value?.$el?.querySelector('input')?.blur()
} else {
aselect.value?.$el?.querySelector('input')?.focus()
}
}
})
@ -100,11 +109,15 @@ useSelectedCellKeyupListener(active, (e) => {
isOpen.value = false
break
case 'Enter':
if (active.value && !isOpen.value) {
if (editAllowed.value && active.value && !isOpen.value) {
isOpen.value = true
}
break
default:
if (!editAllowed.value) {
e.preventDefault()
break
}
// toggle only if char key pressed
if (!(e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) && e.key?.length === 1) {
e.stopPropagation()
@ -174,7 +187,7 @@ const toggleMenu = (e: Event) => {
vModel.value = ''
return
}
isOpen.value = (active.value || editable.value) && !isOpen.value
isOpen.value = editAllowed.value && !isOpen.value
}
</script>
@ -183,11 +196,12 @@ const toggleMenu = (e: Event) => {
ref="aselect"
v-model:value="vModel"
class="w-full"
:allow-clear="!column.rqd && active"
:class="{ 'caret-transparent': !hasEditRoles }"
:allow-clear="!column.rqd && editAllowed"
:bordered="false"
:open="isOpen && (active || editable)"
:open="isOpen"
:disabled="readOnly"
:show-arrow="!readOnly && (active || editable || vModel === null)"
:show-arrow="hasEditRoles && !readOnly && (editable || (active && vModel === null))"
:dropdown-class-name="`nc-dropdown-single-select-cell ${isOpen ? 'active' : ''}`"
show-search
@select="isOpen = false"
@ -216,8 +230,11 @@ const toggleMenu = (e: Event) => {
</span>
</a-tag>
</a-select-option>
<a-select-option v-if="searchVal && isOptionMissing && !isPublic" :key="searchVal" :value="searchVal">
<a-select-option
v-if="searchVal && isOptionMissing && !isPublic && (hasRole('owner', true) || hasRole('creator', true))"
:key="searchVal"
:value="searchVal"
>
<div class="flex gap-2 text-gray-500 items-center h-full">
<MdiPlusThick class="min-w-4" />
<div class="text-xs whitespace-normal">

16
packages/nc-gui/components/dashboard/settings/Modal.vue

@ -1,10 +1,8 @@
<script setup lang="ts">
import type { FunctionalComponent, SVGAttributes } from 'vue'
import AppStore from './AppStore.vue'
import DataSources from './DataSources.vue'
import Misc from './Misc.vue'
import { DataSourcesSubTab, useI18n, useNuxtApp, useUIPermission, useVModel, watch } from '#imports'
import StoreFrontOutline from '~icons/mdi/storefront-outline'
import TeamFillIcon from '~icons/ri/team-fill'
import MultipleTableIcon from '~icons/mdi/table-multiple'
import NotebookOutline from '~icons/mdi/notebook-outline'
@ -81,20 +79,6 @@ const tabsInfo: TabGroup = {
$e('c:settings:team-auth')
},
},
appStore: {
// App Store
title: t('title.appStore'),
icon: StoreFrontOutline,
subTabs: {
new: {
title: 'Apps',
body: AppStore,
},
},
onClick: () => {
$e('c:settings:appstore')
},
},
dataSources: {
// Data Sources
title: 'Data Sources',

3
packages/nc-gui/components/shared-view/Grid.vue

@ -23,7 +23,7 @@ const { signedIn } = useGlobal()
const { loadProject } = useProject()
useProvideSmartsheetStore(sharedView, meta, true, sorts, nestedFilters)
const { isLocked } = useProvideSmartsheetStore(sharedView, meta, true, sorts, nestedFilters)
const reloadEventHook = createEventHook()
@ -33,6 +33,7 @@ provide(MetaInj, meta)
provide(ActiveViewInj, sharedView)
provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
provide(IsLockedInj, isLocked)
if (signedIn.value) {
try {

11
packages/nc-gui/components/smartsheet/Gallery.vue

@ -8,6 +8,7 @@ import {
IsGalleryInj,
IsGridInj,
MetaInj,
NavigateDir,
OpenNewRecordFormHookInj,
PaginationDataInj,
ReloadRowDataHookInj,
@ -17,6 +18,7 @@ import {
createEventHook,
extractPkFromRow,
inject,
isLTAR,
nextTick,
onMounted,
provide,
@ -47,6 +49,7 @@ const {
galleryData,
changePage,
addEmptyRow,
navigateToSiblingRow,
} = useViewData(meta, view)
provide(IsFormInj, ref(false))
@ -210,7 +213,10 @@ watch(view, async (nextView) => {
</template>
<div v-for="col in fieldsWithoutCover" :key="`record-${record.row.id}-${col.id}`">
<div v-if="!isRowEmpty(record, col)" class="flex flex-col space-y-1 px-4 mb-6 bg-gray-50 rounded-lg w-full">
<div
v-if="!isRowEmpty(record, col) || isLTAR(col.uidt)"
class="flex flex-col space-y-1 px-4 mb-6 bg-gray-50 rounded-lg w-full"
>
<div class="flex flex-row w-full justify-start border-b-1 border-gray-100 py-2.5">
<div class="w-full text-gray-600">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" :hide-menu="true" />
@ -266,6 +272,9 @@ watch(view, async (nextView) => {
:meta="meta"
:row-id="route.query.rowId"
:view="view"
show-next-prev-icons
@next="navigateToSiblingRow(NavigateDir.NEXT)"
@prev="navigateToSiblingRow(NavigateDir.PREV)"
/>
</Suspense>
</div>

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

@ -117,6 +117,7 @@ const {
deleteSelectedRows,
selectedAllRecords,
removeRowIfNew,
navigateToSiblingRow,
} = useViewData(meta, view, xWhere)
const { getMeta } = useMetas()
@ -201,7 +202,7 @@ const { isCellSelected, activeCell, handleMouseDown, handleMouseOver, handleCell
const cmdOrCtrl = isMac() ? e.metaKey : e.ctrlKey
const altOrOptionKey = e.altKey
if (e.key === ' ') {
if (activeCell.row != null && !editEnabled) {
if (activeCell.row != null && !editEnabled && hasEditPermission) {
e.preventDefault()
clearSelectedRange()
const row = data.value[activeCell.row]
@ -805,6 +806,7 @@ const closeAddColumnDropdown = () => {
:column="columnObj"
:active="activeCell.col === colIndex && activeCell.row === rowIndex"
:row="row"
:read-only="readOnly"
@navigate="onNavigate"
/>
@ -817,6 +819,7 @@ const closeAddColumnDropdown = () => {
"
:row-index="rowIndex"
:active="activeCell.col === colIndex && activeCell.row === rowIndex"
:read-only="readOnly"
@update:edit-enabled="editEnabled = $event"
@save="updateOrSaveRow(row, columnObj.title, state)"
@navigate="onNavigate"
@ -916,6 +919,9 @@ const closeAddColumnDropdown = () => {
:meta="meta"
:row-id="routeQuery.rowId"
:view="view"
show-next-prev-icons
@next="navigateToSiblingRow(NavigateDir.NEXT)"
@prev="navigateToSiblingRow(NavigateDir.PREV)"
/>
</Suspense>
</div>

60
packages/nc-gui/components/smartsheet/Kanban.vue

@ -13,6 +13,7 @@ import {
MetaInj,
OpenNewRecordFormHookInj,
inject,
isLTAR,
onBeforeMount,
onBeforeUnmount,
provide,
@ -472,35 +473,40 @@ watch(view, async (nextView) => {
:key="`record-${record.row.id}-${col.id}`"
class="flex flex-col rounded-lg w-full"
>
<!-- Smartsheet Header (Virtual) Cell -->
<div v-if="!isRowEmpty(record, col)" class="flex flex-row w-full justify-start pt-2">
<div class="w-full text-gray-400">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" :hide-menu="true" />
<LazySmartsheetHeaderCell v-else :column="col" :hide-menu="true" />
<div v-if="!isRowEmpty(record, col) || isLTAR(col.uidt)">
<!-- Smartsheet Header (Virtual) Cell -->
<div class="flex flex-row w-full justify-start pt-2">
<div class="w-full text-gray-400">
<LazySmartsheetHeaderVirtualCell
v-if="isVirtualCol(col)"
:column="col"
:hide-menu="true"
/>
<LazySmartsheetHeaderCell v-else :column="col" :hide-menu="true" />
</div>
</div>
</div>
<!-- Smartsheet (Virtual) Cell -->
<div
v-if="!isRowEmpty(record, col)"
class="flex flex-row w-full items-center justify-start pl-[6px]"
:class="{ '!ml-[-12px]': col.uidt === UITypes.SingleSelect }"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(col)"
v-model="record.row[col.title]"
class="text-sm pt-1"
:column="col"
:row="record"
/>
<LazySmartsheetCell
v-else
v-model="record.row[col.title]"
class="text-sm pt-1"
:column="col"
:edit-enabled="false"
:read-only="true"
/>
<!-- Smartsheet (Virtual) Cell -->
<div
class="flex flex-row w-full items-center justify-start pl-[6px]"
:class="{ '!ml-[-12px]': col.uidt === UITypes.SingleSelect }"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(col)"
v-model="record.row[col.title]"
class="text-sm pt-1"
:column="col"
:row="record"
/>
<LazySmartsheetCell
v-else
v-model="record.row[col.title]"
class="text-sm pt-1"
:column="col"
:edit-enabled="false"
:read-only="true"
/>
</div>
</div>
</div>
</a-card>

2
packages/nc-gui/components/smartsheet/column/LookupOptions.vue

@ -56,7 +56,7 @@ const columns = $computed<ColumnType[]>(() => {
<template>
<div class="p-6 w-full flex flex-col border-2 mb-2 mt-4">
<div class="w-full flex flex-row space-x-2">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.childTable')" v-bind="validateInfos.fk_relation_column_id">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.linkToAnotherRecord')" v-bind="validateInfos.fk_relation_column_id">
<a-select
v-model:value="vModel.fk_relation_column_id"
dropdown-class-name="!w-64 nc-dropdown-relation-table"

2
packages/nc-gui/components/smartsheet/column/RollupOptions.vue

@ -76,7 +76,7 @@ const columns = $computed(() => {
<template>
<div class="p-6 w-full flex flex-col border-2 mb-2 mt-4">
<div class="w-full flex flex-row space-x-2">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.childTable')" v-bind="validateInfos.fk_relation_column_id">
<a-form-item class="flex w-1/2 pb-2" :label="$t('labels.linkToAnotherRecord')" v-bind="validateInfos.fk_relation_column_id">
<a-select
v-model:value="vModel.fk_relation_column_id"
dropdown-class-name="!w-64 nc-dropdown-relation-table"

155
packages/nc-gui/components/smartsheet/column/SelectOptions.vue

@ -3,6 +3,14 @@ import Draggable from 'vuedraggable'
import { UITypes } from 'nocodb-sdk'
import { IsKanbanInj, enumColor, onMounted, useColumnCreateStoreOrThrow, useVModel, watch } from '#imports'
interface Option {
color: string
title: string
id?: string
fk_colum_id?: string
order?: number
}
const props = defineProps<{
value: any
}>()
@ -13,7 +21,10 @@ const vModel = useVModel(props, 'value', emit)
const { setAdditionalValidations, validateInfos, isPg, isMysql } = useColumnCreateStoreOrThrow()
let options = $ref<any[]>([])
let options = $ref<Option[]>([])
let renderedOptions = $ref<(Option & { status?: 'remove' })[]>([])
let savedDefaultOption = $ref<Option | null>(null)
let savedCdf = $ref<string | null>(null)
const colorMenus = $ref<any>({})
@ -58,6 +69,9 @@ onMounted(() => {
}
}
options = vModel.value.colOptions.options
renderedOptions = [...options]
// Support for older options
for (const op of options.filter((el) => el.order === null)) {
op.title = op.title.replace(/^'/, '').replace(/'$/, '')
@ -87,13 +101,6 @@ const optionChanged = (changedId: string) => {
}
}
const optionDropped = (changedId: string) => {
if (changedId && changedId === defaultOption.value?.id) {
vModel.value.cdf = null
defaultOption.value = null
}
}
const getNextColor = () => {
let tempColor = colors[0]
if (options.length && options[options.length - 1].color) {
@ -108,13 +115,40 @@ const addNewOption = () => {
title: '',
color: getNextColor(),
}
renderedOptions.push(tempOption)
options.push(tempOption)
}
const removeOption = (index: number) => {
const optionId = options[index]?.id
options.splice(index, 1)
optionDropped(optionId)
const syncOptions = () => {
vModel.value.colOptions.options = renderedOptions.filter((op) => op.status !== 'remove')
}
const removeRenderedOption = (index: number) => {
renderedOptions[index].status = 'remove'
syncOptions()
const optionId = renderedOptions[index]?.id
if (optionId === defaultOption.value?.id) {
savedDefaultOption = { ...defaultOption.value }
savedCdf = vModel.value.cdf
defaultOption.value = null
vModel.value.cdf = null
}
}
const undoRemoveRenderedOption = (index: number) => {
renderedOptions[index].status = undefined
syncOptions()
const optionId = renderedOptions[index]?.id
if (optionId === savedDefaultOption?.id) {
defaultOption.value = { ...savedDefaultOption }
vModel.value.cdf = savedCdf
savedDefaultOption = null
savedCdf = null
}
}
// focus last created input
@ -128,47 +162,62 @@ watch(inputs, () => {
<template>
<div class="w-full">
<div class="max-h-[250px] overflow-x-auto scrollbar-thin-dull pr-3">
<Draggable :list="options" item-key="id" handle=".nc-child-draggable-icon">
<Draggable :list="renderedOptions" item-key="id" handle=".nc-child-draggable-icon" @change="syncOptions">
<template #item="{ element, index }">
<div class="flex py-1 items-center nc-select-option">
<MdiDragVertical
v-if="!isKanban"
small
class="nc-child-draggable-icon handle"
:data-testid="`select-option-column-handle-icon-${element.title}`"
/>
<a-dropdown
v-model:visible="colorMenus[index]"
:trigger="['click']"
overlay-class-name="nc-dropdown-select-color-options"
<div class="flex p-1 items-center nc-select-option">
<div
class="flex items-center w-full"
:data-testid="`select-column-option-${index}`"
:class="{ removed: element.status === 'remove' }"
>
<template #overlay>
<LazyGeneralColorPicker
v-model="element.color"
:pick-button="true"
@update:model-value="colorMenus[index] = false"
<MdiDragVertical
v-if="!isKanban"
small
class="nc-child-draggable-icon handle"
:data-testid="`select-option-column-handle-icon-${element.title}`"
/>
<a-dropdown
v-model:visible="colorMenus[index]"
:trigger="['click']"
overlay-class-name="nc-dropdown-select-color-options"
>
<template #overlay>
<LazyGeneralColorPicker
v-model="element.color"
:pick-button="true"
@update:model-value="colorMenus[index] = false"
/>
</template>
<MdiArrowDownDropCircle
class="mr-2 text-[1.5em] outline-0 hover:!text-[1.75em]"
:class="{ 'text-[1.75em]': colorMenus[index] }"
:style="{ color: element.color }"
/>
</template>
<MdiArrowDownDropCircle
class="mr-2 text-[1.5em] outline-0 hover:!text-[1.75em]"
:class="{ 'text-[1.75em]': colorMenus[index] }"
:style="{ color: element.color }"
</a-dropdown>
<a-input
ref="inputs"
v-model:value="element.title"
class="caption"
:data-testid="`select-column-option-input-${index}`"
:disabled="element.status === 'remove'"
@keydown.enter.prevent="element.title?.trim() && addNewOption()"
@change="optionChanged(element.id)"
/>
</a-dropdown>
<a-input
ref="inputs"
v-model:value="element.title"
class="caption"
:data-testid="`select-column-option-input-${index}`"
@keydown.enter.prevent="element.title?.trim() && addNewOption()"
@change="optionChanged(element.id)"
/>
</div>
<MdiClose
v-if="element.status !== 'remove'"
class="ml-2 hover:!text-black-500 text-gray-500 cursor-pointer"
:data-testid="`select-column-option-remove-${index}`"
@click="removeOption(index)"
@click="removeRenderedOption(index)"
/>
<MdiArrowULeftBottom
v-else
class="ml-2 hover:!text-black-500 text-gray-500 cursor-pointer"
:data-testid="`select-column-option-remove-undo-${index}`"
@click="undoRemoveRenderedOption(index)"
/>
</div>
</template>
@ -186,3 +235,19 @@ watch(inputs, () => {
</a-button>
</div>
</template>
<style scoped>
.removed {
position: relative;
}
.removed:after {
position: absolute;
left: 0;
top: 50%;
height: 1px;
background: #ccc;
content: '';
width: calc(100% + 5px);
display: block;
}
</style>

2
packages/nc-gui/components/smartsheet/expanded-form/Header.vue

@ -204,5 +204,3 @@ const onConfirmDeleteRowClick = async () => {
</a-dropdown-button>
</div>
</template>
<style scoped></style>

33
packages/nc-gui/components/smartsheet/expanded-form/index.vue

@ -32,11 +32,12 @@ interface Props {
useMetaFields?: boolean
rowId?: string
view?: ViewType
showNextPrevIcons?: boolean
}
const props = defineProps<Props>()
const emits = defineEmits(['update:modelValue', 'cancel'])
const emits = defineEmits(['update:modelValue', 'cancel', 'next', 'prev'])
const row = ref(props.row)
@ -164,7 +165,7 @@ export default {
<a-drawer
v-model:visible="isExpanded"
:footer="null"
width="min(90vw,1000px)"
width="min(90vw,800px)"
:body-style="{ 'padding': 0, 'display': 'flex', 'flex-direction': 'column' }"
:closable="false"
class="nc-drawer-expanded-form"
@ -172,7 +173,22 @@ export default {
>
<SmartsheetExpandedFormHeader :view="props.view" @cancel="onClose" @duplicateRow="onDuplicateRow" />
<div class="!bg-gray-100 rounded flex-1">
<div class="!bg-gray-100 rounded flex-1 relative">
<template v-if="props.showNextPrevIcons">
<a-tooltip placement="bottom">
<template #title>
{{ $t('labels.nextRow') }}
</template>
<MdiChevronRight class="cursor-pointer nc-next-arrow" @click="$emit('next')" />
</a-tooltip>
<a-tooltip placement="bottom">
<template #title>
{{ $t('labels.prevRow') }}
</template>
<MdiChevronLeft class="cursor-pointer nc-prev-arrow" @click="$emit('prev')" />
</a-tooltip>
</template>
<div class="flex h-full nc-form-wrapper items-stretch min-h-[max(70vh,100%)]">
<div class="flex-1 overflow-auto scrollbar-thin-dull nc-form-fields-container">
<div class="w-[500px] mx-auto">
@ -241,4 +257,15 @@ export default {
max-height: max(calc(100vh - 65px), 600px);
height: max-content !important;
}
.nc-prev-arrow,
.nc-next-arrow {
@apply absolute opacity-70 rounded-full transition-transform transition-background transition-opacity transform bg-white hover:(bg-gray-200) active:(scale-125 opacity-100) text-xl;
}
.nc-prev-arrow {
@apply left-4 top-4;
}
.nc-next-arrow {
@apply right-4 top-4;
}
</style>

51
packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue

@ -1,6 +1,5 @@
<script setup lang="ts">
import type { FilterType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import {
ActiveViewInj,
MetaInj,
@ -70,15 +69,7 @@ const types = computed(() => {
}
return meta.value?.columns?.reduce((obj: any, col: any) => {
switch (col.uidt) {
case UITypes.Number:
case UITypes.Decimal:
obj[col.title] = obj[col.column_name] = 'number'
break
case UITypes.Checkbox:
obj[col.title] = obj[col.column_name] = 'boolean'
break
}
obj[col.id] = col.uidt
return obj
}, {})
})
@ -112,6 +103,21 @@ const applyChanges = async (hookId?: string, _nested = false) => {
}
}
const isComparisonOpAllowed = (filter: FilterType, compOp: typeof comparisonOpList[number]) => {
// show current selected value in list even if not allowed
if (filter.comparison_op === compOp.value) return true
// include allowed values only if selected column type matches
if (compOp.includedTypes) {
return filter.fk_column_id && compOp.includedTypes.includes(types.value[filter.fk_column_id])
}
// include not allowed values only if selected column type not matches
else if (compOp.excludedTypes) {
return filter.fk_column_id && !compOp.excludedTypes.includes(types.value[filter.fk_column_id])
}
return true
}
defineExpose({
applyChanges,
parentId,
@ -186,7 +192,7 @@ defineExpose({
@click.stop
@change="filterUpdateCondition(filter, i)"
>
<a-select-option v-for="op in logicalOps" :key="op.value" :value="op.value">
<a-select-option v-for="op of logicalOps" :key="op.value" :value="op.value">
{{ op.text }}
</a-select-option>
</a-select>
@ -213,30 +219,27 @@ defineExpose({
dropdown-class-name="nc-dropdown-filter-comp-op"
@change="filterUpdateCondition(filter, i)"
>
<a-select-option v-for="compOp in comparisonOpList" :key="compOp.value" :value="compOp.value" class="">
{{ compOp.text }}
</a-select-option>
<template v-for="compOp of comparisonOpList" :key="compOp.value">
<a-select-option v-if="isComparisonOpAllowed(filter, compOp)" :value="compOp.value">
{{ compOp.text }}
</a-select-option>
</template>
</a-select>
<span
v-if="filter.comparison_op && ['null', 'notnull', 'empty', 'notempty'].includes(filter.comparison_op)"
v-if="
filter.comparison_op &&
['null', 'notnull', 'checked', 'notchecked', 'empty', 'notempty'].includes(filter.comparison_op)
"
:key="`span${i}`"
/>
<a-checkbox
v-else-if="filter.field && types[filter.field] === 'boolean'"
v-model:checked="filter.value"
dense
:disabled="filter.readOnly"
@change="saveOrUpdate(filter, i)"
/>
<a-input
v-else
:key="`${i}_7`"
v-model:value="filter.value"
class="nc-filter-value-select"
:disabled="filter.readOnly"
:disabled="filter.readOnly || !filter.fk_column_id"
@click.stop
@input="saveOrUpdate(filter, i)"
/>

45
packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue

@ -27,7 +27,7 @@ const activeView = inject(ActiveViewInj, ref())
const reloadDataHook = inject(ReloadViewDataHookInj)!
const reloadViewMetaHook = inject(ReloadViewMetaHookInj)!
const reloadViewMetaHook = inject(ReloadViewMetaHookInj, undefined)!
const rootFields = inject(FieldsInj)
@ -86,11 +86,31 @@ const onMove = (_event: { moved: { newIndex: number } }) => {
$e('a:fields:reorder')
}
const coverOptions = computed<SelectProps['options']>(() => {
const filterFields =
fields.value
?.filter((el) => el.fk_column_id && metaColumnById.value[el.fk_column_id].uidt === UITypes.Attachment)
.map((field) => {
return {
value: field.fk_column_id,
label: field.title,
}
}) ?? []
return [{ value: null, label: 'No Image' }, ...filterFields]
})
const coverImageColumnId = computed({
get: () =>
(activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN) && activeView.value?.view
? (activeView.value?.view as GalleryType).fk_cover_image_col_id
: undefined,
get: () => {
const fk_cover_image_col_id =
(activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN) && activeView.value?.view
? (activeView.value?.view as GalleryType).fk_cover_image_col_id
: undefined
// check if `fk_cover_image_col_id` is in `coverOptions`
// e.g. in share view, users may not share the cover image column
if (coverOptions.value?.find((o) => o.value === fk_cover_image_col_id)) return fk_cover_image_col_id
// set to `No Image`
return null
},
set: async (val) => {
if (
(activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN) &&
@ -110,24 +130,11 @@ const coverImageColumnId = computed({
})
;(activeView.value.view as KanbanType).fk_cover_image_col_id = val
}
reloadViewMetaHook.trigger()
reloadViewMetaHook?.trigger()
}
},
})
const coverOptions = computed<SelectProps['options']>(() => {
const filterFields =
fields.value
?.filter((el) => el.fk_column_id && metaColumnById.value[el.fk_column_id].uidt === UITypes.Attachment)
.map((field) => {
return {
value: field.fk_column_id,
label: field.title,
}
}) ?? []
return [{ value: null, label: 'No Image' }, ...filterFields]
})
const getIcon = (c: ColumnType) =>
h(isVirtualCol(c) ? resolveComponent('SmartsheetHeaderVirtualCellIcon') : resolveComponent('SmartsheetHeaderCellIcon'), {
columnMeta: c,

13
packages/nc-gui/components/smartsheet/toolbar/ShareView.vue

@ -88,10 +88,17 @@ const genShareLink = async () => {
if (!view.value?.id) return
const response = (await $api.dbViewShare.create(view.value.id)) as SharedView
const meta = isString(response.meta) ? JSON.parse(response.meta) : response.meta
shared.value = { ...response, meta }
if (shared.value.type === ViewTypes.KANBAN) {
const { groupingFieldColumn } = useKanbanViewStoreOrThrow()
shared.value.meta = { ...shared.value.meta, groupingFieldColumn: groupingFieldColumn.value }
await updateSharedViewMeta(true)
}
passwordProtected.value = !!shared.value.password && shared.value.password !== ''
showShareModel = true
@ -135,7 +142,7 @@ async function saveTheme() {
// const saveTransitionDuration = useDebounceFn(updateSharedViewMeta, 1000, { maxWait: 2000 })
async function updateSharedViewMeta() {
async function updateSharedViewMeta(silentMessage = false) {
try {
const meta = shared.value.meta && isString(shared.value.meta) ? JSON.parse(shared.value.meta) : shared.value.meta
@ -143,7 +150,7 @@ async function updateSharedViewMeta() {
meta,
})
message.success(t('msg.success.updated'))
if (!silentMessage) message.success(t('msg.success.updated'))
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
@ -207,7 +214,7 @@ const iframeCode = computed(() => {
frameborder="0"
width="100%"
height="700"
style="background: transparent; border: 1px solid #ddd"/>`
style="background: transparent; border: 1px solid #ddd"></iframe>`
})
const copyIframeCode = async () => {

3
packages/nc-gui/components/virtual-cell/Formula.vue

@ -24,11 +24,10 @@ const { showEditNonEditableFieldWarning, showClearNonEditableFieldWarning, activ
<template #title>
<span class="font-bold">{{ column.colOptions.error }}</span>
</template>
<span>ERR!</span>
</a-tooltip>
<div class="p-2" @dblclick="activateShowEditNonEditableFieldWarning">
<div v-else class="p-2" @dblclick="activateShowEditNonEditableFieldWarning">
<div v-if="urls" v-html="urls" />
<div v-else>{{ result }}</div>

4
packages/nc-gui/composables/useApi/interceptors.ts

@ -38,7 +38,7 @@ export function addAxiosInterceptors(api: Api<any>) {
}
// Logout user if token refresh didn't work or user is disabled
if (error.config.url === '/auth/refresh-token') {
if (error.config.url === '/auth/token/refresh') {
state.signOut()
return Promise.reject(error)
@ -46,7 +46,7 @@ export function addAxiosInterceptors(api: Api<any>) {
// Try request again with new token
return api.instance
.post('/auth/refresh-token', null, {
.post('/auth/token/refresh', null, {
withCredentials: true,
})
.then((token) => {

2
packages/nc-gui/composables/useGlobal/actions.ts

@ -33,7 +33,7 @@ export function useGlobalActions(state: State): Actions {
const t = nuxtApp.vueApp.i18n.global.t
nuxtApp.$api.instance
.post('/auth/refresh-token', null, {
.post('/auth/token/refresh', null, {
withCredentials: true,
})
.then((response) => {

15
packages/nc-gui/composables/useKanbanViewStore.ts

@ -112,7 +112,10 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
let res
if (isPublic.value) {
res = await fetchSharedViewGroupedData(groupingFieldColumn!.value!.id!)
res = await fetchSharedViewGroupedData(groupingFieldColumn!.value!.id!, {
sortsArr: sorts.value,
filtersArr: nestedFilters.value,
})
} else {
res = await api.dbViewRow.groupedDataList(
'noco',
@ -138,6 +141,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
if (stackTitle === null) {
where = `(${groupingField.value},is,null)`
}
const response = !isPublic.value
? await api.dbViewRow.list('noco', project.value.id!, meta.value!.id!, viewMeta.value!.id!, {
...params,
@ -145,7 +149,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
...(isUIAllowed('filterSync') ? {} : { filterArrJson: JSON.stringify(nestedFilters.value) }),
where,
})
: await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value })
: await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value, offset: params.offset })
formattedData.value.set(stackTitle, [...formattedData.value.get(stackTitle)!, ...formatData(response.list)])
}
@ -155,9 +159,12 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
kanbanMetaData.value = isPublic.value
? (sharedView.value?.view as KanbanType)
: await $api.dbView.kanbanRead(viewMeta.value.id)
// set groupingField
groupingFieldColumn.value =
(meta.value.columns as ColumnType[]).filter((f) => f.id === kanbanMetaData.value.fk_grp_col_id)[0] || {}
groupingFieldColumn.value = !isPublic.value
? (meta.value.columns as ColumnType[]).filter((f) => f.id === kanbanMetaData.value.fk_grp_col_id)[0] || {}
: ((typeof sharedView.value?.meta === 'string' ? JSON.parse(sharedView.value?.meta) : sharedView.value?.meta)
.groupingFieldColumn! as ColumnType)
groupingField.value = groupingFieldColumn.value.title!

3
packages/nc-gui/composables/useMultiSelect/index.ts

@ -267,7 +267,8 @@ export function useMultiSelect(
// copy - ctrl/cmd +c
case 67:
// set clipboard context only if single cell selected
if (selectedRange.isSingleCell() && rowObj.row[columnObj.title!]) {
// or if selected range is empty
if (selectedRange.isSingleCell() || (selectedRange.isEmpty() && rowObj && columnObj)) {
clipboardContext = {
value: rowObj.row[columnObj.title!],
uidt: columnObj.uidt as UITypes,

13
packages/nc-gui/composables/useSharedFormViewStore.ts

@ -43,7 +43,7 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share
const { metas, setMeta } = useMetas()
const { loadProject } = useProject()
const { project } = useProject()
const { t } = useI18n()
@ -86,7 +86,16 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share
await setMeta(viewMeta.model)
await loadProject(true, viewMeta.project_id)
// if project is not defined then set it with an object containing base
if (!project.value?.bases)
project.value = {
bases: [
{
id: viewMeta.base_id,
type: viewMeta.client,
},
],
}
const relatedMetas = { ...viewMeta.relatedMetas }

42
packages/nc-gui/composables/useSharedView.ts

@ -1,14 +1,4 @@
import type {
Api,
ExportTypes,
FilterType,
KanbanType,
PaginatedType,
RequestParams,
SortType,
TableType,
ViewType,
} from 'nocodb-sdk'
import type { ExportTypes, FilterType, KanbanType, PaginatedType, RequestParams, SortType, TableType, ViewType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import { computed, useGlobal, useMetas, useNuxtApp, useState } from '#imports'
@ -70,6 +60,7 @@ export function useSharedView() {
meta.value = { ...viewMeta.model }
let order = 1
meta.value!.columns = [...viewMeta.model.columns]
.filter((c) => c.show)
.map((c) => ({ ...c, order: order++ }))
@ -92,16 +83,27 @@ export function useSharedView() {
Object.keys(relatedMetas).forEach((key) => setMeta(relatedMetas[key]))
}
const fetchSharedViewData = async ({ sortsArr, filtersArr }: { sortsArr: SortType[]; filtersArr: FilterType[] }) => {
const fetchSharedViewData = async ({
sortsArr,
filtersArr,
offset,
}: {
sortsArr: SortType[]
filtersArr: FilterType[]
offset?: number
}) => {
if (!sharedView.value) return
const page = paginationData.value.page || 1
const pageSize = paginationData.value.pageSize || appInfoDefaultLimit
if (!offset) {
const page = paginationData.value.page || 1
const pageSize = paginationData.value.pageSize || appInfoDefaultLimit
offset = (page - 1) * pageSize
}
const { data } = await $api.public.dataList(
sharedView.value.uuid!,
{
offset: (page - 1) * pageSize,
offset,
filterArrJson: JSON.stringify(filtersArr ?? nestedFilters.value),
sortArrJson: JSON.stringify(sortsArr ?? sorts.value),
} as any,
@ -114,7 +116,10 @@ export function useSharedView() {
return data
}
const fetchSharedViewGroupedData = async (columnId: string, params: Parameters<Api<any>['dbViewRow']['list']>[4] = {}) => {
const fetchSharedViewGroupedData = async (
columnId: string,
{ sortsArr, filtersArr }: { sortsArr: SortType[]; filtersArr: FilterType[] },
) => {
if (!sharedView.value) return
const page = paginationData.value.page || 1
@ -125,9 +130,8 @@ export function useSharedView() {
columnId,
{
offset: (page - 1) * pageSize,
filterArrJson: JSON.stringify(nestedFilters.value),
sortArrJson: JSON.stringify(sorts.value),
...params,
filterArrJson: JSON.stringify(filtersArr ?? nestedFilters.value),
sortArrJson: JSON.stringify(sortsArr ?? sorts.value),
} as any,
{
headers: {

4
packages/nc-gui/composables/useTable.ts

@ -1,5 +1,5 @@
import type { LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import { UITypes, isSystemColumn } from 'nocodb-sdk'
import {
Modal,
SYSTEM_COLUMNS,
@ -84,7 +84,7 @@ export function useTable(onTableCreate?: (tableMeta: TableType) => void, baseId?
async onOk() {
try {
const meta = (await getMeta(table.id as string, true)) as TableType
const relationColumns = meta?.columns?.filter((c) => c.uidt === UITypes.LinkToAnotherRecord)
const relationColumns = meta?.columns?.filter((c) => c.uidt === UITypes.LinkToAnotherRecord && !isSystemColumn(c))
if (relationColumns?.length) {
const refColMsgs = await Promise.all(

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

@ -4,6 +4,7 @@ import type { ComputedRef, Ref } from 'vue'
import {
IsPublicInj,
NOCO,
NavigateDir,
computed,
extractPkFromRow,
extractSdkResponseErrorMsg,
@ -18,6 +19,8 @@ import {
useMetas,
useNuxtApp,
useProject,
useRoute,
useRouter,
useSharedView,
useSmartsheetStoreOrThrow,
useUIPermission,
@ -44,12 +47,18 @@ export function useViewData(
const { api, isLoading, error } = useApi()
const router = useRouter()
const route = useRoute()
const { appInfo } = $(useGlobal())
const { getMeta } = useMetas()
const appInfoDefaultLimit = appInfo.defaultLimit || 25
const _paginationData = ref<PaginatedType>({ page: 1, pageSize: appInfoDefaultLimit })
const aggCommentCount = ref<{ row_id: string; count: number }[]>([])
const galleryData = ref<GalleryType>()
@ -64,7 +73,7 @@ export function useViewData(
const { project, isSharedBase } = useProject()
const { fetchSharedViewData, paginationData: sharedPaginationData } = useSharedView()
const { sharedView, fetchSharedViewData, paginationData: sharedPaginationData } = useSharedView()
const { $api, $e } = useNuxtApp()
@ -72,6 +81,8 @@ export function useViewData(
const { isUIAllowed } = useUIPermission()
const routeQuery = $computed(() => route.query as Record<string, string>)
const paginationData = computed({
get: () => (isPublic.value ? sharedPaginationData.value : _paginationData.value),
set: (value) => {
@ -203,8 +214,10 @@ export function useViewData(
}
async function loadGalleryData() {
if (!viewMeta?.value?.id || isPublic.value) return
galleryData.value = await $api.dbView.galleryRead(viewMeta.value.id)
if (!viewMeta?.value?.id) return
galleryData.value = isPublic.value
? (sharedView.value?.view as GalleryType)
: await $api.dbView.galleryRead(viewMeta.value.id)
}
async function insertRow(
@ -465,6 +478,47 @@ export function useViewData(
}
}
const navigateToSiblingRow = async (dir: NavigateDir) => {
// get current expanded row index
const expandedRowIndex = formattedData.value.findIndex(
(row: Row) => routeQuery.rowId === extractPkFromRow(row.row, meta.value?.columns as ColumnType[]),
)
// calculate next row index based on direction
let siblingRowIndex = expandedRowIndex + (dir === NavigateDir.NEXT ? 1 : -1)
const currentPage = paginationData?.value?.page || 1
// if next row index is less than 0, go to previous page and point to last element
if (siblingRowIndex < 0) {
// if first page, do nothing
if (currentPage === 1) return message.info(t('msg.info.noMoreRecords'))
await changePage(currentPage - 1)
siblingRowIndex = formattedData.value.length - 1
// if next row index is greater than total rows in current view
// then load next page of formattedData and set next row index to 0
} else if (siblingRowIndex >= formattedData.value.length) {
if (paginationData?.value?.isLastPage) return message.info(t('msg.info.noMoreRecords'))
await changePage(currentPage + 1)
siblingRowIndex = 0
}
// extract the row id of the sibling row
const rowId = extractPkFromRow(formattedData.value[siblingRowIndex].row, meta.value?.columns as ColumnType[])
if (rowId) {
router.push({
query: {
...routeQuery,
rowId,
},
})
}
}
return {
error,
isLoading,
@ -493,5 +547,6 @@ export function useViewData(
loadAggCommentsCount,
removeLastEmptyRow,
removeRowIfNew,
navigateToSiblingRow,
}
}

8
packages/nc-gui/lang/ar.json

@ -277,6 +277,7 @@
"selectUserRole": "حدد دور المستخدم",
"childTable": "جدول فرعي",
"childColumn": "عمود فرعي",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "عند التحديث",
"onDelete": "عند الحذف",
"account": "حساب",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "بالتسجيل، أنت توافق على شروط الخدمة",
"welcomeToNc": "مرحبا بكم في NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "إنشاء مشروع",
@ -628,7 +631,8 @@
"showM2mTables": "إظهار جداول M2M",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "البحث عن {بحث} لم يتم العثور على نتائج",

8
packages/nc-gui/lang/bn_IN.json

@ -277,6 +277,7 @@
"selectUserRole": "বযবহরকর ভিিচন করন",
"childTable": "Child table",
"childColumn": "Child column",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "আপড",
"onDelete": "ডিিটএ",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "পরকলপ তি করন",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "আপনর অনসনন {search} এর জনয কনও ফলফল পওযি",

8
packages/nc-gui/lang/cs.json

@ -277,6 +277,7 @@
"selectUserRole": "Vybrat uživatelskou roli",
"childTable": "Podřízená tabulka",
"childColumn": "Podřízený sloupec",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Při aktualizaci",
"onDelete": "Při odstranění",
"account": "Účet",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Povolit registraci pouze pomocí pozvánky s odkazem"
"inviteOnlySignup": "Povolit registraci pouze pomocí pozvánky s odkazem",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Vytvořit projekt",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Your search for {search} found no results",

8
packages/nc-gui/lang/da.json

@ -277,6 +277,7 @@
"selectUserRole": "Vælg brugerrolle",
"childTable": "Børnebord",
"childColumn": "Barn kolonne",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "På opdatering",
"onDelete": "På Delete.",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Opret projekt",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Din søgning efter {Søg} viste ingen resultater",

11
packages/nc-gui/lang/de.json

@ -277,6 +277,7 @@
"selectUserRole": "Benutzerrolle auswählen",
"childTable": "Child-Tabelle",
"childColumn": "Child-Spalte",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Update",
"onDelete": "Löschen",
"account": "Benutzerkonto",
@ -311,7 +312,9 @@
"signInWithGoogle": "Mit Google einloggen",
"agreeToTos": "Mit Ihrer Anmeldung stimmen Sie den allgemeinen Nutzungsbedingungen zu",
"welcomeToNc": "Willkommen bei NocoDB!",
"inviteOnlySignup": "Anmeldung nur über Einladungs-URL zulassen"
"inviteOnlySignup": "Anmeldung nur über Einladungs-URL zulassen",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Projekt erstellen",
@ -504,8 +507,7 @@
},
"nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed.",
"barcodeFieldsCannotBeDirectlyChanged": "Warning: Barcode fields cannot be directly changed."
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed."
}
},
"info": {
@ -629,7 +631,8 @@
"showM2mTables": "M2M Tabellen anzeigen",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Ihre Suche nach {search} fand keine Ergebnisse",

8
packages/nc-gui/lang/en.json

@ -278,6 +278,7 @@
"selectUserRole": "Select User Role",
"childTable": "Child table",
"childColumn": "Child column",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "On Update",
"onDelete": "On Delete",
"account": "Account",
@ -312,7 +313,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Create Project",
@ -637,7 +640,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Your search for {search} found no results",

8
packages/nc-gui/lang/es.json

@ -277,6 +277,7 @@
"selectUserRole": "Seleccione el rol de usuario",
"childTable": "Tabla hija",
"childColumn": "Columna hija",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "En actualización",
"onDelete": "En eliminar",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Crear proyecto",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Tu búsqueda de {search} no encontró resultados",

194
packages/nc-gui/lang/eu.json

@ -1,55 +1,55 @@
{
"general": {
"home": "Home",
"load": "Load",
"open": "Open",
"close": "Close",
"yes": "Yes",
"no": "No",
"ok": "OK",
"and": "And",
"or": "Or",
"add": "Add",
"edit": "Edit",
"remove": "Remove",
"save": "Save",
"cancel": "Cancel",
"submit": "Submit",
"create": "Create",
"duplicate": "Duplicate",
"insert": "Insert",
"delete": "Delete",
"update": "Update",
"rename": "Rename",
"reload": "Reload",
"reset": "Reset",
"install": "Install",
"show": "Show",
"hide": "Hide",
"showAll": "Show all",
"hideAll": "Hide all",
"showMore": "Show more",
"showOptions": "Show options",
"hideOptions": "Hide options",
"showMenu": "Show menu",
"hideMenu": "Hide menu",
"addAll": "Add all",
"removeAll": "Remove all",
"signUp": "SIGN UP",
"signIn": "SIGN IN",
"signOut": "Sign Out",
"required": "Required",
"home": "Hasiera",
"load": "Kargatu",
"open": "Ireki",
"close": "Itxi",
"yes": "Bai",
"no": "Ez",
"ok": "Ados",
"and": "Eta",
"or": "Edo",
"add": "Gehitu",
"edit": "Editatu",
"remove": "Ezabatu",
"save": "Gorde",
"cancel": "Ezeztatu",
"submit": "Bidali",
"create": "Sortu",
"duplicate": "Bikoiztu",
"insert": "Txertatu",
"delete": "Ezabatu",
"update": "Eguneratu",
"rename": "Berrizendatu",
"reload": "Birkargatu",
"reset": "Berrezarri",
"install": "Instalatu",
"show": "Erakutsi",
"hide": "Ezkutatu",
"showAll": "Dena erakutsi",
"hideAll": "Ezkutatu dena",
"showMore": "Erakutsi gehiago",
"showOptions": "Erakutsi aukerak",
"hideOptions": "Ezkutatu aukerak",
"showMenu": "Menua erakutsi",
"hideMenu": "Ezkutatu menua",
"addAll": "Guztiak gehitu",
"removeAll": "Kendu denak",
"signUp": "IZENA EMAN",
"signIn": "SARTU",
"signOut": "Saioa amaitu",
"required": "Beharrezkoa",
"preferred": "Preferred",
"mandatory": "Mandatory",
"loading": "Loading ...",
"title": "Title",
"upload": "Upload",
"download": "Download",
"default": "Default",
"more": "More",
"less": "Less",
"event": "Event",
"condition": "Condition",
"mandatory": "Derrigorrezkoa",
"loading": "Kargatzen ...",
"title": "Titulua",
"upload": "Igo",
"download": "Deskargatu",
"default": "Lehenetsia",
"more": "Gehiago",
"less": "Gutxiago",
"event": "Gertaera",
"condition": "Baldintza",
"after": "After",
"before": "Before",
"search": "Search",
@ -105,11 +105,11 @@
"role": "Role",
"roles": "Roles",
"roleType": {
"owner": "Owner",
"creator": "Creator",
"editor": "Editor",
"commenter": "Commenter",
"viewer": "Viewer",
"owner": "Jabea",
"creator": "Sortzailea",
"editor": "Editorea",
"commenter": "Iruzkinlaria",
"viewer": "Ikuslea",
"orgLevelCreator": "Organization Level Creator",
"orgLevelViewer": "Organization Level Viewer"
},
@ -119,25 +119,25 @@
"ID": "ID",
"ForeignKey": "Foreign Key",
"SingleLineText": "Single Line Text",
"LongText": "Long Text",
"Attachment": "Attachment",
"Checkbox": "Checkbox",
"MultiSelect": "Multi Select",
"SingleSelect": "Single Select",
"LongText": "Testu luzea",
"Attachment": "Eranskina",
"Checkbox": "Kontrol laukia",
"MultiSelect": "Aukera anitza",
"SingleSelect": "Aukera bakarra",
"Collaborator": "Collaborator",
"Date": "Date",
"Year": "Year",
"Time": "Time",
"PhoneNumber": "Phone Number",
"Email": "Email",
"URL": "URL",
"Number": "Number",
"Decimal": "Decimal",
"Currency": "Currency",
"Percent": "Percent",
"Duration": "Duration",
"Rating": "Rating",
"Formula": "Formula",
"Date": "Data",
"Year": "Urtea",
"Time": "Ordua",
"PhoneNumber": "Telefono zenbakia",
"Email": "Eposta",
"URL": "URL-a",
"Number": "Zenbakia",
"Decimal": "Dezimala",
"Currency": "Moneta",
"Percent": "Ehunekoa",
"Duration": "Iraupena",
"Rating": "Balorazioa",
"Formula": "Ekuazioa",
"Rollup": "Rollup",
"Count": "Count",
"Lookup": "Lookup",
@ -146,21 +146,21 @@
"LastModifiedTime": "Last Modified Time",
"AutoNumber": "Auto Number",
"Barcode": "Barcode",
"Button": "Button",
"Password": "Password",
"Button": "Botoia",
"Password": "Pasahitza",
"relationProperties": {
"noAction": "No Action",
"noAction": "Ekintzarik ez",
"cascade": "Cascade",
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
"restrict": "Mugatu",
"setNull": "Ezarri NULLa",
"setDefault": "Ezarri lehenetsia"
}
},
"filterOperation": {
"isEqual": "is equal",
"isNotEqual": "is not equal",
"isLike": "is like",
"isNot like": "is not like",
"isEqual": "honen berdina da",
"isNotEqual": "ez da honen berdina",
"isLike": "honen antzekoa da",
"isNot like": "ez da honen antzekoa",
"isEmpty": "is empty",
"isNotEmpty": "is not empty",
"isNull": "is null",
@ -197,9 +197,9 @@
"teamAndSettings": "Team & Settings",
"apiDocs": "API Docs",
"importFromAirtable": "Import From Airtable",
"generateToken": "Generate Token",
"APIsAndSupport": "APIs & Support",
"helpCenter": "Help center",
"generateToken": "Sortu tokena",
"APIsAndSupport": "APIak & laguntza",
"helpCenter": "Laguntza gunea",
"swaggerDocumentation": "Swagger Documentation",
"quickImportFrom": "Quick Import From",
"quickImport": "Quick Import",
@ -224,17 +224,17 @@
"sqliteFile": "SQLite File",
"hostAddress": "Host Address",
"port": "Port Number",
"username": "Username",
"password": "Password",
"username": "Erabiltzaile izena",
"password": "Pasahitza",
"schemaName": "Schema name",
"database": "Database",
"action": "Action",
"actions": "Actions",
"database": "Datu-basea",
"action": "Ekintza",
"actions": "Ekintzak",
"operation": "Operation",
"operationType": "Operation type",
"operationSubType": "Operation sub-type",
"description": "Description",
"authentication": "Authentication",
"description": "Deskribapena",
"authentication": "Autentifikazioa",
"token": "Token",
"where": "Where",
"cache": "Cache",
@ -246,7 +246,7 @@
"syncState": "Sync state",
"created": "Created",
"sqlOutput": "SQL Output",
"addOption": "Add option",
"addOption": "Gehitu aukera",
"qrCodeValueColumn": "Column with QR code value",
"barcodeValueColumn": "Column with Barcode value",
"barcodeFormat": "Barcode format",
@ -277,6 +277,7 @@
"selectUserRole": "Select User Role",
"childTable": "Child table",
"childColumn": "Child column",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "On Update",
"onDelete": "On Delete",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Create Project",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Your search for {search} found no results",

8
packages/nc-gui/lang/fa.json

@ -277,6 +277,7 @@
"selectUserRole": "نقش کاربر را انتخاب کنید",
"childTable": "جدول فرزند",
"childColumn": "ستون فرزند",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "هنگام به روز رسانی",
"onDelete": "هنگام حذف",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "ایجاد پروژه",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "جستوجوی شما برای {search} نتیجهای نداشت",

8
packages/nc-gui/lang/fi.json

@ -277,6 +277,7 @@
"selectUserRole": "Valitse käyttäjän rooli",
"childTable": "Lapsipöytä",
"childColumn": "Lapsipylväs",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Päivitys",
"onDelete": "Poista",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Luo projekti",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Hakusi {haku} ei löytänyt tuloksia",

136
packages/nc-gui/lang/fr.json

@ -26,9 +26,9 @@
"install": "Installer",
"show": "Montrer",
"hide": "Cacher",
"showAll": "Afficher tout",
"hideAll": "Cacher tout",
"showMore": "Montrer plus",
"showAll": "Tout afficher",
"hideAll": "Tout cacher",
"showMore": "Afficher davantage",
"showOptions": "Afficher les options",
"hideOptions": "Masquer les options",
"showMenu": "Afficher le menu",
@ -59,7 +59,7 @@
"confirm": "Confirmer",
"generate": "Générer",
"copy": "Copier",
"misc": "Miscellaneous",
"misc": "Divers",
"lock": "Verrouiller",
"unlock": "Déverrouiller",
"credentials": "Identifiants",
@ -68,10 +68,10 @@
"reachOut": "Reach out here",
"betaNote": "Cette fonctionnalité est encore en développement.",
"moreInfo": "Plus d'informations peuvent être trouvées ici",
"logs": "Logs",
"groupingField": "Grouping Field",
"insertAfter": "Insert After",
"insertBefore": "Insert Before",
"logs": "Journaux",
"groupingField": "Champ de regroupement",
"insertAfter": "Insérer après",
"insertBefore": "Insérer avant",
"hideField": "Masquer le champ",
"sortAsc": "Trier par ordre croissant",
"sortDesc": "Trier par ordre décroissant"
@ -198,20 +198,20 @@
"apiDocs": "Docs API",
"importFromAirtable": "Importer depuis Airtable",
"generateToken": "Générer un jeton",
"APIsAndSupport": "Les API et la prise en charge",
"helpCenter": "Help center",
"swaggerDocumentation": "Swagger Documentation",
"APIsAndSupport": "API & Assistance",
"helpCenter": "Centre d'aide",
"swaggerDocumentation": "Documentation de Swagger",
"quickImportFrom": "Quick Import From",
"quickImport": "Importation rapide",
"advancedSettings": "Paramètres avancés",
"codeSnippet": "Code Snippet",
"keyboardShortcut": "Keyboard Shortcuts"
"codeSnippet": "Extrait de code",
"keyboardShortcut": "Raccourcis clavier"
},
"labels": {
"createdBy": "Créé par",
"notifyVia": "Notifier via",
"projName": "Nom du projet",
"tableName": "Nom de la table",
"tableName": "Nom du tableau",
"viewName": "Vue",
"viewLink": "Lien de vue",
"columnName": "Nom de la colonne",
@ -241,17 +241,17 @@
"chat": "Discussion",
"email": "Courriel",
"storage": "Stockage",
"uiAcl": "UI-ACL",
"uiAcl": "IU ACL",
"models": "Modèles",
"syncState": "État de synchronisation",
"created": "Créé",
"sqlOutput": "Sortie SQL",
"addOption": "Ajouter une option",
"qrCodeValueColumn": "Column with QR code value",
"barcodeValueColumn": "Column with Barcode value",
"barcodeFormat": "Barcode format",
"qrCodeValueColumn": "Colonne avec une valeur code QR",
"barcodeValueColumn": "Colonne avec une valeur code-barres",
"barcodeFormat": "Format du code-barres",
"qrCodeValueTooLong": "Trop de caractères pour un code QR",
"barcodeValueTooLong": "Too many characters for a barcode",
"barcodeValueTooLong": "Trop de caractères pour un code-barres",
"aggregateFunction": "Fonction agrégée",
"dbCreateIfNotExists": "Base de données : la créer si elle n'existe pas",
"clientKey": "Clé client",
@ -264,9 +264,9 @@
"columnName": "Inflexion - Nom de la colonne"
},
"community": {
"starUs1": "Étoile",
"starUs1": "Mettre en favoris",
"starUs2": "sur Github",
"bookDemo": "Planifier une démonstration gratuite",
"bookDemo": "Réserver une démonstration gratuite",
"getAnswered": "Obtenir des réponses à vos questions",
"joinDiscord": "Rejoindre le serveur Discord",
"joinCommunity": "Rejoindre la communauté NocoDB",
@ -277,12 +277,13 @@
"selectUserRole": "Sélectionner le rôle d'utilisateur",
"childTable": "Table enfant",
"childColumn": "Colonne enfant",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Mise à jour en cours",
"onDelete": "Suppression en cours",
"account": "Compte",
"language": "Langue",
"primaryColor": "Primary Color",
"accentColor": "Accent Color",
"primaryColor": "Couleur primaire",
"accentColor": "Couleur secondaire",
"customTheme": "Thème personnalisé",
"requestDataSource": "Request a data source you need?",
"apiKey": "Clé d'API",
@ -311,7 +312,9 @@
"signInWithGoogle": "Se connecter avec Google",
"agreeToTos": "En continuant, vous acceptez les Conditions d'Utilisation",
"welcomeToNc": "Bienvenue sur NocoDB !",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Créer un projet",
@ -339,7 +342,7 @@
"translate": "Aider à la traduction",
"account": {
"authToken": "Copier le jeton d'authentification",
"swagger": "Swagger : les API REST",
"swagger": "Swagger : API REST",
"projInfo": "Copier les informations du projet",
"themes": "Thèmes"
},
@ -350,7 +353,7 @@
"share": "Partager",
"shareBase": {
"disable": "Désactiver la base partagée",
"enable": "N'importe qui avec le lien",
"enable": "N'importe qui disposant du lien",
"link": "Partager le lien de la base"
},
"invite": "Inviter",
@ -375,7 +378,7 @@
"refreshTable": "Actualiser le tableau",
"renameTable": "Renommer le tableau",
"deleteTable": "Supprimer le tableau",
"addField": "Ajouter un nouveau champ à cette table",
"addField": "Ajouter un nouveau champ à ce tableau",
"setPrimary": "Définir comme valeur primaire",
"addRow": "Ajouter une nouvelle ligne",
"saveRow": "Enregistrer la ligne",
@ -431,7 +434,7 @@
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw",
"toggleCommentsDraw": "Afficher ou masquer le panneau des commentaires",
"expandRecord": "Expand Record",
"deleteRecord": "Delete Record",
"erd": {
@ -445,7 +448,7 @@
"collapseStack": "Collapse Stack",
"deleteStack": "Delete Stack",
"stackedBy": "Stacked By",
"chooseGroupingField": "Choose a Grouping Field",
"chooseGroupingField": "Choisir un champ de regroupement",
"addOrEditStack": "Add / Edit Stack"
}
},
@ -459,9 +462,9 @@
"dark": "Nuit (^⇧B)",
"light": "Jour (^⇧B)"
},
"addTable": "Ajouter une nouvelle table",
"addTable": "Ajouter un nouveau tableau",
"inviteMore": "Inviter plus d'utilisateurs",
"toggleNavDraw": "Basculer le tiroir de navigation",
"toggleNavDraw": "Afficher ou masquer le panneau de navigation",
"reloadApiToken": "Recharger les jetons API",
"generateNewApiToken": "Générer de nouveaux jetons d'API",
"addRole": "Ajouter un nouveau rôle",
@ -500,11 +503,11 @@
"msg": {
"warning": {
"barcode": {
"renderError": "Barcode error - please check compatibility between input and barcode type"
"renderError": "Erreur de code-barres - veuillez vérifier la compatibiltié entre la donnée d'entrée et le type de code-barres"
},
"nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed."
"qrFieldsCannotBeDirectlyChanged": "Attention : les champs QR code ne peuvent pas être modifiés directement."
}
},
"info": {
@ -518,7 +521,7 @@
"upload_sub": "ou glisser-déposer un fichier",
"excelSupport": "Pris en charge: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Définir l'URL du fichier Excel",
"csvURL": "Définir l'URL du fichier CSV",
"csvURL": "URL vers le fichier CSV",
"footMsg": "Nombre de lignes à analyser pour déduire le type de données",
"excelImport": "Les tableaux sont disponibles pour l'import",
"exportMetadata": "Voulez-vous exporter des métadonnées des méta-tables?",
@ -536,19 +539,19 @@
"formInput": "Entrer le libellé du formulaire",
"formHelpText": "Ajouter un texte d'aide",
"onlyCreator": "Visible uniquement pour les créateurs",
"formDesc": "Ajouter une description du formulaire",
"formDesc": "Ajouter une description au formulaire",
"beforeEnablePwd": "Restreindre l’accès à l’aide d’un mot de passe",
"afterEnablePwd": "L’accès est restreint par un mot de passe",
"privateLink": "Cette vue est partagée avec un lien privé",
"privateLinkAdditionalInfo": "Les personnes ayant le lien privé peuvent voir uniquement les cellules visibles de cette vue",
"afterFormSubmitted": "Après que le formulaire est soumis",
"afterFormSubmitted": "Après que le formulaire ait été soumis",
"apiOptions": "Accéder au projet via",
"submitAnotherForm": "Afficher le bouton \"Soumettre un autre formulaire\"",
"showBlankForm": "Montrer un formulaire vierge après 5 secondes",
"emailForm": "Écrivez-moi à",
"showSysFields": "Afficher les champs système",
"filterAutoApply": "Appliquer automatiquement",
"showMessage": "Montrer ce message",
"showMessage": "Montrer ce message ",
"viewNotShared": "La vue actuelle n'est pas partagée!",
"showAllViews": "Montrer toutes les vues partagées sur cette table",
"collabView": "Les collaborateurs avec des autorisations d'édition ou plus peuvent modifier la configuration de la vue.",
@ -574,7 +577,7 @@
},
"sponsor": {
"header": "Vous pouvez nous aider !",
"message": "Nous sommes une petite équipe travaillant à plein temps pour rendre Nocodb Open-Source. Nous croyons qu'un outil comme Nocodb devrait être disponible librement à chaque solveur de problèmes sur Internet."
"message": "Nous sommes une petite équipe travaillant à plein temps pour rendre NocoDB open-Source. Nous croyons qu'un outil comme NocoDB devrait être disponible librement à chaque solutionneur de problème sur Internet."
},
"loginMsg": "Se connecter à NocoDB",
"passwordRecovery": {
@ -583,7 +586,7 @@
"success": "Veuillez vérifier votre email pour réinitialiser le mot de passe"
},
"signUp": {
"superAdmin": "Vous serez le 'super admin'",
"superAdmin": "Vous serez le « super administrateur »",
"alreadyHaveAccount": "Avez-vous déjà un compte ?",
"workEmail": "Saisir votre adresse mail professionnelle",
"enterPassword": "Saisir votre mot de passe",
@ -599,20 +602,20 @@
},
"tablesMetadataInSync": "Les métadonnées de tables sont en synchronisation",
"addMultipleUsers": "Vous pouvez ajouter plusieurs courriels séparés par des virgules (,)",
"enterTableName": "Entrer le nom de la table",
"enterTableName": "Entrez le nom du tableau",
"addDefaultColumns": "Ajouter des colonnes par défaut",
"tableNameInDb": "Nom de la table tel qu'enregistré dans la base de données",
"airtable": {
"credentials": "Where to find this?"
"credentials": "Où trouver ceci ?"
},
"import": {
"clickOrDrag": "Click or drag file to this area to upload"
"clickOrDrag": "Cliquez ou glissez un fichier dans cette zone pour téléverser"
},
"metaDataRecreated": "Table metadata recreated successfully",
"invalidCredentials": "Invalid credentials",
"downloadingMoreFiles": "Downloading more files",
"invalidCredentials": "Identifiants invalides",
"downloadingMoreFiles": "Téléchargement de fichiers supplémentaires",
"copiedToClipboard": "Copié dans le presse-papier",
"requriedFieldsCantBeMoved": "Required field can't be moved",
"requriedFieldsCantBeMoved": "Les champs requis ne peuvent pas être déplacés",
"updateNotAllowedWithoutPK": "Update not allowed for table which doesn't have primary key",
"autoIncFieldNotEditable": "Auto increment field is not editable",
"editingPKnotSupported": "Modification de la clé primaire non prise en charge",
@ -620,15 +623,16 @@
"cacheEmpty": "Le cache est vide",
"exportedCache": "Exported Cache Successfully",
"valueAlreadyInList": "This value is already in the list",
"noColumnsToUpdate": "No columns to update",
"tableDeleted": "Deleted table successfully",
"generatePublicShareableReadonlyBase": "Generate publicly shareable readonly base",
"noColumnsToUpdate": "Aucune colonne à mettre à jour",
"tableDeleted": "Tableau supprimé avec succès",
"generatePublicShareableReadonlyBase": "Génère une base publique partagée en lecture seule",
"deleteViewConfirmation": "Êtes-vous sûr de vouloir effacer cette vue ?",
"deleteTableConfirmation": "Voulez-vous supprimer ce tableau",
"showM2mTables": "Show M2M Tables",
"showM2mTables": "Afficher les tables plusieurs à plusieurs",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Votre recherche pour {search} n'a renvoyé aucun résultat",
@ -640,7 +644,7 @@
"dbConnectionFailed": "Echec de connexion :",
"signUpRules": {
"emailReqd": "Adresse mail requise",
"emailInvalid": "L'adresse mail doit être valide",
"emailInvalid": "L'adresse électronique doit être valide",
"passwdRequired": "Mot de passe requis",
"passwdLength": "Votre mot de passe doit contenir au moins 8 caractères",
"passwdMismatch": "Les mots de passe ne correspondent pas",
@ -654,12 +658,12 @@
"invalidURL": "URL invalide",
"internalError": "Une erreur interne est survenue",
"templateGeneratorNotFound": "Template Generator cannot be found!",
"fileUploadFailed": "Failed to upload file",
"fileUploadFailed": "Échec du téléversement du fichier",
"primaryColumnUpdateFailed": "Failed to update primary column",
"formDescriptionTooLong": "Data too long for Form Description",
"columnsRequired": "Following columns are required",
"selectAtleastOneColumn": "At least one column has to be selected",
"columnDescriptionNotFound": "Cannot find the destination column for",
"selectAtleastOneColumn": "Au moins une colonne doit être sélectionnée",
"columnDescriptionNotFound": "Impossible de trouver la colonne de destination pour",
"duplicateMappingFound": "Duplicate mapping found, please remove one of the mapping",
"nullValueViolatesNotNull": "Null value violates not-null constraint",
"sourceHasInvalidNumbers": "Source data contains some invalid numbers",
@ -675,14 +679,14 @@
"deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Échec de la mise à jour de la vue du formulaire",
"tableNameRequired": "Table name is required",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _",
"followingCharactersAreNotAllowed": "Following characters are not allowed",
"columnNameRequired": "Column name is required",
"projectNameExceeds50Characters": "Project name exceeds 50 characters",
"projectNameCannotStartWithSpace": "Project name cannot start with space",
"requiredField": "Required field",
"ipNotAllowed": "IP not allowed",
"tableNameRequired": "Nom du tableau requis",
"nameShouldStartWithAnAlphabetOr_": "Le nom doit commencer par une lettre de l'alphabet ou _",
"followingCharactersAreNotAllowed": "Les caractères suivants ne sont pas autorisés",
"columnNameRequired": "Nom de la colonne requis",
"projectNameExceeds50Characters": "Le nom du projet dépasse les 50 caractères",
"projectNameCannotStartWithSpace": "Le nom du projet ne peut pas commencer par un espace",
"requiredField": "Champ requis",
"ipNotAllowed": "Adresse IP non autorisée",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
@ -704,7 +708,7 @@
"projInfo": "Informations de projet copiées dans le presse-papier",
"inviteUrlCopy": "URL d'invitation copiée dans le presse-papier",
"createView": "Vue créée avec succès",
"formEmailSMTP": "Veuillez activer le plugin SMTP dans l'App Store pour permettre la notification par courrier électronique",
"formEmailSMTP": "Veuillez activer le plugin SMTP dans le magasin d'applications pour permettre la notification par courriel",
"collabView": "Vous êtes bien dans la vue collaborative",
"lockedView": "Vous êtes bien dans la vue vérouillée",
"futureRelease": "Bientôt disponible !"
@ -715,10 +719,10 @@
"pluginUninstalled": "Plugin uninstalled successfully",
"pluginSettingsSaved": "Plugin settings saved successfully",
"pluginTested": "Successfully tested plugin settings",
"tableRenamed": "Table renamed successfully",
"tableRenamed": "Tableau renommé avec succès",
"viewDeleted": "Vue effacée avec succès",
"primaryColumnUpdated": "Successfully updated as primary column",
"tableDataExported": "Toutes les données de la table ont été exportées avec succès",
"tableDataExported": "Toutes les données du tableau ont été exportées avec succès",
"updated": "Mise à jour réussie",
"sharedViewDeleted": "Vue partagée effacée avec succès",
"userDeleted": "Utilisateur supprimé avec succès",
@ -734,7 +738,7 @@
"shareableURLCopied": "Copied shareable base URL to clipboard!",
"embeddableHTMLCodeCopied": "Copied embeddable HTML code!",
"userDetailsUpdated": "Successfully updated the user details",
"tableDataImported": "Successfully imported table data",
"tableDataImported": "Données du tableau importées avec succès",
"webhookUpdated": "Webhook details updated successfully",
"webhookDeleted": "Hook deleted successfully",
"webhookTested": "Webhook tested successfully",

8
packages/nc-gui/lang/he.json

@ -277,6 +277,7 @@
"selectUserRole": "בחר תפקיד משתמש",
"childTable": "טבלת ילדים",
"childColumn": "טור ילדים",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "על עדכון",
"onDelete": "על מחיקה",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "צור פרויקט",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "החיפוש שלך {חיפוש} לא נמצא תוצאות",

8
packages/nc-gui/lang/hi.json

@ -277,6 +277,7 @@
"selectUserRole": "Select User Role",
"childTable": "Child table",
"childColumn": "Child column",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "On Update",
"onDelete": "On Delete",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "पट बन",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "{search} किए आपकज कई परिम नहि",

8
packages/nc-gui/lang/hr.json

@ -277,6 +277,7 @@
"selectUserRole": "Odaberite korisničku ulogu",
"childTable": "Dječji stol",
"childColumn": "Dječji stupac",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Na ažuriranje",
"onDelete": "Na brisanje",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Stvoriti projekt",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Vaša potraga za {Search} nije pronašla rezultate",

8
packages/nc-gui/lang/id.json

@ -277,6 +277,7 @@
"selectUserRole": "Pilih Peran Pengguna",
"childTable": "Tabel Anak",
"childColumn": "Kolom anak.",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Pada pembaruan",
"onDelete": "Hapus",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Buat Proyek",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Pencarian Anda untuk {Search} tidak menemukan hasil",

8
packages/nc-gui/lang/it.json

@ -277,6 +277,7 @@
"selectUserRole": "Seleziona il ruolo utente",
"childTable": "Sottotabella",
"childColumn": "Sottocolonna",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "All'aggiornamento",
"onDelete": "All'eliminazione",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Crea progetto",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "La tua ricerca di {search} non ha trovato risultati",

8
packages/nc-gui/lang/ja.json

@ -277,6 +277,7 @@
"selectUserRole": "ユーザーのロールを選択してください",
"childTable": "子テーブル",
"childColumn": "子カラム",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "更新中",
"onDelete": "削除中",
"account": "アカウント",
@ -311,7 +312,9 @@
"signInWithGoogle": "Googleでログイン",
"agreeToTos": "サインアップすることで、利用規約に同意するものとみなされます。",
"welcomeToNc": "NocoDB へようこそ!",
"inviteOnlySignup": "招待URL からのサインアップのみ許可"
"inviteOnlySignup": "招待URL からのサインアップのみ許可",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "プロジェクトを作成",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "スタックを削除すると、`{stackToBeDeleted}`から選択肢`{groupingField}`も削除されます。レコードは未分類スタックに移動します。",
"computedFieldEditWarning": "計算フィールド: コンテンツは読み取り専用です。列編集メニューを使用して再設定してください。",
"computedFieldDeleteWarning": "計算フィールド: コンテンツは読み取り専用です。コンテンツを消去できません。"
"computedFieldDeleteWarning": "計算フィールド: コンテンツは読み取り専用です。コンテンツを消去できません。",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "{search} の検索結果が見つかりませんでした",

8
packages/nc-gui/lang/ko.json

@ -277,6 +277,7 @@
"selectUserRole": "사용자 역할을 선택하세요",
"childTable": "자식 테이블",
"childColumn": "자식 컬럼",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "업데이트 시 ",
"onDelete": "삭제 시",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "프로젝트 생성",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "검색 결과가 없습니다",

8
packages/nc-gui/lang/lv.json

@ -277,6 +277,7 @@
"selectUserRole": "Izvēlēties lietotāja lomu",
"childTable": "Apakštabula",
"childColumn": "Apakškolonna",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Atjaunojot",
"onDelete": "Dzēšot",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Izveidot projektu",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Nav atrasti rezultāti meklējot pēc atslēgvārda {search}",

8
packages/nc-gui/lang/nl.json

@ -277,6 +277,7 @@
"selectUserRole": "Selecteer de rol van de gebruiker",
"childTable": "Child Tabel",
"childColumn": "Child Kolom",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Bij update",
"onDelete": "Bij verwijdering",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Maak project",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Uw zoekopdracht voor {search} heeft geen resultaten opgeleverd",

8
packages/nc-gui/lang/no.json

@ -277,6 +277,7 @@
"selectUserRole": "Velg Brukerrolle",
"childTable": "Barnbord",
"childColumn": "Barn kolonne",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "På oppdatering",
"onDelete": "På slette",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Opprett prosjekt",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Søket ditt etter {søk} fant ingen resultater",

8
packages/nc-gui/lang/pl.json

@ -277,6 +277,7 @@
"selectUserRole": "Wybierz rolę użytkownika",
"childTable": "Stół dziecka.",
"childColumn": "Kolumna dla dzieci",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Na aktualizacji",
"onDelete": "Na delete.",
"account": "Konto",
@ -311,7 +312,9 @@
"signInWithGoogle": "Zaloguj się przez Google",
"agreeToTos": "Rejestrując się, akceptujesz warunki korzystania z usługi",
"welcomeToNc": "Witaj w NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Utwórz projekt",
@ -628,7 +631,8 @@
"showM2mTables": "Pokaż tabele M2M",
"deleteKanbanStackConfirmation": "Usunięcie tego stosu spowoduje również usunięcie wybranej opcji `{stackToBeDeleted}` z `{groupingField}`. Rekordy przeniosą się do nieskategoryzowanego stosu.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Twoje wyszukiwanie dla {search}, nie znaleziono żadnych wyników",

8
packages/nc-gui/lang/pt.json

@ -277,6 +277,7 @@
"selectUserRole": "Selecione a função do usuário",
"childTable": "Mesa de criança",
"childColumn": "Coluna de criança",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Na atualização",
"onDelete": "Em excluir",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Criar Projecto",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "A sua pesquisa por {search} não encontrou resultados",

8
packages/nc-gui/lang/pt_BR.json

@ -277,6 +277,7 @@
"selectUserRole": "Selecione a função do usuário",
"childTable": "Mesa de criança",
"childColumn": "Coluna de criança",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Na atualização",
"onDelete": "Em excluir",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Criar Projeto",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "A sua pesquisa por {search} não encontrou resultados",

8
packages/nc-gui/lang/ru.json

@ -277,6 +277,7 @@
"selectUserRole": "Выберите роль пользователя",
"childTable": "Дочерняя таблица",
"childColumn": "Дочерний столбец",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "При обновлении",
"onDelete": "При удалении",
"account": "Учётная запись",
@ -311,7 +312,9 @@
"signInWithGoogle": "Войти при помощи Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Добро пожаловать в NocoDB!",
"inviteOnlySignup": "Разрешить регистрацию только по ссылке"
"inviteOnlySignup": "Разрешить регистрацию только по ссылке",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Создать проект",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Ваш поиск {поиск} не дал результатов",

8
packages/nc-gui/lang/sk.json

@ -277,6 +277,7 @@
"selectUserRole": "Select User Role",
"childTable": "Child table",
"childColumn": "Child column",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "On Update",
"onDelete": "On Delete",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Create Project",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Your search for {search} found no results",

8
packages/nc-gui/lang/sl.json

@ -277,6 +277,7 @@
"selectUserRole": "Izberite vlogo uporabnika",
"childTable": "Otroška miza",
"childColumn": "Otroška stolpec",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Na posodobitvi",
"onDelete": "Na izbrisu",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Ustvari projek",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Vaše iskanje {search} ni dalo rezultatov",

8
packages/nc-gui/lang/sv.json

@ -277,6 +277,7 @@
"selectUserRole": "Välj användarroll",
"childTable": "Barnbord",
"childColumn": "Barnkolonn",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Vid uppdatering",
"onDelete": "På radera",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Skapa projekt",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Din sökning efter {Sök} har inga resultat",

8
packages/nc-gui/lang/th.json

@ -277,6 +277,7 @@
"selectUserRole": "เลอกบทบาทผใช",
"childTable": "โตะเดก",
"childColumn": "คอลมนเดก",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "เมออปเดต",
"onDelete": "ในการลบ",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "สรางโครงการ",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "การคนหาของคณสำหรบ {search} ไมพบผลลพธ",

8
packages/nc-gui/lang/tr.json

@ -277,6 +277,7 @@
"selectUserRole": "Kullanıcı Rolü Seç",
"childTable": "Alt tablo",
"childColumn": "Alt sütun",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Güncellenince",
"onDelete": "Silinince",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Proje Oluştur",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "{search} için aramanız hiç bir sonuç bulamadı",

8
packages/nc-gui/lang/uk.json

@ -277,6 +277,7 @@
"selectUserRole": "Виберіть Роль користувача",
"childTable": "Дитячий стіл",
"childColumn": "Дитяча колонка",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "На оновлення",
"onDelete": "На видалі",
"account": "Обліковий запис",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Створити проект",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Ваш пошук {пошук} не знайдено жодних результатів",

8
packages/nc-gui/lang/vi.json

@ -277,6 +277,7 @@
"selectUserRole": "Chọn vai trò người dùng",
"childTable": "Bảng con",
"childColumn": "Cột trẻ con.",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "Trên bản cập nhật",
"onDelete": "Trên xóa",
"account": "Tài khoản",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "Tạo dự án",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "Tìm kiếm của bạn cho {search} tìm thấy không có kết quả",

8
packages/nc-gui/lang/zh-Hans.json

@ -277,6 +277,7 @@
"selectUserRole": "选择用户角色",
"childTable": "子表",
"childColumn": "子列",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "更新",
"onDelete": "删除",
"account": "帐户",
@ -311,7 +312,9 @@
"signInWithGoogle": "使用 Google 登录",
"agreeToTos": "注册即表明您同意服务条款",
"welcomeToNc": "欢迎来到NocoDB!",
"inviteOnlySignup": "Allow signup only using invite url"
"inviteOnlySignup": "Allow signup only using invite url",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "创建项目",
@ -628,7 +631,8 @@
"showM2mTables": "Show M2M Tables",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "搜索: {search} 没有发现匹配的结果",

8
packages/nc-gui/lang/zh-Hant.json

@ -277,6 +277,7 @@
"selectUserRole": "選擇使用者角色",
"childTable": "子表格",
"childColumn": "子欄",
"linkToAnotherRecord": "Link to another record",
"onUpdate": "更新",
"onDelete": "在刪除",
"account": "Account",
@ -311,7 +312,9 @@
"signInWithGoogle": "Sign in with Google",
"agreeToTos": "By signing up, you agree to the Terms of Service",
"welcomeToNc": "Welcome to NocoDB!",
"inviteOnlySignup": "只接受使用邀請連結進行註冊"
"inviteOnlySignup": "只接受使用邀請連結進行註冊",
"nextRow": "Next Row",
"prevRow": "Previous Row"
},
"activity": {
"createProject": "建立專案",
@ -628,7 +631,8 @@
"showM2mTables": "顯示多對多資料表",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content."
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"
},
"error": {
"searchProject": "您的搜尋 {search} 找不到結果",

7
packages/nc-gui/layouts/shared-view.vue

@ -1,7 +1,10 @@
<script lang="ts" setup>
import { navigateTo, useEventListener, useRouter } from '#imports'
const { isLoading, currentVersion } = useGlobal()
const { isLoading, appInfo } = useGlobal()
const { sharedView } = useSharedView()
const router = useRouter()
onMounted(() => {
@ -43,7 +46,7 @@ export default {
<div class="transition-all duration-200 p-2 cursor-pointer transform hover:scale-105" @click="navigateTo('/')">
<a-tooltip placement="bottom">
<template #title>
{{ currentVersion }}
{{ appInfo.version }}
</template>
<img width="35" alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" />
</a-tooltip>

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

@ -139,8 +139,8 @@ export default defineNuxtConfig({
}),
monacoEditorPlugin({
languageWorkers: ['json'],
customDistPath: (root: string, buildOutDir: string, base: string) => {
return buildOutDir + '/' + 'monacoeditorwork'
customDistPath: (root: string, buildOutDir: string) => {
return `${buildOutDir}/` + `monacoeditorwork`
},
}),
PurgeIcons({

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

@ -10689,9 +10689,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@ -12135,7 +12135,7 @@
}
},
"node_modules/nocodb-sdk": {
"version": "0.101.0-beta.0",
"version": "0.101.2",
"resolved": "file:../nocodb-sdk",
"license": "AGPL-3.0-or-later",
"dependencies": {
@ -15917,9 +15917,9 @@
}
},
"node_modules/tsconfig-paths/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@ -25840,9 +25840,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"jsonc-eslint-parser": {
@ -26911,7 +26911,7 @@
}
},
"nocodb-sdk": {
"version": "0.101.0-beta.0",
"version": "0.101.2",
"requires": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
@ -29746,9 +29746,9 @@
},
"dependencies": {
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"

8
packages/nc-gui/pages/[projectType]/form/[viewId]/index/index.vue

@ -85,7 +85,7 @@ function isRequired(_columnObj: Record<string, any>, required = false) {
<LazySmartsheetVirtualCell
v-if="isVirtualCol(field)"
:model-value="null"
class="mt-0 nc-input"
class="mt-0 nc-input nc-cell"
:data-testid="`nc-form-input-cell-${field.label || field.title}`"
:class="`nc-form-input-${field.title?.replaceAll(' ', '')}`"
:column="field"
@ -133,3 +133,9 @@ function isRequired(_columnObj: Record<string, any>, required = false) {
</div>
</div>
</template>
<style lang="scss" scoped>
:deep(.nc-cell .nc-action-icon) {
@apply !text-white-500 !bg-white/50 !rounded-full !p-1 !text-xs !w-7 !h-7 !flex !items-center !justify-center !cursor-pointer !hover:!bg-white-600 !hover:!text-white-600 !transition;
}
</style>

50
packages/nc-gui/utils/filterUtils.ts

@ -1,4 +1,24 @@
export const comparisonOpList = [
import { UITypes } from 'nocodb-sdk'
export const comparisonOpList: {
text: string
value: string
ignoreVal?: boolean
includedTypes?: UITypes[]
excludedTypes?: UITypes[]
}[] = [
{
text: 'is checked',
value: 'checked',
ignoreVal: true,
includedTypes: [UITypes.Checkbox],
},
{
text: 'is not checked',
value: 'notchecked',
ignoreVal: true,
includedTypes: [UITypes.Checkbox],
},
{
text: 'is equal',
value: 'eq',
@ -10,20 +30,24 @@ export const comparisonOpList = [
{
text: 'is like',
value: 'like',
excludedTypes: [UITypes.Checkbox],
},
{
text: 'is not like',
value: 'nlike',
excludedTypes: [UITypes.Checkbox],
},
{
text: 'is empty',
value: 'empty',
ignoreVal: true,
excludedTypes: [UITypes.Checkbox],
},
{
text: 'is not empty',
value: 'notempty',
ignoreVal: true,
excludedTypes: [UITypes.Checkbox],
},
{
text: 'is null',
@ -35,20 +59,44 @@ export const comparisonOpList = [
value: 'notnull',
ignoreVal: true,
},
{
text: 'contains all of',
value: 'allof',
includedTypes: [UITypes.MultiSelect],
},
{
text: 'contains any of',
value: 'anyof',
includedTypes: [UITypes.MultiSelect],
},
{
text: 'does not contain all of',
value: 'nallof',
includedTypes: [UITypes.MultiSelect],
},
{
text: 'does not contain any of',
value: 'nanyof',
includedTypes: [UITypes.MultiSelect],
},
{
text: '>',
value: 'gt',
excludedTypes: [UITypes.Checkbox],
},
{
text: '<',
value: 'lt',
excludedTypes: [UITypes.Checkbox],
},
{
text: '>=',
value: 'gte',
excludedTypes: [UITypes.Checkbox],
},
{
text: '<=',
value: 'lte',
excludedTypes: [UITypes.Checkbox],
},
]

4
packages/nc-gui/utils/parsers/parserHelpers.ts

@ -64,7 +64,7 @@ export const extractMultiOrSingleSelectProps = (colData: []) => {
: [],
)
const uniqueVals = [...new Set(flattenedVals.map((v: any) => v.toString().trim().toLowerCase()))]
const uniqueVals = [...new Set(flattenedVals.map((v: any) => v.toString().trim()))]
if (uniqueVals.length > maxSelectOptionsAllowed) {
// too many options are detected, convert the column to SingleLineText instead
@ -81,7 +81,7 @@ export const extractMultiOrSingleSelectProps = (colData: []) => {
colProps.dtxp = `${uniqueVals.map((v) => `'${v.replace(/'/gi, "''")}'`).join(',')}`
}
} else {
const uniqueVals = [...new Set(colData.map((v: any) => v.toString().trim().toLowerCase()))]
const uniqueVals = [...new Set(colData.map((v: any) => v.toString().trim()))]
if (uniqueVals.length > maxSelectOptionsAllowed) {
// too many options are detected, convert the column to SingleLineText instead

2
packages/nc-lib-gui/package.json

@ -1,6 +1,6 @@
{
"name": "nc-lib-gui",
"version": "0.101.0-beta.0",
"version": "0.101.2",
"description": "NocoDB GUI",
"author": {
"name": "NocoDB",

24
packages/nc-plugin/package-lock.json generated

@ -84,9 +84,9 @@
}
},
"node_modules/@babel/core/node_modules/json5": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@ -7629,9 +7629,9 @@
"dev": true
},
"node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@ -12312,9 +12312,9 @@
},
"dependencies": {
"json5": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"semver": {
@ -18140,9 +18140,9 @@
"dev": true
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"

4
packages/noco-docs/content/en/developer-resources/rest-apis.md

@ -221,6 +221,10 @@ Currently, the default value for {orgs} is <b>noco</b>. Users will be able to ch
| btw | between | (colName,btw,val1,val2) |
| nbtw | not between | (colName,nbtw,val1,val2) |
| like | like | (colName,like,%name) |
| allof | includes all of | (colName,allof,val1,val2,...) |
| anyof | includes any of | (colName,anyof,val1,val2,...) |
| nallof | does not include all of (includes none or some, but not all of) | (colName,nallof,val1,val2,...) |
| nanyof | does not include any of (includes none of) | (colName,nanyof,val1,val2,...) |
## Logical Operators

27
packages/noco-docs/content/en/setup-and-usages/account-settings.md

@ -27,14 +27,25 @@ If you are a super admin, you can also manage all user roles in organization lev
## User Management
Super-admin has new privelege to do user management at root-level.
Permissions within NocoDB are divided into two levels: Organisation level and Project level.
- `org-level-creator` - this user can create a new project and access any invited project.
- `org-level-viewer` - this user can't create a new project but they can access any invited project.
### Organisation Level Permissions:
- `Org Level Creator`: Allows users to create new projects and access invited projects.
- `Org Level Viewer`: Allows users to access invited projects but does not permit the creation of new projects.
![image](https://user-images.githubusercontent.com/35857179/203261168-5ba75f9c-476e-4fe7-ace4-f81051f42773.png)
### Project Level Permissions:
- `Owner`: The user who created the project. A project can have only one owner. The owner persists until the project exists and the role is non-transferable. The owner has access to carry out any operations within the project, including deleting it.
- `Creator`: Has access to carry out any operations within the project except deleting the project and removing the "Owner."
- `Editor`: Can modify data but cannot modify the schema (add/remove columns, tables, users, and such).
- `Commenter`: Can neither modify data nor schema, can only see data and can mark row-level comments.
- `Viewer`: Can only see data.
Additional access details for project level permissions can be found [here](https://docs.nocodb.com/setup-and-usages/team-and-auth#advanced-options--configurations).
Please note that the above-mentioned Project Level Permissions are additional to the already defined Organisation Level Permissions.
In addition to the previously defined permissions, NocoDB also includes the role of "Super Admin." The "Super Admin" is the first user to sign up on this NocoDB installation. An organisation can have only one "Super Admin" and this role is non-transferable. The "Super Admin" will have the equivalent permissions of an "Org Level Creator" and "Owner" for all projects within the organisation.
## Enable / Disable Signup
Signup without an invitation is disabled by default and can be managed from UI by a super admin.
@ -45,4 +56,10 @@ Signup without an invitation is disabled by default and can be managed from UI b
You can also manage the app store plugins here.
![image](https://user-images.githubusercontent.com/35857179/203267619-24a8f5f5-1c8c-4419-a7a1-be4377fe6216.png)
![image](https://user-images.githubusercontent.com/35857179/203267619-24a8f5f5-1c8c-4419-a7a1-be4377fe6216.png)
## License
You can configure NocoDB Enterprise `License key` here
![Screenshot 2023-01-12 at 2 30 57 PM](https://user-images.githubusercontent.com/86527202/212023989-0129af0a-689d-465e-bdda-3d54399ea6b7.png)

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

@ -1,12 +1,12 @@
{
"name": "nocodb-sdk",
"version": "0.101.0-beta.0",
"version": "0.101.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nocodb-sdk",
"version": "0.101.0-beta.0",
"version": "0.101.2",
"license": "AGPL-3.0-or-later",
"dependencies": {
"axios": "^0.21.1",
@ -2654,11 +2654,10 @@
"license": "MIT"
},
"node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"minimist": "^1.2.0"
},
@ -5823,9 +5822,9 @@
"dev": true
},
"json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"requires": {
"minimist": "^1.2.0"

2
packages/nocodb-sdk/package.json

@ -1,6 +1,6 @@
{
"name": "nocodb-sdk",
"version": "0.101.0-beta.0",
"version": "0.101.2",
"description": "NocoDB SDK",
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",

20
packages/nocodb-sdk/src/lib/Api.ts

@ -2264,6 +2264,7 @@ export class Api<
*
* @tags DB table column
* @name Delete
* @summary Column Delete
* @request DELETE:/api/v1/db/meta/columns/{columnId}
* @response `200` `void` OK
*/
@ -2274,6 +2275,22 @@ export class Api<
...params,
}),
/**
* No description
*
* @tags DB Table Column
* @name Get
* @summary Column Get
* @request GET:/api/v1/db/meta/columns/{columnId}
* @response `200` `void` OK
*/
get: (columnId: string, params: RequestParams = {}) =>
this.request<void, any>({
path: `/api/v1/db/meta/columns/${columnId}`,
method: 'GET',
...params,
}),
/**
* No description
*
@ -3576,6 +3593,7 @@ export class Api<
where?: string;
/** Query params for nested data */
nested?: any;
offset?: number;
},
params: RequestParams = {}
) =>
@ -4004,6 +4022,7 @@ export class Api<
* @response `200` `(ViewType & {
relatedMetas?: any,
client?: string,
base_id?: string,
columns?: ((GridColumnType | FormColumnType | GalleryColumnType) & ColumnType),
model?: TableType,
@ -4017,6 +4036,7 @@ export class Api<
ViewType & {
relatedMetas?: any;
client?: string;
base_id?: string;
columns?: (GridColumnType | FormColumnType | GalleryColumnType) &
ColumnType;
model?: TableType;

17
packages/nocodb-sdk/src/lib/formulaHelpers.ts

@ -8,21 +8,28 @@ export const jsepCurlyHook = {
jsep.hooks.add('gobble-token', function gobbleCurlyLiteral(env) {
const OCURLY_CODE = 123; // {
const CCURLY_CODE = 125; // }
let start = -1;
const { context } = env;
if (
!jsep.isIdentifierStart(context.code) &&
context.code === OCURLY_CODE
) {
if (start == -1) {
start = context.index;
}
context.index += 1;
const nodes = context.gobbleExpressions(CCURLY_CODE);
context.gobbleExpressions(CCURLY_CODE);
if (context.code === CCURLY_CODE) {
context.index += 1;
env.node = {
type: jsep.IDENTIFIER,
// column name with space would break it down to jsep.IDENTIFIER + jsep.LITERAL
// either take node.name for jsep.IDENTIFIER
// or take node.value for jsep.LITERAL
name: nodes.map((node) => node.name || node.value).join(' '),
name: /{{(.*?)}}/.test(context.expr)
? // start would be the position of the first curly bracket
// add 2 to point to the first character for expressions like {{col1}}
context.expr.slice(start + 2, context.index - 1)
: // start would be the position of the first curly bracket
// add 1 to point to the first character for expressions like {col1}
context.expr.slice(start + 1, context.index - 1),
};
return env.node;
} else {

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

Loading…
Cancel
Save