Browse Source

Merge pull request #4810 from nocodb/develop

pull/4812/head 0.101.0
github-actions[bot] 2 years ago committed by GitHub
parent
commit
996026341c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/workflows/pr-to-master.yml
  2. 2
      .github/workflows/release-draft.yml
  3. 94
      .github/workflows/release-executables.yml
  4. 2
      .github/workflows/release-nightly-dev.yml
  5. 4
      .github/workflows/release-npm.yml
  6. 2
      .github/workflows/release-pr.yml
  7. 4
      .github/workflows/update-sdk-path.yml
  8. 20
      packages/nc-cli/package-lock.json
  9. 13
      packages/nc-gui/components/cell/Currency.vue
  10. 8
      packages/nc-gui/components/cell/Json.vue
  11. 37
      packages/nc-gui/components/cell/MultiSelect.vue
  12. 13
      packages/nc-gui/components/cell/Percent.vue
  13. 39
      packages/nc-gui/components/cell/SingleSelect.vue
  14. 8
      packages/nc-gui/components/dashboard/TreeView.vue
  15. 4
      packages/nc-gui/components/general/ViewIcon.vue
  16. 6
      packages/nc-gui/components/smartsheet/Gallery.vue
  17. 60
      packages/nc-gui/components/smartsheet/Kanban.vue
  18. 2
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  19. 3
      packages/nc-gui/components/virtual-cell/Formula.vue
  20. 1
      packages/nc-gui/components/virtual-cell/barcode/Barcode.vue
  21. 3
      packages/nc-gui/composables/useMultiSelect/index.ts
  22. 8
      packages/nc-gui/composables/useProject.ts
  23. 748
      packages/nc-gui/lang/cs.json
  24. 748
      packages/nc-gui/lang/eu.json
  25. 160
      packages/nc-gui/lang/fr.json
  26. 748
      packages/nc-gui/lang/sk.json
  27. 3
      packages/nc-gui/lib/enums.ts
  28. 3
      packages/nc-gui/nuxt.config.ts
  29. 76
      packages/nc-gui/package-lock.json
  30. 2
      packages/nc-gui/package.json
  31. 18
      packages/nc-gui/pages/[projectType]/[projectId]/index/index.vue
  32. 10
      packages/nc-gui/pages/index/index/[projectId].vue
  33. 65
      packages/nc-plugin/package-lock.json
  34. 112
      packages/noco-docs/content/en/getting-started/installation.md
  35. 2
      packages/noco-docs/content/en/setup-and-usages/dashboard.md
  36. 99
      packages/noco-docs/content/en/setup-and-usages/meta-management.md
  37. 21
      packages/noco-docs/content/en/setup-and-usages/project-settings.md
  38. 2
      packages/noco-docs/content/en/setup-and-usages/sync-schema.md
  39. 9233
      packages/noco-docs/package-lock.json
  40. 17
      packages/nocodb-sdk/package-lock.json
  41. 17
      packages/nocodb-sdk/src/lib/formulaHelpers.ts
  42. 511
      packages/nocodb/package-lock.json
  43. 6
      packages/nocodb/package.json
  44. 2
      packages/nocodb/src/lib/Noco.ts
  45. 132
      packages/nocodb/src/lib/db/sql-client/lib/mysql/mysql.queries.ts
  46. 14
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts
  47. 2
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts
  48. 86
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts
  49. 15
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts
  50. 53
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts
  51. 6
      packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts
  52. 21
      packages/nocodb/src/lib/meta/api/columnApis.ts
  53. 13
      packages/nocodb/src/lib/meta/api/sync/helpers/job.ts
  54. 6
      packages/nocodb/src/lib/meta/helpers/populateSamplePayload.ts
  55. 2
      packages/nocodb/src/lib/models/Base.ts
  56. 13
      packages/nocodb/src/lib/models/Filter.ts
  57. 27
      packages/nocodb/src/lib/models/Model.ts
  58. 2
      packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts
  59. 34
      packages/nocodb/src/lib/version-upgrader/ncFilterUpgrader.ts
  60. 14
      tests/playwright/package-lock.json
  61. 13
      tests/playwright/pages/Dashboard/common/Cell/DateTimeCell.ts
  62. 12
      tests/playwright/tests/columnFormula.spec.ts
  63. 3
      tests/playwright/tests/language.spec.ts

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

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

2
.github/workflows/release-draft.yml

@ -56,7 +56,7 @@ jobs:
echo "TARGET_SHA=${TARGET_SHA}" >> $GITHUB_OUTPUT echo "TARGET_SHA=${TARGET_SHA}" >> $GITHUB_OUTPUT
echo "Setting TARGET_SHA: ${TARGET_SHA}" echo "Setting TARGET_SHA: ${TARGET_SHA}"
- name: Create tag - name: Create tag
uses: actions/github-script@v3 uses: actions/github-script@v6
with: with:
# need workflows permission but it's not in GITHUB_TOKEN scope # need workflows permission but it's not in GITHUB_TOKEN scope
# need a custom PAT with workflows permission here # need a custom PAT with workflows permission here

94
.github/workflows/release-executables.yml

@ -21,14 +21,6 @@ jobs:
build-executables: build-executables:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: 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 - uses: actions/checkout@v3
- name: Cache node modules - name: Cache node modules
id: cache-npm id: cache-npm
@ -107,54 +99,23 @@ jobs:
mv ./dist/Noco-macos-arm64 ./mac-dist/ mv ./dist/Noco-macos-arm64 ./mac-dist/
mv ./dist/Noco-macos-x64 ./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 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: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.get_release.outputs.upload_url }} files: |
asset_path: ./scripts/pkg-executable/dist/Noco-linux-x64 ./scripts/pkg-executable/dist/Noco-win-arm64.exe
asset_name: Noco-linux-x64 ./scripts/pkg-executable/dist/Noco-win-x64.exe
asset_content_type: application/octet-stream ./scripts/pkg-executable/dist/Noco-linux-arm64
./scripts/pkg-executable/dist/Noco-linux-x64
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
with: with:
name: ${{ github.event.inputs.tag || inputs.tag }} name: ${{ github.event.inputs.tag || inputs.tag }}
path: scripts/pkg-executable/mac-dist path: scripts/pkg-executable/mac-dist
retention-days: 1 retention-days: 1
outputs:
upload_url: ${{ steps.get_release.outputs.upload_url }}
sign-mac-executables: sign-mac-executables:
runs-on: macos-latest runs-on: macos-latest
needs: build-executables needs: build-executables
@ -205,40 +166,15 @@ jobs:
id: compress id: compress
- name: Upload macos-x64 build to asset - name: Upload macos executable to asset
uses: actions/upload-release-asset@v1 uses: softprops/action-gh-release@v1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ needs.build-executables.outputs.upload_url }} files: |
asset_path: ./scripts/pkg-executable/mac-dist/Noco-macos-x64 ./scripts/pkg-executable/mac-dist/Noco-macos-x64
asset_name: Noco-macos-x64 ./scripts/pkg-executable/mac-dist/Noco-macos-arm64
asset_content_type: application/octet-stream ./scripts/pkg-executable/mac-dist/nocodb.tar.gz
- name: Upload macos-arm64 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-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
- name: Generate Homebrew Formula class and push - name: Generate Homebrew Formula class and push
run: | run: |
@ -267,7 +203,3 @@ jobs:
git commit ./Formula/nocodb.rb -m "Automatic publish" git commit ./Formula/nocodb.rb -m "Automatic publish"
git push git push

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

@ -21,7 +21,7 @@ jobs:
TAG_NAME=${CURRENT_DATE}-${CURRENT_TIME} TAG_NAME=${CURRENT_DATE}-${CURRENT_TIME}
IS_DAILY='Y' IS_DAILY='Y'
# Get current version # Get current version
CURRENT_VERSION=$(basename $(curl -fs -o/dev/null -w %{redirect_url} https://github.com/nocodb/nocodb/releases/latest)) CURRENT_VERSION=$(curl -fs https://docs.nocodb.com/releases | grep article | grep div | grep h2 | grep 'id\="[^"]*' -o | cut -c 5-)
# Set the tag # Set the tag
if [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then if [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then
IS_DAILY='N' IS_DAILY='N'

4
.github/workflows/release-npm.yml

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

2
.github/workflows/release-pr.yml

@ -33,7 +33,7 @@ jobs:
# Get current PR number # Get current PR number
PR_NUMBER=${{github.event.number}} PR_NUMBER=${{github.event.number}}
# Get current version # Get current version
CURRENT_VERSION=$(basename $(curl -fs -o/dev/null -w %{redirect_url} https://github.com/nocodb/nocodb/releases/latest)) CURRENT_VERSION=$(curl -fs https://docs.nocodb.com/releases | grep article | grep div | grep h2 | grep 'id\="[^"]*' -o | cut -c 5-)
# Construct tag name # Construct tag name
TAG_NAME=pr-${PR_NUMBER}-${CURRENT_DATE}-${CURRENT_TIME} TAG_NAME=pr-${PR_NUMBER}-${CURRENT_DATE}-${CURRENT_TIME}
echo "TARGET_TAG=${TAG_NAME}" >> $GITHUB_OUTPUT echo "TARGET_TAG=${TAG_NAME}" >> $GITHUB_OUTPUT

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

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

20
packages/nc-cli/package-lock.json generated

@ -8753,13 +8753,10 @@
"dev": true "dev": true
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.0", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
"dev": true, "dev": true,
"dependencies": {
"minimist": "^1.2.5"
},
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
}, },
@ -22229,13 +22226,10 @@
"dev": true "dev": true
}, },
"json5": { "json5": {
"version": "2.2.0", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
"dev": true, "dev": true
"requires": {
"minimist": "^1.2.5"
}
}, },
"jsonfile": { "jsonfile": {
"version": "6.1.0", "version": "6.1.0",

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

@ -14,7 +14,18 @@ const column = inject(ColumnInj)!
const editEnabled = inject(EditModeInj)! 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() const lastSaved = ref()

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

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

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

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

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

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

8
packages/nc-gui/components/dashboard/TreeView.vue

@ -35,7 +35,7 @@ const { addTab, updateTab } = useTabs()
const { $api, $e } = useNuxtApp() const { $api, $e } = useNuxtApp()
const { bases, tables, loadTables, isSharedBase } = useProject() const { project, loadProject, bases, tables, loadTables, isSharedBase } = useProject()
const { activeTab } = useTabs() const { activeTab } = useTabs()
@ -324,6 +324,12 @@ const setIcon = async (icon: string, table: TableType) => {
message.error(await extractSdkResponseErrorMsg(e)) message.error(await extractSdkResponseErrorMsg(e))
} }
} }
onMounted(async () => {
if (!project.value?.id) {
await loadProject()
}
})
</script> </script>
<template> <template>

4
packages/nc-gui/components/general/ViewIcon.vue

@ -10,7 +10,7 @@ const props = defineProps<{
const viewMeta = toRef(props, 'meta') const viewMeta = toRef(props, 'meta')
</script> </script>
<template> <template v-if="viewMeta">
<IcIcon <IcIcon
v-if="viewMeta?.meta?.icon" v-if="viewMeta?.meta?.icon"
:data-testid="`nc-icon-${viewMeta?.meta?.icon}`" :data-testid="`nc-icon-${viewMeta?.meta?.icon}`"
@ -19,7 +19,7 @@ const viewMeta = toRef(props, 'meta')
/> />
<component <component
:is="viewIcons[viewMeta.type]?.icon" :is="viewIcons[viewMeta.type]?.icon"
v-else v-else-if="viewMeta?.type"
class="nc-view-icon group-hover" class="nc-view-icon group-hover"
:style="{ color: viewIcons[viewMeta.type]?.color }" :style="{ color: viewIcons[viewMeta.type]?.color }"
/> />

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

@ -17,6 +17,7 @@ import {
createEventHook, createEventHook,
extractPkFromRow, extractPkFromRow,
inject, inject,
isLTAR,
nextTick, nextTick,
onMounted, onMounted,
provide, provide,
@ -210,7 +211,10 @@ watch(view, async (nextView) => {
</template> </template>
<div v-for="col in fieldsWithoutCover" :key="`record-${record.row.id}-${col.id}`"> <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="flex flex-row w-full justify-start border-b-1 border-gray-100 py-2.5">
<div class="w-full text-gray-600"> <div class="w-full text-gray-600">
<LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" :hide-menu="true" /> <LazySmartsheetHeaderVirtualCell v-if="isVirtualCol(col)" :column="col" :hide-menu="true" />

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

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

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

@ -236,7 +236,7 @@ defineExpose({
:key="`${i}_7`" :key="`${i}_7`"
v-model:value="filter.value" v-model:value="filter.value"
class="nc-filter-value-select" class="nc-filter-value-select"
:disabled="filter.readOnly" :disabled="filter.readOnly || !filter.fk_column_id"
@click.stop @click.stop
@input="saveOrUpdate(filter, i)" @input="saveOrUpdate(filter, i)"
/> />

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

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

1
packages/nc-gui/components/virtual-cell/barcode/Barcode.vue

@ -46,7 +46,6 @@ const { showEditNonEditableFieldWarning, showClearNonEditableFieldWarning } = us
v-if="showBarcode" v-if="showBarcode"
:barcode-value="barcodeValue" :barcode-value="barcodeValue"
:barcode-format="barcodeMeta.barcodeFormat" :barcode-format="barcodeMeta.barcodeFormat"
class="nc-barcode-svg"
@on-click-barcode="showBarcodeModal" @on-click-barcode="showBarcodeModal"
> >
<template #barcodeRenderError> <template #barcodeRenderError>

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

@ -267,7 +267,8 @@ export function useMultiSelect(
// copy - ctrl/cmd +c // copy - ctrl/cmd +c
case 67: case 67:
// set clipboard context only if single cell selected // 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 = { clipboardContext = {
value: rowObj.row[columnObj.title!], value: rowObj.row[columnObj.title!],
uidt: columnObj.uidt as UITypes, uidt: columnObj.uidt as UITypes,

8
packages/nc-gui/composables/useProject.ts

@ -1,6 +1,7 @@
import type { BaseType, OracleUi, ProjectType, TableType } from 'nocodb-sdk' import type { BaseType, OracleUi, ProjectType, TableType } from 'nocodb-sdk'
import { SqlUiFactory } from 'nocodb-sdk' import { SqlUiFactory } from 'nocodb-sdk'
import { isString } from '@vueuse/core' import { isString } from '@vueuse/core'
import { useRoute } from 'vue-router'
import { import {
ClientType, ClientType,
computed, computed,
@ -11,7 +12,6 @@ import {
useInjectionState, useInjectionState,
useNuxtApp, useNuxtApp,
useRoles, useRoles,
useRoute,
useRouter, useRouter,
useTheme, useTheme,
} from '#imports' } from '#imports'
@ -42,9 +42,9 @@ const [setup, use] = useInjectionState(() => {
const lastOpenedViewMap = ref<Record<string, string>>({}) const lastOpenedViewMap = ref<Record<string, string>>({})
let forcedProjectId: string | undefined const forcedProjectId = ref<string>()
const projectId = computed(() => forcedProjectId || (route.params.projectId as string)) const projectId = computed(() => forcedProjectId.value || (route.params.projectId as string))
// todo: refactor path param name and variable name // todo: refactor path param name and variable name
const projectType = $computed(() => route.params.projectType as string) const projectType = $computed(() => route.params.projectType as string)
@ -107,7 +107,7 @@ const [setup, use] = useInjectionState(() => {
} }
async function loadProject(withTheme = true, forcedId?: string) { async function loadProject(withTheme = true, forcedId?: string) {
if (forcedId) forcedProjectId = forcedId if (forcedId) forcedProjectId.value = forcedId
if (projectType === 'base') { if (projectType === 'base') {
try { try {
const baseData = await api.public.sharedBaseGet(route.params.projectId as string) const baseData = await api.public.sharedBaseGet(route.params.projectId as string)

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

@ -0,0 +1,748 @@
{
"general": {
"home": "Domů",
"load": "Načíst",
"open": "Otevřít",
"close": "Zavřít",
"yes": "Ano",
"no": "Ne",
"ok": "OK",
"and": "a",
"or": "nebo",
"add": "Přidat",
"edit": "Upravit",
"remove": "Odstranit",
"save": "Uložit",
"cancel": "Zrušit",
"submit": "Potvrdit",
"create": "Vytvořit",
"duplicate": "Duplikovat",
"insert": "Vložit",
"delete": "Smazat",
"update": "Aktualizovat",
"rename": "Přejmenovat",
"reload": "Znovu načíst",
"reset": "Obnovit",
"install": "Instalovat",
"show": "Zobrazit",
"hide": "Skrýt",
"showAll": "Zobrazit vše",
"hideAll": "Skrýt vše",
"showMore": "Zobrazit více",
"showOptions": "Zobrazit možnosti",
"hideOptions": "Skrýt možnosti",
"showMenu": "Zobrazit menu",
"hideMenu": "Skrýt menu",
"addAll": "Přidat vše",
"removeAll": "Odstranit vše",
"signUp": "REGISTROVAT",
"signIn": "PŘIHLÁSIT SE",
"signOut": "Odhlásit se",
"required": "Vyžadováno",
"preferred": "Preferováno",
"mandatory": "Povinné",
"loading": "Načítání ...",
"title": "Název",
"upload": "Nahrát",
"download": "Stáhnout",
"default": "Výchozí",
"more": "Více",
"less": "Méně",
"event": "Událost",
"condition": "Podmínka",
"after": "Po",
"before": "Před",
"search": "Hledat",
"notification": "Oznámení",
"reference": "Reference",
"function": "Funkce",
"confirm": "Potvrdit",
"generate": "Generovat",
"copy": "Kopírovat",
"misc": "Ostatní",
"lock": "Uzamknout",
"unlock": "Odemknout",
"credentials": "Přihlašovací údaje",
"help": "Pomoc",
"questions": "Otázky",
"reachOut": "Reach out here",
"betaNote": "Tato funkce je momentálně v beta verzi.",
"moreInfo": "Více informací naleznete zde",
"logs": "Protokoly",
"groupingField": "Grouping Field",
"insertAfter": "Vložit za",
"insertBefore": "Vložit před",
"hideField": "Skrýt pole",
"sortAsc": "Seřadit vzestupně",
"sortDesc": "Seřadit sestupně"
},
"objects": {
"project": "Projekt",
"projects": "Projekty",
"table": "Tabulka",
"tables": "Tabulky",
"field": "Pole",
"fields": "Pole",
"column": "Sloupec",
"columns": "Sloupce",
"page": "Stránka",
"pages": "Stránky",
"record": "záznam",
"records": "záznamy",
"webhook": "Webhook",
"webhooks": "Webhooky",
"view": "Pohled",
"views": "Pohledy",
"viewType": {
"grid": "Mřížka",
"gallery": "Galerie",
"form": "Formulář",
"kanban": "Kanban",
"calendar": "Kalendář"
},
"user": "Uživatel",
"users": "Uživatelé",
"role": "Role",
"roles": "Role",
"roleType": {
"owner": "Vlastník",
"creator": "Autor",
"editor": "Editor",
"commenter": "Komentátor",
"viewer": "Sledující",
"orgLevelCreator": "Organization Level Creator",
"orgLevelViewer": "Organization Level Viewer"
},
"sqlVIew": "SQL pohled"
},
"datatype": {
"ID": "ID",
"ForeignKey": "Cizí klíč",
"SingleLineText": "Jednořádkový text",
"LongText": "Dlouhý text",
"Attachment": "Příloha",
"Checkbox": "Zaškrtávací políčko",
"MultiSelect": "Vícenásobný výběr",
"SingleSelect": "Jednoduchý výběr",
"Collaborator": "Spolupracovník",
"Date": "Datum",
"Year": "Rok",
"Time": "Čas",
"PhoneNumber": "Telefonní číslo",
"Email": "E-mail",
"URL": "URL",
"Number": "Číslo",
"Decimal": "Desetinné číslo",
"Currency": "Měna",
"Percent": "Procenta",
"Duration": "Doba trvání",
"Rating": "Hodnocení",
"Formula": "Vzorec",
"Rollup": "Rollup",
"Count": "Počet",
"Lookup": "Lookup",
"DateTime": "Datum a čas",
"CreateTime": "Create Time",
"LastModifiedTime": "Čas poslední úpravy",
"AutoNumber": "Auto Number",
"Barcode": "Čárový kód",
"Button": "Tlačítko",
"Password": "Heslo",
"relationProperties": {
"noAction": "Žádná akce",
"cascade": "Kaskádově",
"restrict": "Restrict",
"setNull": "Nastavit NULL",
"setDefault": "Nastavit výchozí"
}
},
"filterOperation": {
"isEqual": "je rovno",
"isNotEqual": "není rovno",
"isLike": "je jako",
"isNot like": "není jako",
"isEmpty": "je prázdný",
"isNotEmpty": "is not empty",
"isNull": "is null",
"isNotNull": "is not null"
},
"title": {
"erdView": "ERD View",
"newProj": "New Project",
"myProject": "My Projects",
"formTitle": "Form Title",
"collabView": "Collaborative View",
"lockedView": "Locked View",
"personalView": "Personal View",
"appStore": "App Store",
"teamAndAuth": "Team & Auth",
"rolesUserMgmt": "Roles & Users Management",
"userMgmt": "Users Management",
"apiTokenMgmt": "API Tokens Management",
"rolesMgmt": "Roles Management",
"projMeta": "Project Metadata",
"metaMgmt": "Meta Management",
"metadata": "Metadata",
"exportImportMeta": "Export / Import Metadata",
"uiACL": "UI Access Control",
"metaOperations": "Metadata Operations",
"audit": "Audit",
"auditLogs": "Audit Log",
"sqlMigrations": "SQL migrace",
"dbCredentials": "Database Credentials",
"advancedParameters": "SSL & Advanced parameters",
"headCreateProject": "Vytvořit projekt | NocoDB",
"headLogin": "Přihlásit se | NocoDB",
"resetPassword": "Obnovit heslo",
"teamAndSettings": "Tým a nastavení",
"apiDocs": "API Docs",
"importFromAirtable": "Import From Airtable",
"generateToken": "Generovat token",
"APIsAndSupport": "APIs & Support",
"helpCenter": "Help center",
"swaggerDocumentation": "Swagger Documentation",
"quickImportFrom": "Rychlý import z",
"quickImport": "Rychlý import",
"advancedSettings": "Pokročilá nastavení",
"codeSnippet": "Úryvek kódu",
"keyboardShortcut": "Klávesové zkratky"
},
"labels": {
"createdBy": "Vytvořil/a",
"notifyVia": "Upozornit pomocí",
"projName": "Název projektu",
"tableName": "Název tabulky",
"viewName": "Název zobrazení",
"viewLink": "Zobrazit odkaz",
"columnName": "Název sloupce",
"columnType": "Typ sloupce",
"roleName": "Název role",
"roleDescription": "Popis role",
"databaseType": "Typ v databázi",
"lengthValue": "Délka / hodnota",
"dbType": "Typ databáze",
"sqliteFile": "SQLite soubor",
"hostAddress": "Adresa hostitele",
"port": "Číslo portu",
"username": "Uživatelské jméno",
"password": "Heslo",
"schemaName": "Název schématu",
"database": "Databáze",
"action": "Akce",
"actions": "Akce",
"operation": "Operace",
"operationType": "Typ operace",
"operationSubType": "Podtyp operace",
"description": "Popis",
"authentication": "Authentication",
"token": "Token",
"where": "Kde",
"cache": "Mezipaměť",
"chat": "Chat",
"email": "E-mail",
"storage": "Úložiště",
"uiAcl": "UI-ACL",
"models": "Modely",
"syncState": "Stav synchronizace",
"created": "Vytvořeno",
"sqlOutput": "Výstup SQL",
"addOption": "Přidat možnost",
"qrCodeValueColumn": "Sloupec s hodnotou QR kódu",
"barcodeValueColumn": "Sloupec s hodnotou čárového kódu",
"barcodeFormat": "Formát čárového kódu",
"qrCodeValueTooLong": "Příliš mnoho znaků pro QR kód",
"barcodeValueTooLong": "Příliš mnoho znaků pro čárový kód",
"aggregateFunction": "Agregační funkce",
"dbCreateIfNotExists": "Databáze : vytvořit, pokud neexistuje",
"clientKey": "Klíč klienta",
"clientCert": "Certifikát klienta",
"serverCA": "CA serveru",
"requriedCa": "Požadovaná CA",
"requriedIdentity": "Required-IDENTITY",
"inflection": {
"tableName": "Inflection - Table name",
"columnName": "Inflection - Column name"
},
"community": {
"starUs1": "Star",
"starUs2": "nás na Githubu",
"bookDemo": "Zarezervujte si DEMO zdarma",
"getAnswered": "Get your questions answered",
"joinDiscord": "Připojte se na Discord",
"joinCommunity": "Připojte se k NocoDB komunitě",
"joinReddit": "Připojte se k /r/NocoDB",
"followNocodb": "Sledovat NocoDB"
},
"docReference": "Odkaz na dokument",
"selectUserRole": "Vybrat uživatelskou roli",
"childTable": "Podřízená tabulka",
"childColumn": "Podřízený sloupec",
"onUpdate": "Při aktualizaci",
"onDelete": "Při odstranění",
"account": "Účet",
"language": "Jazyk",
"primaryColor": "Hlavní barva",
"accentColor": "Barva zvýraznění",
"customTheme": "Vlastní motiv",
"requestDataSource": "Request a data source you need?",
"apiKey": "API klíč",
"sharedBase": "Shared Base",
"importData": "Importovat data",
"importSecondaryViews": "Import Secondary Views",
"importRollupColumns": "Import Rollup Columns",
"importLookupColumns": "Import Lookup Columns",
"importAttachmentColumns": "Import Attachment Columns",
"importFormulaColumns": "Import Formula Columns",
"noData": "Žádná data",
"goToDashboard": "Přejít na přehled",
"importing": "Importing",
"flattenNested": "Flatten Nested",
"downloadAllowed": "Download allowed",
"weAreHiring": "We are Hiring!",
"primaryKey": "Primární klíč",
"hasMany": "má mnoho",
"belongsTo": "patří do",
"manyToMany": "má mnoho vztahů",
"extraConnectionParameters": "Extra connection parameters",
"commentsOnly": "Pouze komentáře",
"documentation": "Dokumentace",
"subscribeNewsletter": "Subscribe to our weekly newsletter",
"signUpWithGoogle": "Sign up with Google",
"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"
},
"activity": {
"createProject": "Vytvořit projekt",
"importProject": "Import projektu",
"searchProject": "Vyhledat projekt",
"editProject": "Upravit projekt",
"stopProject": "Zastavit projekt",
"startProject": "Spustit projekt",
"restartProject": "Restartovat projekt",
"deleteProject": "Smazat projekt",
"refreshProject": "Aktualizovat projekty",
"saveProject": "Uložit projekt",
"deleteKanbanStack": "Delete stack?",
"createProjectExtended": {
"extDB": "Vytvořit připojením <br>k externí databázi",
"excel": "Vytvořit projekt z Excelu",
"template": "Vytvořit projekt ze šablony"
},
"OkSaveProject": "Potvrdit a uložit projekt",
"upgrade": {
"available": "Dostupná aktualizace",
"releaseNote": "Seznam změn",
"howTo": "Jak aktualizovat?"
},
"translate": "Pomozte s překladem",
"account": {
"authToken": "Kopírovat ověřovací token",
"swagger": "Swagger: REST API",
"projInfo": "Kopírovat informace o projektu",
"themes": "Motivy"
},
"sort": "Řazení",
"addSort": "Přidat možnost řazení",
"filter": "Filtr",
"addFilter": "Přidat filtr",
"share": "Sdílet",
"shareBase": {
"disable": "Disable shared base",
"enable": "Anyone with the link",
"link": "Shared base link"
},
"invite": "Invite",
"inviteMore": "Invite more",
"inviteTeam": "Invite Team",
"inviteUser": "Invite User",
"inviteToken": "Invite Token",
"newUser": "New User",
"editUser": "Edit user",
"deleteUser": "Remove user from project",
"resendInvite": "Resend invite E-mail",
"copyInviteURL": "Copy invite URL",
"copyPasswordResetURL": "Copy password reset URL",
"newRole": "New role",
"reloadRoles": "Reload roles",
"nextPage": "Next page",
"prevPage": "Previous page",
"nextRecord": "Next record",
"previousRecord": "Previous record",
"copyApiURL": "Copy API URL",
"createTable": "Table Create",
"refreshTable": "Tables Refresh",
"renameTable": "Table Rename",
"deleteTable": "Table Delete",
"addField": "Add new field to this table",
"setPrimary": "Set as Primary value",
"addRow": "Přidat nový řádek",
"saveRow": "Uložit řádek",
"saveAndExit": "Uložit a odejít",
"saveAndStay": "Uložit a zůstat",
"insertRow": "Vložit nový řádek",
"deleteRow": "Odstranit řádek",
"deleteSelectedRow": "Odstranit vybrané řádky",
"importExcel": "Importovat Excel",
"importCSV": "Importovat CSV",
"downloadCSV": "Stáhnout jako CSV",
"downloadExcel": "Stáhnout jako XLSX",
"uploadCSV": "Nahrát CSV",
"import": "Importovat",
"importMetadata": "Importovat metadata",
"exportMetadata": "Exportovat metadata",
"clearMetadata": "Vymazat metadata",
"exportToFile": "Exportovat do souboru",
"changePwd": "Změnit heslo",
"createView": "Vytvořit pohled",
"shareView": "Sdílet pohled",
"listSharedView": "Shared View List",
"ListView": "Seznam pohledů",
"copyView": "Kopírovat pohled",
"renameView": "Přejmenovat pohled",
"deleteView": "Odstranit pohled",
"createGrid": "Create Grid View",
"createGallery": "Create Gallery View",
"createCalendar": "Create Calendar View",
"createKanban": "Create Kanban View",
"createForm": "Create Form View",
"showSystemFields": "Show system fields",
"copyUrl": "Kopírovat URL adresu",
"openTab": "Otevřít novou kartu",
"iFrame": "Copy embeddable HTML code",
"addWebhook": "Přidat nový webhook",
"newToken": "Přidat nový token",
"exportZip": "Exportovat zip archív",
"importZip": "Importovat zip archív",
"metaSync": "Synchronizovat nyní",
"settings": "Nastavení",
"previewAs": "Náhled jako",
"resetReview": "Obnovit náhled",
"testDbConn": "Otestovat připojení k databázi",
"removeDbFromEnv": "Odstranit databázi z prostředí",
"editConnJson": "Edit connection JSON",
"sponsorUs": "Sponsor Us",
"sendEmail": "SEND EMAIL",
"addUserToProject": "Add user to project",
"getApiSnippet": "Get API Snippet",
"clearCell": "Clear cell",
"addFilterGroup": "Add Filter Group",
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw",
"expandRecord": "Expand Record",
"deleteRecord": "Delete Record",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
},
"kanban": {
"collapseStack": "Collapse Stack",
"deleteStack": "Delete Stack",
"stackedBy": "Stacked By",
"chooseGroupingField": "Choose a Grouping Field",
"addOrEditStack": "Add / Edit Stack"
}
},
"tooltip": {
"saveChanges": "Save changes",
"xcDB": "Create a new project",
"extDB": "Supports MySQL, PostgreSQL, SQL Server & SQLite",
"apiRest": "Accessible via REST APIs",
"apiGQL": "Accessible via GraphQL APIs",
"theme": {
"dark": "It does come in Black (^⇧B)",
"light": "Does it come in Black ? (^⇧B)"
},
"addTable": "Add new table",
"inviteMore": "Invite more users",
"toggleNavDraw": "Toggle navigation drawer",
"reloadApiToken": "Reload API tokens",
"generateNewApiToken": "Generate new API token",
"addRole": "Add new role",
"reloadList": "Reload list",
"metaSync": "Sync metadata",
"sqlMigration": "Reload migrations",
"updateRestart": "Update & Restart",
"cancelReturn": "Cancel and Return",
"exportMetadata": "Export all metadata from the meta tables to meta directory.",
"importMetadata": "Import all metadata from the meta directory to meta tables.",
"clearMetadata": "Clear all metadata from meta tables.",
"clientKey": "Select .key file",
"clientCert": "Select .cert file",
"clientCA": "Select CA file"
},
"placeholder": {
"projName": "Enter Project Name",
"password": {
"enter": "Enter the password",
"current": "Current password",
"new": "New password",
"save": "Save password",
"confirm": "Confirm new password"
},
"searchProjectTree": "Search tables",
"searchFields": "Search fields",
"searchColumn": "Search {search} column",
"searchApps": "Search apps",
"searchModels": "Search models",
"noItemsFound": "No items found",
"defaultValue": "Default value",
"filterByEmail": "Filter by E-mail",
"filterQuery": "Filter query",
"selectField": "Select field"
},
"msg": {
"warning": {
"barcode": {
"renderError": "Barcode error - please check compatibility between input and barcode type"
},
"nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed."
}
},
"info": {
"pasteNotSupported": "Paste operation is not supported on the active cell",
"roles": {
"orgCreator": "Creator can create new projects and access any invited project.",
"orgViewer": "Viewer is not allowed to create new projects but they can access any invited project."
},
"footerInfo": "Rows per page",
"upload": "Select file to Upload",
"upload_sub": "or drag and drop file",
"excelSupport": "Supported: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Enter excel file URL",
"csvURL": "Enter CSV file URL",
"footMsg": "# of rows to parse to infer datatype",
"excelImport": "sheet(s) are available for import",
"exportMetadata": "Do you want to export metadata from meta tables?",
"importMetadata": "Do you want to import metadata from meta tables?",
"clearMetadata": "Do you want to clear metadata from meta tables?",
"projectEmptyMessage": "Get started by creating a new project",
"stopProject": "Do you want to stop the project?",
"startProject": "Do you want to start the project?",
"restartProject": "Do you want to restart the project?",
"deleteProject": "Do you want to delete the project?",
"shareBasePrivate": "Generate publicly shareable readonly base",
"shareBasePublic": "Anyone on the internet with this link can view",
"userInviteNoSMTP": "Looks like you have not configured mailer yet! Please copy above invite link and send it to",
"dragDropHide": "Drag and drop fields here to hide",
"formInput": "Enter form input label",
"formHelpText": "Add some help text",
"onlyCreator": "Only visible to Creator",
"formDesc": "Add form description",
"beforeEnablePwd": "Restrict access with a password",
"afterEnablePwd": "Access is password restricted",
"privateLink": "This view is shared via a private link",
"privateLinkAdditionalInfo": "People with private link can only see cells visible in this view",
"afterFormSubmitted": "After form is submitted",
"apiOptions": "Access Project via",
"submitAnotherForm": "Show 'Submit Another Form' button",
"showBlankForm": "Show a blank form after 5 seconds",
"emailForm": "E-mail me at",
"showSysFields": "Show system fields",
"filterAutoApply": "Auto apply",
"showMessage": "Show this message",
"viewNotShared": "Current view is not shared!",
"showAllViews": "Show all shared views of this table",
"collabView": "Collaborators with edit permissions or higher can change the view configuration.",
"lockedView": "No one can edit the view configuration until it is unlocked.",
"personalView": "Only you can edit the view configuration. Other collaborators’ personal views are hidden by default.",
"ownerDesc": "Can add/remove creators. And full edit database structures & fields.",
"creatorDesc": "Can fully edit database structure & values.",
"editorDesc": "Can edit records but cannot change structure of database/fields.",
"commenterDesc": "Can view and comment the records but cannot edit anything",
"viewerDesc": "Can view the records but cannot edit anything",
"addUser": "Add new user",
"staticRoleInfo": "System defined roles can't be edited",
"exportZip": "Export project meta to zip file and download.",
"importZip": "Import project meta zip file and restart.",
"importText": "Import NocoDB Project by uploading metadata zip file",
"metaNoChange": "No change identified",
"sqlMigration": "Schema migrations will be created automatically. Create a table and refresh this page.",
"dbConnectionStatus": "Environment validated",
"dbConnected": "Connection was successful",
"notifications": {
"no_new": "No new notifications",
"clear": "Clear"
},
"sponsor": {
"header": "You can help us!",
"message": "We are a tiny team working full time to make NocoDB Open-source. We believe a tool like NocoDB should be available freely to every problem solver on Internet."
},
"loginMsg": "Log In To NocoDB",
"passwordRecovery": {
"message_1": "Please provide the email address you used when you signed up.",
"message_2": "We will send you an email with a link to reset your password.",
"success": "Please check your email to reset the password"
},
"signUp": {
"superAdmin": "You will be the 'Super Admin'",
"alreadyHaveAccount": "Already have an account ?",
"workEmail": "Enter your work email",
"enterPassword": "Enter your password",
"forgotPassword": "Forgot your password ?",
"dontHaveAccount": "Don't have an account ?"
},
"addView": {
"grid": "Add Grid View",
"gallery": "Add Gallery View",
"form": "Add Form View",
"kanban": "Add Kanban View",
"calendar": "Add Calendar View"
},
"tablesMetadataInSync": "Tables metadata is in Sync",
"addMultipleUsers": "You can add multiple comma(,) separated emails",
"enterTableName": "Enter table name",
"addDefaultColumns": "Add default columns",
"tableNameInDb": "Table name as saved in database",
"airtable": {
"credentials": "Where to find this?"
},
"import": {
"clickOrDrag": "Click or drag file to this area to upload"
},
"metaDataRecreated": "Table metadata recreated successfully",
"invalidCredentials": "Invalid credentials",
"downloadingMoreFiles": "Downloading more files",
"copiedToClipboard": "Copied to clipboard",
"requriedFieldsCantBeMoved": "Required field can't be moved",
"updateNotAllowedWithoutPK": "Update not allowed for table which doesn't have primary key",
"autoIncFieldNotEditable": "Auto increment field is not editable",
"editingPKnotSupported": "Editing primary key not supported",
"deletedCache": "Deleted cache successfully",
"cacheEmpty": "Cache is empty",
"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",
"deleteViewConfirmation": "Are you sure you want to delete this view?",
"deleteTableConfirmation": "Do you want to delete the table",
"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."
},
"error": {
"searchProject": "Your search for {search} found no results",
"invalidChar": "Invalid character in folder path.",
"invalidDbCredentials": "Invalid database credentials.",
"unableToConnectToDb": "Unable to connect to database, please check your database is up.",
"userDoesntHaveSufficientPermission": "User does not exist or have sufficient permission to create schema.",
"dbConnectionStatus": "Invalid database parameters",
"dbConnectionFailed": "Connection Failure:",
"signUpRules": {
"emailReqd": "E-mail is required",
"emailInvalid": "E-mail must be valid",
"passwdRequired": "Password is required",
"passwdLength": "You password must be atleast 8 characters",
"passwdMismatch": "Passwords do not match",
"completeRuleSet": "At least 8 characters with one Uppercase, one number and one special character",
"atLeast8Char": "At least 8 characters",
"atLeastOneUppercase": "One Uppercase letter",
"atLeastOneNumber": "One Number",
"atLeastOneSpecialChar": "One special character",
"allowedSpecialCharList": "Allowed special character list"
},
"invalidURL": "Invalid URL",
"internalError": "Some internal error occurred",
"templateGeneratorNotFound": "Template Generator cannot be found!",
"fileUploadFailed": "Failed to upload file",
"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",
"duplicateMappingFound": "Duplicate mapping found, please remove one of the mapping",
"nullValueViolatesNotNull": "Null value violates not-null constraint",
"sourceHasInvalidNumbers": "Source data contains some invalid numbers",
"sourceHasInvalidBoolean": "Source data contains some invalid boolean values",
"invalidForm": "Invalid Form",
"formValidationFailed": "Form validation failed",
"youHaveBeenSignedOut": "You have been signed out",
"failedToLoadList": "Failed to load list",
"failedToLoadChildrenList": "Failed to load children list",
"deleteFailed": "Delete failed",
"unlinkFailed": "Unlink failed",
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view",
"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",
"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",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed",
"fieldRequired": "{value} cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard"
},
"toast": {
"exportMetadata": "Project metadata exported successfully",
"importMetadata": "Project metadata imported successfully",
"clearMetadata": "Project metadata cleared successfully",
"stopProject": "Project stopped successfully",
"startProject": "Project started successfully",
"restartProject": "Project restarted successfully",
"deleteProject": "Project deleted successfully",
"authToken": "Auth token copied to clipboard",
"projInfo": "Copied project info to clipboard",
"inviteUrlCopy": "Copied invite URL to clipboard",
"createView": "View created successfully",
"formEmailSMTP": "Please activate SMTP plugin in App store for enabling email notification",
"collabView": "Successfully Switched to collaborative view",
"lockedView": "Successfully Switched to locked view",
"futureRelease": "Coming soon!"
},
"success": {
"columnDuplicated": "Column duplicated successfully",
"updatedUIACL": "Updated UI ACL for tables successfully",
"pluginUninstalled": "Plugin uninstalled successfully",
"pluginSettingsSaved": "Plugin settings saved successfully",
"pluginTested": "Successfully tested plugin settings",
"tableRenamed": "Table renamed successfully",
"viewDeleted": "View deleted successfully",
"primaryColumnUpdated": "Successfully updated as primary column",
"tableDataExported": "Successfully exported all table data",
"updated": "Successfully updated",
"sharedViewDeleted": "Deleted shared view successfully",
"userDeleted": "User deleted successfully",
"viewRenamed": "View renamed successfully",
"tokenGenerated": "Token generated successfully",
"tokenDeleted": "Token deleted successfully",
"userAddedToProject": "Successfully added user to project",
"userAdded": "Successfully added user",
"userDeletedFromProject": "Successfully deleted user from project",
"inviteEmailSent": "Invite Email sent successfully",
"inviteURLCopied": "Invite URL copied to clipboard",
"passwordResetURLCopied": "Password reset URL copied to clipboard",
"shareableURLCopied": "Copied shareable base URL to clipboard!",
"embeddableHTMLCodeCopied": "Copied embeddable HTML code!",
"userDetailsUpdated": "Successfully updated the user details",
"tableDataImported": "Successfully imported table data",
"webhookUpdated": "Webhook details updated successfully",
"webhookDeleted": "Hook deleted successfully",
"webhookTested": "Webhook tested successfully",
"columnUpdated": "Column updated",
"columnCreated": "Column created",
"passwordChanged": "Password changed successfully. Please login again.",
"settingsSaved": "Settings saved successfully",
"roleUpdated": "Role updated successfully"
}
}
}

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

@ -0,0 +1,748 @@
{
"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",
"preferred": "Preferred",
"mandatory": "Mandatory",
"loading": "Loading ...",
"title": "Title",
"upload": "Upload",
"download": "Download",
"default": "Default",
"more": "More",
"less": "Less",
"event": "Event",
"condition": "Condition",
"after": "After",
"before": "Before",
"search": "Search",
"notification": "Notification",
"reference": "Reference",
"function": "Function",
"confirm": "Confirm",
"generate": "Generate",
"copy": "Copy",
"misc": "Miscellaneous",
"lock": "Lock",
"unlock": "Unlock",
"credentials": "Credentials",
"help": "Help",
"questions": "Questions",
"reachOut": "Reach out here",
"betaNote": "This feature is currently in beta.",
"moreInfo": "More information can be found here",
"logs": "Logs",
"groupingField": "Grouping Field",
"insertAfter": "Insert After",
"insertBefore": "Insert Before",
"hideField": "Hide Field",
"sortAsc": "Sort Ascending",
"sortDesc": "Sort Descending"
},
"objects": {
"project": "Project",
"projects": "Projects",
"table": "Table",
"tables": "Tables",
"field": "Field",
"fields": "Fields",
"column": "Column",
"columns": "Columns",
"page": "Page",
"pages": "Pages",
"record": "record",
"records": "records",
"webhook": "Webhook",
"webhooks": "Webhooks",
"view": "View",
"views": "Views",
"viewType": {
"grid": "Grid",
"gallery": "Gallery",
"form": "Form",
"kanban": "Kanban",
"calendar": "Calendar"
},
"user": "User",
"users": "Users",
"role": "Role",
"roles": "Roles",
"roleType": {
"owner": "Owner",
"creator": "Creator",
"editor": "Editor",
"commenter": "Commenter",
"viewer": "Viewer",
"orgLevelCreator": "Organization Level Creator",
"orgLevelViewer": "Organization Level Viewer"
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
"ForeignKey": "Foreign Key",
"SingleLineText": "Single Line Text",
"LongText": "Long Text",
"Attachment": "Attachment",
"Checkbox": "Checkbox",
"MultiSelect": "Multi Select",
"SingleSelect": "Single Select",
"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",
"Rollup": "Rollup",
"Count": "Count",
"Lookup": "Lookup",
"DateTime": "Date Time",
"CreateTime": "Create Time",
"LastModifiedTime": "Last Modified Time",
"AutoNumber": "Auto Number",
"Barcode": "Barcode",
"Button": "Button",
"Password": "Password",
"relationProperties": {
"noAction": "No Action",
"cascade": "Cascade",
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"filterOperation": {
"isEqual": "is equal",
"isNotEqual": "is not equal",
"isLike": "is like",
"isNot like": "is not like",
"isEmpty": "is empty",
"isNotEmpty": "is not empty",
"isNull": "is null",
"isNotNull": "is not null"
},
"title": {
"erdView": "ERD View",
"newProj": "New Project",
"myProject": "My Projects",
"formTitle": "Form Title",
"collabView": "Collaborative View",
"lockedView": "Locked View",
"personalView": "Personal View",
"appStore": "App Store",
"teamAndAuth": "Team & Auth",
"rolesUserMgmt": "Roles & Users Management",
"userMgmt": "Users Management",
"apiTokenMgmt": "API Tokens Management",
"rolesMgmt": "Roles Management",
"projMeta": "Project Metadata",
"metaMgmt": "Meta Management",
"metadata": "Metadata",
"exportImportMeta": "Export / Import Metadata",
"uiACL": "UI Access Control",
"metaOperations": "Metadata Operations",
"audit": "Audit",
"auditLogs": "Audit Log",
"sqlMigrations": "SQL Migrations",
"dbCredentials": "Database Credentials",
"advancedParameters": "SSL & Advanced parameters",
"headCreateProject": "Create Project | NocoDB",
"headLogin": "Log In | NocoDB",
"resetPassword": "Reset your password",
"teamAndSettings": "Team & Settings",
"apiDocs": "API Docs",
"importFromAirtable": "Import From Airtable",
"generateToken": "Generate Token",
"APIsAndSupport": "APIs & Support",
"helpCenter": "Help center",
"swaggerDocumentation": "Swagger Documentation",
"quickImportFrom": "Quick Import From",
"quickImport": "Quick Import",
"advancedSettings": "Advanced Settings",
"codeSnippet": "Code Snippet",
"keyboardShortcut": "Keyboard Shortcuts"
},
"labels": {
"createdBy": "Created By",
"notifyVia": "Notify Via",
"projName": "Project name",
"tableName": "Table name",
"viewName": "View name",
"viewLink": "View Link",
"columnName": "Column Name",
"columnType": "Column Type",
"roleName": "Role Name",
"roleDescription": "Role Description",
"databaseType": "Type in Database",
"lengthValue": "Length/ value",
"dbType": "Database Type",
"sqliteFile": "SQLite File",
"hostAddress": "Host Address",
"port": "Port Number",
"username": "Username",
"password": "Password",
"schemaName": "Schema name",
"database": "Database",
"action": "Action",
"actions": "Actions",
"operation": "Operation",
"operationType": "Operation type",
"operationSubType": "Operation sub-type",
"description": "Description",
"authentication": "Authentication",
"token": "Token",
"where": "Where",
"cache": "Cache",
"chat": "Chat",
"email": "E-mail",
"storage": "Storage",
"uiAcl": "UI-ACL",
"models": "Models",
"syncState": "Sync state",
"created": "Created",
"sqlOutput": "SQL Output",
"addOption": "Add option",
"qrCodeValueColumn": "Column with QR code value",
"barcodeValueColumn": "Column with Barcode value",
"barcodeFormat": "Barcode format",
"qrCodeValueTooLong": "Too many characters for a QR code",
"barcodeValueTooLong": "Too many characters for a barcode",
"aggregateFunction": "Aggregate function",
"dbCreateIfNotExists": "Database : create if not exists",
"clientKey": "Client Key",
"clientCert": "Client Cert",
"serverCA": "Server CA",
"requriedCa": "Required-CA",
"requriedIdentity": "Required-IDENTITY",
"inflection": {
"tableName": "Inflection - Table name",
"columnName": "Inflection - Column name"
},
"community": {
"starUs1": "Star",
"starUs2": "us on Github",
"bookDemo": "Book a Free DEMO",
"getAnswered": "Get your questions answered",
"joinDiscord": "Join Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Join /r/NocoDB",
"followNocodb": "Follow NocoDB"
},
"docReference": "Document Reference",
"selectUserRole": "Select User Role",
"childTable": "Child table",
"childColumn": "Child column",
"onUpdate": "On Update",
"onDelete": "On Delete",
"account": "Account",
"language": "Language",
"primaryColor": "Primary Color",
"accentColor": "Accent Color",
"customTheme": "Custom Theme",
"requestDataSource": "Request a data source you need?",
"apiKey": "API Key",
"sharedBase": "Shared Base",
"importData": "Import Data",
"importSecondaryViews": "Import Secondary Views",
"importRollupColumns": "Import Rollup Columns",
"importLookupColumns": "Import Lookup Columns",
"importAttachmentColumns": "Import Attachment Columns",
"importFormulaColumns": "Import Formula Columns",
"noData": "No Data",
"goToDashboard": "Go to Dashboard",
"importing": "Importing",
"flattenNested": "Flatten Nested",
"downloadAllowed": "Download allowed",
"weAreHiring": "We are Hiring!",
"primaryKey": "Primary key",
"hasMany": "has many",
"belongsTo": "belongs to",
"manyToMany": "have many to many relation",
"extraConnectionParameters": "Extra connection parameters",
"commentsOnly": "Comments only",
"documentation": "Documentation",
"subscribeNewsletter": "Subscribe to our weekly newsletter",
"signUpWithGoogle": "Sign up with Google",
"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"
},
"activity": {
"createProject": "Create Project",
"importProject": "Import Project",
"searchProject": "Search Project",
"editProject": "Edit Project",
"stopProject": "Stop Project",
"startProject": "Start Project",
"restartProject": "Restart Project",
"deleteProject": "Delete Project",
"refreshProject": "Refresh projects",
"saveProject": "Save Project",
"deleteKanbanStack": "Delete stack?",
"createProjectExtended": {
"extDB": "Create By Connecting <br>To An External Database",
"excel": "Create Project from excel",
"template": "Create Project from template"
},
"OkSaveProject": "Ok & Save Project",
"upgrade": {
"available": "Upgrade available",
"releaseNote": "Release notes",
"howTo": "How to upgrade ?"
},
"translate": "Help translate",
"account": {
"authToken": "Copy Auth Token",
"swagger": "Swagger: REST APIs",
"projInfo": "Copy Project Info",
"themes": "Themes"
},
"sort": "Sort",
"addSort": "Add Sort Option",
"filter": "Filter",
"addFilter": "Add Filter",
"share": "Share",
"shareBase": {
"disable": "Disable shared base",
"enable": "Anyone with the link",
"link": "Shared base link"
},
"invite": "Invite",
"inviteMore": "Invite more",
"inviteTeam": "Invite Team",
"inviteUser": "Invite User",
"inviteToken": "Invite Token",
"newUser": "New User",
"editUser": "Edit user",
"deleteUser": "Remove user from project",
"resendInvite": "Resend invite E-mail",
"copyInviteURL": "Copy invite URL",
"copyPasswordResetURL": "Copy password reset URL",
"newRole": "New role",
"reloadRoles": "Reload roles",
"nextPage": "Next page",
"prevPage": "Previous page",
"nextRecord": "Next record",
"previousRecord": "Previous record",
"copyApiURL": "Copy API URL",
"createTable": "Table Create",
"refreshTable": "Tables Refresh",
"renameTable": "Table Rename",
"deleteTable": "Table Delete",
"addField": "Add new field to this table",
"setPrimary": "Set as Primary value",
"addRow": "Add new row",
"saveRow": "Save row",
"saveAndExit": "Save & Exit",
"saveAndStay": "Save & Stay",
"insertRow": "Insert New Row",
"deleteRow": "Delete Row",
"deleteSelectedRow": "Delete Selected Rows",
"importExcel": "Import Excel",
"importCSV": "Import CSV",
"downloadCSV": "Download as CSV",
"downloadExcel": "Download as XLSX",
"uploadCSV": "Upload CSV",
"import": "Import",
"importMetadata": "Import Metadata",
"exportMetadata": "Export Metadata",
"clearMetadata": "Clear Metadata",
"exportToFile": "Export to file",
"changePwd": "Change Password",
"createView": "Create a View",
"shareView": "Share View",
"listSharedView": "Shared View List",
"ListView": "Views List",
"copyView": "Copy view",
"renameView": "Rename view",
"deleteView": "Delete view",
"createGrid": "Create Grid View",
"createGallery": "Create Gallery View",
"createCalendar": "Create Calendar View",
"createKanban": "Create Kanban View",
"createForm": "Create Form View",
"showSystemFields": "Show system fields",
"copyUrl": "Copy URL",
"openTab": "Open new tab",
"iFrame": "Copy embeddable HTML code",
"addWebhook": "Add New Webhook",
"newToken": "Add New Token",
"exportZip": "Export zip",
"importZip": "Import zip",
"metaSync": "Sync Now",
"settings": "Settings",
"previewAs": "Preview as",
"resetReview": "Reset Preview",
"testDbConn": "Test Database Connection",
"removeDbFromEnv": "Remove Database from environment",
"editConnJson": "Edit connection JSON",
"sponsorUs": "Sponsor Us",
"sendEmail": "SEND EMAIL",
"addUserToProject": "Add user to project",
"getApiSnippet": "Get API Snippet",
"clearCell": "Clear cell",
"addFilterGroup": "Add Filter Group",
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw",
"expandRecord": "Expand Record",
"deleteRecord": "Delete Record",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
},
"kanban": {
"collapseStack": "Collapse Stack",
"deleteStack": "Delete Stack",
"stackedBy": "Stacked By",
"chooseGroupingField": "Choose a Grouping Field",
"addOrEditStack": "Add / Edit Stack"
}
},
"tooltip": {
"saveChanges": "Save changes",
"xcDB": "Create a new project",
"extDB": "Supports MySQL, PostgreSQL, SQL Server & SQLite",
"apiRest": "Accessible via REST APIs",
"apiGQL": "Accessible via GraphQL APIs",
"theme": {
"dark": "It does come in Black (^⇧B)",
"light": "Does it come in Black ? (^⇧B)"
},
"addTable": "Add new table",
"inviteMore": "Invite more users",
"toggleNavDraw": "Toggle navigation drawer",
"reloadApiToken": "Reload API tokens",
"generateNewApiToken": "Generate new API token",
"addRole": "Add new role",
"reloadList": "Reload list",
"metaSync": "Sync metadata",
"sqlMigration": "Reload migrations",
"updateRestart": "Update & Restart",
"cancelReturn": "Cancel and Return",
"exportMetadata": "Export all metadata from the meta tables to meta directory.",
"importMetadata": "Import all metadata from the meta directory to meta tables.",
"clearMetadata": "Clear all metadata from meta tables.",
"clientKey": "Select .key file",
"clientCert": "Select .cert file",
"clientCA": "Select CA file"
},
"placeholder": {
"projName": "Enter Project Name",
"password": {
"enter": "Enter the password",
"current": "Current password",
"new": "New password",
"save": "Save password",
"confirm": "Confirm new password"
},
"searchProjectTree": "Search tables",
"searchFields": "Search fields",
"searchColumn": "Search {search} column",
"searchApps": "Search apps",
"searchModels": "Search models",
"noItemsFound": "No items found",
"defaultValue": "Default value",
"filterByEmail": "Filter by E-mail",
"filterQuery": "Filter query",
"selectField": "Select field"
},
"msg": {
"warning": {
"barcode": {
"renderError": "Barcode error - please check compatibility between input and barcode type"
},
"nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed."
}
},
"info": {
"pasteNotSupported": "Paste operation is not supported on the active cell",
"roles": {
"orgCreator": "Creator can create new projects and access any invited project.",
"orgViewer": "Viewer is not allowed to create new projects but they can access any invited project."
},
"footerInfo": "Rows per page",
"upload": "Select file to Upload",
"upload_sub": "or drag and drop file",
"excelSupport": "Supported: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Enter excel file URL",
"csvURL": "Enter CSV file URL",
"footMsg": "# of rows to parse to infer datatype",
"excelImport": "sheet(s) are available for import",
"exportMetadata": "Do you want to export metadata from meta tables?",
"importMetadata": "Do you want to import metadata from meta tables?",
"clearMetadata": "Do you want to clear metadata from meta tables?",
"projectEmptyMessage": "Get started by creating a new project",
"stopProject": "Do you want to stop the project?",
"startProject": "Do you want to start the project?",
"restartProject": "Do you want to restart the project?",
"deleteProject": "Do you want to delete the project?",
"shareBasePrivate": "Generate publicly shareable readonly base",
"shareBasePublic": "Anyone on the internet with this link can view",
"userInviteNoSMTP": "Looks like you have not configured mailer yet! Please copy above invite link and send it to",
"dragDropHide": "Drag and drop fields here to hide",
"formInput": "Enter form input label",
"formHelpText": "Add some help text",
"onlyCreator": "Only visible to Creator",
"formDesc": "Add form description",
"beforeEnablePwd": "Restrict access with a password",
"afterEnablePwd": "Access is password restricted",
"privateLink": "This view is shared via a private link",
"privateLinkAdditionalInfo": "People with private link can only see cells visible in this view",
"afterFormSubmitted": "After form is submitted",
"apiOptions": "Access Project via",
"submitAnotherForm": "Show 'Submit Another Form' button",
"showBlankForm": "Show a blank form after 5 seconds",
"emailForm": "E-mail me at",
"showSysFields": "Show system fields",
"filterAutoApply": "Auto apply",
"showMessage": "Show this message",
"viewNotShared": "Current view is not shared!",
"showAllViews": "Show all shared views of this table",
"collabView": "Collaborators with edit permissions or higher can change the view configuration.",
"lockedView": "No one can edit the view configuration until it is unlocked.",
"personalView": "Only you can edit the view configuration. Other collaborators’ personal views are hidden by default.",
"ownerDesc": "Can add/remove creators. And full edit database structures & fields.",
"creatorDesc": "Can fully edit database structure & values.",
"editorDesc": "Can edit records but cannot change structure of database/fields.",
"commenterDesc": "Can view and comment the records but cannot edit anything",
"viewerDesc": "Can view the records but cannot edit anything",
"addUser": "Add new user",
"staticRoleInfo": "System defined roles can't be edited",
"exportZip": "Export project meta to zip file and download.",
"importZip": "Import project meta zip file and restart.",
"importText": "Import NocoDB Project by uploading metadata zip file",
"metaNoChange": "No change identified",
"sqlMigration": "Schema migrations will be created automatically. Create a table and refresh this page.",
"dbConnectionStatus": "Environment validated",
"dbConnected": "Connection was successful",
"notifications": {
"no_new": "No new notifications",
"clear": "Clear"
},
"sponsor": {
"header": "You can help us!",
"message": "We are a tiny team working full time to make NocoDB Open-source. We believe a tool like NocoDB should be available freely to every problem solver on Internet."
},
"loginMsg": "Log In To NocoDB",
"passwordRecovery": {
"message_1": "Please provide the email address you used when you signed up.",
"message_2": "We will send you an email with a link to reset your password.",
"success": "Please check your email to reset the password"
},
"signUp": {
"superAdmin": "You will be the 'Super Admin'",
"alreadyHaveAccount": "Already have an account ?",
"workEmail": "Enter your work email",
"enterPassword": "Enter your password",
"forgotPassword": "Forgot your password ?",
"dontHaveAccount": "Don't have an account ?"
},
"addView": {
"grid": "Add Grid View",
"gallery": "Add Gallery View",
"form": "Add Form View",
"kanban": "Add Kanban View",
"calendar": "Add Calendar View"
},
"tablesMetadataInSync": "Tables metadata is in Sync",
"addMultipleUsers": "You can add multiple comma(,) separated emails",
"enterTableName": "Enter table name",
"addDefaultColumns": "Add default columns",
"tableNameInDb": "Table name as saved in database",
"airtable": {
"credentials": "Where to find this?"
},
"import": {
"clickOrDrag": "Click or drag file to this area to upload"
},
"metaDataRecreated": "Table metadata recreated successfully",
"invalidCredentials": "Invalid credentials",
"downloadingMoreFiles": "Downloading more files",
"copiedToClipboard": "Copied to clipboard",
"requriedFieldsCantBeMoved": "Required field can't be moved",
"updateNotAllowedWithoutPK": "Update not allowed for table which doesn't have primary key",
"autoIncFieldNotEditable": "Auto increment field is not editable",
"editingPKnotSupported": "Editing primary key not supported",
"deletedCache": "Deleted cache successfully",
"cacheEmpty": "Cache is empty",
"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",
"deleteViewConfirmation": "Are you sure you want to delete this view?",
"deleteTableConfirmation": "Do you want to delete the table",
"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."
},
"error": {
"searchProject": "Your search for {search} found no results",
"invalidChar": "Invalid character in folder path.",
"invalidDbCredentials": "Invalid database credentials.",
"unableToConnectToDb": "Unable to connect to database, please check your database is up.",
"userDoesntHaveSufficientPermission": "User does not exist or have sufficient permission to create schema.",
"dbConnectionStatus": "Invalid database parameters",
"dbConnectionFailed": "Connection Failure:",
"signUpRules": {
"emailReqd": "E-mail is required",
"emailInvalid": "E-mail must be valid",
"passwdRequired": "Password is required",
"passwdLength": "You password must be atleast 8 characters",
"passwdMismatch": "Passwords do not match",
"completeRuleSet": "At least 8 characters with one Uppercase, one number and one special character",
"atLeast8Char": "At least 8 characters",
"atLeastOneUppercase": "One Uppercase letter",
"atLeastOneNumber": "One Number",
"atLeastOneSpecialChar": "One special character",
"allowedSpecialCharList": "Allowed special character list"
},
"invalidURL": "Invalid URL",
"internalError": "Some internal error occurred",
"templateGeneratorNotFound": "Template Generator cannot be found!",
"fileUploadFailed": "Failed to upload file",
"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",
"duplicateMappingFound": "Duplicate mapping found, please remove one of the mapping",
"nullValueViolatesNotNull": "Null value violates not-null constraint",
"sourceHasInvalidNumbers": "Source data contains some invalid numbers",
"sourceHasInvalidBoolean": "Source data contains some invalid boolean values",
"invalidForm": "Invalid Form",
"formValidationFailed": "Form validation failed",
"youHaveBeenSignedOut": "You have been signed out",
"failedToLoadList": "Failed to load list",
"failedToLoadChildrenList": "Failed to load children list",
"deleteFailed": "Delete failed",
"unlinkFailed": "Unlink failed",
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view",
"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",
"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",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed",
"fieldRequired": "{value} cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard"
},
"toast": {
"exportMetadata": "Project metadata exported successfully",
"importMetadata": "Project metadata imported successfully",
"clearMetadata": "Project metadata cleared successfully",
"stopProject": "Project stopped successfully",
"startProject": "Project started successfully",
"restartProject": "Project restarted successfully",
"deleteProject": "Project deleted successfully",
"authToken": "Auth token copied to clipboard",
"projInfo": "Copied project info to clipboard",
"inviteUrlCopy": "Copied invite URL to clipboard",
"createView": "View created successfully",
"formEmailSMTP": "Please activate SMTP plugin in App store for enabling email notification",
"collabView": "Successfully Switched to collaborative view",
"lockedView": "Successfully Switched to locked view",
"futureRelease": "Coming soon!"
},
"success": {
"columnDuplicated": "Column duplicated successfully",
"updatedUIACL": "Updated UI ACL for tables successfully",
"pluginUninstalled": "Plugin uninstalled successfully",
"pluginSettingsSaved": "Plugin settings saved successfully",
"pluginTested": "Successfully tested plugin settings",
"tableRenamed": "Table renamed successfully",
"viewDeleted": "View deleted successfully",
"primaryColumnUpdated": "Successfully updated as primary column",
"tableDataExported": "Successfully exported all table data",
"updated": "Successfully updated",
"sharedViewDeleted": "Deleted shared view successfully",
"userDeleted": "User deleted successfully",
"viewRenamed": "View renamed successfully",
"tokenGenerated": "Token generated successfully",
"tokenDeleted": "Token deleted successfully",
"userAddedToProject": "Successfully added user to project",
"userAdded": "Successfully added user",
"userDeletedFromProject": "Successfully deleted user from project",
"inviteEmailSent": "Invite Email sent successfully",
"inviteURLCopied": "Invite URL copied to clipboard",
"passwordResetURLCopied": "Password reset URL copied to clipboard",
"shareableURLCopied": "Copied shareable base URL to clipboard!",
"embeddableHTMLCodeCopied": "Copied embeddable HTML code!",
"userDetailsUpdated": "Successfully updated the user details",
"tableDataImported": "Successfully imported table data",
"webhookUpdated": "Webhook details updated successfully",
"webhookDeleted": "Hook deleted successfully",
"webhookTested": "Webhook tested successfully",
"columnUpdated": "Column updated",
"columnCreated": "Column created",
"passwordChanged": "Password changed successfully. Please login again.",
"settingsSaved": "Settings saved successfully",
"roleUpdated": "Role updated successfully"
}
}
}

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

@ -16,7 +16,7 @@
"cancel": "Annuler", "cancel": "Annuler",
"submit": "Soumettre", "submit": "Soumettre",
"create": "Créer", "create": "Créer",
"duplicate": "Duplicate", "duplicate": "Dupliquer",
"insert": "Insérer", "insert": "Insérer",
"delete": "Supprimer", "delete": "Supprimer",
"update": "Mettre à jour", "update": "Mettre à jour",
@ -56,25 +56,25 @@
"notification": "Notification", "notification": "Notification",
"reference": "Référence", "reference": "Référence",
"function": "Fonction", "function": "Fonction",
"confirm": "Confirm", "confirm": "Confirmer",
"generate": "Generate", "generate": "Générer",
"copy": "Copy", "copy": "Copier",
"misc": "Miscellaneous", "misc": "Miscellaneous",
"lock": "Lock", "lock": "Verrouiller",
"unlock": "Unlock", "unlock": "Déverrouiller",
"credentials": "Credentials", "credentials": "Identifiants",
"help": "Help", "help": "Aide",
"questions": "Questions", "questions": "Questions",
"reachOut": "Reach out here", "reachOut": "Reach out here",
"betaNote": "This feature is currently in beta.", "betaNote": "Cette fonctionnalité est encore en développement.",
"moreInfo": "More information can be found here", "moreInfo": "Plus d'informations peuvent être trouvées ici",
"logs": "Logs", "logs": "Logs",
"groupingField": "Grouping Field", "groupingField": "Grouping Field",
"insertAfter": "Insert After", "insertAfter": "Insert After",
"insertBefore": "Insert Before", "insertBefore": "Insert Before",
"hideField": "Hide Field", "hideField": "Masquer le champ",
"sortAsc": "Sort Ascending", "sortAsc": "Trier par ordre croissant",
"sortDesc": "Sort Descending" "sortDesc": "Trier par ordre décroissant"
}, },
"objects": { "objects": {
"project": "Projet", "project": "Projet",
@ -197,21 +197,21 @@
"teamAndSettings": "Équipe & paramètres", "teamAndSettings": "Équipe & paramètres",
"apiDocs": "Docs API", "apiDocs": "Docs API",
"importFromAirtable": "Importer depuis Airtable", "importFromAirtable": "Importer depuis Airtable",
"generateToken": "Generate Token", "generateToken": "Générer un jeton",
"APIsAndSupport": "Les API et la prise en charge", "APIsAndSupport": "Les API et la prise en charge",
"helpCenter": "Help center", "helpCenter": "Help center",
"swaggerDocumentation": "Swagger Documentation", "swaggerDocumentation": "Swagger Documentation",
"quickImportFrom": "Quick Import From", "quickImportFrom": "Quick Import From",
"quickImport": "Quick Import", "quickImport": "Importation rapide",
"advancedSettings": "Advanced Settings", "advancedSettings": "Paramètres avancés",
"codeSnippet": "Code Snippet", "codeSnippet": "Code Snippet",
"keyboardShortcut": "Keyboard Shortcuts" "keyboardShortcut": "Keyboard Shortcuts"
}, },
"labels": { "labels": {
"createdBy": "Created By", "createdBy": "Créé par",
"notifyVia": "Notifier via", "notifyVia": "Notifier via",
"projName": "Nom du projet", "projName": "Nom du projet",
"tableName": "Nom de la table", "tableName": "Nom du tableau",
"viewName": "Vue", "viewName": "Vue",
"viewLink": "Lien de vue", "viewLink": "Lien de vue",
"columnName": "Nom de la colonne", "columnName": "Nom de la colonne",
@ -280,37 +280,37 @@
"onUpdate": "Mise à jour en cours", "onUpdate": "Mise à jour en cours",
"onDelete": "Suppression en cours", "onDelete": "Suppression en cours",
"account": "Compte", "account": "Compte",
"language": "Language", "language": "Langue",
"primaryColor": "Primary Color", "primaryColor": "Couleur primaire",
"accentColor": "Accent Color", "accentColor": "Couleur secondaire",
"customTheme": "Thème personnalisé", "customTheme": "Thème personnalisé",
"requestDataSource": "Request a data source you need?", "requestDataSource": "Request a data source you need?",
"apiKey": "Clé d'API", "apiKey": "Clé d'API",
"sharedBase": "Shared Base", "sharedBase": "Shared Base",
"importData": "Import Data", "importData": "Importer des données",
"importSecondaryViews": "Importer des vues secondaires", "importSecondaryViews": "Importer des vues secondaires",
"importRollupColumns": "Import Rollup Columns", "importRollupColumns": "Import Rollup Columns",
"importLookupColumns": "Import Lookup Columns", "importLookupColumns": "Import Lookup Columns",
"importAttachmentColumns": "Import Attachment Columns", "importAttachmentColumns": "Import Attachment Columns",
"importFormulaColumns": "Import Formula Columns", "importFormulaColumns": "Import Formula Columns",
"noData": "No Data", "noData": "Aucune donnée",
"goToDashboard": "Go to Dashboard", "goToDashboard": "Accéder au tableau de bord",
"importing": "Importing", "importing": "Importing",
"flattenNested": "Flatten Nested", "flattenNested": "Flatten Nested",
"downloadAllowed": "Download allowed", "downloadAllowed": "Téléchargement autorisé",
"weAreHiring": "We are Hiring!", "weAreHiring": "Nous recrutons !",
"primaryKey": "Primary key", "primaryKey": "Primary key",
"hasMany": "has many", "hasMany": "a plusieurs",
"belongsTo": "belongs to", "belongsTo": "appartient à",
"manyToMany": "have many to many relation", "manyToMany": "have many to many relation",
"extraConnectionParameters": "Extra connection parameters", "extraConnectionParameters": "Extra connection parameters",
"commentsOnly": "Comments only", "commentsOnly": "Commentaires uniquement",
"documentation": "Documentation", "documentation": "Documentation",
"subscribeNewsletter": "Subscribe to our weekly newsletter", "subscribeNewsletter": "Abonnez-vous à notre newsletter hebdomadaire",
"signUpWithGoogle": "S’enregistrer avec Google", "signUpWithGoogle": "S’enregistrer avec Google",
"signInWithGoogle": "Se connecter avec Google", "signInWithGoogle": "Se connecter avec Google",
"agreeToTos": "By signing up, you agree to the Terms of Service", "agreeToTos": "En continuant, vous acceptez les Conditions d'Utilisation",
"welcomeToNc": "Welcome to NocoDB!", "welcomeToNc": "Bienvenue sur NocoDB !",
"inviteOnlySignup": "Allow signup only using invite url" "inviteOnlySignup": "Allow signup only using invite url"
}, },
"activity": { "activity": {
@ -356,7 +356,7 @@
"invite": "Inviter", "invite": "Inviter",
"inviteMore": "Inviter plus", "inviteMore": "Inviter plus",
"inviteTeam": "Inviter une équipe", "inviteTeam": "Inviter une équipe",
"inviteUser": "Invite User", "inviteUser": "Inviter un utilisateur",
"inviteToken": "Inviter via un jeton", "inviteToken": "Inviter via un jeton",
"newUser": "Nouvel utilisateur", "newUser": "Nouvel utilisateur",
"editUser": "Modifier l'utilisateur", "editUser": "Modifier l'utilisateur",
@ -375,17 +375,17 @@
"refreshTable": "Actualiser le tableau", "refreshTable": "Actualiser le tableau",
"renameTable": "Renommer le tableau", "renameTable": "Renommer le tableau",
"deleteTable": "Supprimer 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", "setPrimary": "Définir comme valeur primaire",
"addRow": "Ajouter une nouvelle ligne", "addRow": "Ajouter une nouvelle ligne",
"saveRow": "Enregistrer la ligne", "saveRow": "Enregistrer la ligne",
"saveAndExit": "Save & Exit", "saveAndExit": "Enregistrer et quitter",
"saveAndStay": "Save & Stay", "saveAndStay": "Enregistrer et rester",
"insertRow": "Insérer une nouvelle ligne", "insertRow": "Insérer une nouvelle ligne",
"deleteRow": "Supprimer la ligne", "deleteRow": "Supprimer la ligne",
"deleteSelectedRow": "Supprimer les lignes sélectionnées", "deleteSelectedRow": "Supprimer les lignes sélectionnées",
"importExcel": "Importer depuis Excel", "importExcel": "Importer depuis Excel",
"importCSV": "Import CSV", "importCSV": "Importer un fichier CSV",
"downloadCSV": "Télécharger comme CSV", "downloadCSV": "Télécharger comme CSV",
"downloadExcel": "Télécharger comme XLSX", "downloadExcel": "Télécharger comme XLSX",
"uploadCSV": "Téléverser un CSV", "uploadCSV": "Téléverser un CSV",
@ -424,10 +424,10 @@
"editConnJson": "Éditer le JSON de connexion", "editConnJson": "Éditer le JSON de connexion",
"sponsorUs": "Nous Parrainer", "sponsorUs": "Nous Parrainer",
"sendEmail": "ENVOYER UN EMAIL", "sendEmail": "ENVOYER UN EMAIL",
"addUserToProject": "Add user to project", "addUserToProject": "Ajouter un utilisateur au projet",
"getApiSnippet": "Récupérer le Snippet API", "getApiSnippet": "Récupérer le Snippet API",
"clearCell": "Clear cell", "clearCell": "Vider la cellule",
"addFilterGroup": "Add Filter Group", "addFilterGroup": "Ajouter un groupe de filtres",
"linkRecord": "Link record", "linkRecord": "Link record",
"addNewRecord": "Add new record", "addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL", "useConnectionUrl": "Use Connection URL",
@ -459,7 +459,7 @@
"dark": "Nuit (^⇧B)", "dark": "Nuit (^⇧B)",
"light": "Jour (^⇧B)" "light": "Jour (^⇧B)"
}, },
"addTable": "Ajouter une nouvelle table", "addTable": "Ajouter un nouveau tableau",
"inviteMore": "Inviter plus d'utilisateurs", "inviteMore": "Inviter plus d'utilisateurs",
"toggleNavDraw": "Basculer le tiroir de navigation", "toggleNavDraw": "Basculer le tiroir de navigation",
"reloadApiToken": "Recharger les jetons API", "reloadApiToken": "Recharger les jetons API",
@ -493,9 +493,9 @@
"searchModels": "Chercher un modèle", "searchModels": "Chercher un modèle",
"noItemsFound": "Aucun élément trouvé", "noItemsFound": "Aucun élément trouvé",
"defaultValue": "Valeur par défaut", "defaultValue": "Valeur par défaut",
"filterByEmail": "Filtrer par courriel", "filterByEmail": "Rechercher un courriel",
"filterQuery": "Filter query", "filterQuery": "Rechercher",
"selectField": "Select field" "selectField": "Sélectionner un champ"
}, },
"msg": { "msg": {
"warning": { "warning": {
@ -504,7 +504,7 @@
}, },
"nonEditableFields": { "nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text", "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": { "info": {
@ -599,32 +599,32 @@
}, },
"tablesMetadataInSync": "Les métadonnées de tables sont en synchronisation", "tablesMetadataInSync": "Les métadonnées de tables sont en synchronisation",
"addMultipleUsers": "Vous pouvez ajouter plusieurs courriels séparés par des virgules (,)", "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", "addDefaultColumns": "Ajouter des colonnes par défaut",
"tableNameInDb": "Nom de la table tel qu'enregistré dans la base de données", "tableNameInDb": "Nom de la table tel qu'enregistré dans la base de données",
"airtable": { "airtable": {
"credentials": "Where to find this?" "credentials": "Où trouver ceci ?"
}, },
"import": { "import": {
"clickOrDrag": "Click or drag file to this area to upload" "clickOrDrag": "Click or drag file to this area to upload"
}, },
"metaDataRecreated": "Table metadata recreated successfully", "metaDataRecreated": "Table metadata recreated successfully",
"invalidCredentials": "Invalid credentials", "invalidCredentials": "Identifiants invalides",
"downloadingMoreFiles": "Downloading more files", "downloadingMoreFiles": "Téléchargement de fichiers supplémentaires",
"copiedToClipboard": "Copied to clipboard", "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", "updateNotAllowedWithoutPK": "Update not allowed for table which doesn't have primary key",
"autoIncFieldNotEditable": "Auto increment field is not editable", "autoIncFieldNotEditable": "Auto increment field is not editable",
"editingPKnotSupported": "Modification de la clé primaire non prise en charge", "editingPKnotSupported": "Modification de la clé primaire non prise en charge",
"deletedCache": "Deleted cache successfully", "deletedCache": "Deleted cache successfully",
"cacheEmpty": "Cache is empty", "cacheEmpty": "Le cache est vide",
"exportedCache": "Exported Cache Successfully", "exportedCache": "Exported Cache Successfully",
"valueAlreadyInList": "This value is already in the list", "valueAlreadyInList": "This value is already in the list",
"noColumnsToUpdate": "No columns to update", "noColumnsToUpdate": "Aucune colonne à mettre à jour",
"tableDeleted": "Deleted table successfully", "tableDeleted": "Tableau supprimé avec succès",
"generatePublicShareableReadonlyBase": "Generate publicly shareable readonly base", "generatePublicShareableReadonlyBase": "Generate publicly shareable readonly base",
"deleteViewConfirmation": "Êtes-vous sûr de vouloir effacer cette vue ?", "deleteViewConfirmation": "Êtes-vous sûr de vouloir effacer cette vue ?",
"deleteTableConfirmation": "Do you want to delete the table", "deleteTableConfirmation": "Voulez-vous supprimer ce tableau",
"showM2mTables": "Show M2M Tables", "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.", "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", "computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
@ -644,15 +644,15 @@
"passwdRequired": "Mot de passe requis", "passwdRequired": "Mot de passe requis",
"passwdLength": "Votre mot de passe doit contenir au moins 8 caractères", "passwdLength": "Votre mot de passe doit contenir au moins 8 caractères",
"passwdMismatch": "Les mots de passe ne correspondent pas", "passwdMismatch": "Les mots de passe ne correspondent pas",
"completeRuleSet": "At least 8 characters with one Uppercase, one number and one special character", "completeRuleSet": "Au moins 8 caractères avec une majuscule, un chiffre et un caractère spécial",
"atLeast8Char": "At least 8 characters", "atLeast8Char": "Au moins 8 caractères",
"atLeastOneUppercase": "One Uppercase letter", "atLeastOneUppercase": "Une lettre majuscule",
"atLeastOneNumber": "One Number", "atLeastOneNumber": "Un chiffre",
"atLeastOneSpecialChar": "One special character", "atLeastOneSpecialChar": "Un caractère spécial",
"allowedSpecialCharList": "Allowed special character list" "allowedSpecialCharList": "Allowed special character list"
}, },
"invalidURL": "Invalid URL", "invalidURL": "URL invalide",
"internalError": "Some internal error occurred", "internalError": "Une erreur interne est survenue",
"templateGeneratorNotFound": "Template Generator cannot be found!", "templateGeneratorNotFound": "Template Generator cannot be found!",
"fileUploadFailed": "Failed to upload file", "fileUploadFailed": "Failed to upload file",
"primaryColumnUpdateFailed": "Failed to update primary column", "primaryColumnUpdateFailed": "Failed to update primary column",
@ -675,14 +675,14 @@
"deleteRowFailed": "Failed to delete row", "deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data", "setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Échec de la mise à jour de la vue du formulaire", "formViewUpdateFailed": "Échec de la mise à jour de la vue du formulaire",
"tableNameRequired": "Table name is required", "tableNameRequired": "Nom du tableau requis",
"nameShouldStartWithAnAlphabetOr_": "Name should start with an alphabet or _", "nameShouldStartWithAnAlphabetOr_": "Le nom doit commencer par une lettre de l'alphabet ou _",
"followingCharactersAreNotAllowed": "Following characters are not allowed", "followingCharactersAreNotAllowed": "Les caractères suivants ne sont pas autorisés",
"columnNameRequired": "Column name is required", "columnNameRequired": "Nom de la colonne requis",
"projectNameExceeds50Characters": "Project name exceeds 50 characters", "projectNameExceeds50Characters": "Le nom du projet dépasse les 50 caractères",
"projectNameCannotStartWithSpace": "Project name cannot start with space", "projectNameCannotStartWithSpace": "Le nom du projet ne peut pas commencer par un espace",
"requiredField": "Required field", "requiredField": "Champ requis",
"ipNotAllowed": "IP not allowed", "ipNotAllowed": "Adresse IP non autorisée",
"targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type", "targetFileIsNotAnAcceptedFileType": "Target file is not an accepted file type",
"theAcceptedFileTypeIsCsv": "The accepted file type is .csv", "theAcceptedFileTypeIsCsv": "The accepted file type is .csv",
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots", "theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "The accepted file types are .xls, .xlsx, .xlsm, .ods, .ots",
@ -715,15 +715,15 @@
"pluginUninstalled": "Plugin uninstalled successfully", "pluginUninstalled": "Plugin uninstalled successfully",
"pluginSettingsSaved": "Plugin settings saved successfully", "pluginSettingsSaved": "Plugin settings saved successfully",
"pluginTested": "Successfully tested plugin settings", "pluginTested": "Successfully tested plugin settings",
"tableRenamed": "Table renamed successfully", "tableRenamed": "Tableau renommé avec succès",
"viewDeleted": "Vue effacée avec succès", "viewDeleted": "Vue effacée avec succès",
"primaryColumnUpdated": "Successfully updated as primary column", "primaryColumnUpdated": "Successfully updated as primary column",
"tableDataExported": "Successfully exported all table data", "tableDataExported": "Toutes les données du tableau ont été exportées avec succès",
"updated": "Successfully updated", "updated": "Mise à jour réussie",
"sharedViewDeleted": "Vue partagée effacée avec succès", "sharedViewDeleted": "Vue partagée effacée avec succès",
"userDeleted": "User deleted successfully", "userDeleted": "Utilisateur supprimé avec succès",
"viewRenamed": "Vue renommée avec succès", "viewRenamed": "Vue renommée avec succès",
"tokenGenerated": "Token generated successfully", "tokenGenerated": "Jeton généré avec succès",
"tokenDeleted": "Token deleted successfully", "tokenDeleted": "Token deleted successfully",
"userAddedToProject": "Successfully added user to project", "userAddedToProject": "Successfully added user to project",
"userAdded": "Successfully added user", "userAdded": "Successfully added user",
@ -734,14 +734,14 @@
"shareableURLCopied": "Copied shareable base URL to clipboard!", "shareableURLCopied": "Copied shareable base URL to clipboard!",
"embeddableHTMLCodeCopied": "Copied embeddable HTML code!", "embeddableHTMLCodeCopied": "Copied embeddable HTML code!",
"userDetailsUpdated": "Successfully updated the user details", "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", "webhookUpdated": "Webhook details updated successfully",
"webhookDeleted": "Hook deleted successfully", "webhookDeleted": "Hook deleted successfully",
"webhookTested": "Webhook tested successfully", "webhookTested": "Webhook tested successfully",
"columnUpdated": "Column updated", "columnUpdated": "Colonne mise à jour",
"columnCreated": "Column created", "columnCreated": "Colonne créée",
"passwordChanged": "Password changed successfully. Please login again.", "passwordChanged": "Mot de passe modifié avec succès. Veuillez vous reconnecter.",
"settingsSaved": "Settings saved successfully", "settingsSaved": "Paramètres modifiés avec succès",
"roleUpdated": "Role updated successfully" "roleUpdated": "Role updated successfully"
} }
} }

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

@ -0,0 +1,748 @@
{
"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",
"preferred": "Preferred",
"mandatory": "Mandatory",
"loading": "Loading ...",
"title": "Title",
"upload": "Upload",
"download": "Download",
"default": "Default",
"more": "More",
"less": "Less",
"event": "Event",
"condition": "Condition",
"after": "After",
"before": "Before",
"search": "Search",
"notification": "Notification",
"reference": "Reference",
"function": "Function",
"confirm": "Confirm",
"generate": "Generate",
"copy": "Copy",
"misc": "Miscellaneous",
"lock": "Lock",
"unlock": "Unlock",
"credentials": "Credentials",
"help": "Help",
"questions": "Questions",
"reachOut": "Reach out here",
"betaNote": "This feature is currently in beta.",
"moreInfo": "More information can be found here",
"logs": "Logs",
"groupingField": "Grouping Field",
"insertAfter": "Insert After",
"insertBefore": "Insert Before",
"hideField": "Hide Field",
"sortAsc": "Sort Ascending",
"sortDesc": "Sort Descending"
},
"objects": {
"project": "Project",
"projects": "Projects",
"table": "Table",
"tables": "Tables",
"field": "Field",
"fields": "Fields",
"column": "Column",
"columns": "Columns",
"page": "Page",
"pages": "Pages",
"record": "record",
"records": "records",
"webhook": "Webhook",
"webhooks": "Webhooks",
"view": "View",
"views": "Views",
"viewType": {
"grid": "Grid",
"gallery": "Gallery",
"form": "Form",
"kanban": "Kanban",
"calendar": "Calendar"
},
"user": "User",
"users": "Users",
"role": "Role",
"roles": "Roles",
"roleType": {
"owner": "Owner",
"creator": "Creator",
"editor": "Editor",
"commenter": "Commenter",
"viewer": "Viewer",
"orgLevelCreator": "Organization Level Creator",
"orgLevelViewer": "Organization Level Viewer"
},
"sqlVIew": "SQL View"
},
"datatype": {
"ID": "ID",
"ForeignKey": "Foreign Key",
"SingleLineText": "Single Line Text",
"LongText": "Long Text",
"Attachment": "Attachment",
"Checkbox": "Checkbox",
"MultiSelect": "Multi Select",
"SingleSelect": "Single Select",
"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",
"Rollup": "Rollup",
"Count": "Count",
"Lookup": "Lookup",
"DateTime": "Date Time",
"CreateTime": "Create Time",
"LastModifiedTime": "Last Modified Time",
"AutoNumber": "Auto Number",
"Barcode": "Barcode",
"Button": "Button",
"Password": "Password",
"relationProperties": {
"noAction": "No Action",
"cascade": "Cascade",
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"filterOperation": {
"isEqual": "is equal",
"isNotEqual": "is not equal",
"isLike": "is like",
"isNot like": "is not like",
"isEmpty": "is empty",
"isNotEmpty": "is not empty",
"isNull": "is null",
"isNotNull": "is not null"
},
"title": {
"erdView": "ERD View",
"newProj": "New Project",
"myProject": "My Projects",
"formTitle": "Form Title",
"collabView": "Collaborative View",
"lockedView": "Locked View",
"personalView": "Personal View",
"appStore": "App Store",
"teamAndAuth": "Team & Auth",
"rolesUserMgmt": "Roles & Users Management",
"userMgmt": "Users Management",
"apiTokenMgmt": "API Tokens Management",
"rolesMgmt": "Roles Management",
"projMeta": "Project Metadata",
"metaMgmt": "Meta Management",
"metadata": "Metadata",
"exportImportMeta": "Export / Import Metadata",
"uiACL": "UI Access Control",
"metaOperations": "Metadata Operations",
"audit": "Audit",
"auditLogs": "Audit Log",
"sqlMigrations": "SQL Migrations",
"dbCredentials": "Database Credentials",
"advancedParameters": "SSL & Advanced parameters",
"headCreateProject": "Create Project | NocoDB",
"headLogin": "Log In | NocoDB",
"resetPassword": "Reset your password",
"teamAndSettings": "Team & Settings",
"apiDocs": "API Docs",
"importFromAirtable": "Import From Airtable",
"generateToken": "Generate Token",
"APIsAndSupport": "APIs & Support",
"helpCenter": "Help center",
"swaggerDocumentation": "Swagger Documentation",
"quickImportFrom": "Quick Import From",
"quickImport": "Quick Import",
"advancedSettings": "Advanced Settings",
"codeSnippet": "Code Snippet",
"keyboardShortcut": "Keyboard Shortcuts"
},
"labels": {
"createdBy": "Created By",
"notifyVia": "Notify Via",
"projName": "Project name",
"tableName": "Table name",
"viewName": "View name",
"viewLink": "View Link",
"columnName": "Column Name",
"columnType": "Column Type",
"roleName": "Role Name",
"roleDescription": "Role Description",
"databaseType": "Type in Database",
"lengthValue": "Length/ value",
"dbType": "Database Type",
"sqliteFile": "SQLite File",
"hostAddress": "Host Address",
"port": "Port Number",
"username": "Username",
"password": "Password",
"schemaName": "Schema name",
"database": "Database",
"action": "Action",
"actions": "Actions",
"operation": "Operation",
"operationType": "Operation type",
"operationSubType": "Operation sub-type",
"description": "Description",
"authentication": "Authentication",
"token": "Token",
"where": "Where",
"cache": "Cache",
"chat": "Chat",
"email": "E-mail",
"storage": "Storage",
"uiAcl": "UI-ACL",
"models": "Models",
"syncState": "Sync state",
"created": "Created",
"sqlOutput": "SQL Output",
"addOption": "Add option",
"qrCodeValueColumn": "Column with QR code value",
"barcodeValueColumn": "Column with Barcode value",
"barcodeFormat": "Barcode format",
"qrCodeValueTooLong": "Too many characters for a QR code",
"barcodeValueTooLong": "Too many characters for a barcode",
"aggregateFunction": "Aggregate function",
"dbCreateIfNotExists": "Database : create if not exists",
"clientKey": "Client Key",
"clientCert": "Client Cert",
"serverCA": "Server CA",
"requriedCa": "Required-CA",
"requriedIdentity": "Required-IDENTITY",
"inflection": {
"tableName": "Inflection - Table name",
"columnName": "Inflection - Column name"
},
"community": {
"starUs1": "Star",
"starUs2": "us on Github",
"bookDemo": "Book a Free DEMO",
"getAnswered": "Get your questions answered",
"joinDiscord": "Join Discord",
"joinCommunity": "Join NocoDB Community",
"joinReddit": "Join /r/NocoDB",
"followNocodb": "Follow NocoDB"
},
"docReference": "Document Reference",
"selectUserRole": "Select User Role",
"childTable": "Child table",
"childColumn": "Child column",
"onUpdate": "On Update",
"onDelete": "On Delete",
"account": "Account",
"language": "Language",
"primaryColor": "Primary Color",
"accentColor": "Accent Color",
"customTheme": "Custom Theme",
"requestDataSource": "Request a data source you need?",
"apiKey": "API Key",
"sharedBase": "Shared Base",
"importData": "Import Data",
"importSecondaryViews": "Import Secondary Views",
"importRollupColumns": "Import Rollup Columns",
"importLookupColumns": "Import Lookup Columns",
"importAttachmentColumns": "Import Attachment Columns",
"importFormulaColumns": "Import Formula Columns",
"noData": "No Data",
"goToDashboard": "Go to Dashboard",
"importing": "Importing",
"flattenNested": "Flatten Nested",
"downloadAllowed": "Download allowed",
"weAreHiring": "We are Hiring!",
"primaryKey": "Primary key",
"hasMany": "has many",
"belongsTo": "belongs to",
"manyToMany": "have many to many relation",
"extraConnectionParameters": "Extra connection parameters",
"commentsOnly": "Comments only",
"documentation": "Documentation",
"subscribeNewsletter": "Subscribe to our weekly newsletter",
"signUpWithGoogle": "Sign up with Google",
"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"
},
"activity": {
"createProject": "Create Project",
"importProject": "Import Project",
"searchProject": "Search Project",
"editProject": "Edit Project",
"stopProject": "Stop Project",
"startProject": "Start Project",
"restartProject": "Restart Project",
"deleteProject": "Delete Project",
"refreshProject": "Refresh projects",
"saveProject": "Save Project",
"deleteKanbanStack": "Delete stack?",
"createProjectExtended": {
"extDB": "Create By Connecting <br>To An External Database",
"excel": "Create Project from excel",
"template": "Create Project from template"
},
"OkSaveProject": "Ok & Save Project",
"upgrade": {
"available": "Upgrade available",
"releaseNote": "Release notes",
"howTo": "How to upgrade ?"
},
"translate": "Help translate",
"account": {
"authToken": "Copy Auth Token",
"swagger": "Swagger: REST APIs",
"projInfo": "Copy Project Info",
"themes": "Themes"
},
"sort": "Sort",
"addSort": "Add Sort Option",
"filter": "Filter",
"addFilter": "Add Filter",
"share": "Share",
"shareBase": {
"disable": "Disable shared base",
"enable": "Anyone with the link",
"link": "Shared base link"
},
"invite": "Invite",
"inviteMore": "Invite more",
"inviteTeam": "Invite Team",
"inviteUser": "Invite User",
"inviteToken": "Invite Token",
"newUser": "New User",
"editUser": "Edit user",
"deleteUser": "Remove user from project",
"resendInvite": "Resend invite E-mail",
"copyInviteURL": "Copy invite URL",
"copyPasswordResetURL": "Copy password reset URL",
"newRole": "New role",
"reloadRoles": "Reload roles",
"nextPage": "Next page",
"prevPage": "Previous page",
"nextRecord": "Next record",
"previousRecord": "Previous record",
"copyApiURL": "Copy API URL",
"createTable": "Table Create",
"refreshTable": "Tables Refresh",
"renameTable": "Table Rename",
"deleteTable": "Table Delete",
"addField": "Add new field to this table",
"setPrimary": "Set as Primary value",
"addRow": "Add new row",
"saveRow": "Save row",
"saveAndExit": "Save & Exit",
"saveAndStay": "Save & Stay",
"insertRow": "Insert New Row",
"deleteRow": "Delete Row",
"deleteSelectedRow": "Delete Selected Rows",
"importExcel": "Import Excel",
"importCSV": "Import CSV",
"downloadCSV": "Download as CSV",
"downloadExcel": "Download as XLSX",
"uploadCSV": "Upload CSV",
"import": "Import",
"importMetadata": "Import Metadata",
"exportMetadata": "Export Metadata",
"clearMetadata": "Clear Metadata",
"exportToFile": "Export to file",
"changePwd": "Change Password",
"createView": "Create a View",
"shareView": "Share View",
"listSharedView": "Shared View List",
"ListView": "Views List",
"copyView": "Copy view",
"renameView": "Rename view",
"deleteView": "Delete view",
"createGrid": "Create Grid View",
"createGallery": "Create Gallery View",
"createCalendar": "Create Calendar View",
"createKanban": "Create Kanban View",
"createForm": "Create Form View",
"showSystemFields": "Show system fields",
"copyUrl": "Copy URL",
"openTab": "Open new tab",
"iFrame": "Copy embeddable HTML code",
"addWebhook": "Add New Webhook",
"newToken": "Add New Token",
"exportZip": "Export zip",
"importZip": "Import zip",
"metaSync": "Sync Now",
"settings": "Settings",
"previewAs": "Preview as",
"resetReview": "Reset Preview",
"testDbConn": "Test Database Connection",
"removeDbFromEnv": "Remove Database from environment",
"editConnJson": "Edit connection JSON",
"sponsorUs": "Sponsor Us",
"sendEmail": "SEND EMAIL",
"addUserToProject": "Add user to project",
"getApiSnippet": "Get API Snippet",
"clearCell": "Clear cell",
"addFilterGroup": "Add Filter Group",
"linkRecord": "Link record",
"addNewRecord": "Add new record",
"useConnectionUrl": "Use Connection URL",
"toggleCommentsDraw": "Toggle comments draw",
"expandRecord": "Expand Record",
"deleteRecord": "Delete Record",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
},
"kanban": {
"collapseStack": "Collapse Stack",
"deleteStack": "Delete Stack",
"stackedBy": "Stacked By",
"chooseGroupingField": "Choose a Grouping Field",
"addOrEditStack": "Add / Edit Stack"
}
},
"tooltip": {
"saveChanges": "Save changes",
"xcDB": "Create a new project",
"extDB": "Supports MySQL, PostgreSQL, SQL Server & SQLite",
"apiRest": "Accessible via REST APIs",
"apiGQL": "Accessible via GraphQL APIs",
"theme": {
"dark": "It does come in Black (^⇧B)",
"light": "Does it come in Black ? (^⇧B)"
},
"addTable": "Add new table",
"inviteMore": "Invite more users",
"toggleNavDraw": "Toggle navigation drawer",
"reloadApiToken": "Reload API tokens",
"generateNewApiToken": "Generate new API token",
"addRole": "Add new role",
"reloadList": "Reload list",
"metaSync": "Sync metadata",
"sqlMigration": "Reload migrations",
"updateRestart": "Update & Restart",
"cancelReturn": "Cancel and Return",
"exportMetadata": "Export all metadata from the meta tables to meta directory.",
"importMetadata": "Import all metadata from the meta directory to meta tables.",
"clearMetadata": "Clear all metadata from meta tables.",
"clientKey": "Select .key file",
"clientCert": "Select .cert file",
"clientCA": "Select CA file"
},
"placeholder": {
"projName": "Enter Project Name",
"password": {
"enter": "Enter the password",
"current": "Current password",
"new": "New password",
"save": "Save password",
"confirm": "Confirm new password"
},
"searchProjectTree": "Search tables",
"searchFields": "Search fields",
"searchColumn": "Search {search} column",
"searchApps": "Search apps",
"searchModels": "Search models",
"noItemsFound": "No items found",
"defaultValue": "Default value",
"filterByEmail": "Filter by E-mail",
"filterQuery": "Filter query",
"selectField": "Select field"
},
"msg": {
"warning": {
"barcode": {
"renderError": "Barcode error - please check compatibility between input and barcode type"
},
"nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed."
}
},
"info": {
"pasteNotSupported": "Paste operation is not supported on the active cell",
"roles": {
"orgCreator": "Creator can create new projects and access any invited project.",
"orgViewer": "Viewer is not allowed to create new projects but they can access any invited project."
},
"footerInfo": "Rows per page",
"upload": "Select file to Upload",
"upload_sub": "or drag and drop file",
"excelSupport": "Supported: .xls, .xlsx, .xlsm, .ods, .ots",
"excelURL": "Enter excel file URL",
"csvURL": "Enter CSV file URL",
"footMsg": "# of rows to parse to infer datatype",
"excelImport": "sheet(s) are available for import",
"exportMetadata": "Do you want to export metadata from meta tables?",
"importMetadata": "Do you want to import metadata from meta tables?",
"clearMetadata": "Do you want to clear metadata from meta tables?",
"projectEmptyMessage": "Get started by creating a new project",
"stopProject": "Do you want to stop the project?",
"startProject": "Do you want to start the project?",
"restartProject": "Do you want to restart the project?",
"deleteProject": "Do you want to delete the project?",
"shareBasePrivate": "Generate publicly shareable readonly base",
"shareBasePublic": "Anyone on the internet with this link can view",
"userInviteNoSMTP": "Looks like you have not configured mailer yet! Please copy above invite link and send it to",
"dragDropHide": "Drag and drop fields here to hide",
"formInput": "Enter form input label",
"formHelpText": "Add some help text",
"onlyCreator": "Only visible to Creator",
"formDesc": "Add form description",
"beforeEnablePwd": "Restrict access with a password",
"afterEnablePwd": "Access is password restricted",
"privateLink": "This view is shared via a private link",
"privateLinkAdditionalInfo": "People with private link can only see cells visible in this view",
"afterFormSubmitted": "After form is submitted",
"apiOptions": "Access Project via",
"submitAnotherForm": "Show 'Submit Another Form' button",
"showBlankForm": "Show a blank form after 5 seconds",
"emailForm": "E-mail me at",
"showSysFields": "Show system fields",
"filterAutoApply": "Auto apply",
"showMessage": "Show this message",
"viewNotShared": "Current view is not shared!",
"showAllViews": "Show all shared views of this table",
"collabView": "Collaborators with edit permissions or higher can change the view configuration.",
"lockedView": "No one can edit the view configuration until it is unlocked.",
"personalView": "Only you can edit the view configuration. Other collaborators’ personal views are hidden by default.",
"ownerDesc": "Can add/remove creators. And full edit database structures & fields.",
"creatorDesc": "Can fully edit database structure & values.",
"editorDesc": "Can edit records but cannot change structure of database/fields.",
"commenterDesc": "Can view and comment the records but cannot edit anything",
"viewerDesc": "Can view the records but cannot edit anything",
"addUser": "Add new user",
"staticRoleInfo": "System defined roles can't be edited",
"exportZip": "Export project meta to zip file and download.",
"importZip": "Import project meta zip file and restart.",
"importText": "Import NocoDB Project by uploading metadata zip file",
"metaNoChange": "No change identified",
"sqlMigration": "Schema migrations will be created automatically. Create a table and refresh this page.",
"dbConnectionStatus": "Environment validated",
"dbConnected": "Connection was successful",
"notifications": {
"no_new": "No new notifications",
"clear": "Clear"
},
"sponsor": {
"header": "You can help us!",
"message": "We are a tiny team working full time to make NocoDB Open-source. We believe a tool like NocoDB should be available freely to every problem solver on Internet."
},
"loginMsg": "Log In To NocoDB",
"passwordRecovery": {
"message_1": "Please provide the email address you used when you signed up.",
"message_2": "We will send you an email with a link to reset your password.",
"success": "Please check your email to reset the password"
},
"signUp": {
"superAdmin": "You will be the 'Super Admin'",
"alreadyHaveAccount": "Already have an account ?",
"workEmail": "Enter your work email",
"enterPassword": "Enter your password",
"forgotPassword": "Forgot your password ?",
"dontHaveAccount": "Don't have an account ?"
},
"addView": {
"grid": "Add Grid View",
"gallery": "Add Gallery View",
"form": "Add Form View",
"kanban": "Add Kanban View",
"calendar": "Add Calendar View"
},
"tablesMetadataInSync": "Tables metadata is in Sync",
"addMultipleUsers": "You can add multiple comma(,) separated emails",
"enterTableName": "Enter table name",
"addDefaultColumns": "Add default columns",
"tableNameInDb": "Table name as saved in database",
"airtable": {
"credentials": "Where to find this?"
},
"import": {
"clickOrDrag": "Click or drag file to this area to upload"
},
"metaDataRecreated": "Table metadata recreated successfully",
"invalidCredentials": "Invalid credentials",
"downloadingMoreFiles": "Downloading more files",
"copiedToClipboard": "Copied to clipboard",
"requriedFieldsCantBeMoved": "Required field can't be moved",
"updateNotAllowedWithoutPK": "Update not allowed for table which doesn't have primary key",
"autoIncFieldNotEditable": "Auto increment field is not editable",
"editingPKnotSupported": "Editing primary key not supported",
"deletedCache": "Deleted cache successfully",
"cacheEmpty": "Cache is empty",
"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",
"deleteViewConfirmation": "Are you sure you want to delete this view?",
"deleteTableConfirmation": "Do you want to delete the table",
"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."
},
"error": {
"searchProject": "Your search for {search} found no results",
"invalidChar": "Invalid character in folder path.",
"invalidDbCredentials": "Invalid database credentials.",
"unableToConnectToDb": "Unable to connect to database, please check your database is up.",
"userDoesntHaveSufficientPermission": "User does not exist or have sufficient permission to create schema.",
"dbConnectionStatus": "Invalid database parameters",
"dbConnectionFailed": "Connection Failure:",
"signUpRules": {
"emailReqd": "E-mail is required",
"emailInvalid": "E-mail must be valid",
"passwdRequired": "Password is required",
"passwdLength": "You password must be atleast 8 characters",
"passwdMismatch": "Passwords do not match",
"completeRuleSet": "At least 8 characters with one Uppercase, one number and one special character",
"atLeast8Char": "At least 8 characters",
"atLeastOneUppercase": "One Uppercase letter",
"atLeastOneNumber": "One Number",
"atLeastOneSpecialChar": "One special character",
"allowedSpecialCharList": "Allowed special character list"
},
"invalidURL": "Invalid URL",
"internalError": "Some internal error occurred",
"templateGeneratorNotFound": "Template Generator cannot be found!",
"fileUploadFailed": "Failed to upload file",
"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",
"duplicateMappingFound": "Duplicate mapping found, please remove one of the mapping",
"nullValueViolatesNotNull": "Null value violates not-null constraint",
"sourceHasInvalidNumbers": "Source data contains some invalid numbers",
"sourceHasInvalidBoolean": "Source data contains some invalid boolean values",
"invalidForm": "Invalid Form",
"formValidationFailed": "Form validation failed",
"youHaveBeenSignedOut": "You have been signed out",
"failedToLoadList": "Failed to load list",
"failedToLoadChildrenList": "Failed to load children list",
"deleteFailed": "Delete failed",
"unlinkFailed": "Unlink failed",
"rowUpdateFailed": "Row update failed",
"deleteRowFailed": "Failed to delete row",
"setFormDataFailed": "Failed to set form data",
"formViewUpdateFailed": "Failed to update form view",
"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",
"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",
"parameterKeyCannotBeEmpty": "Parameter key cannot be empty",
"duplicateParameterKeysAreNotAllowed": "Duplicate parameter keys are not allowed",
"fieldRequired": "{value} cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard"
},
"toast": {
"exportMetadata": "Project metadata exported successfully",
"importMetadata": "Project metadata imported successfully",
"clearMetadata": "Project metadata cleared successfully",
"stopProject": "Project stopped successfully",
"startProject": "Project started successfully",
"restartProject": "Project restarted successfully",
"deleteProject": "Project deleted successfully",
"authToken": "Auth token copied to clipboard",
"projInfo": "Copied project info to clipboard",
"inviteUrlCopy": "Copied invite URL to clipboard",
"createView": "View created successfully",
"formEmailSMTP": "Please activate SMTP plugin in App store for enabling email notification",
"collabView": "Successfully Switched to collaborative view",
"lockedView": "Successfully Switched to locked view",
"futureRelease": "Coming soon!"
},
"success": {
"columnDuplicated": "Column duplicated successfully",
"updatedUIACL": "Updated UI ACL for tables successfully",
"pluginUninstalled": "Plugin uninstalled successfully",
"pluginSettingsSaved": "Plugin settings saved successfully",
"pluginTested": "Successfully tested plugin settings",
"tableRenamed": "Table renamed successfully",
"viewDeleted": "View deleted successfully",
"primaryColumnUpdated": "Successfully updated as primary column",
"tableDataExported": "Successfully exported all table data",
"updated": "Successfully updated",
"sharedViewDeleted": "Deleted shared view successfully",
"userDeleted": "User deleted successfully",
"viewRenamed": "View renamed successfully",
"tokenGenerated": "Token generated successfully",
"tokenDeleted": "Token deleted successfully",
"userAddedToProject": "Successfully added user to project",
"userAdded": "Successfully added user",
"userDeletedFromProject": "Successfully deleted user from project",
"inviteEmailSent": "Invite Email sent successfully",
"inviteURLCopied": "Invite URL copied to clipboard",
"passwordResetURLCopied": "Password reset URL copied to clipboard",
"shareableURLCopied": "Copied shareable base URL to clipboard!",
"embeddableHTMLCodeCopied": "Copied embeddable HTML code!",
"userDetailsUpdated": "Successfully updated the user details",
"tableDataImported": "Successfully imported table data",
"webhookUpdated": "Webhook details updated successfully",
"webhookDeleted": "Hook deleted successfully",
"webhookTested": "Webhook tested successfully",
"columnUpdated": "Column updated",
"columnCreated": "Column created",
"passwordChanged": "Password changed successfully. Please login again.",
"settingsSaved": "Settings saved successfully",
"roleUpdated": "Role updated successfully"
}
}
}

3
packages/nc-gui/lib/enums.ts

@ -26,10 +26,12 @@ export enum ClientType {
export enum Language { export enum Language {
ar = 'العربية', ar = 'العربية',
bn_IN = 'ব', bn_IN = 'ব',
cs = 'Czech',
da = 'Dansk', da = 'Dansk',
de = 'Deutsch', de = 'Deutsch',
en = 'English', en = 'English',
es = 'Español', es = 'Español',
eu = 'Basque',
fa = 'فارسی', fa = 'فارسی',
fi = 'Suomalainen', fi = 'Suomalainen',
fr = 'Français', fr = 'Français',
@ -47,6 +49,7 @@ export enum Language {
pt = 'Português', pt = 'Português',
pt_BR = 'Português (Brasil)', pt_BR = 'Português (Brasil)',
ru = 'Pусский', ru = 'Pусский',
sk = 'Slovenčina',
sl = 'Slovenščina', sl = 'Slovenščina',
sv = 'Svenska', sv = 'Svenska',
th = 'ไทย', th = 'ไทย',

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

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

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

@ -29,7 +29,7 @@
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"locale-codes": "^1.3.1", "locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"nocodb-sdk": "0.101.0-beta.0", "nocodb-sdk": "file:../nocodb-sdk",
"papaparse": "^5.3.2", "papaparse": "^5.3.2",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"socket.io-client": "^4.5.1", "socket.io-client": "^4.5.1",
@ -96,7 +96,6 @@
}, },
"../nocodb-sdk": { "../nocodb-sdk": {
"version": "0.101.0-beta.0", "version": "0.101.0-beta.0",
"extraneous": true,
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
@ -8544,6 +8543,7 @@
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"devOptional": true,
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -10518,9 +10518,9 @@
"dev": true "dev": true
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.1", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true, "dev": true,
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
@ -11959,21 +11959,8 @@
} }
}, },
"node_modules/nocodb-sdk": { "node_modules/nocodb-sdk": {
"version": "0.101.0-beta.0", "resolved": "../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.101.0-beta.0.tgz", "link": true
"integrity": "sha512-/h12sltRNdbCXop/iGYyWCHQ0iU8CKYNn7VrMrTA+u1kykHBu1ja/zhF6Kk98+m5XGNYAasASxLOFzk2GHvwCw==",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
}
},
"node_modules/nocodb-sdk/node_modules/axios": {
"version": "0.21.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
"dependencies": {
"follow-redirects": "^1.14.0"
}
}, },
"node_modules/node-abi": { "node_modules/node-abi": {
"version": "3.23.0", "version": "3.23.0",
@ -15716,9 +15703,9 @@
} }
}, },
"node_modules/tsconfig-paths/node_modules/json5": { "node_modules/tsconfig-paths/node_modules/json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -23937,7 +23924,8 @@
"follow-redirects": { "follow-redirects": {
"version": "1.15.1", "version": "1.15.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
"integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==" "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
"devOptional": true
}, },
"form-data": { "form-data": {
"version": "4.0.0", "version": "4.0.0",
@ -25344,9 +25332,9 @@
"dev": true "dev": true
}, },
"json5": { "json5": {
"version": "2.2.1", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true "dev": true
}, },
"jsonc-eslint-parser": { "jsonc-eslint-parser": {
@ -26410,22 +26398,22 @@
} }
}, },
"nocodb-sdk": { "nocodb-sdk": {
"version": "0.101.0-beta.0", "version": "file:../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.101.0-beta.0.tgz",
"integrity": "sha512-/h12sltRNdbCXop/iGYyWCHQ0iU8CKYNn7VrMrTA+u1kykHBu1ja/zhF6Kk98+m5XGNYAasASxLOFzk2GHvwCw==",
"requires": { "requires": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"jsep": "^1.3.6" "cspell": "^4.1.0",
}, "eslint": "^7.8.0",
"dependencies": { "eslint-config-prettier": "^6.11.0",
"axios": { "eslint-plugin-eslint-comments": "^3.2.0",
"version": "0.21.4", "eslint-plugin-functional": "^3.0.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", "eslint-plugin-import": "^2.22.0",
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", "eslint-plugin-prettier": "^4.0.0",
"requires": { "jsep": "^1.3.6",
"follow-redirects": "^1.14.0" "npm-run-all": "^4.1.5",
} "prettier": "^2.1.1",
} "typescript": "^4.0.2"
} }
}, },
"node-abi": { "node-abi": {
@ -29229,9 +29217,9 @@
}, },
"dependencies": { "dependencies": {
"json5": { "json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.0" "minimist": "^1.2.0"

2
packages/nc-gui/package.json

@ -52,7 +52,7 @@
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"locale-codes": "^1.3.1", "locale-codes": "^1.3.1",
"monaco-editor": "^0.33.0", "monaco-editor": "^0.33.0",
"nocodb-sdk": "0.101.0-beta.0", "nocodb-sdk": "file:../nocodb-sdk",
"papaparse": "^5.3.2", "papaparse": "^5.3.2",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"socket.io-client": "^4.5.1", "socket.io-client": "^4.5.1",

18
packages/nc-gui/pages/[projectType]/[projectId]/index/index.vue

@ -47,7 +47,7 @@ function onEdit(targetKey: number, action: 'add' | 'remove' | string) {
<a-tabs v-model:activeKey="activeTabIndex" class="nc-root-tabs" type="editable-card" @edit="onEdit"> <a-tabs v-model:activeKey="activeTabIndex" class="nc-root-tabs" type="editable-card" @edit="onEdit">
<a-tab-pane v-for="(tab, i) of tabs" :key="i"> <a-tab-pane v-for="(tab, i) of tabs" :key="i">
<template #tab> <template #tab>
<div class="flex items-center gap-2 max-w-[110px]" data-testid="nc-tab-title"> <div class="flex items-center gap-2" data-testid="nc-tab-title">
<div class="flex items-center"> <div class="flex items-center">
<Icon <Icon
v-if="tab.meta?.icon" v-if="tab.meta?.icon"
@ -58,15 +58,11 @@ function onEdit(targetKey: number, action: 'add' | 'remove' | string) {
<component :is="icon(tab)" v-else class="text-sm" /> <component :is="icon(tab)" v-else class="text-sm" />
</div> </div>
<a-tooltip v-if="tab.title?.length > 12" placement="bottom"> <div :data-testid="`nc-root-tabs-${tab.title}`">
<div class="truncate" :data-testid="`nc-root-tabs-${tab.title}`">{{ tab.title }}</div> <GeneralTruncateText :key="tab.title" :length="12">
{{ tab.title }}
<template #title> </GeneralTruncateText>
<div>{{ tab.title }}</div> </div>
</template>
</a-tooltip>
<div v-else :data-testid="`nc-root-tabs-${tab.title}`">{{ tab.title }}</div>
</div> </div>
</template> </template>
</a-tab-pane> </a-tab-pane>
@ -146,6 +142,6 @@ function onEdit(targetKey: number, action: 'add' | 'remove' | string) {
} }
:deep(.ant-tabs-tab-remove) { :deep(.ant-tabs-tab-remove) {
@apply mt-[3px]; @apply flex mt-[2px];
} }
</style> </style>

10
packages/nc-gui/pages/index/index/[projectId].vue

@ -16,9 +16,7 @@ import {
const route = useRoute() const route = useRoute()
const { loadProject, updateProject, isLoading } = useProject() const { project, loadProject, updateProject, isLoading } = useProject()
loadProject(false)
const nameValidationRules = [ const nameValidationRules = [
{ {
@ -44,6 +42,12 @@ const renameProject = async () => {
} }
} }
onBeforeMount(async () => {
await loadProject(false)
formState.title = project.value?.title
})
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus() const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</script> </script>

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

@ -84,13 +84,10 @@
} }
}, },
"node_modules/@babel/core/node_modules/json5": { "node_modules/@babel/core/node_modules/json5": {
"version": "2.2.0", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true, "dev": true,
"dependencies": {
"minimist": "^1.2.5"
},
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
}, },
@ -7632,9 +7629,9 @@
"dev": true "dev": true
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -11690,17 +11687,26 @@
} }
}, },
"node_modules/tsconfig-paths": { "node_modules/tsconfig-paths": {
"version": "3.9.0", "version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
"integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/json5": "^0.0.29", "@types/json5": "^0.0.29",
"json5": "^1.0.1", "json5": "^1.0.1",
"minimist": "^1.2.0", "minimist": "^1.2.6",
"strip-bom": "^3.0.0" "strip-bom": "^3.0.0"
} }
}, },
"node_modules/tsconfig-paths/node_modules/minimist": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "1.14.1", "version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
@ -12306,13 +12312,10 @@
}, },
"dependencies": { "dependencies": {
"json5": { "json5": {
"version": "2.2.0", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true, "dev": true
"requires": {
"minimist": "^1.2.5"
}
}, },
"semver": { "semver": {
"version": "6.3.0", "version": "6.3.0",
@ -18137,9 +18140,9 @@
"dev": true "dev": true
}, },
"json5": { "json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -21142,15 +21145,23 @@
} }
}, },
"tsconfig-paths": { "tsconfig-paths": {
"version": "3.9.0", "version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
"integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/json5": "^0.0.29", "@types/json5": "^0.0.29",
"json5": "^1.0.1", "json5": "^1.0.1",
"minimist": "^1.2.0", "minimist": "^1.2.6",
"strip-bom": "^3.0.0" "strip-bom": "^3.0.0"
},
"dependencies": {
"minimist": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
"dev": true
}
} }
}, },
"tslib": { "tslib": {

112
packages/noco-docs/content/en/getting-started/installation.md

@ -298,7 +298,6 @@ npm start
<alert> <alert>
If your service fails to start, you may check the logs in ECS console or in Cloudwatch. Generally it fails due to the connection between ECS container and NC_DB. Make sure the security groups have the correct inbound and outbound rules. If your service fails to start, you may check the logs in ECS console or in Cloudwatch. Generally it fails due to the connection between ECS container and NC_DB. Make sure the security groups have the correct inbound and outbound rules.
</alert> </alert>
```
</details> </details>
@ -444,62 +443,61 @@ npm start
See [here](https://gist.github.com/Zamana/e9281d736f9e9ce5882c6f4b140a590e) provided by [C. R. Zamana](https://github.com/Zamana). See [here](https://gist.github.com/Zamana/e9281d736f9e9ce5882c6f4b140a590e) provided by [C. R. Zamana](https://github.com/Zamana).
## Production Setup ## Environment Variables
It is mandatory to configure `NC_DB` environment variables for production usecases.
Here is the list of the environment variables that you can use. Even though they are optional, it is **recommended** to configure `NC_DB`, `NC_AUTH_JWT_SECRET`, and `NC_PUBLIC_URL` for production use cases.
### Environment variables
| Variable | Comments | If absent | |
| Variable | Mandatory | Comments | If absent | | |------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|---|
|------------------------------------|-----------|-------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|---| | NC_DB | See our database URLs | A local SQLite will be created in root folder if `NC_DB` is not provided | |
| NC_DB | Yes | See our database URLs | A local SQLite will be created in root folder | | | NC_DB_JSON | Can be used instead of `NC_DB` and value should be valid knex connection JSON | | |
| NC_DB_JSON | Yes | Can be used instead of `NC_DB` and value should be valid knex connection JSON | | | | NC_DB_JSON_FILE | Can be used instead of `NC_DB` and value should be a valid path to knex connection JSON | | |
| NC_DB_JSON_FILE | Yes | Can be used instead of `NC_DB` and value should be a valid path to knex connection JSON | | | | DATABASE_URL | JDBC URL Format. Can be used instead of NC_DB. | | |
| DATABASE_URL | No | JDBC URL Format. Can be used instead of NC_DB. | | | | DATABASE_URL_FILE | Can be used instead of DATABASE_URL: path to file containing JDBC URL Format. | | |
| DATABASE_URL_FILE | No | Can be used instead of DATABASE_URL: path to file containing JDBC URL Format. | | | | NC_AUTH_JWT_SECRET | JWT secret used for auth and storing other secrets | A random secret will be generated | |
| NC_AUTH_JWT_SECRET | Yes | JWT secret used for auth and storing other secrets | A Random secret will be generated | | | PORT | For setting app running port | `8080` | |
| PORT | No | For setting app running port | `8080` | | | DB_QUERY_LIMIT_DEFAULT | Default pagination limit | 25 | |
| DB_QUERY_LIMIT_DEFAULT | No | Default pagination limit | 25 | | | DB_QUERY_LIMIT_MAX | Maximum allowed pagination limit | 1000 | |
| DB_QUERY_LIMIT_MAX | No | Maximum allowed pagination limit | 1000 | | | DB_QUERY_LIMIT_MIN | Minimum allowed pagination limit | 1 | |
| DB_QUERY_LIMIT_MIN | No | Minimum allowed pagination limit | 1 | | | NC_TOOL_DIR | App directory to keep metadata and app related files | Defaults to current working directory. In docker maps to `/usr/app/data/` for mounting volume. | |
| NC_TOOL_DIR | No | App directory to keep metadata and app related files | Defaults to current working directory. In docker maps to `/usr/app/data/` for mounting volume. | | | NC_PUBLIC_URL | Used for sending Email invitations | Best guess from http request params | |
| NC_PUBLIC_URL | Yes | Used for sending Email invitations | Best guess from http request params | | | NC_JWT_EXPIRES_IN | JWT token expiry time | `10h` | |
| NC_JWT_EXPIRES_IN | No | JWT token expiry time | `10h` | | | NC_CONNECT_TO_EXTERNAL_DB_DISABLED | Disable Project creation with external database | | |
| NC_CONNECT_TO_EXTERNAL_DB_DISABLED | No | Disable Project creation with external database | | | | NC_INVITE_ONLY_SIGNUP | Removed since version 0.99.0 and now it's recommended to use [super admin settings menu](/setup-and-usages/account-settings#enable--disable-signup). Allow users to signup only via invite url, value should be any non-empty string. | | |
| NC_INVITE_ONLY_SIGNUP | No | <strong>Removed</strong> since version <kbd>0.99.0</kbd> and now it's recommended to use [super admin settings menu](/setup-and-usages/account-settings#enable--disable-signup). <br><br>Allow users to signup only via invite url, value should be any non-empty string. | | | | NUXT_PUBLIC_NC_BACKEND_URL | Custom Backend URL | ``http://localhost:8080`` will be used | |
| NUXT_PUBLIC_NC_BACKEND_URL | No | Custom Backend URL | ``http://localhost:8080`` will be used | | | NC_REQUEST_BODY_SIZE | Request body size [limit](https://expressjs.com/en/resources/middleware/body-parser.html#limit) | `1048576` | |
| NC_REQUEST_BODY_SIZE | No | Request body size [limit](https://expressjs.com/en/resources/middleware/body-parser.html#limit) | `1048576` | | | NC_EXPORT_MAX_TIMEOUT | After NC_EXPORT_MAX_TIMEOUT csv gets downloaded in batches | Default value 5000(in millisecond) will be used | |
| NC_EXPORT_MAX_TIMEOUT | No | After NC_EXPORT_MAX_TIMEOUT csv gets downloaded in batches | Default value 5000(in millisecond) will be used | | | NC_DISABLE_TELE | Disable telemetry | | |
| NC_DISABLE_TELE | No | Disable telemetry | | | | NC_DASHBOARD_URL | Custom dashboard url path | `/dashboard` | |
| NC_DASHBOARD_URL | No | Custom dashboard url path | `/dashboard` | | | NC_GOOGLE_CLIENT_ID | Google client id to enable google authentication | | |
| NC_GOOGLE_CLIENT_ID | No | Google client id to enable google authentication | | | | NC_GOOGLE_CLIENT_SECRET | Google client secret to enable google authentication | | |
| NC_GOOGLE_CLIENT_SECRET | No | Google client secret to enable google authentication | | | | NC_MIGRATIONS_DISABLED | Disable NocoDB migration | | |
| NC_MIGRATIONS_DISABLED | No | Disable NocoDB migration | | | | NC_MIN | If set to any non-empty string the default splash screen(initial welcome animation) and matrix screensaver will disable | | |
| NC_MIN | No | If set to any non-empty string the default splash screen(initial welcome animation) and matrix screensaver will disable | | | | NC_SENTRY_DSN | For Sentry monitoring | | |
| NC_SENTRY_DSN | No | For Sentry monitoring | | | | NC_REDIS_URL | Custom Redis URL. Example: `redis://:authpassword@127.0.0.1:6380/4` | Meta data will be stored in memory | |
| NC_REDIS_URL | No | Custom Redis URL. Example: `redis://:authpassword@127.0.0.1:6380/4` | Meta data will be stored in memory | | | NC_DISABLE_ERR_REPORT | Disable error reporting | | |
| NC_DISABLE_ERR_REPORT | No | Disable error reporting | | | | NC_DISABLE_CACHE | To be used only while debugging. On setting this to `true` - meta data be fetched from db instead of redis/cache. | `false` | |
| NC_DISABLE_CACHE | No | To be used only while debugging. On setting this to `true` - meta data be fetched from db instead of redis/cache. | `false` | | | NC_BASEURL_INTERNAL | Used as base url for internal(server) API calls | Default value in docker will be `http://localhost:$PORT` and in all other case it's populated from request object | |
| NC_BASEURL_INTERNAL | No | Used as base url for internal(server) API calls | Default value in docker will be `http://localhost:$PORT` and in all other case it's populated from request object | | | AWS_ACCESS_KEY_ID | For Litestream - S3 access key id | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | |
| AWS_ACCESS_KEY_ID | No | For Litestream - S3 access key id | If Litestream is configured and NC_DB is not present. SQLite gets backed up to S3 | | | AWS_SECRET_ACCESS_KEY | For Litestream - S3 secret access key | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | |
| AWS_SECRET_ACCESS_KEY | No | For Litestream - S3 secret access key | If Litestream is configured and NC_DB is not present. SQLite gets backed up to S3 | | | AWS_BUCKET | For Litestream - S3 bucket | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | |
| AWS_BUCKET | No | For Litestream - S3 bucket | If Litestream is configured and NC_DB is not present. SQLite gets backed up to S3 | | | AWS_BUCKET_PATH | For Litestream - S3 bucket path (like folder within S3 bucket) | If Litestream is configured and `NC_DB` is not present. SQLite gets backed up to S3 | |
| AWS_BUCKET_PATH | No | For Litestream - S3 bucket path (like folder within S3 bucket) | If Litestream is configured and NC_DB is not present. SQLite gets backed up to S3 | | | NC_SMTP_FROM | For SMTP plugin - Email sender address | | |
| NC_SMTP_FROM | No | For SMTP plugin - Email sender address | | | | NC_SMTP_HOST | For SMTP plugin - SMTP host value | | |
| NC_SMTP_HOST | No | For SMTP plugin - SMTP host value | | | | NC_SMTP_PORT | For SMTP plugin - SMTP port value | | |
| NC_SMTP_PORT | No | For SMTP plugin - SMTP port value | | | | NC_SMTP_USERNAME | For SMTP plugin (Optional) - SMTP username value for authentication | | |
| NC_SMTP_USERNAME | No | For SMTP plugin (Optional) - SMTP username value for authentication | | | | NC_SMTP_PASSWORD | For SMTP plugin (Optional) - SMTP password value for authentication | | |
| NC_SMTP_PASSWORD | No | For SMTP plugin (Optional) - SMTP password value for authentication | | | | NC_SMTP_SECURE | For SMTP plugin (Optional) - To enable secure set value as `true` any other value treated as false | | |
| NC_SMTP_SECURE | No | For SMTP plugin (Optional) - To enable secure set value as `true` any other value treated as false | | | | NC_SMTP_IGNORE_TLS | For SMTP plugin (Optional) - To ignore tls set value as `true` any other value treated as false. For more info visit https://nodemailer.com/smtp/ | | |
| NC_SMTP_IGNORE_TLS | No | For SMTP plugin (Optional) - To ignore tls set value as `true` any other value treated as false. For more info visit https://nodemailer.com/smtp/ | | | | NC_S3_BUCKET_NAME | For S3 storage plugin - AWS S3 bucket name | | |
| NC_S3_BUCKET_NAME | No | For S3 storage plugin - AWS S3 bucket name | | | | NC_S3_REGION | For S3 storage plugin - AWS S3 region | | |
| NC_S3_REGION | No | For S3 storage plugin - AWS S3 region | | | | NC_S3_ACCESS_KEY | For S3 storage plugin - AWS access key credential for accessing resource | | |
| NC_S3_ACCESS_KEY | No | For S3 storage plugin - AWS access key credential for accessing resource | | | | NC_S3_ACCESS_SECRET | For S3 storage plugin - AWS access secret credential for accessing resource | | |
| NC_S3_ACCESS_SECRET | No | For S3 storage plugin - AWS access secret credential for accessing resource | | | | NC_ADMIN_EMAIL | For updating/creating super admin with provided email and password | | |
| NC_ADMIN_EMAIL | No | For updating/creating super admin with provided email and password | | | | NC_ATTACHMENT_FIELD_SIZE | For setting the attachment field size(in Bytes) | Defaults to 20MB | |
| NC_ATTACHMENT_FIELD_SIZE | No | For setting the attachment field size(in Bytes) | Defaults to 20MB | | | NC_ADMIN_PASSWORD | For updating/creating super admin with provided email and password. Your password should have at least 8 letters with one uppercase, one number and one special letter(Allowed special chars $&+,:;=?@#\|'.^*()%!_-" ) | | |
| NC_ADMIN_PASSWORD | No | For updating/creating super admin with provided email and password. Your password should have at least 8 letters with one uppercase, one number and one special letter(Allowed special chars <code>$&+,:;=?@#&#124;'.^*()%!_-"</code> ) | | | | NODE_OPTIONS | For passing Node.js [options](https://nodejs.org/api/cli.html#node_optionsoptions) to instance | | |
| NODE_OPTIONS | No | For passing Node.js [options](https://nodejs.org/api/cli.html#node_optionsoptions) to instance | | | | NC_MINIMAL_DBS | Create a new SQLite file for each project. All the db files are stored in `nc_minimal_dbs` folder in current working directory. (This option restricts project creation on external sources) | | |
| NC_MINIMAL_DBS | No | Create a new SQLite file for each project. All the db files are stored in `nc_minimal_dbs` folder in current working directory. (This option restricts project creation on external sources) | | |
## Sample Demos ## Sample Demos

2
packages/noco-docs/content/en/setup-and-usages/dashboard.md

@ -15,7 +15,7 @@ Enter your work email and your password.
<img width="1492" alt="image" src="https://user-images.githubusercontent.com/35857179/194793294-fa027496-c3c3-44eb-a613-2ba3e3bd26c1.png"> <img width="1492" alt="image" src="https://user-images.githubusercontent.com/35857179/194793294-fa027496-c3c3-44eb-a613-2ba3e3bd26c1.png">
<alert id="password-conditions"> <alert id="password-conditions">
Your password has at least 8 letters with one uppercase, one number and one special letter Your password has at least 8 letters. No other constraints on case, numbers or special characters.
</alert> </alert>
## Initialize Your First Project ## Initialize Your First Project

99
packages/noco-docs/content/en/setup-and-usages/meta-management.md

@ -1,81 +1,92 @@
--- ---
title: 'Team & Settings > Project Metadata' title: 'Team & Settings > Data Sources'
description: 'NocoDB Project Metadata' description: 'NocoDB Data-Source sync, access control & re-config'
position: 600 position: 600
category: 'Product' category: 'Product'
menuTitle: 'Team & Settings > Project Metadata' menuTitle: 'Team & Settings > Data Sources'
--- ---
Project Metadata includes Database Metadata, UI Access Control and Miscellaneous. `Data Sources` sub-menu includes
- Database Metadata
- UI Access Control
- ERD
- Add/Remove new data source
- Edit existing data source configuration
- Edit data source visibility options
To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings` and clicking `Project Metadata`.
Note that, currently only one external data source can be added per project.
<img width="322" alt="image" src="https://user-images.githubusercontent.com/35857179/194856648-67936db0-ee4d-4060-be3d-af9f86ef8fc6.png"> | <img width="471" alt="image" src="https://user-images.githubusercontent.com/35857179/194850848-869c69a4-e9b6-4a84-8cc0-7fd4b01eb1ad.png"> To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings` and clicking `Data Sources`.
|--|--|
<!-- ## Project Metadata <!-- ![Screenshot 2022-12-29 at 4 26 27 PM](https://user-images.githubusercontent.com/86527202/209941709-1bfdbb01-ebd0-4c85-a966-2a8b4fc6ade7.png) -->
![Screenshot 2022-12-29 at 4 29 24 PM](https://user-images.githubusercontent.com/86527202/209941906-a9c8d48d-d604-4a2f-8ffb-7a9a494bac6b.png)
![Screenshot 2022-12-29 at 4 27 14 PM](https://user-images.githubusercontent.com/86527202/209941716-70f2aaa7-b035-42b2-835e-eb2ca348be42.png)
The metadata is stored in meta directory in project level, database level, and API level.
Under ``Project Metadata``, you can perform the following operations. <!-- ![Screenshot 2022-12-29 at 3 54 55 PM](https://user-images.githubusercontent.com/86527202/209938195-7384b4d8-0289-447f-bd39-1ec600cd1723.png) -->
<!-- <img width="322" alt="image" src="https://user-images.githubusercontent.com/86527202/209941709-1bfdbb01-ebd0-4c85-a966-2a8b4fc6ade7.png"> | <img alt="image" src="https://user-images.githubusercontent.com/86527202/209941716-70f2aaa7-b035-42b2-835e-eb2ca348be42.png"> -->
<!-- |--|--| -->
![Screenshot 2022-12-29 at 4 15 00 PM](https://user-images.githubusercontent.com/86527202/209940452-5b867b71-b9f1-4e64-af69-14715ab73be7.png)
- Export all metadata from the meta tables to meta directory
- Import all metadata from the meta directory to meta tables
- Export project meta to zip file and download
- Import project meta zip file and restart
- Clear all metadata from meta tables
<alert> ## Sync Metadata
Import won't work with zip files exported from the older version of apps (< 0.11.6). <br>
Import / Export will only transfer metadata and files related to the project and not any table data in the project.
</alert>
## Migration Example Go to `Data Sources`, click ``Sync Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See <a href="./sync-schema">Sync Schema</a> for more.0
### Export Metadata ![Screenshot 2022-12-29 at 4 19 35 PM](https://user-images.githubusercontent.com/86527202/209940903-396650b4-e219-494a-863f-c3f1beb51c5e.png)
From the source project, go to `Project Metadata`. Under ``Export / Import Metadata`` tab, select ``Export zip``, click ``Submit``. This step extracts project metadata and stores it in compressed (zip) format.
![image](https://user-images.githubusercontent.com/35857179/161904400-b926494a-4533-41e4-85c3-5c6ca9ea0803.png) <!-- <img width="1333" alt="image" src="https://user-images.githubusercontent.com/35857179/194850034-5330458e-85a9-4a3c-87a3-dd2f3edc5b46.png"> -->
### Import Metadata
From the destination project, go to `Project Metadata`. Under ``Export / Import Metadata`` tab, select ``Import zip``, select ``meta.zip`` file stored in previous step. This step imports project metadata from compressed file (zip) selected and restarts the project.
![image](https://user-images.githubusercontent.com/35857179/161904452-da0ac683-1715-438a-9c9c-91b34f8f45ba.png) -->
## Database Metadata
Go to `Project Metadata`, under ``Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See <a href="./sync-schema">Sync Schema</a> for more.
<img width="1333" alt="image" src="https://user-images.githubusercontent.com/35857179/194850034-5330458e-85a9-4a3c-87a3-dd2f3edc5b46.png">
## UI Access Control ## UI Access Control
Go to `Project Metadata`, under ``UI Access Control``, you can control the access to each table by roles. Go to `Data Sources`, click ``UI ACL``, you can control the access to each table by roles.
<img width="1336" alt="image" src="https://user-images.githubusercontent.com/35857179/194850281-9030f4c5-06bc-4780-b8fd-5d0c209867e0.png"> <!-- <img width="1336" alt="image" src="https://user-images.githubusercontent.com/35857179/194850281-9030f4c5-06bc-4780-b8fd-5d0c209867e0.png"> -->
![Screenshot 2022-12-29 at 4 20 57 PM](https://user-images.githubusercontent.com/86527202/209941141-deed80a9-7682-48e1-8de9-9c965c990d2d.png)
## ERD ## ERD
Go to `Project Metadata`, under ``ERD View``, you can see the ERD of your database. Go to `Data Sources`, click ``ERD``, you can see the ERD of your database.
<img width="1338" alt="image" src="https://user-images.githubusercontent.com/35857179/194850416-54bc49cf-c32f-45e8-aea1-62b07645c26e.png"> ![Screenshot 2022-12-29 at 4 21 55 PM](https://user-images.githubusercontent.com/86527202/209941168-b53d2898-8448-47fa-a8b3-6f3572f6b3a2.png)
<!-- <img width="1338" alt="image" src="https://user-images.githubusercontent.com/35857179/194850416-54bc49cf-c32f-45e8-aea1-62b07645c26e.png"> -->
### Junction table names within ERD ### Junction table names within ERD
- Enable `Show M2M Tables` within Miscellaneous tab - Enable `Show M2M Tables` within `Project Settings` menu
- Double click on `Show Columns` to see additional checkboxes get enabled. - Double click on `Show Columns` to see additional checkboxes get enabled.
- Enabling which you should be able to see junction tables and their table names. - Enabling which you should be able to see junction tables and their table names.
<img width="1681" alt="Show Junction table names for many to many table" src="https://user-images.githubusercontent.com/5435402/192140913-9da37700-28fe-404d-88e8-35ba0c8e2f53.png"> <img width="1681" alt="Show Junction table names for many to many table" src="https://user-images.githubusercontent.com/5435402/192140913-9da37700-28fe-404d-88e8-35ba0c8e2f53.png">
## Miscellaneous ## Edit external database configuration parameters
Go to `Data Sources`, click ``Edit``, you can re-configure database credentials.
Please make sure database configuration parameters are valid. Any incorrect parameters could lead to schema loss!
![Screenshot 2022-12-29 at 4 22 08 PM](https://user-images.githubusercontent.com/86527202/209941211-de9670c9-a73c-4719-9957-eeaf05f3a7ee.png)
## Unlink data source
Go to `Data Sources`, click ``Delete`` against the data source that you wish to un-link.
![Screenshot 2022-12-29 at 4 31 16 PM](https://user-images.githubusercontent.com/86527202/209942178-5ae40f14-0e87-41f7-9630-e2bf6f59a906.png)
## Data source visibility
Go to `Data Sources`, toggle ``Radio-button`` against the data source that you wish to hide/un-hide.
![Screenshot 2022-12-29 at 4 31 16 PM 2](https://user-images.githubusercontent.com/86527202/209942198-627f7f14-761b-4709-b9ca-fde5111fa207.png)
<!-- ## Miscellaneous
- Enabling, `Show M2M Tables` will show junction tables between many to many tables. - Enabling, `Show M2M Tables` will show junction tables between many to many tables.
<img width="1340" alt="image" src="https://user-images.githubusercontent.com/35857179/194850461-3e88752a-ba4f-4ead-9426-9a9e57020061.png"> <img width="1340" alt="image" src="https://user-images.githubusercontent.com/35857179/194850461-3e88752a-ba4f-4ead-9426-9a9e57020061.png">
-->

21
packages/noco-docs/content/en/setup-and-usages/project-settings.md

@ -0,0 +1,21 @@
---
title: 'Team & Settings > Project settings'
description: 'General project configuration options'
position: 612
category: 'Product'
menuTitle: 'Team & Settings > Project Settings'
---
## Overview
Generic project configuration options are retained under `Project Settings` menu. To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings`.
<img width="322" alt="image" src="https://user-images.githubusercontent.com/35857179/194856648-67936db0-ee4d-4060-be3d-af9f86ef8fc6.png">
Then, under SETTINGS, click `Project Settings`.
## Miscellaneous
- Enabling, `Show M2M Tables` will show junction tables between many to many tables.
![Screenshot 2022-12-29 at 7 05 04 PM](https://user-images.githubusercontent.com/86527202/209961654-ffe8ddc6-c7e2-4c0d-9762-2b57fb883cfa.png)

2
packages/noco-docs/content/en/setup-and-usages/sync-schema.md

@ -1,7 +1,7 @@
--- ---
title: 'Sync Schema' title: 'Sync Schema'
description: 'Schema changes made to database from outside NocoDB GUI can be synced' description: 'Schema changes made to database from outside NocoDB GUI can be synced'
position: 610 position: 613
category: 'Product' category: 'Product'
menuTitle: 'Sync Schema' menuTitle: 'Sync Schema'
--- ---

9233
packages/noco-docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

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

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

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

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

511
packages/nocodb/package-lock.json generated

@ -52,7 +52,7 @@
"isomorphic-dompurify": "^0.19.0", "isomorphic-dompurify": "^0.19.0",
"jsep": "^1.3.6", "jsep": "^1.3.6",
"jsonfile": "^6.1.0", "jsonfile": "^6.1.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^9.0.0",
"knex": "2.2.0", "knex": "2.2.0",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"lru-cache": "^6.0.0", "lru-cache": "^6.0.0",
@ -68,7 +68,7 @@
"nc-lib-gui": "0.101.0-beta.0", "nc-lib-gui": "0.101.0-beta.0",
"nc-plugin": "0.1.2", "nc-plugin": "0.1.2",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nocodb-sdk": "0.101.0-beta.0", "nocodb-sdk": "file:../nocodb-sdk",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",
"object-hash": "^3.0.0", "object-hash": "^3.0.0",
"os-locale": "^5.0.0", "os-locale": "^5.0.0",
@ -154,7 +154,6 @@
}, },
"../nocodb-sdk": { "../nocodb-sdk": {
"version": "0.101.0-beta.0", "version": "0.101.0-beta.0",
"extraneous": true,
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
@ -492,6 +491,54 @@
"node": "10 || 12 || 14 || 16 || 18" "node": "10 || 12 || 14 || 16 || 18"
} }
}, },
"node_modules/@azure/msal-node/node_modules/jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=4",
"npm": ">=1.4.28"
}
},
"node_modules/@azure/msal-node/node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/@azure/msal-node/node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/@azure/msal-node/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/@azure/storage-blob": { "node_modules/@azure/storage-blob": {
"version": "12.12.0", "version": "12.12.0",
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.12.0.tgz", "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.12.0.tgz",
@ -9380,9 +9427,9 @@
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "2.2.1", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true, "dev": true,
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
@ -9403,24 +9450,18 @@
} }
}, },
"node_modules/jsonwebtoken": { "node_modules/jsonwebtoken": {
"version": "8.5.1", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
"dependencies": { "dependencies": {
"jws": "^3.2.2", "jws": "^3.2.2",
"lodash.includes": "^4.3.0", "lodash": "^4.17.21",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1", "ms": "^2.1.1",
"semver": "^5.6.0" "semver": "^7.3.8"
}, },
"engines": { "engines": {
"node": ">=4", "node": ">=12",
"npm": ">=1.4.28" "npm": ">=6"
} }
}, },
"node_modules/jsonwebtoken/node_modules/jwa": { "node_modules/jsonwebtoken/node_modules/jwa": {
@ -9443,11 +9484,17 @@
} }
}, },
"node_modules/jsonwebtoken/node_modules/semver": { "node_modules/jsonwebtoken/node_modules/semver": {
"version": "5.7.1", "version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": { "bin": {
"semver": "bin/semver" "semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
} }
}, },
"node_modules/jsprim": { "node_modules/jsprim": {
@ -9857,9 +9904,9 @@
} }
}, },
"node_modules/luxon": { "node_modules/luxon": {
"version": "1.28.0", "version": "1.28.1",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz",
"integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==",
"engines": { "engines": {
"node": "*" "node": "*"
} }
@ -11175,13 +11222,8 @@
"dev": true "dev": true
}, },
"node_modules/nocodb-sdk": { "node_modules/nocodb-sdk": {
"version": "0.101.0-beta.0", "resolved": "../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.101.0-beta.0.tgz", "link": true
"integrity": "sha512-/h12sltRNdbCXop/iGYyWCHQ0iU8CKYNn7VrMrTA+u1kykHBu1ja/zhF6Kk98+m5XGNYAasASxLOFzk2GHvwCw==",
"dependencies": {
"axios": "^0.21.1",
"jsep": "^1.3.6"
}
}, },
"node_modules/node-abort-controller": { "node_modules/node-abort-controller": {
"version": "3.0.1", "version": "3.0.1",
@ -12662,6 +12704,54 @@
"passport-strategy": "^1.0.0" "passport-strategy": "^1.0.0"
} }
}, },
"node_modules/passport-jwt/node_modules/jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=4",
"npm": ">=1.4.28"
}
},
"node_modules/passport-jwt/node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/passport-jwt/node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/passport-jwt/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/passport-local": { "node_modules/passport-local": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
@ -14491,6 +14581,46 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/snowflake-sdk/node_modules/jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=4",
"npm": ">=1.4.28"
}
},
"node_modules/snowflake-sdk/node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/snowflake-sdk/node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/snowflake-sdk/node_modules/mkdirp": { "node_modules/snowflake-sdk/node_modules/mkdirp": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@ -14531,6 +14661,14 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/snowflake-sdk/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/snowflake-sdk/node_modules/tmp": { "node_modules/snowflake-sdk/node_modules/tmp": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
@ -16370,9 +16508,9 @@
} }
}, },
"node_modules/tsconfig-paths/node_modules/json5": { "node_modules/tsconfig-paths/node_modules/json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -16466,6 +16604,46 @@
"follow-redirects": "^1.14.8" "follow-redirects": "^1.14.8"
} }
}, },
"node_modules/twilio/node_modules/jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
},
"engines": {
"node": ">=4",
"npm": ">=1.4.28"
}
},
"node_modules/twilio/node_modules/jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/twilio/node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/twilio/node_modules/q": { "node_modules/twilio/node_modules/q": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz", "resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz",
@ -16476,6 +16654,14 @@
"weak-map": "^1.0.5" "weak-map": "^1.0.5"
} }
}, },
"node_modules/twilio/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -17596,9 +17782,9 @@
} }
}, },
"node_modules/webpack-cli/node_modules/json5": { "node_modules/webpack-cli/node_modules/json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -18011,9 +18197,9 @@
} }
}, },
"node_modules/webpack/node_modules/json5": { "node_modules/webpack/node_modules/json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -19057,6 +19243,49 @@
"@azure/msal-common": "^7.6.0", "@azure/msal-common": "^7.6.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"uuid": "^8.3.0" "uuid": "^8.3.0"
},
"dependencies": {
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"requires": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
} }
}, },
"@azure/storage-blob": { "@azure/storage-blob": {
@ -26050,9 +26279,9 @@
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
}, },
"json5": { "json5": {
"version": "2.2.1", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true "dev": true
}, },
"jsonfile": { "jsonfile": {
@ -26065,20 +26294,14 @@
} }
}, },
"jsonwebtoken": { "jsonwebtoken": {
"version": "8.5.1", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
"requires": { "requires": {
"jws": "^3.2.2", "jws": "^3.2.2",
"lodash.includes": "^4.3.0", "lodash": "^4.17.21",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1", "ms": "^2.1.1",
"semver": "^5.6.0" "semver": "^7.3.8"
}, },
"dependencies": { "dependencies": {
"jwa": { "jwa": {
@ -26101,9 +26324,12 @@
} }
}, },
"semver": { "semver": {
"version": "5.7.1", "version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"requires": {
"lru-cache": "^6.0.0"
}
} }
} }
}, },
@ -26437,9 +26663,9 @@
} }
}, },
"luxon": { "luxon": {
"version": "1.28.0", "version": "1.28.1",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz",
"integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" "integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw=="
}, },
"mailersend": { "mailersend": {
"version": "1.3.2", "version": "1.3.2",
@ -27510,12 +27736,22 @@
"dev": true "dev": true
}, },
"nocodb-sdk": { "nocodb-sdk": {
"version": "0.101.0-beta.0", "version": "file:../nocodb-sdk",
"resolved": "https://registry.npmjs.org/nocodb-sdk/-/nocodb-sdk-0.101.0-beta.0.tgz",
"integrity": "sha512-/h12sltRNdbCXop/iGYyWCHQ0iU8CKYNn7VrMrTA+u1kykHBu1ja/zhF6Kk98+m5XGNYAasASxLOFzk2GHvwCw==",
"requires": { "requires": {
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"axios": "^0.21.1", "axios": "^0.21.1",
"jsep": "^1.3.6" "cspell": "^4.1.0",
"eslint": "^7.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^3.0.2",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^4.0.0",
"jsep": "^1.3.6",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.1",
"typescript": "^4.0.2"
} }
}, },
"node-abort-controller": { "node-abort-controller": {
@ -28657,6 +28893,49 @@
"requires": { "requires": {
"jsonwebtoken": "^8.2.0", "jsonwebtoken": "^8.2.0",
"passport-strategy": "^1.0.0" "passport-strategy": "^1.0.0"
},
"dependencies": {
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"requires": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
} }
}, },
"passport-local": { "passport-local": {
@ -30095,6 +30374,42 @@
"is-docker": "^2.0.0" "is-docker": "^2.0.0"
} }
}, },
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"requires": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"mkdirp": { "mkdirp": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
@ -30117,6 +30432,11 @@
"glob": "^7.1.3" "glob": "^7.1.3"
} }
}, },
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"tmp": { "tmp": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
@ -31538,9 +31858,9 @@
}, },
"dependencies": { "dependencies": {
"json5": { "json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -31620,6 +31940,42 @@
"follow-redirects": "^1.14.8" "follow-redirects": "^1.14.8"
} }
}, },
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"requires": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"q": { "q": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz", "resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz",
@ -31629,6 +31985,11 @@
"pop-iterate": "^1.0.1", "pop-iterate": "^1.0.1",
"weak-map": "^1.0.5" "weak-map": "^1.0.5"
} }
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
} }
} }
}, },
@ -32537,9 +32898,9 @@
} }
}, },
"json5": { "json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -32834,9 +33195,9 @@
"dev": true "dev": true
}, },
"json5": { "json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.0" "minimist": "^1.2.0"

6
packages/nocodb/package.json

@ -92,7 +92,7 @@
"isomorphic-dompurify": "^0.19.0", "isomorphic-dompurify": "^0.19.0",
"jsep": "^1.3.6", "jsep": "^1.3.6",
"jsonfile": "^6.1.0", "jsonfile": "^6.1.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^9.0.0",
"knex": "2.2.0", "knex": "2.2.0",
"lodash": "^4.17.19", "lodash": "^4.17.19",
"lru-cache": "^6.0.0", "lru-cache": "^6.0.0",
@ -108,7 +108,7 @@
"nc-lib-gui": "0.101.0-beta.0", "nc-lib-gui": "0.101.0-beta.0",
"nc-plugin": "0.1.2", "nc-plugin": "0.1.2",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"nocodb-sdk": "0.101.0-beta.0", "nocodb-sdk": "file:../nocodb-sdk",
"nodemailer": "^6.4.10", "nodemailer": "^6.4.10",
"object-hash": "^3.0.0", "object-hash": "^3.0.0",
"os-locale": "^5.0.0", "os-locale": "^5.0.0",
@ -183,4 +183,4 @@
"prettier": { "prettier": {
"singleQuote": true "singleQuote": true
} }
} }

2
packages/nocodb/src/lib/Noco.ts

@ -104,7 +104,7 @@ export default class Noco {
constructor() { constructor() {
process.env.PORT = process.env.PORT || '8080'; process.env.PORT = process.env.PORT || '8080';
// todo: move // todo: move
process.env.NC_VERSION = '0098005'; process.env.NC_VERSION = '0100002';
// if env variable NC_MINIMAL_DBS is set, then disable project creation with external sources // if env variable NC_MINIMAL_DBS is set, then disable project creation with external sources
if (process.env.NC_MINIMAL_DBS) { if (process.env.NC_MINIMAL_DBS) {

132
packages/nocodb/src/lib/db/sql-client/lib/mysql/mysql.queries.ts

@ -212,7 +212,7 @@ AND t.table_name=?;`,
kcu.TABLE_NAME as tn, kcu.TABLE_NAME as tn,
kcu.COLUMN_NAME as cn, kcu.COLUMN_NAME as cn,
kcu.POSITION_IN_UNIQUE_CONSTRAINT as puc, kcu.POSITION_IN_UNIQUE_CONSTRAINT as puc,
kcu.REFERENCED_TABLE_NAME as rtn, kcu.REFERENCED_TABLE_NAME as rtn,
kcu.REFERENCED_COLUMN_NAME as rcn, kcu.REFERENCED_COLUMN_NAME as rcn,
rc.MATCH_OPTION as mo, rc.MATCH_OPTION as mo,
rc.UPDATE_RULE as ur, rc.UPDATE_RULE as ur,
@ -222,7 +222,8 @@ AND t.table_name=?;`,
information_schema.KEY_COLUMN_USAGE AS kcu information_schema.KEY_COLUMN_USAGE AS kcu
INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS rc ON INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS rc ON
kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
Group by kcu.CONSTRAINT_NAME, Group by
kcu.CONSTRAINT_NAME,
kcu.TABLE_NAME, kcu.TABLE_NAME,
kcu.COLUMN_NAME, kcu.COLUMN_NAME,
kcu.POSITION_IN_UNIQUE_CONSTRAINT, kcu.POSITION_IN_UNIQUE_CONSTRAINT,
@ -230,71 +231,90 @@ AND t.table_name=?;`,
kcu.REFERENCED_COLUMN_NAME, kcu.REFERENCED_COLUMN_NAME,
rc.MATCH_OPTION, rc.MATCH_OPTION,
rc.UPDATE_RULE, rc.UPDATE_RULE,
rc.DELETE_RULE ,kcu.table_schema rc.DELETE_RULE ,
kcu.table_schema
Having Having
kcu.table_schema = ? kcu.table_schema = ?
AND kcu.referenced_column_name IS NOT NULL AND kcu.referenced_column_name IS NOT NULL
AND kcu.table_name=?`, AND kcu.table_name =?`,
paramsHints: ['database', 'tn'], paramsHints: ['database', 'tn'],
}, },
}, },
relationListAll: { relationListAll: {
default: { default: {
sql: ` sql: `SELECT
kcu.constraint_name AS cstn,
kcu.table_name AS tn,
kcu.column_name AS cn,
kcu.position_in_unique_constraint AS puc,
kcu.referenced_table_name AS rtn,
kcu.referenced_column_name AS rcn,
rc.match_option AS mo,
rc.update_rule AS ur,
rc.delete_rule AS dr,
kcu.table_schema AS ts
FROM
(
SELECT
table_schema,
constraint_name,
table_name,
column_name,
position_in_unique_constraint,
referenced_table_name,
referenced_column_name
FROM
information_schema.KEY_COLUMN_USAGE
WHERE
table_schema = :databaseName) AS kcu
INNER JOIN
(
SELECT
constraint_schema,
match_option,
update_rule,
delete_rule,
constraint_name
FROM
information_schema.REFERENTIAL_CONSTRAINTS
WHERE
constraint_schema = :databaseName) AS rc ON
kcu.constraint_name = rc.constraint_name
AND kcu.table_schema = rc.constraint_schema
INNER JOIN
(
SELECT
table_schema,
table_name,
column_name
FROM
information_schema.COLUMNS
WHERE
table_schema = :databaseName
AND table_name IN (
SELECT SELECT
kcu.CONSTRAINT_NAME AS cstn, table_name
kcu.TABLE_NAME AS tn,
kcu.COLUMN_NAME AS cn,
kcu.POSITION_IN_UNIQUE_CONSTRAINT AS puc,
kcu.REFERENCED_TABLE_NAME AS rtn,
kcu.REFERENCED_COLUMN_NAME AS rcn,
rc.MATCH_OPTION AS mo,
rc.UPDATE_RULE AS ur,
rc.DELETE_RULE AS dr,
kcu.table_schema AS ts
FROM FROM
(SELECT information_schema.TABLES
table_schema, WHERE
CONSTRAINT_NAME, table_schema = :databaseName
TABLE_NAME, AND Lower(table_type) = 'base table')) AS col ON
COLUMN_NAME, col.table_schema = kcu.table_schema
POSITION_IN_UNIQUE_CONSTRAINT, AND col.table_name = kcu.table_name
REFERENCED_TABLE_NAME, AND kcu.referenced_column_name IS NOT NULL
REFERENCED_COLUMN_NAME GROUP BY
FROM cstn ,
information_schema.KEY_COLUMN_USAGE tn ,
WHERE rcn ,
table_schema = :databaseName) AS kcu cn ,
INNER JOIN puc ,
(SELECT rtn ,
CONSTRAINT_SCHEMA, cn,
MATCH_OPTION, mo ,
UPDATE_RULE, ur ,
DELETE_RULE, dr ,
CONSTRAINT_NAME ts`,
FROM
information_schema.REFERENTIAL_CONSTRAINTS
WHERE
CONSTRAINT_SCHEMA = :databaseName) AS rc ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
AND kcu.table_schema = rc.CONSTRAINT_SCHEMA
INNER JOIN
(SELECT
table_schema, TABLE_NAME, COLUMN_NAME
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
table_schema = :databaseName AND TABLE_NAME IN (SELECT
TABLE_NAME
FROM
INFORMATION_SCHEMA.TABLES
WHERE
table_schema = :databaseName
AND LOWER(TABLE_TYPE) = 'base table')) AS col ON col.table_schema = kcu.table_schema
AND col.table_name = kcu.TABLE_NAME
AND kcu.REFERENCED_COLUMN_NAME IS NOT NULL
GROUP BY cstn , tn , rcn , cn , puc , rtn ,cn, mo , ur , dr , ts`,
paramsHints: ['database'], paramsHints: ['database'],
}, },
}, },

14
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts

@ -1206,14 +1206,14 @@ class BaseModelSqlv2 {
private async getSelectQueryBuilderForFormula(column: Column<any>) { private async getSelectQueryBuilderForFormula(column: Column<any>) {
const formula = await column.getColOptions<FormulaColumn>(); const formula = await column.getColOptions<FormulaColumn>();
if (formula.error) throw new Error(`Formula error: ${formula.error}`); if (formula.error) throw new Error(`Formula error: ${formula.error}`);
const selectQb = await formulaQueryBuilderv2( const qb = await formulaQueryBuilderv2(
formula.formula, formula.formula,
null, null,
this.dbDriver, this.dbDriver,
this.model this.model,
column
); );
return qb;
return selectQb;
} }
async getProto() { async getProto() {
@ -1502,7 +1502,6 @@ class BaseModelSqlv2 {
const selectQb = await this.getSelectQueryBuilderForFormula( const selectQb = await this.getSelectQueryBuilderForFormula(
column column
); );
// todo: verify syntax of as ? / ??
qb.select( qb.select(
this.dbDriver.raw(`?? as ??`, [ this.dbDriver.raw(`?? as ??`, [
selectQb.builder, selectQb.builder,
@ -1510,7 +1509,10 @@ class BaseModelSqlv2 {
]) ])
); );
} catch { } catch {
continue; // return dummy select
qb.select(
this.dbDriver.raw(`'ERR' as ??`, [sanitize(column.title)])
);
} }
} }
break; break;

2
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts

@ -246,7 +246,7 @@ const parseConditionV2 = async (
const model = await column.getModel(); const model = await column.getModel();
const formula = await column.getColOptions<FormulaColumn>(); const formula = await column.getColOptions<FormulaColumn>();
const builder = ( const builder = (
await formulaQueryBuilderv2(formula.formula, null, knex, model) await formulaQueryBuilderv2(formula.formula, null, knex, model, column)
).builder; ).builder;
return parseConditionV2( return parseConditionV2(
new Filter({ ...filter, value: knex.raw('?', [filter.value]) } as any), new Filter({ ...filter, value: knex.raw('?', [filter.value]) } as any),

86
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2.ts

@ -1,6 +1,7 @@
import jsep from 'jsep'; import jsep from 'jsep';
import mapFunctionName from '../mapFunctionName'; import mapFunctionName from '../mapFunctionName';
import Model from '../../../../../models/Model'; import Model from '../../../../../models/Model';
import Column from '../../../../../models/Column';
import genRollupSelectv2 from '../genRollupSelectv2'; import genRollupSelectv2 from '../genRollupSelectv2';
import RollupColumn from '../../../../../models/RollupColumn'; import RollupColumn from '../../../../../models/RollupColumn';
import FormulaColumn from '../../../../../models/FormulaColumn'; import FormulaColumn from '../../../../../models/FormulaColumn';
@ -9,6 +10,8 @@ import LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecord
import LookupColumn from '../../../../../models/LookupColumn'; import LookupColumn from '../../../../../models/LookupColumn';
import { jsepCurlyHook, UITypes } from 'nocodb-sdk'; import { jsepCurlyHook, UITypes } from 'nocodb-sdk';
import { validateDateWithUnknownFormat } from '../helpers/formulaFnHelper'; import { validateDateWithUnknownFormat } from '../helpers/formulaFnHelper';
import { CacheGetType, CacheScope } from '../../../../../utils/globals';
import NocoCache from '../../../../../cache/NocoCache';
// todo: switch function based on database // todo: switch function based on database
@ -45,16 +48,16 @@ const getAggregateFn: (fnName: string) => (args: { qb; knex?; cn }) => any = (
} }
}; };
export default async function formulaQueryBuilderv2( async function _formulaQueryBuilder(
_tree, _tree,
alias, alias,
knex: XKnex, knex: XKnex,
model: Model, model: Model,
aliasToColumn = {} aliasToColumn = {}
) { ) {
// register jsep curly hook // formula may include double curly brackets in previous version
jsep.plugins.register(jsepCurlyHook); // convert to single curly bracket here for compatibility
const tree = jsep(_tree); const tree = jsep(_tree.replaceAll('{{', '{').replaceAll('}}', '}'));
const columnIdToUidt = {}; const columnIdToUidt = {};
@ -66,7 +69,7 @@ export default async function formulaQueryBuilderv2(
case UITypes.Formula: case UITypes.Formula:
{ {
const formulOption = await col.getColOptions<FormulaColumn>(); const formulOption = await col.getColOptions<FormulaColumn>();
const { builder } = await formulaQueryBuilderv2( const { builder } = await _formulaQueryBuilder(
formulOption.formula, formulOption.formula,
alias, alias,
knex, knex,
@ -340,7 +343,7 @@ export default async function formulaQueryBuilderv2(
const formulaOption = const formulaOption =
await lookupColumn.getColOptions<FormulaColumn>(); await lookupColumn.getColOptions<FormulaColumn>();
const lookupModel = await lookupColumn.getModel(); const lookupModel = await lookupColumn.getModel();
const { builder } = await formulaQueryBuilderv2( const { builder } = await _formulaQueryBuilder(
formulaOption.formula, formulaOption.formula,
'', '',
knex, knex,
@ -771,3 +774,74 @@ export default async function formulaQueryBuilderv2(
}; };
return { builder: fn(tree, alias) }; return { builder: fn(tree, alias) };
} }
function getTnPath(tb: Model, knex) {
const schema = knex.searchPath?.();
if (knex.clientType() === 'mssql' && schema) {
return knex.raw('??.??', [schema, tb.table_name]);
} else if (knex.clientType() === 'snowflake') {
return [
knex.client.config.connection.database,
knex.client.config.connection.schema,
tb.table_name,
].join('.');
} else {
return tb.table_name;
}
}
export default async function formulaQueryBuilderv2(
_tree,
alias,
knex: XKnex,
model: Model,
column?: Column,
aliasToColumn = {}
) {
// register jsep curly hook once only
jsep.plugins.register(jsepCurlyHook);
// generate qb
const qb = await _formulaQueryBuilder(
_tree,
alias,
knex,
model,
aliasToColumn
);
try {
// dry run qb.builder to see if it will break the grid view or not
// if so, set formula error and show empty selectQb instead
await knex(getTnPath(model, knex)).select(qb.builder).as('dry-run-only');
// if column is provided, i.e. formula has been created
if (column) {
const formula = await column.getColOptions<FormulaColumn>();
// clean the previous formula error if the formula works this time
if (formula.error) {
await FormulaColumn.update(formula.id, {
error: null,
});
}
}
} catch (e) {
console.error(e);
if (column) {
const formula = await column.getColOptions<FormulaColumn>();
// add formula error to show in UI
await FormulaColumn.update(formula.id, {
error: e.message,
});
// update cache to reflect the error in UI
const key = `${CacheScope.COL_FORMULA}:${column.id}`;
let o = await NocoCache.get(key, CacheGetType.TYPE_OBJECT);
if (o) {
o = { ...o, error: e.message };
// set cache
await NocoCache.set(key, o);
}
}
throw new Error(`Formula error: ${e.message}`);
}
return qb;
}

15
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts

@ -138,6 +138,21 @@ const pg = {
.toQuery()} THEN 1 ELSE 0 END ${args.colAlias}` .toQuery()} THEN 1 ELSE 0 END ${args.colAlias}`
); );
}, },
SUBSTR: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
const str = fn(pt.arguments[0]);
const positionFrom = fn(pt.arguments[1] ?? 1);
const numberOfCharacters = fn(pt.arguments[2] ?? '');
return knex.raw(
`SUBSTR(${str}::TEXT, ${positionFrom}${
numberOfCharacters ? ', ' + numberOfCharacters : ''
})${colAlias}`
);
},
MOD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
const x = fn(pt.arguments[0]);
const y = fn(pt.arguments[1]);
return knex.raw(`MOD((${x})::NUMERIC, (${y})::NUMERIC) ${colAlias}`);
},
}; };
export default pg; export default pg;

53
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts

@ -83,19 +83,25 @@ const sqlite3 = {
); );
}, },
DATETIME_DIFF: ({ fn, knex, pt, colAlias }: MapFnArgs) => { DATETIME_DIFF: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
let datetime_expr1 = fn(pt.arguments[0]).bindings[0]; let datetime_expr1 = fn(pt.arguments[0]);
let datetime_expr2 = fn(pt.arguments[1]).bindings[0]; let datetime_expr2 = fn(pt.arguments[1]);
// JULIANDAY takes YYYY-MM-DD // JULIANDAY takes YYYY-MM-DD
datetime_expr1 = convertToTargetFormat( if (datetime_expr1.sql === '?' && datetime_expr1.bindings?.[0]) {
datetime_expr1, datetime_expr1 = `'${convertToTargetFormat(
getDateFormat(datetime_expr1), datetime_expr1.bindings[0],
'YYYY-MM-DD' getDateFormat(datetime_expr1.bindings[0]),
); 'YYYY-MM-DD'
datetime_expr2 = convertToTargetFormat( )}'`;
datetime_expr2, }
getDateFormat(datetime_expr2),
'YYYY-MM-DD' if (datetime_expr2.sql === '?' && datetime_expr2.bindings?.[0]) {
); datetime_expr2 = `'${convertToTargetFormat(
datetime_expr2.bindings[0],
getDateFormat(datetime_expr2.bindings[0]),
'YYYY-MM-DD'
)}'`;
}
const rawUnit = pt.arguments[2] const rawUnit = pt.arguments[2]
? fn(pt.arguments[2]).bindings[0] ? fn(pt.arguments[2]).bindings[0]
: 'seconds'; : 'seconds';
@ -103,36 +109,31 @@ const sqlite3 = {
const unit = convertUnits(rawUnit, 'sqlite'); const unit = convertUnits(rawUnit, 'sqlite');
switch (unit) { switch (unit) {
case 'seconds': case 'seconds':
sql = `ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) * 86400)`; sql = `(strftime('%s', ${datetime_expr1}) - strftime('%s', ${datetime_expr2}))`;
break; break;
case 'minutes': case 'minutes':
sql = `ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) * 1440)`; sql = `(strftime('%s', ${datetime_expr1}) - strftime('%s', ${datetime_expr2})) / 60`;
break; break;
case 'hours': case 'hours':
sql = `ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) * 24)`; sql = `(strftime('%s', ${datetime_expr1}) - strftime('%s', ${datetime_expr2})) / 3600`;
break; break;
case 'milliseconds': case 'milliseconds':
sql = `ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) * 86400000)`; sql = `(strftime('%s', ${datetime_expr1}) - strftime('%s', ${datetime_expr2})) * 1000`;
break; break;
case 'weeks': case 'weeks':
sql = `ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) / 7)`; sql = `ROUND((JULIANDAY(${datetime_expr1}) - JULIANDAY(${datetime_expr2})) / 7)`;
break; break;
case 'months': case 'months':
sql = `(ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) / 365)) sql = `(strftime('%Y', ${datetime_expr1}) - strftime('%Y', ${datetime_expr2})) * 12 + (strftime('%m', ${datetime_expr1}) - strftime('%m', ${datetime_expr2})) `;
* 12 + (ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) / 365 / 12))`;
break; break;
case 'quarters': case 'quarters':
sql = ` sql = `(strftime('%Y', ${datetime_expr1}) - strftime('%Y', ${datetime_expr2})) * 4 + (strftime('%m', ${datetime_expr1}) - strftime('%m', ${datetime_expr2})) / 3`;
ROUND((JULIANDAY('${datetime_expr1}')) / 365 / 4) -
ROUND((JULIANDAY('${datetime_expr2}')) / 365 / 4) +
(ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) / 365)) * 4
`;
break; break;
case 'years': case 'years':
sql = `ROUND((JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')) / 365)`; sql = `strftime('%Y', ${datetime_expr1}) - strftime('%Y', ${datetime_expr2})`;
break; break;
case 'days': case 'days':
sql = `JULIANDAY('${datetime_expr1}') - JULIANDAY('${datetime_expr2}')`; sql = `JULIANDAY(${datetime_expr1}) - JULIANDAY(${datetime_expr2})`;
break; break;
default: default:
sql = ''; sql = '';

6
packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/sortV2.ts

@ -51,7 +51,8 @@ export default async function sortV2(
).formula, ).formula,
null, null,
knex, knex,
model model,
column
) )
).builder; ).builder;
qb.orderBy(builder, sort.direction || 'asc'); qb.orderBy(builder, sort.direction || 'asc');
@ -161,7 +162,8 @@ export default async function sortV2(
).formula, ).formula,
null, null,
knex, knex,
model model,
column
) )
).builder; ).builder;

21
packages/nocodb/src/lib/meta/api/columnApis.ts

@ -40,6 +40,7 @@ import { metaApiMetrics } from '../helpers/apiMetrics';
import FormulaColumn from '../../models/FormulaColumn'; import FormulaColumn from '../../models/FormulaColumn';
import KanbanView from '../../models/KanbanView'; import KanbanView from '../../models/KanbanView';
import { MetaTable } from '../../utils/globals'; import { MetaTable } from '../../utils/globals';
import formulaQueryBuilderv2 from '../../db/sql-data-mapper/lib/sql/formulav2/formulaQueryBuilderv2';
const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10); const randomID = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz_', 10);
@ -523,6 +524,16 @@ export async function columnAdd(
colBody.formula_raw || colBody.formula, colBody.formula_raw || colBody.formula,
table.columns table.columns
); );
try {
// test the query to see if it is valid in db level
const dbDriver = NcConnectionMgrv2.get(base);
await formulaQueryBuilderv2(colBody.formula, null, dbDriver, table);
} catch (e) {
console.error(e);
NcError.badRequest('Invalid Formula');
}
await Column.insert({ await Column.insert({
...colBody, ...colBody,
fk_model_id: table.id, fk_model_id: table.id,
@ -759,6 +770,16 @@ export async function columnUpdate(req: Request, res: Response<TableType>) {
colBody.formula_raw || colBody.formula, colBody.formula_raw || colBody.formula,
table.columns table.columns
); );
try {
// test the query to see if it is valid in db level
const dbDriver = NcConnectionMgrv2.get(base);
await formulaQueryBuilderv2(colBody.formula, null, dbDriver, table);
} catch (e) {
console.error(e);
NcError.badRequest('Invalid Formula');
}
await Column.update(column.id, { await Column.update(column.id, {
// title: colBody.title, // title: colBody.title,
...column, ...column,

13
packages/nocodb/src/lib/meta/api/sync/helpers/job.ts

@ -246,7 +246,7 @@ export default async (
count: UITypes.Count, count: UITypes.Count,
lookup: UITypes.Lookup, lookup: UITypes.Lookup,
autoNumber: UITypes.AutoNumber, autoNumber: UITypes.AutoNumber,
barcode: UITypes.Barcode, barcode: UITypes.SingleLineText,
button: UITypes.Button, button: UITypes.Button,
}; };
@ -1401,10 +1401,6 @@ export default async (
} else rec[key] = `${value?.name} <${value?.email}>`; } else rec[key] = `${value?.name} <${value?.email}>`;
break; break;
case UITypes.Barcode:
rec[key] = value.text;
break;
case UITypes.Button: case UITypes.Button:
rec[key] = `${value?.label} <${value?.url}>`; rec[key] = `${value?.label} <${value?.url}>`;
break; break;
@ -1473,6 +1469,13 @@ export default async (
} }
break; break;
case UITypes.SingleLineText:
// Barcode data
if (value?.text) {
rec[key] = value.text;
}
break;
default: default:
break; break;
} }

6
packages/nocodb/src/lib/meta/helpers/populateSamplePayload.ts

@ -84,12 +84,12 @@ async function getSampleColumnValue(column: Column): Promise<any> {
break; break;
case UITypes.SingleLineText: case UITypes.SingleLineText:
{ {
return 'Text'; return 'Sample Text';
} }
break; break;
case UITypes.LongText: case UITypes.LongText:
{ {
return 'Long text'; return 'Sample Long text';
} }
break; break;
case UITypes.Attachment: case UITypes.Attachment:
@ -189,7 +189,7 @@ async function getSampleColumnValue(column: Column): Promise<any> {
break; break;
case UITypes.Formula: case UITypes.Formula:
{ {
return 'output'; return 'Sample Output';
} }
break; break;
case UITypes.Rollup: case UITypes.Rollup:

2
packages/nocodb/src/lib/models/Base.ts

@ -278,7 +278,7 @@ export default class Base implements BaseType {
ncMeta ncMeta
); );
for (const model of models) { for (const model of models) {
await model.delete(ncMeta); await model.delete(ncMeta, true);
} }
await NocoCache.deepDel( await NocoCache.deepDel(
CacheScope.BASE, CacheScope.BASE,

13
packages/nocodb/src/lib/models/Filter.ts

@ -1,6 +1,7 @@
import Noco from '../Noco'; import Noco from '../Noco';
import Model from './Model'; import Model from './Model';
import Column from './Column'; import Column from './Column';
import Hook from './Hook';
import { import {
CacheDelDirection, CacheDelDirection,
CacheGetType, CacheGetType,
@ -10,6 +11,7 @@ import {
import View from './View'; import View from './View';
import { FilterType, UITypes } from 'nocodb-sdk'; import { FilterType, UITypes } from 'nocodb-sdk';
import NocoCache from '../cache/NocoCache'; import NocoCache from '../cache/NocoCache';
import { NcError } from '../meta/helpers/catchError';
export default class Filter { export default class Filter {
id: string; id: string;
@ -90,7 +92,16 @@ export default class Filter {
}), }),
}; };
if (!(filter.project_id && filter.base_id)) { if (!(filter.project_id && filter.base_id)) {
const model = await Column.get({ colId: filter.fk_column_id }, ncMeta); let model: { project_id?: string; base_id?: string };
if (filter.fk_view_id) {
model = await View.get(filter.fk_view_id, ncMeta);
} else if (filter.fk_hook_id) {
model = await Hook.get(filter.fk_hook_id, ncMeta);
} else if (filter.fk_column_id) {
model = await Column.get({ colId: filter.fk_column_id }, ncMeta);
} else {
NcError.badRequest('Invalid filter');
}
insertObj.project_id = model.project_id; insertObj.project_id = model.project_id;
insertObj.base_id = model.base_id; insertObj.base_id = model.base_id;
} }

27
packages/nocodb/src/lib/models/Model.ts

@ -345,7 +345,7 @@ export default class Model implements TableType {
}); });
} }
async delete(ncMeta = Noco.ncMeta): Promise<boolean> { async delete(ncMeta = Noco.ncMeta, force = false): Promise<boolean> {
await Audit.deleteRowComments(this.id); await Audit.deleteRowComments(this.id);
for (const view of await this.getViews(true)) { for (const view of await this.getViews(true)) {
@ -391,6 +391,31 @@ export default class Model implements TableType {
} }
} }
if (force) {
const leftOverColumns = await ncMeta.metaList2(
null,
null,
MetaTable.COL_RELATIONS,
{
condition: {
fk_related_model_id: this.id,
},
}
);
for (const col of leftOverColumns) {
await NocoCache.deepDel(
CacheScope.COL_RELATION,
`${CacheScope.COL_RELATION}:${col.fk_column_id}`,
CacheDelDirection.CHILD_TO_PARENT
);
}
await ncMeta.metaDelete(null, null, MetaTable.COL_RELATIONS, {
fk_related_model_id: this.id,
});
}
await NocoCache.deepDel( await NocoCache.deepDel(
CacheScope.COLUMN, CacheScope.COLUMN,
`${CacheScope.COLUMN}:${this.id}`, `${CacheScope.COLUMN}:${this.id}`,

2
packages/nocodb/src/lib/version-upgrader/NcUpgrader.ts

@ -8,6 +8,7 @@ import ncProjectEnvUpgrader0011045 from './ncProjectEnvUpgrader0011045';
import ncProjectUpgraderV2_0090000 from './ncProjectUpgraderV2_0090000'; import ncProjectUpgraderV2_0090000 from './ncProjectUpgraderV2_0090000';
import ncDataTypesUpgrader from './ncDataTypesUpgrader'; import ncDataTypesUpgrader from './ncDataTypesUpgrader';
import ncProjectRolesUpgrader from './ncProjectRolesUpgrader'; import ncProjectRolesUpgrader from './ncProjectRolesUpgrader';
import ncFilterUpgrader from './ncFilterUpgrader';
const log = debug('nc:version-upgrader'); const log = debug('nc:version-upgrader');
import boxen from 'boxen'; import boxen from 'boxen';
@ -35,6 +36,7 @@ export default class NcUpgrader {
{ name: '0090000', handler: ncProjectUpgraderV2_0090000 }, { name: '0090000', handler: ncProjectUpgraderV2_0090000 },
{ name: '0098004', handler: ncDataTypesUpgrader }, { name: '0098004', handler: ncDataTypesUpgrader },
{ name: '0098005', handler: ncProjectRolesUpgrader }, { name: '0098005', handler: ncProjectRolesUpgrader },
{ name: '0100002', handler: ncFilterUpgrader },
]; ];
if (!(await ctx.ncMeta.knexConnection?.schema?.hasTable?.('nc_store'))) { if (!(await ctx.ncMeta.knexConnection?.schema?.hasTable?.('nc_store'))) {
return; return;

34
packages/nocodb/src/lib/version-upgrader/ncFilterUpgrader.ts

@ -0,0 +1,34 @@
import { NcUpgraderCtx } from './NcUpgrader';
import { MetaTable } from '../utils/globals';
import View from '../models/View';
import Hook from '../models/Hook';
import Column from '../models/Column';
// before 0.101.0, an incorrect project_id was inserted when
// a filter is created without specifying the column
// this upgrader is to retrieve the correct project id from either view, hook, or column
// and update the project id
export default async function ({ ncMeta }: NcUpgraderCtx) {
const filters = await ncMeta.metaList2(null, null, MetaTable.FILTER_EXP);
for (const filter of filters) {
let model: { project_id?: string; base_id?: string };
if (filter.fk_view_id) {
model = await View.get(filter.fk_view_id, ncMeta);
} else if (filter.fk_hook_id) {
model = await Hook.get(filter.fk_hook_id, ncMeta);
} else if (filter.fk_column_id) {
model = await Column.get({ colId: filter.fk_column_id }, ncMeta);
} else {
continue;
}
if (filter.project_id != model.project_id) {
await ncMeta.metaUpdate(
null,
null,
MetaTable.FILTER_EXP,
{ base_id: model.base_id, project_id: model.project_id },
filter.id
);
}
}
}

14
tests/playwright/package-lock.json generated

@ -14,7 +14,7 @@
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.27.1", "@playwright/test": "1.27.1",
"@typescript-eslint/eslint-plugin": "^4.0.1", "@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1", "@typescript-eslint/parser": "^4.0.1",
"axios": "^0.24.0", "axios": "^0.24.0",
@ -2726,9 +2726,9 @@
"dev": true "dev": true
}, },
"node_modules/json5": { "node_modules/json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.0" "minimist": "^1.2.0"
@ -6911,9 +6911,9 @@
"dev": true "dev": true
}, },
"json5": { "json5": {
"version": "1.0.1", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.0" "minimist": "^1.2.0"

13
tests/playwright/pages/Dashboard/common/Cell/DateTimeCell.ts

@ -33,7 +33,18 @@ export class DateTimeCellPageObject extends BasePage {
date: string; date: string;
}) { }) {
// title date format needs to be YYYY-MM-DD // title date format needs to be YYYY-MM-DD
await this.rootPage.locator(`td[title="${date}"]`).click(); const [year, month, day] = date.split('-');
// configure year
await this.rootPage.locator('.ant-picker-year-btn').click();
await this.rootPage.locator(`td[title="${year}"]`).click();
// configure month
await this.rootPage.locator('.ant-picker-month-btn').click();
await this.rootPage.locator(`td[title="${year}-${month}"]`).click();
// configure day
await this.rootPage.locator(`td[title="${year}-${month}-${day}"]`).click();
} }
async selectTime({ async selectTime({

12
tests/playwright/tests/columnFormula.spec.ts

@ -66,10 +66,22 @@ const formulaDataByDbType = (context: NcContext) => [
formula: `DATETIME_DIFF("2022/10/14", "2023/10/14", "y")`, formula: `DATETIME_DIFF("2022/10/14", "2023/10/14", "y")`,
result: ['-1', '-1', '-1', '-1', '-1'], result: ['-1', '-1', '-1', '-1', '-1'],
}, },
{
formula: `DATETIME_DIFF(NOW(), "2023/10/14", "y")`,
result: ['0', '0', '0', '0', '0'],
},
{
formula: `DATETIME_DIFF("2023/10/14", NOW(), "y")`,
result: ['0', '0', '0', '0', '0'],
},
{ {
formula: `DATETIME_DIFF("2022/10/14", "2023/10/14", "d")`, formula: `DATETIME_DIFF("2022/10/14", "2023/10/14", "d")`,
result: ['-365', '-365', '-365', '-365', '-365'], result: ['-365', '-365', '-365', '-365', '-365'],
}, },
{
formula: `DATETIME_DIFF("2022/10/14", NOW(), "d")`,
result: ['-90', '-90', '-90', '-90', '-90'],
},
{ {
formula: `CONCAT(UPPER({City}), LOWER({City}), TRIM(' trimmed '))`, formula: `CONCAT(UPPER({City}), LOWER({City}), TRIM(' trimmed '))`,
result: [ result: [

3
tests/playwright/tests/language.spec.ts

@ -7,10 +7,12 @@ const langMenu = [
'help-translate', 'help-translate',
'ar.json', 'ar.json',
'bn_IN.json', 'bn_IN.json',
'cs.json',
'da.json', 'da.json',
'de.json', 'de.json',
'en.json', 'en.json',
'es.json', 'es.json',
'eu.json',
'fa.json', 'fa.json',
'fi.json', 'fi.json',
'fr.json', 'fr.json',
@ -28,6 +30,7 @@ const langMenu = [
'pt.json', 'pt.json',
'pt_BR.json', 'pt_BR.json',
'ru.json', 'ru.json',
'sk.json',
'sl.json', 'sl.json',
'sv.json', 'sv.json',
'th.json', 'th.json',

Loading…
Cancel
Save