Browse Source

Merge pull request #7762 from nocodb/develop

pull/7763/head 0.204.2
github-actions[bot] 6 months ago committed by GitHub
parent
commit
42ae12b823
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      .github/workflows/ci-cd.yml
  2. 2
      .github/workflows/playwright-test-workflow.yml
  3. 2
      .github/workflows/pre-build-for-playwright.yml
  4. 2
      .github/workflows/publish-blog.yml
  5. 2
      .github/workflows/publish-dev-docs.yml
  6. 2
      .github/workflows/publish-docs.yml
  7. 2
      .github/workflows/publish-noco-i18n.yml
  8. 2
      .github/workflows/publish-prev-docs.yml
  9. 2
      .github/workflows/release-docker.yml
  10. 2
      .github/workflows/release-draft.yml
  11. 2
      .github/workflows/release-executables.yml
  12. 4
      .github/workflows/release-npm.yml
  13. 2
      .github/workflows/release-timely-executables.yml
  14. 2
      .github/workflows/update-sdk-path.yml
  15. 2
      .npmrc
  16. 8
      README.md
  17. 6
      markdown/readme/languages/chinese.md
  18. 2
      markdown/readme/languages/dutch.md
  19. 2
      markdown/readme/languages/french.md
  20. 2
      markdown/readme/languages/german.md
  21. 6
      markdown/readme/languages/indonesian.md
  22. 2
      markdown/readme/languages/italian.md
  23. 2
      markdown/readme/languages/japanese.md
  24. 2
      markdown/readme/languages/korean.md
  25. 2
      markdown/readme/languages/portuguese.md
  26. 2
      markdown/readme/languages/russian.md
  27. 2
      markdown/readme/languages/spanish.md
  28. 8
      markdown/readme/languages/ukrainian.md
  29. 4
      package.json
  30. 77
      packages/nc-gui/app.vue
  31. 4
      packages/nc-gui/assets/nc-icons/bold.svg
  32. 15
      packages/nc-gui/assets/nc-icons/crop.svg
  33. 14
      packages/nc-gui/assets/nc-icons/eye-off.svg
  34. 10
      packages/nc-gui/assets/nc-icons/eye.svg
  35. 5
      packages/nc-gui/assets/nc-icons/italic.svg
  36. 6
      packages/nc-gui/assets/nc-icons/underline.svg
  37. 36
      packages/nc-gui/assets/style.scss
  38. 361
      packages/nc-gui/components/cell/MultiSelect.vue
  39. 2
      packages/nc-gui/components/cell/RichText.vue
  40. 221
      packages/nc-gui/components/cell/SingleSelect.vue
  41. 17
      packages/nc-gui/components/cell/TextArea.vue
  42. 2
      packages/nc-gui/components/cell/Url.vue
  43. 373
      packages/nc-gui/components/cell/User.vue
  44. 3
      packages/nc-gui/components/cell/attachment/utils.ts
  45. 18
      packages/nc-gui/components/dlg/TableDuplicate.vue
  46. 2
      packages/nc-gui/components/dlg/ViewCreate.vue
  47. 17
      packages/nc-gui/components/general/FormBanner.vue
  48. 141
      packages/nc-gui/components/general/ImageCropper.vue
  49. 2
      packages/nc-gui/components/nc/DateWeekSelector.vue
  50. 2
      packages/nc-gui/components/nc/Select.vue
  51. 429
      packages/nc-gui/components/smartsheet/Form.vue
  52. 2
      packages/nc-gui/components/smartsheet/Kanban.vue
  53. 370
      packages/nc-gui/components/smartsheet/calendar/Cell.vue
  54. 58
      packages/nc-gui/components/smartsheet/calendar/DayView/DateField.vue
  55. 122
      packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue
  56. 94
      packages/nc-gui/components/smartsheet/calendar/MonthView.vue
  57. 19
      packages/nc-gui/components/smartsheet/calendar/RecordCard.vue
  58. 27
      packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue
  59. 67
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue
  60. 205
      packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue
  61. 15
      packages/nc-gui/components/smartsheet/calendar/index.vue
  62. 293
      packages/nc-gui/components/smartsheet/form/LimitOptions.vue
  63. 37
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  64. 3
      packages/nc-gui/components/virtual-cell/components/ListChildItems.vue
  65. 3
      packages/nc-gui/components/virtual-cell/components/ListItems.vue
  66. 2
      packages/nc-gui/composables/useKanbanViewStore.ts
  67. 32
      packages/nc-gui/composables/useMultiSelect/convertCellData.ts
  68. 2
      packages/nc-gui/composables/useMultiSelect/index.ts
  69. 1
      packages/nc-gui/composables/useSharedFormViewStore.ts
  70. 12
      packages/nc-gui/composables/useViewColumns.ts
  71. 1
      packages/nc-gui/composables/useViewData.ts
  72. 44
      packages/nc-gui/lang/ar.json
  73. 44
      packages/nc-gui/lang/bn_IN.json
  74. 44
      packages/nc-gui/lang/cs.json
  75. 44
      packages/nc-gui/lang/da.json
  76. 44
      packages/nc-gui/lang/de.json
  77. 32
      packages/nc-gui/lang/en.json
  78. 230
      packages/nc-gui/lang/es.json
  79. 44
      packages/nc-gui/lang/eu.json
  80. 44
      packages/nc-gui/lang/fa.json
  81. 44
      packages/nc-gui/lang/fi.json
  82. 44
      packages/nc-gui/lang/fr.json
  83. 44
      packages/nc-gui/lang/he.json
  84. 44
      packages/nc-gui/lang/hi.json
  85. 44
      packages/nc-gui/lang/hr.json
  86. 44
      packages/nc-gui/lang/id.json
  87. 44
      packages/nc-gui/lang/it.json
  88. 44
      packages/nc-gui/lang/ja.json
  89. 44
      packages/nc-gui/lang/ko.json
  90. 44
      packages/nc-gui/lang/lv.json
  91. 44
      packages/nc-gui/lang/nl.json
  92. 44
      packages/nc-gui/lang/no.json
  93. 44
      packages/nc-gui/lang/pl.json
  94. 210
      packages/nc-gui/lang/pt.json
  95. 136
      packages/nc-gui/lang/pt_BR.json
  96. 44
      packages/nc-gui/lang/ru.json
  97. 44
      packages/nc-gui/lang/sk.json
  98. 44
      packages/nc-gui/lang/sl.json
  99. 44
      packages/nc-gui/lang/sv.json
  100. 44
      packages/nc-gui/lang/th.json
  101. Some files were not shown because too many files have changed in this diff Show More

4
.github/workflows/ci-cd.yml

@ -40,7 +40,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name: Checkout
uses: actions/checkout@v3
with:
@ -75,7 +75,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name: Checkout
uses: actions/checkout@v3
with:

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

@ -23,7 +23,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:

2
.github/workflows/pre-build-for-playwright.yml

@ -13,7 +13,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:

2
.github/workflows/publish-blog.yml

@ -17,7 +17,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name: Build blogs
run: |
cd packages/noco-blog

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

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

2
.github/workflows/publish-docs.yml

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

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

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

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

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

2
.github/workflows/release-docker.yml

@ -84,7 +84,7 @@ jobs:
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name: upgrade packages for nightly build or pr build
if: ${{ github.event.inputs.targetEnv == 'DEV' || inputs.targetEnv == 'DEV' }}

2
.github/workflows/release-draft.yml

@ -70,5 +70,5 @@ jobs:
})
- uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- run: "npx github-release-notes@0.17.2 release --token ${{ secrets.GITHUB_TOKEN }} --draft --tags ${{ github.event.inputs.tag || inputs.tag }}..${{ github.event.inputs.prev_tag || inputs.prev_tag }}"

2
.github/workflows/release-executables.yml

@ -63,7 +63,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name : Install nocodb, other dependencies and build executables
run: |

4
.github/workflows/release-npm.yml

@ -46,11 +46,11 @@ jobs:
with:
fetch-depth: 0
ref: ${{ github.ref }}
- name: pnpm Setup and Publish with 18.19.0
- name: pnpm Setup and Publish with 18.19.1
# Setup .npmrc file to publish to npm
uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
registry-url: 'https://registry.npmjs.org'
- run: |
export NODE_OPTIONS="--max_old_space_size=16384"

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

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

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

@ -16,7 +16,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.19.0
node-version: 18.19.1
- name: Checkout
uses: actions/checkout@v3
with:

2
.npmrc

@ -1,3 +1,3 @@
engine-strict=true
shamefully-hoist=true
use-node-version=18.19.0
use-node-version=18.19.1

8
README.md

@ -15,7 +15,7 @@ Turns any MySQL, PostgreSQL, SQL Server, SQLite & MariaDB into a smart spreadshe
<div align="center">
[![Node version](https://img.shields.io/badge/node-%3E%3D%2018.19.0-brightgreen)](http://nodejs.org/download/)
[![Node version](https://img.shields.io/badge/node-%3E%3D%2018.19.1-brightgreen)](http://nodejs.org/download/)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-green.svg)](https://conventionalcommits.org)
</div>
@ -265,11 +265,11 @@ We provide the following ways to let users programmatically invoke actions. You
### Sync Schema
We allow you to sync schema changes if you have made changes outside NocoDB GUI. However, it has to be noted then you will have to bring your own schema migrations for moving from one environment to another. See <a href="https://docs.nocodb.com/setup-and-usages/sync-schema/" target="_blank">Sync Schema</a> for details.
We allow you to sync schema changes if you have made changes outside NocoDB GUI. However, it has to be noted then you will have to bring your own schema migrations for moving from one environment to another. See <a href="https://docs.nocodb.com/data-sources/sync-with-data-source" target="_blank">Sync Schema</a> for details.
### Audit
We are keeping all the user operation logs in one place. See <a href="https://docs.nocodb.com/setup-and-usages/audit" target="_blank">Audit</a> for details.
We are keeping all the user operation logs in one place. See <a href="https://docs.nocodb.com/data-sources/actions-on-data-sources/#audit-logs" target="_blank">Audit</a> for details.
# Production Setup
@ -277,7 +277,7 @@ By default, SQLite is used for storing metadata. However, you can specify your d
## Environment variables
Please refer to the [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Please refer to the [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Development Setup

6
markdown/readme/languages/chinese.md

@ -189,11 +189,11 @@ docker-compose up -d
### 架构同步
如果您在 NocoDB GUI 之外进行了更改,我们允许您同步架构更改。 但是,必须注意的是,您必须附有自己的迁移架构才能从一个环境迁移到其他环境。 有关详细信息,请参阅 <a href="https://docs.nocodb.com/setup-and-usages/sync-schema/" target="_blank">同步架构</a>
如果您在 NocoDB GUI 之外进行了更改,我们允许您同步架构更改。 但是,必须注意的是,您必须附有自己的迁移架构才能从一个环境迁移到其他环境。 有关详细信息,请参阅 <a href="https://docs.nocodb.com/data-sources/sync-with-data-source" target="_blank">同步架构</a>
### 审计
我们将所有用户操作日志保存在一起。 有关详细信息,请参阅 <a href="https://docs.nocodb.com/setup-and-usages/audit" target="_blank">审计</a>
我们将所有用户操作日志保存在一起。 有关详细信息,请参阅 <a href="https://docs.nocodb.com/data-sources/actions-on-data-sources/#audit-logs" target="_blank">审计</a>
# 生产部署
@ -201,7 +201,7 @@ docker-compose up -d
## 环境变量
参见[环境变量](https://docs.nocodb.com/getting-started/environment-variables)
参见[环境变量](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# 开发

2
markdown/readme/languages/dutch.md

@ -181,7 +181,7 @@ docker-compose up -d
## Environment variables
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Development setup

2
markdown/readme/languages/french.md

@ -182,7 +182,7 @@ docker-compose up -d
## Variables d'environnement
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Paramétrage du développement

2
markdown/readme/languages/german.md

@ -190,7 +190,7 @@ docker-compose up -d
## Umgebungsvariablen
Siehe [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Siehe [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Entwicklungsaufbau

6
markdown/readme/languages/indonesian.md

@ -256,11 +256,11 @@ Akses dasbor menggunakan : [http://localhost:8080/dashboard](http://localhost:80
### Sinkronisasi Skema
Kami memungkinkan Anda untuk menyinkronkan perubahan skema jika Anda telah melakukan perubahan di luar antarmuka NocoDB GUI. Namun, perlu diperhatikan bahwa Anda harus menyediakan migrasi skema sendiri untuk berpindah dari satu lingkungan ke lingkungan lainnya. Lihat [Sinkronisasi Skema](https://docs.nocodb.com/setup-and-usages/sync-schema/) untuk detail lebih lanjut.
Kami memungkinkan Anda untuk menyinkronkan perubahan skema jika Anda telah melakukan perubahan di luar antarmuka NocoDB GUI. Namun, perlu diperhatikan bahwa Anda harus menyediakan migrasi skema sendiri untuk berpindah dari satu lingkungan ke lingkungan lainnya. Lihat [Sinkronisasi Skema](https://docs.nocodb.com/data-sources/sync-with-data-source) untuk detail lebih lanjut.
### Audit
Kami menyimpan semua log operasi pengguna di satu tempat. Lihat [Audit](https://docs.nocodb.com/setup-and-usages/audit) untuk detail lebih lanjut.
Kami menyimpan semua log operasi pengguna di satu tempat. Lihat [Audit](https://docs.nocodb.com/data-sources/actions-on-data-sources/#audit-logs) untuk detail lebih lanjut.
# Pengaturan Produksi
@ -268,7 +268,7 @@ Secara default, SQLite digunakan untuk menyimpan metadata. Namun, Anda dapat men
## Environment variables
Silakan lihat [Environment Variables](https://docs.nocodb.com/getting-started/environment-variables) untuk informasi lebih lanjut.
Silakan lihat [Environment Variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables) untuk informasi lebih lanjut.
# Pengaturan Pengembangan

2
markdown/readme/languages/italian.md

@ -185,7 +185,7 @@ docker-compose up -d
## Variabili d'ambiente
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Setup di sviluppo

2
markdown/readme/languages/japanese.md

@ -184,7 +184,7 @@ docker-compose up -d
## 環境変数
[環境変数](https://docs.nocodb.com/getting-started/environment-variables)をご参照ください
[環境変数](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)をご参照ください
# 開発セットアップ

2
markdown/readme/languages/korean.md

@ -185,7 +185,7 @@ docker-compose up -d
## 환경변수
여기서 확인해주세요.
[환경변수 ](https://docs.nocodb.com/getting-started/environment-variables)
[환경변수 ](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# 개발 환경에 설치

2
markdown/readme/languages/portuguese.md

@ -183,7 +183,7 @@ docker-compose up -d
## Environment variables
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Development setup

2
markdown/readme/languages/russian.md

@ -185,7 +185,7 @@ docker-compose up -d
## Переменные среды
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Please refer to [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Настройка разработки

2
markdown/readme/languages/spanish.md

@ -182,7 +182,7 @@ docker-compose up -d
## Variables de entorno
Por favor diríjase a [Environment variables](https://docs.nocodb.com/getting-started/environment-variables)
Por favor diríjase a [Environment variables](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Configuración de desarollo

8
markdown/readme/languages/ukrainian.md

@ -15,7 +15,7 @@ Nocodb перетворює будь-яку базу даних MySQL, PostgreSQ
<div align="center">
[![Node version](https://img.shields.io/badge/node-%3E%3D%2018.19.0-brightgreen)](http://nodejs.org/download/)
[![Node version](https://img.shields.io/badge/node-%3E%3D%2018.19.1-brightgreen)](http://nodejs.org/download/)
[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-green.svg)](https://conventionalcommits.org)
</div>
@ -238,11 +238,11 @@ npm start
### Синхронізація схеми
Ми дозволяємо вам синхронізувати зміни схеми, якщо ви внесли зміни поза NocoDB GUI. Проте слід зауважити, що вам доведеться мати власні міграції схеми для переміщення з одного середовища в інше. Деталі дивіться у <a href="https://docs.nocodb.com/setup-and-usages/sync-schema/" target="_blank">Sync Schema</a>.
Ми дозволяємо вам синхронізувати зміни схеми, якщо ви внесли зміни поза NocoDB GUI. Проте слід зауважити, що вам доведеться мати власні міграції схеми для переміщення з одного середовища в інше. Деталі дивіться у <a href="https://docs.nocodb.com/data-sources/sync-with-data-source" target="_blank">Sync Schema</a>.
### Аудит
Ми зберігаємо всі журнали операцій користувача в одному місці. Деталі дивіться у <a href="https://docs.nocodb.com/setup-and-usages/audit" target="_blank">Audit</a>.
Ми зберігаємо всі журнали операцій користувача в одному місці. Деталі дивіться у <a href="https://docs.nocodb.com/data-sources/actions-on-data-sources/#audit-logs" target="_blank">Audit</a>.
# Налаштування продукції
@ -250,7 +250,7 @@ npm start
## Змінні середовища
Будь ласка, звертайтеся до [Змінні середовища](https://docs.nocodb.com/getting-started/environment-variables)
Будь ласка, звертайтеся до [Змінні середовища](https://docs.nocodb.com/getting-started/self-hosted/environment-variables)
# Налаштування розробки

4
package.json

@ -17,9 +17,9 @@
"license": "AGPL-3.0-or-later",
"devDependencies": {
"fs": "0.0.1-security",
"lerna": "^7.0.2",
"lerna": "^7.4.2",
"husky": "^8.0.3",
"xlsx": "^0.17.4"
"xlsx": "^0.17.5"
},
"husky": {
"hooks": {

77
packages/nc-gui/app.vue

@ -1,4 +1,6 @@
<script setup lang="ts">
import { message } from 'ant-design-vue'
import { extractSdkResponseErrorMsg } from './utils'
import { applyNonSelectable, computed, isEeUI, isMac, useCommandPalette, useRouter, useTheme } from '#imports'
import type { CommandPaletteType } from '~/lib'
@ -96,27 +98,70 @@ onMounted(() => {
refreshCommandPalette()
})
})
let errorCount = 0
const handleError = async (error, clearError) => {
console.error('UI ERROR', error.value)
// if error is api error, show toast message with error message
if (error.value?.response) {
message.warn(await extractSdkResponseErrorMsg(error.value))
} else {
// else show generic error message
message.warn('Something went wrong. Please reload the page if page is not functioning properly.')
}
clearError()
// if error count is more than 3 within 3 second, navigate to home
// since it's likely endless loop of errors due to some UI issue in certain page
errorCount++
if (errorCount > 3) {
router.push('/')
}
// reset error count after 1 second
setTimeout(() => {
errorCount = 0
}, 3000)
}
</script>
<template>
<a-config-provider>
<NuxtLayout :name="disableBaseLayout ? false : 'base'">
<NuxtPage :key="key" :transition="false" />
<NuxtErrorBoundary>
<NuxtPage :key="key" :transition="false" />
<!-- on error, clear error and show toast message -->
<template #error="{ error, clearError }">
{{ handleError(error, clearError) }}
</template>
</NuxtErrorBoundary>
</NuxtLayout>
</a-config-provider>
<!-- Command Menu -->
<CmdK
ref="commandPalette"
v-model:open="cmdK"
:scope="activeScope.scope"
:data="cmdData"
:placeholder="cmdPlaceholder"
:load-temporary-scope="loadTemporaryScope"
:set-active-cmd-view="setActiveCmdView"
@scope="onScope"
/>
<!-- Recent Views. Cycles through recently visited Views -->
<CmdL v-model:open="cmdL" :set-active-cmd-view="setActiveCmdView" />
<!-- Documentation. Integrated NocoDB Docs directlt inside the Product -->
<CmdJ />
<NuxtErrorBoundary>
<div>
<!-- Command Menu -->
<CmdK
ref="commandPalette"
v-model:open="cmdK"
:scope="activeScope.scope"
:data="cmdData"
:placeholder="cmdPlaceholder"
:load-temporary-scope="loadTemporaryScope"
:set-active-cmd-view="setActiveCmdView"
@scope="onScope"
/>
<!-- Recent Views. Cycles through recently visited Views -->
<CmdL v-model:open="cmdL" :set-active-cmd-view="setActiveCmdView" />
<!-- Documentation. Integrated NocoDB Docs directly inside the Product -->
<CmdJ />
</div>
<!-- on error, clear error and show toast message -->
<template #error="{ error, clearError }">
{{ handleError(error, clearError) }}
</template>
</NuxtErrorBoundary>
</template>

4
packages/nc-gui/assets/nc-icons/bold.svg

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 8H10C10.7072 8 11.3855 8.28095 11.8856 8.78105C12.3857 9.28115 12.6667 9.95942 12.6667 10.6667C12.6667 11.3739 12.3857 12.0522 11.8856 12.5523C11.3855 13.0524 10.7072 13.3333 10 13.3333H4V8Z" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4 2.66663H9.33333C10.0406 2.66663 10.7189 2.94758 11.219 3.44767C11.719 3.94777 12 4.62605 12 5.33329C12 6.04054 11.719 6.71881 11.219 7.21891C10.7189 7.71901 10.0406 7.99996 9.33333 7.99996H4V2.66663Z" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 672 B

15
packages/nc-gui/assets/nc-icons/crop.svg

@ -0,0 +1,15 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_184_5665)">
<path
d="M4.08667 0.666626L4 10.6666C4 11.0202 4.14048 11.3594 4.39052 11.6094C4.64057 11.8595 4.97971 12 5.33333 12H15.3333"
stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round" />
<path
d="M0.666672 4.08667L10.6667 4C11.0203 4 11.3594 4.14048 11.6095 4.39052C11.8595 4.64057 12 4.97971 12 5.33333V15.3333"
stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round" />
</g>
<defs>
<clipPath id="clip0_184_5665">
<rect width="16" height="16" fill="white" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 797 B

14
packages/nc-gui/assets/nc-icons/eye-off.svg

@ -0,0 +1,14 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_453_14719)">
<path
d="M6.59984 2.82676C7.05873 2.71935 7.52855 2.66566 7.99984 2.66676C12.6665 2.66676 15.3332 8.0001 15.3332 8.0001C14.9285 8.75717 14.4459 9.46992 13.8932 10.1268M9.41317 9.41343C9.23007 9.60993 9.00927 9.76754 8.76394 9.87685C8.51861 9.98616 8.25377 10.0449 7.98523 10.0497C7.71669 10.0544 7.44995 10.005 7.20091 9.90443C6.95188 9.80384 6.72565 9.65412 6.53573 9.4642C6.34582 9.27428 6.1961 9.04806 6.09551 8.79902C5.99492 8.54999 5.94552 8.28325 5.95026 8.0147C5.955 7.74616 6.01378 7.48133 6.12309 7.236C6.2324 6.99067 6.39001 6.76986 6.5865 6.58677M11.9598 11.9601C10.8202 12.8288 9.43258 13.31 7.99984 13.3334C3.33317 13.3334 0.666504 8.0001 0.666504 8.0001C1.49576 6.4547 2.64593 5.1045 4.03984 4.0401L11.9598 11.9601Z"
stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round" />
<path d="M0.666504 0.666748L15.3332 15.3334" stroke="currentColor" stroke-width="1.33333" stroke-linecap="round"
stroke-linejoin="round" />
</g>
<defs>
<clipPath id="clip0_453_14719">
<rect width="16" height="16" fill="white" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

10
packages/nc-gui/assets/nc-icons/eye.svg

@ -1,4 +1,8 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.666656 7.99996C0.666656 7.99996 3.33332 2.66663 7.99999 2.66663C12.6667 2.66663 15.3333 7.99996 15.3333 7.99996C15.3333 7.99996 12.6667 13.3333 7.99999 13.3333C3.33332 13.3333 0.666656 7.99996 0.666656 7.99996Z" stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<path
d="M0.666504 8.00008C0.666504 8.00008 3.33317 2.66675 7.99984 2.66675C12.6665 2.66675 15.3332 8.00008 15.3332 8.00008C15.3332 8.00008 12.6665 13.3334 7.99984 13.3334C3.33317 13.3334 0.666504 8.00008 0.666504 8.00008Z"
stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round" />
<path
d="M8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z"
stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round" />
</svg>

Before

Width:  |  Height:  |  Size: 634 B

After

Width:  |  Height:  |  Size: 675 B

5
packages/nc-gui/assets/nc-icons/italic.svg

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.33325 13.3334H3.33325" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.6667 2.66663H6.66675" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 2.66663L6 13.3333" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 433 B

6
packages/nc-gui/assets/nc-icons/underline.svg

@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="underline">
<path id="Vector" d="M2.66675 14H13.3334" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M4 2V6.66667C4 7.72753 4.42143 8.74495 5.17157 9.49509C5.92172 10.2452 6.93913 10.6667 8 10.6667C9.06087 10.6667 10.0783 10.2452 10.8284 9.49509C11.5786 8.74495 12 7.72753 12 6.66667V2" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 547 B

36
packages/nc-gui/assets/style.scss

@ -749,3 +749,39 @@ svg.nc-cell-icon, svg.nc-virtual-cell-icon {
@apply w-1em h-1em flex-none;
font-size: 1rem;
}
// For select type field list layout
.nc-field-layout-list {
@apply !flex !flex-col !items-start w-full !space-y-0.5 !max-w-full;
.ant-checkbox-wrapper {
@apply !m-0 !h-9 !mr-0 !flex !items-center w-full !max-w-full pl-2 rounded-lg hover:bg-gray-100;
&:hover {
.ant-checkbox-checked:after {
@apply !rounded;
}
}
.ant-checkbox {
@apply !top-0;
& + span {
@apply !flex !pl-4 max-w-[calc(100%_-_16px)];
}
.ant-checkbox-checked:after,
.ant-checkbox-inner {
@apply !rounded;
}
}
}
.ant-radio-wrapper {
@apply !m-0 !h-9 !mr-0 !flex !items-center w-full !max-w-full pl-2 rounded-lg hover:bg-gray-100;
.ant-radio {
@apply !top-0;
}
.ant-radio + span {
@apply !flex !pl-4 max-w-[calc(100%_-_16px)];
}
}
}

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

@ -3,6 +3,7 @@ import { message } from 'ant-design-vue'
import tinycolor from 'tinycolor2'
import type { Select as AntSelect } from 'ant-design-vue'
import type { SelectOptionType, SelectOptionsType } from 'nocodb-sdk'
import type { FormFieldsLimitOptionsType } from '~/lib'
import {
ActiveCellInj,
ColumnInj,
@ -95,7 +96,43 @@ const options = computed<(SelectOptionType & { value?: string })[]>(() => {
for (const op of opts.filter((el: SelectOptionType) => el.order === null)) {
op.title = op.title?.replace(/^'/, '').replace(/'$/, '')
}
return opts.map((o: SelectOptionType) => ({ ...o, value: o.title }))
let order = 1
const limitOptionsById =
((parseProp(column.value.meta)?.limitOptions || []).reduce(
(o: Record<string, FormFieldsLimitOptionsType>, f: FormFieldsLimitOptionsType) => {
if (order < (f?.order ?? 0)) {
order = f.order
}
return {
...o,
[f.id]: f,
}
},
{},
) as Record<string, FormFieldsLimitOptionsType>) ?? {}
if (
!isEditColumn.value &&
isForm.value &&
parseProp(column.value.meta)?.isLimitOption &&
(parseProp(column.value.meta)?.limitOptions || []).length
) {
return opts
.filter((o: SelectOptionType) => {
if (limitOptionsById[o.id!]?.show !== undefined) {
return limitOptionsById[o.id!]?.show
}
return false
})
.map((o) => ({
...o,
value: o.title,
order: o.id && limitOptionsById[o.id] ? limitOptionsById[o.id]?.order : order++,
}))
.sort((a, b) => a.order - b.order)
} else {
return opts.map((o: SelectOptionType) => ({ ...o, value: o.title }))
}
}
return []
})
@ -353,154 +390,194 @@ const onFocus = () => {
<template>
<div
class="nc-cell-field nc-multi-select h-full w-full flex items-center"
:class="{ 'read-only': readOnly }"
:class="{ 'read-only': readOnly, 'max-w-full': isForm }"
@click="toggleMenu"
>
<div
v-if="!active"
class="flex flex-wrap"
:style="{
'display': '-webkit-box',
'max-width': '100%',
'-webkit-line-clamp': rowHeight || 1,
'-webkit-box-orient': 'vertical',
'overflow': 'hidden',
}"
>
<template v-for="selectedOpt of selectedOpts" :key="selectedOpt.value">
<a-tag class="rounded-tag max-w-full" :color="selectedOpt.color">
<span
:style="{
'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(selectedOpt.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ selectedOpt.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ selectedOpt.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</template>
<div v-if="!isEditColumn && isForm && parseProp(column.meta)?.isList" class="w-full max-w-full">
<a-checkbox-group v-model:value="vModel" class="nc-field-layout-list">
<a-checkbox
v-for="op of options"
:key="op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
>
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-checkbox>
</a-checkbox-group>
</div>
<a-select
v-else
ref="aselect"
v-model:value="vModel"
mode="multiple"
class="w-full overflow-hidden"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:bordered="false"
clear-icon
:show-search="!isMobileMode"
:show-arrow="editAllowed && !readOnly"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-multi-select-cell !min-w-200px ${isOpen ? 'active' : ''}`"
@search="search"
@keydown="onKeyDown"
@focus="onFocus"
@blur="isOpen = false"
>
<template #suffixIcon>
<GeneralIcon icon="arrowDown" class="text-gray-700 nc-select-expand-btn" />
</template>
<a-select-option
v-for="op of options"
:key="op.id || op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
@click.stop
<template v-else>
<div
v-if="!active"
class="flex flex-wrap"
:style="{
'display': '-webkit-box',
'max-width': '100%',
'-webkit-line-clamp': rowHeight || 1,
'-webkit-box-orient': 'vertical',
'overflow': 'hidden',
}"
>
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
<a-select-option
v-if="searchVal && isOptionMissing && !isPublic && !disableOptionCreation && isUIAllowed('fieldEdit')"
:key="searchVal"
:value="searchVal"
<template v-for="selectedOpt of selectedOpts" :key="selectedOpt.value">
<a-tag class="rounded-tag max-w-full" :color="selectedOpt.color">
<span
:style="{
'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(selectedOpt.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ selectedOpt.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ selectedOpt.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</template>
</div>
<a-select
v-else
ref="aselect"
v-model:value="vModel"
mode="multiple"
class="w-full overflow-hidden"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:bordered="false"
clear-icon
:show-search="!isMobileMode"
:show-arrow="editAllowed && !readOnly"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-multi-select-cell !min-w-200px ${isOpen ? 'active' : ''}`"
@search="search"
@keydown="onKeyDown"
@focus="onFocus"
@blur="isOpen = false"
>
<div class="flex gap-2 text-gray-500 items-center h-full">
<component :is="iconMap.plusThick" class="min-w-4" />
<div class="text-xs whitespace-normal">
{{ $t('msg.selectOption.createNewOptionNamed') }} <strong>{{ searchVal }}</strong>
</div>
</div>
</a-select-option>
<template #tagRender="{ value: val, onClose }">
<a-tag
v-if="options.find((el) => el.title === val)"
class="rounded-tag nc-selected-option"
:style="{ display: 'flex', alignItems: 'center' }"
:color="options.find((el) => el.title === val)?.color"
:closable="editAllowed && (vModel.length > 1 || !column?.rqd)"
:close-icon="h(MdiCloseCircle, { class: ['ms-close-icon'] })"
@click="onTagClick($event, onClose)"
@close="onClose"
<template #suffixIcon>
<GeneralIcon icon="arrowDown" class="text-gray-700 nc-select-expand-btn" />
</template>
<a-select-option
v-for="op of options"
:key="op.id || op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
@click.stop
>
<span
:style="{
'color': tinycolor.isReadable(options.find((el) => el.title === val)?.color || '#ccc', '#fff', {
level: 'AA',
size: 'large',
})
? '#fff'
: tinycolor
.mostReadable(options.find((el) => el.title === val)?.color || '#ccc', ['#0b1d05', '#fff'])
.toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
<a-select-option
v-if="searchVal && isOptionMissing && !isPublic && !disableOptionCreation && isUIAllowed('fieldEdit')"
:key="searchVal"
:value="searchVal"
>
<div class="flex gap-2 text-gray-500 items-center h-full">
<component :is="iconMap.plusThick" class="min-w-4" />
<div class="text-xs whitespace-normal">
{{ $t('msg.selectOption.createNewOptionNamed') }} <strong>{{ searchVal }}</strong>
</div>
</div>
</a-select-option>
<template #tagRender="{ value: val, onClose }">
<a-tag
v-if="options.find((el) => el.title === val)"
class="rounded-tag nc-selected-option"
:style="{ display: 'flex', alignItems: 'center' }"
:color="options.find((el) => el.title === val)?.color"
:closable="editAllowed && (vModel.length > 1 || !column?.rqd)"
:close-icon="h(MdiCloseCircle, { class: ['ms-close-icon'] })"
@click="onTagClick($event, onClose)"
@close="onClose"
>
{{ val }}
</span>
</a-tag>
</template>
</a-select>
<span
:style="{
'color': tinycolor.isReadable(options.find((el) => el.title === val)?.color || '#ccc', '#fff', {
level: 'AA',
size: 'large',
})
? '#fff'
: tinycolor
.mostReadable(options.find((el) => el.title === val)?.color || '#ccc', ['#0b1d05', '#fff'])
.toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
{{ val }}
</span>
</a-tag>
</template>
</a-select>
</template>
</div>
</template>

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

@ -187,7 +187,7 @@ watch(editorDom, () => {
'max-w-[calc(100%_-_198px)] flex justify-end rounded-tr-2xl overflow-hidden': fullMode,
}"
>
<div class="nc-scrollbar-x-md">
<div class="nc-longtext-scrollbar">
<CellRichTextSelectedBubbleMenu v-if="editor" :editor="editor" embed-mode />
</div>
</div>

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

@ -3,6 +3,7 @@ import { message } from 'ant-design-vue'
import tinycolor from 'tinycolor2'
import type { Select as AntSelect } from 'ant-design-vue'
import type { SelectOptionType } from 'nocodb-sdk'
import type { FormFieldsLimitOptionsType } from '~/lib'
import {
ActiveCellInj,
ColumnInj,
@ -88,7 +89,44 @@ const options = computed<(SelectOptionType & { value: string })[]>(() => {
for (const op of opts.filter((el: any) => el.order === null)) {
op.title = op.title.replace(/^'/, '').replace(/'$/, '')
}
return opts.map((o: any) => ({ ...o, value: o.title }))
let order = 1
const limitOptionsById =
((parseProp(column.value.meta)?.limitOptions || []).reduce(
(o: Record<string, FormFieldsLimitOptionsType>, f: FormFieldsLimitOptionsType) => {
if (order < (f?.order ?? 0)) {
order = f.order
}
return {
...o,
[f.id]: f,
}
},
{},
) as Record<string, FormFieldsLimitOptionsType>) ?? {}
if (
!isEditColumn.value &&
isForm.value &&
parseProp(column.value.meta)?.isLimitOption &&
(parseProp(column.value.meta)?.limitOptions || []).length
) {
return opts
.filter((o: SelectOptionType & { value: string }) => {
if (limitOptionsById[o.id]?.show !== undefined) {
return limitOptionsById[o.id]?.show
}
return false
})
.map((o: any) => ({
...o,
value: o.title,
order: o.id && limitOptionsById[o.id] ? limitOptionsById[o.id]?.order : order++,
}))
.sort((a, b) => a.order - b.order)
} else {
return opts.map((o: any) => ({ ...o, value: o.title }))
}
}
return []
})
@ -272,82 +310,70 @@ const onFocus = () => {
<template>
<div
class="nc-cell-field h-full w-full flex items-center nc-single-select focus:outline-transparent"
:class="{ 'read-only': readOnly }"
:class="{ 'read-only': readOnly, 'max-w-full': isForm }"
@click="toggleMenu"
@keydown.enter.stop.prevent="toggleMenu"
>
<div v-if="!(active || isEditable)" class="w-full">
<a-tag v-if="selectedOpt" class="rounded-tag max-w-full" :color="selectedOpt.color">
<span
:style="{
'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(selectedOpt.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
<div v-if="!isEditColumn && isForm && parseProp(column.meta)?.isList" class="w-full max-w-full">
<a-radio-group v-model:value="vModel" class="nc-field-layout-list">
<a-radio
v-for="op of options"
:key="op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ selectedOpt.title }}
</template>
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
>
{{ selectedOpt.title }}
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</NcTooltip>
</span>
</a-tag>
</div>
<NcSelect
v-else
ref="aselect"
v-model:value="vModel"
class="w-full overflow-hidden xs:min-h-12"
:class="{ 'caret-transparent': !hasEditRoles }"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:allow-clear="!column.rqd && editAllowed"
:bordered="false"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:show-search="!isMobileMode && isOpen && active"
:show-arrow="hasEditRoles && !readOnly && active && (vModel === null || vModel === undefined)"
:dropdown-class-name="`nc-dropdown-single-select-cell !min-w-200px ${isOpen && active ? 'active' : ''}`"
:dropdown-match-select-width="true"
@select="onSelect"
@keydown="onKeydown($event)"
@search="search"
@blur="isOpen = false"
@focus="onFocus"
>
<a-select-option
v-for="op of options"
:key="op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
@click.stop
</a-tag></a-radio
>
</a-radio-group>
<div
v-if="vModel"
class="inline-block px-2 pt-2 cursor-pointer text-xs text-gray-500 hover:text-gray-800"
@click="vModel = ''"
>
<a-tag class="rounded-tag max-w-full" :color="op.color">
{{ $t('labels.clearSelection') }}
</div>
</div>
<template v-else>
<div v-if="!(active || isEditable)" class="w-full">
<a-tag v-if="selectedOpt" class="rounded-tag max-w-full" :color="selectedOpt.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
: tinycolor.mostReadable(selectedOpt.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
{{ selectedOpt.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
@ -357,21 +383,80 @@ const onFocus = () => {
display: 'inline',
}"
>
{{ op.title }}
{{ selectedOpt.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
<a-select-option v-if="searchVal && isOptionMissing && isNewOptionCreateEnabled" :key="searchVal" :value="searchVal">
<div class="flex gap-2 text-gray-500 items-center h-full">
<component :is="iconMap.plusThick" class="min-w-4" />
<div class="text-xs whitespace-normal">
{{ $t('msg.selectOption.createNewOptionNamed') }} <strong>{{ searchVal }}</strong>
</div>
<NcSelect
v-else
ref="aselect"
v-model:value="vModel"
class="w-full overflow-hidden xs:min-h-12"
:class="{ 'caret-transparent': !hasEditRoles }"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:allow-clear="!column.rqd && editAllowed"
:bordered="false"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:show-search="!isMobileMode && isOpen && active"
:show-arrow="hasEditRoles && !readOnly && active && (vModel === null || vModel === undefined)"
:dropdown-class-name="`nc-dropdown-single-select-cell !min-w-200px ${isOpen && active ? 'active' : ''}`"
:dropdown-match-select-width="true"
@select="onSelect"
@keydown="onKeydown($event)"
@search="search"
@blur="isOpen = false"
@focus="onFocus"
>
<a-select-option
v-for="op of options"
:key="op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
@click.stop
>
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
<a-select-option v-if="searchVal && isOptionMissing && isNewOptionCreateEnabled" :key="searchVal" :value="searchVal">
<div class="flex gap-2 text-gray-500 items-center h-full">
<component :is="iconMap.plusThick" class="min-w-4" />
<div class="text-xs whitespace-normal">
{{ $t('msg.selectOption.createNewOptionNamed') }} <strong>{{ searchVal }}</strong>
</div>
</div>
</div>
</a-select-option>
</NcSelect>
</a-select-option>
</NcSelect>
</template>
</div>
</template>

17
packages/nc-gui/components/cell/TextArea.vue

@ -173,7 +173,7 @@ const dragStart = (e: MouseEvent) => {
}
watch(editEnabled, () => {
if (editEnabled.value) {
if (editEnabled.value && isRichMode.value) {
isVisible.value = true
}
})
@ -227,7 +227,7 @@ watch(inputWrapperRef, () => {
:ref="focus"
v-model="vModel"
:rows="isForm ? 5 : 4"
class="h-full w-full outline-none border-none nc-scrollbar-lg"
class="h-full w-full outline-none border-none nc-longtext-scrollbar"
:class="{
'p-2': editEnabled,
'py-1 h-full': isForm,
@ -270,8 +270,8 @@ watch(inputWrapperRef, () => {
<NcTooltip
v-if="!isVisible"
placement="bottom"
class="!absolute right-1 hidden nc-text-area-expand-btn group-hover:block z-3"
:class="isExpandedFormOpen || isForm ? 'top-1' : 'bottom-1'"
class="!absolute top-1 hidden nc-text-area-expand-btn group-hover:block z-3"
:class="isForm ? 'right-1' : 'right-0'"
>
<template #title>{{ $t('title.expand') }}</template>
<NcButton type="secondary" size="xsmall" data-testid="attachment-cell-file-picker-button" @click.stop="onExpand">
@ -318,7 +318,7 @@ watch(inputWrapperRef, () => {
<a-textarea
ref="inputRef"
v-model:value="vModel"
class="nc-text-area-expanded !py-1 !px-3 !text-black !cursor-text !min-h-[210px] !rounded-lg focus:border-brand-500 disabled:!bg-gray-50"
class="nc-text-area-expanded !py-1 !px-3 !text-black !cursor-text !min-h-[210px] !rounded-lg focus:border-brand-500 disabled:!bg-gray-50 nc-longtext-scrollbar"
:placeholder="$t('activity.enterText')"
:style="{ resize: 'both' }"
:disabled="readOnly"
@ -347,6 +347,9 @@ textarea:focus {
@apply rounded-lg;
}
}
.nc-longtext-scrollbar {
@apply scrollbar-thin scrollbar-thumb-gray-200 hover:scrollbar-thumb-gray-300 scrollbar-track-transparent;
}
</style>
<style lang="scss">
@ -367,6 +370,10 @@ textarea:focus {
max-width: min(1280px, 100vw - 100px);
max-height: min(864px, 100vh - 100px);
.nc-longtext-scrollbar {
@apply scrollbar-thin scrollbar-thumb-gray-200 hover:scrollbar-thumb-gray-300 scrollbar-track-transparent;
}
}
}
}

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

@ -77,7 +77,7 @@ const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && isForm.value && (el as HTMLInputElement)?.focus()
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
watch(
() => editEnabled.value,

373
packages/nc-gui/components/cell/User.vue

@ -1,8 +1,10 @@
<script lang="ts" setup>
import { onUnmounted } from '@vue/runtime-core'
import tinycolor from 'tinycolor2'
import { Checkbox, CheckboxGroup, Radio, RadioGroup } from 'ant-design-vue'
import type { Select as AntSelect } from 'ant-design-vue'
import type { UserFieldRecordType } from 'nocodb-sdk'
import type { FormFieldsLimitOptionsType } from '~/lib'
import {
ActiveCellInj,
CellClickHookInj,
@ -77,16 +79,59 @@ const searchVal = ref<string | null>()
const { isUIAllowed } = useRoles()
const options = computed<UserFieldRecordType[]>(() => {
let order = 1
const limitOptionsById =
((parseProp(column.value.meta)?.limitOptions || []).reduce(
(o: Record<string, FormFieldsLimitOptionsType>, f: FormFieldsLimitOptionsType) => {
if (order < (f?.order ?? 0)) {
order = f.order
}
return {
...o,
[f.id]: f,
}
},
{},
) as Record<string, FormFieldsLimitOptionsType>) ?? {}
const collaborators: UserFieldRecordType[] = []
collaborators.push(
...(baseUsers.value?.map((user: any) => ({
id: user.id,
email: user.email,
display_name: user.display_name,
deleted: user.deleted,
})) || []),
)
if (
!isEditColumn.value &&
isForm.value &&
parseProp(column.value.meta)?.isLimitOption &&
(parseProp(column.value.meta)?.limitOptions || []).length
) {
collaborators.push(
...(baseUsers.value || [])
.filter((user) => {
if (limitOptionsById[user.id]?.show !== undefined) {
return limitOptionsById[user.id]?.show
}
return false
})
.map((user: any) => ({
id: user.id,
email: user.email,
display_name: user.display_name,
deleted: user.deleted,
order: user.id && limitOptionsById[user.id] ? limitOptionsById[user.id]?.order ?? user.order : order++,
}))
.sort((a, b) => a.order - b.order),
)
} else {
collaborators.push(
...(baseUsers.value || [])
.map((user: any) => ({
id: user.id,
email: user.email,
display_name: user.display_name,
deleted: user.deleted,
order: order++,
}))
.sort((a, b) => a.order - b.order),
)
}
return collaborators
})
@ -146,6 +191,14 @@ const vModel = computed({
},
})
const vModelListLayout = computed(() => {
if (isMultiple.value) {
return (vModel.value || []).map((item) => item.value)
} else {
return (vModel.value || [])?.[0]?.value || ''
}
})
watch(isOpen, (n, _o) => {
if (!n) searchVal.value = ''
@ -266,87 +319,85 @@ const filterOption = (input: string, option: any) => {
:class="{ 'read-only': readOnly }"
@click="toggleMenu"
>
<div
v-if="!active"
class="flex flex-wrap"
:style="{
'display': '-webkit-box',
'max-width': '100%',
'-webkit-line-clamp': rowHeight || 1,
'-webkit-box-orient': 'vertical',
'overflow': 'hidden',
}"
>
<template v-for="selectedOpt of vModel" :key="selectedOpt.value">
<a-tag class="rounded-tag max-w-full !pl-0" color="'#ccc'">
<span
:style="{
'color': tinycolor.isReadable('#ccc' || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable('#ccc' || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
class="flex items-stretch gap-2"
:class="{ 'text-sm': isKanban }"
<div v-if="!isEditColumn && isForm && parseProp(column.meta)?.isList" class="w-full max-w-full">
<component
:is="isMultiple ? CheckboxGroup : RadioGroup"
v-model:value="vModelListLayout"
class="nc-field-layout-list"
@update:value="
(value) => {
vModel = isMultiple ? value : [value]
}
"
>
<template v-for="op of options" :key="op.id || op.email">
<component
:is="isMultiple ? Checkbox : Radio"
v-if="!op.deleted"
:key="op.id || op.email"
:value="op.id"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.email}`"
>
<div class="flex-none">
<GeneralUserIcon
size="auto"
:name="!selectedOpt.label?.includes('@') ? selectedOpt.label.trim() : ''"
:email="selectedOpt.label"
class="!text-[0.65rem]"
/>
</div>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ selectedOpt.label }}
</template>
<a-tag class="rounded-tag max-w-full !pl-0" color="'#ccc'">
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
'color': tinycolor.isReadable('#ccc' || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable('#ccc' || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
class="flex items-stretch gap-2"
>
{{ selectedOpt.label }}
<div>
<GeneralUserIcon
size="auto"
:name="op.display_name?.trim() ? op.display_name?.trim() : ''"
:email="op.email"
class="!text-[0.65rem]"
/>
</div>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.display_name?.trim() || op.email }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.display_name?.trim() || op.email }}
</span>
</NcTooltip>
</span>
</NcTooltip>
</span>
</a-tag>
</template>
</a-tag>
</component>
</template>
</component>
<div
v-if="!isMultiple && vModel.length"
class="inline-block px-2 pt-2 cursor-pointer text-xs text-gray-500 hover:text-gray-800"
@click="vModel = []"
>
{{ $t('labels.clearSelection') }}
</div>
</div>
<a-select
v-else
ref="aselect"
v-model:value="vModel"
mode="multiple"
class="w-full overflow-hidden"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:bordered="false"
clear-icon
:show-search="!isMobileMode"
:show-arrow="editAllowed && !readOnly"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-user-select-cell !min-w-200px ${isOpen ? 'active' : ''}`"
:filter-option="filterOption"
@search="search"
@keydown.stop
>
<template #suffixIcon>
<GeneralIcon icon="arrowDown" class="text-gray-700 nc-select-expand-btn" />
</template>
<template v-for="op of options" :key="op.id || op.email">
<a-select-option
v-if="!op.deleted"
:value="op.id"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.email}`"
@click.stop
>
<template v-else>
<div
v-if="!active"
class="flex flex-wrap"
:style="{
'display': '-webkit-box',
'max-width': '100%',
'-webkit-line-clamp': rowHeight || 1,
'-webkit-box-orient': 'vertical',
'overflow': 'hidden',
}"
>
<template v-for="selectedOpt of vModel" :key="selectedOpt.value">
<a-tag class="rounded-tag max-w-full !pl-0" color="'#ccc'">
<span
:style="{
@ -358,17 +409,17 @@ const filterOption = (input: string, option: any) => {
class="flex items-stretch gap-2"
:class="{ 'text-sm': isKanban }"
>
<div>
<div class="flex-none">
<GeneralUserIcon
size="auto"
:name="op.display_name?.trim() ? op.display_name?.trim() : ''"
:email="op.email"
:name="!selectedOpt.label?.includes('@') ? selectedOpt.label.trim() : ''"
:email="selectedOpt.label"
class="!text-[0.65rem]"
/>
</div>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.display_name?.trim() || op.email }}
{{ selectedOpt.label }}
</template>
<span
class="text-ellipsis overflow-hidden"
@ -378,51 +429,121 @@ const filterOption = (input: string, option: any) => {
display: 'inline',
}"
>
{{ op.display_name?.trim() || op.email }}
{{ selectedOpt.label }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
</template>
<template #tagRender="{ label, value: val, onClose }">
<a-tag
v-if="options.find((el) => el.id === val)"
class="rounded-tag nc-selected-option !pl-0"
:style="{ display: 'flex', alignItems: 'center' }"
color="'#ccc'"
:closable="editAllowed && ((vModel?.length ?? 0) > 1 || !column?.rqd)"
:close-icon="h(MdiCloseCircle, { class: ['ms-close-icon'] })"
@click="onTagClick($event, onClose)"
@close="onClose"
>
<span
:style="{
'color': tinycolor.isReadable('#ccc' || '#ccc', '#fff', {
level: 'AA',
size: 'large',
})
? '#fff'
: tinycolor.mostReadable('#ccc' || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
class="flex items-stretch gap-2"
:class="{ 'text-sm': isKanban }"
</template>
</div>
<a-select
v-else
ref="aselect"
v-model:value="vModel"
mode="multiple"
class="w-full overflow-hidden"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:bordered="false"
clear-icon
:show-search="!isMobileMode"
:show-arrow="editAllowed && !readOnly"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-user-select-cell !min-w-200px ${isOpen ? 'active' : ''}`"
:filter-option="filterOption"
@search="search"
@keydown.stop
>
<template #suffixIcon>
<GeneralIcon icon="arrowDown" class="text-gray-700 nc-select-expand-btn" />
</template>
<template v-for="op of options" :key="op.id || op.email">
<a-select-option
v-if="!op.deleted"
:value="op.id"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.email}`"
@click.stop
>
<a-tag class="rounded-tag max-w-full !pl-0" color="'#ccc'">
<span
:style="{
'color': tinycolor.isReadable('#ccc' || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable('#ccc' || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
class="flex items-stretch gap-2"
:class="{ 'text-sm': isKanban }"
>
<div>
<GeneralUserIcon
size="auto"
:name="op.display_name?.trim() ? op.display_name?.trim() : ''"
:email="op.email"
class="!text-[0.65rem]"
/>
</div>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.display_name?.trim() || op.email }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.display_name?.trim() || op.email }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
</template>
<template #tagRender="{ label, value: val, onClose }">
<a-tag
v-if="options.find((el) => el.id === val)"
class="rounded-tag nc-selected-option !pl-0"
:style="{ display: 'flex', alignItems: 'center' }"
color="'#ccc'"
:closable="editAllowed && ((vModel?.length ?? 0) > 1 || !column?.rqd)"
:close-icon="h(MdiCloseCircle, { class: ['ms-close-icon'] })"
@click="onTagClick($event, onClose)"
@close="onClose"
>
<div>
<GeneralUserIcon
size="auto"
:name="!label?.includes('@') ? label.trim() : ''"
:email="label"
class="!text-[0.65rem]"
/>
</div>
{{ label }}
</span>
</a-tag>
</template>
</a-select>
<span
:style="{
'color': tinycolor.isReadable('#ccc' || '#ccc', '#fff', {
level: 'AA',
size: 'large',
})
? '#fff'
: tinycolor.mostReadable('#ccc' || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
class="flex items-stretch gap-2"
:class="{ 'text-sm': isKanban }"
>
<div>
<GeneralUserIcon
size="auto"
:name="!label?.includes('@') ? label.trim() : ''"
:email="label"
class="!text-[0.65rem]"
/>
</div>
{{ label }}
</span>
</a-tag>
</template>
</a-select>
</template>
</div>
</template>

3
packages/nc-gui/components/cell/attachment/utils.ts

@ -1,6 +1,7 @@
import type { AttachmentReqType, AttachmentType } from 'nocodb-sdk'
import { populateUniqueFileName } from 'nocodb-sdk'
import DOMPurify from 'isomorphic-dompurify'
import { saveAs } from 'file-saver'
import RenameFile from './RenameFile.vue'
import {
ColumnInj,
@ -317,7 +318,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
async function downloadFile(item: AttachmentType) {
const src = await getAttachmentSrc(item)
if (src) {
;(await import('file-saver')).saveAs(src, item.title)
saveAs(src, item.title)
} else {
message.error('Failed to download file')
}

18
packages/nc-gui/components/dlg/TableDuplicate.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
import type { TableType } from 'nocodb-sdk'
import { type LinkToAnotherRecordType, type TableType, UITypes } from 'nocodb-sdk'
import { message } from 'ant-design-vue'
import { useVModel } from '#imports'
import type { TabType } from '#imports'
@ -31,6 +31,8 @@ const { loadTables } = baseStore
const { tables } = storeToRefs(baseStore)
const { getMeta } = useMetas()
const { t } = useI18n()
const { activeTable: _activeTable } = storeToRefs(useTablesStore())
@ -74,6 +76,20 @@ const _duplicate = async () => {
}) => {
if (data.status !== 'close') {
if (data.status === JobStatus.COMPLETED) {
const sourceTable = await getMeta(props.table.id!)
if (sourceTable) {
for (const col of sourceTable.columns || []) {
if ([UITypes.Links, UITypes.LinkToAnotherRecord].includes(col.uidt as UITypes)) {
if (col && col.colOptions) {
const relatedTableId = (col.colOptions as LinkToAnotherRecordType)?.fk_related_model_id
if (relatedTableId) {
await getMeta(relatedTableId, true)
}
}
}
}
}
await loadTables()
refreshCommandPalette()
const newTable = tables.value.find((el) => el.id === data?.data?.result?.id)

2
packages/nc-gui/components/dlg/ViewCreate.vue

@ -376,7 +376,7 @@ onMounted(async () => {
<a
v-if="!form.copy_from_id"
class="text-sm !text-gray-600 !hover:text-gray-600"
href="https://docs.nocodb.com/views/view-types/calendar/"
:href="`https://docs.nocodb.com/views/view-types/${typeAlias}`"
target="_blank"
>
Go to Docs

17
packages/nc-gui/components/general/FormBanner.vue

@ -3,19 +3,22 @@ interface Props {
bannerImageUrl?: string | null
}
const { bannerImageUrl } = defineProps<Props>()
const { getPossibleAttachmentSrc } = useAttachment()
</script>
<template>
<div
class="w-full max-w-screen-xl mx-auto bg-white border-1 border-gray-200 rounded-3xl overflow-hidden"
:style="
bannerImageUrl
? { 'background-image': `url(${bannerImageUrl})`, 'background-size': 'cover', 'background-position': 'center' }
: {}
"
class="nc-form-banner-wrapper w-full mx-auto bg-white border-1 border-gray-200 rounded-2xl overflow-hidden"
:style="{ aspectRatio: 4 / 1 }"
>
<LazyCellAttachmentImage
v-if="bannerImageUrl"
:srcs="getPossibleAttachmentSrc(parseProp(bannerImageUrl))"
class="nc-form-banner-image object-cover w-full"
/>
<!-- Todo: aspect ratio and cover image uploader and image cropper to crop image in fixed aspect ratio -->
<div v-if="!bannerImageUrl" class="h-full flex items-stretch justify-between">
<div v-else class="h-full flex items-stretch justify-between">
<div class="flex">
<img src="~assets/img/form-banner-left.png" alt="form-banner-left'" />
</div>

141
packages/nc-gui/components/general/ImageCropper.vue

@ -0,0 +1,141 @@
<script lang="ts" setup>
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
import 'vue-advanced-cropper/dist/theme.classic.css'
import type { AttachmentReqType } from 'nocodb-sdk'
import { extractSdkResponseErrorMsg, useApi } from '#imports'
interface Props {
imageConfig: {
src: string
type: string
name: string
}
cropperConfig: {
aspectRatio?: number
}
uploadConfig?: {
path?: string
}
showCropper: boolean
}
const { imageConfig, cropperConfig, uploadConfig, ...props } = defineProps<Props>()
const emit = defineEmits(['update:showCropper', 'submit'])
const showCropper = useVModel(props, 'showCropper', emit)
const { api, isLoading } = useApi()
const cropperRef = ref()
const previewImage = ref({
canvas: {},
src: '',
})
const handleCropImage = () => {
const { canvas } = cropperRef.value.getResult()
previewImage.value = {
canvas,
src: canvas.toDataURL(),
}
}
const handleUploadImage = async (fileToUpload: AttachmentReqType[]) => {
if (uploadConfig?.path) {
try {
const uploadResult = await api.storage.uploadByUrl(
{
path: uploadConfig?.path as string,
},
fileToUpload,
)
if (uploadResult?.[0]) {
emit('submit', {
...uploadResult[0],
})
} else {
emit('submit', fileToUpload[0])
}
} catch (error: any) {
console.error(error)
message.error(await extractSdkResponseErrorMsg(error))
}
} else {
emit('submit', fileToUpload[0])
}
showCropper.value = false
}
const handleSaveImage = async () => {
if (previewImage.value.canvas) {
;(previewImage.value.canvas as any).toBlob(async (blob: Blob) => {
await handleUploadImage([
{
title: imageConfig.name,
fileName: imageConfig.name,
mimetype: imageConfig.type,
size: blob.size,
url: previewImage.value.src,
},
])
}, imageConfig.type)
}
}
watch(showCropper, () => {
if (!showCropper.value) {
previewImage.value = {
canvas: {},
src: '',
}
}
})
</script>
<template>
<NcModal v-model:visible="showCropper" :mask-closable="false">
<div class="nc-image-cropper-wrapper relative">
<Cropper
ref="cropperRef"
class="nc-cropper relative"
:src="imageConfig.src"
:auto-zoom="true"
:stencil-props="cropperConfig?.aspectRatio ? { aspectRatio: cropperConfig.aspectRatio } : {}"
/>
<div v-if="previewImage.src" class="result_preview">
<img :src="previewImage.src" alt="Preview Image" />
</div>
</div>
<div class="flex justify-between items-center space-x-4 mt-4">
<div class="flex items-center space-x-4">
<NcButton type="secondary" size="small" :disabled="isLoading" @click="showCropper = false"> Cancel </NcButton>
</div>
<div class="flex items-center space-x-4">
<NcButton type="secondary" size="small" :disabled="isLoading" @click="handleCropImage">
<GeneralIcon icon="crop"></GeneralIcon>
<span class="ml-2">Crop</span>
</NcButton>
<NcButton size="small" :loading="isLoading" :disabled="!previewImage.src" @click="handleSaveImage"> Save </NcButton>
</div>
</div>
</NcModal>
</template>
<style lang="scss" scoped>
.nc-cropper {
min-height: 400px;
max-height: 400px;
}
.nc-image-cropper-wrapper {
.result_preview {
@apply absolute right-4 bottom-4 border-1 border-dashed border-white/50 w-28 h-28 opacity-90 pointer-events-none;
img {
@apply w-full h-full object-contain;
}
}
}
</style>

2
packages/nc-gui/components/nc/DateWeekSelector.vue

@ -180,7 +180,7 @@ const paginate = (action: 'next' | 'prev') => {
'text-gray-400': !isDateInCurrentMonth(date),
'nc-selected-week-start': isSameDate(date, selectedWeek?.start),
'nc-selected-week-end': isSameDate(date, selectedWeek?.end),
'rounded-md bg-brand-50 text-brand-500': isSameDate(date, dayjs()) && isDateInCurrentMonth(date),
'rounded-md bg-brand-50 nc-calendar-today text-brand-500': isSameDate(date, dayjs()) && isDateInCurrentMonth(date),
}"
class="h-9 w-9 px-1 py-2 relative font-medium flex items-center cursor-pointer justify-center"
data-testid="nc-calendar-date"

2
packages/nc-gui/components/nc/Select.vue

@ -82,7 +82,7 @@ const onChange = (value: string) => {
height: fit-content;
.ant-select-selector {
box-shadow: 0px 5px 3px -2px rgba(0, 0, 0, 0.02), 0px 3px 1px -2px rgba(0, 0, 0, 0.06);
@apply border-1 border-gray-200 !rounded-lg;
@apply border-1 border-gray-200 rounded-lg;
}
.ant-select-selection-item {

429
packages/nc-gui/components/smartsheet/Form.vue

@ -1,10 +1,18 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import Draggable from 'vuedraggable'
import tinycolor from 'tinycolor2'
import { Pane, Splitpanes } from 'splitpanes'
import 'splitpanes/dist/splitpanes.css'
import { RelationTypes, UITypes, ViewTypes, getSystemColumns, isLinksOrLTAR, isVirtualCol } from 'nocodb-sdk'
import {
ProjectRoles,
RelationTypes,
UITypes,
ViewTypes,
getSystemColumns,
isLinksOrLTAR,
isSelectTypeCol,
isVirtualCol,
} from 'nocodb-sdk'
import type { Permission } from '#imports'
import {
ActiveViewInj,
@ -26,6 +34,7 @@ import {
ref,
useDebounceFn,
useEventListener,
useFileDialog,
useGlobal,
useI18n,
useNuxtApp,
@ -62,6 +71,10 @@ const { $api, $e } = useNuxtApp()
const { isUIAllowed } = useRoles()
const { base } = storeToRefs(useBase())
const { getPossibleAttachmentSrc } = useAttachment()
let formState = reactive<Record<string, any>>({})
const secondsRemain = ref(0)
@ -85,7 +98,7 @@ reloadEventHook.on(async () => {
setFormData()
})
const { fields, showAll, hideAll, saveOrUpdate } = useViewColumnsOrThrow()
const { fields, showAll, hideAll } = useViewColumnsOrThrow()
const { state, row } = useProvideSmartsheetRowStore(
meta,
@ -118,9 +131,35 @@ const isTabPressed = ref(false)
const isLoadingFormView = ref(false)
const focusLabel: VNodeRef = (el) => {
return (el as HTMLInputElement)?.focus()
}
const showCropper = ref(false)
const imageCropperData = ref<{
imageConfig: {
src: string
type: string
name: string
}
cropperConfig: {
aspectRatio?: number
}
uploadConfig?: {
path?: string
}
cropFor: 'banner' | 'logo'
}>({
imageConfig: {
src: '',
type: '',
name: '',
},
cropperConfig: {},
uploadConfig: {
path: '',
},
cropFor: 'banner',
})
const focusLabel = ref<HTMLTextAreaElement>()
const searchQuery = ref('')
@ -128,6 +167,12 @@ const { t } = useI18n()
const { betaFeatureToggleState } = useBetaFeatureToggle()
const { open, onChange: onChangeFile } = useFileDialog({
accept: 'image/*',
multiple: false,
reset: true,
})
const visibleColumns = computed(() => localColumns.value.filter((f) => f.show).sort((a, b) => a.order - b.order))
const updateView = useDebounceFn(
@ -139,6 +184,8 @@ const updateView = useDebounceFn(
)
async function submitForm() {
if (isLocked.value || !isUIAllowed('dataInsert')) return
try {
await formRef.value?.validateFields()
} catch (e: any) {
@ -158,6 +205,8 @@ async function submitForm() {
}
async function clearForm() {
if (isLocked.value || !isUIAllowed('dataInsert')) return
formState = reactive<Record<string, any>>({})
state.value = {}
await formRef.value.clearValidate()
@ -205,14 +254,15 @@ function onMoveCallback(event: any) {
}
}
// Todo: reorder visible form fields
function onMove(event: any, isVisibleFormFields = false) {
async function onMove(event: any, isVisibleFormFields = false) {
if (isLocked.value || !isEditable) return
const { oldIndex } = event.moved
let { newIndex, element } = event.moved
const fieldIndex = fields.value?.findIndex((f) => f?.fk_column_id === element.fk_column_id)
if (fieldIndex === -1 || fieldIndex === undefined) return
if (fieldIndex === -1 || fieldIndex === undefined || !fields.value?.[fieldIndex]) return
if (isVisibleFormFields) {
element = localColumns.value[localColumns.value?.findIndex((c) => c.fk_column_id === element.fk_column_id)]
@ -233,28 +283,38 @@ function onMove(event: any, isVisibleFormFields = false) {
element.order = ((localColumns.value[newIndex - 1]?.order || 0) + (localColumns.value[newIndex + 1].order || 0)) / 2
}
saveOrUpdate(element, fieldIndex)
await $api.dbView.formColumnUpdate(element.id, element)
fields.value[fieldIndex] = element as any
// saveOrUpdate(element, fieldIndex)
$e('a:form-view:reorder')
}
async function showOrHideColumn(column: Record<string, any>, show: boolean, isSidePannel = false) {
if (isLocked.value || !isEditable) return
if (shouldSkipColumn(column)) {
// Required field can't be moved
!isSidePannel && message.info(t('msg.info.requriedFieldsCantBeMoved'))
return
}
const fieldIndex = fields.value?.findIndex((f) => f?.fk_column_id === column.fk_column_id)
if (fieldIndex !== -1 && fieldIndex !== undefined) {
await saveOrUpdate(
{
...column,
show,
},
fieldIndex,
)
if (fieldIndex !== -1 && fieldIndex !== undefined && fields.value?.[fieldIndex]) {
console.log('column', column)
column.show = show
await $api.dbView.formColumnUpdate(column.id, column)
fields.value[fieldIndex] = column as any
// await saveOrUpdate(
// {
// ...column,
// show,
// },
// fieldIndex,
// )
reloadEventHook.trigger()
@ -273,6 +333,8 @@ function shouldSkipColumn(col: Record<string, any>) {
}
async function handleAddOrRemoveAllColumns(value: boolean) {
if (isLocked.value || !isEditable) return
if (value) {
for (const col of (localColumns as Record<string, any>)?.value) {
col.show = true
@ -310,6 +372,8 @@ function setFormData() {
systemFieldsIds.value = getSystemColumns(col).map((c) => c.fk_column_id)
formViewData.value = {
banner_image_url: '',
logo_url: '',
...formViewData.value,
submit_another_form: !!(formViewData.value?.submit_another_form ?? 0),
show_blank_form: !!(formViewData.value?.show_blank_form ?? 0),
@ -383,11 +447,14 @@ const columnSupportsScanning = (elementType: UITypes) =>
const onFormItemClick = (element: any) => {
if (isLocked.value || !isEditable) return
activeRow.value = element.title
isTabPressed.value = false
}
const handleChangeBackground = (color: string) => {
if (isLocked.value || !isEditable) return
const tcolor = tinycolor(color)
if (tcolor.isValid()) {
;(formViewData.value?.meta as Record<string, any>).background_color = color
@ -395,12 +462,74 @@ const handleChangeBackground = (color: string) => {
}
}
onClickOutside(draggableRef, () => {
const openUploadImage = (isUploadBanner: boolean) => {
if (!isEditable) return
imageCropperData.value.uploadConfig = {
path: [NOCO, base.value.id, meta.value?.id, formViewData.value?.id].join('/'),
}
if (isUploadBanner) {
imageCropperData.value.cropperConfig = {
aspectRatio: 4 / 1,
}
imageCropperData.value.cropFor = 'banner'
} else {
imageCropperData.value.cropperConfig = {
aspectRatio: undefined,
}
imageCropperData.value.cropFor = 'logo'
}
open()
}
onChangeFile((files) => {
if (files && files[0]) {
// 1. Revoke the object URL, to allow the garbage collector to destroy the uploaded before file
if (imageCropperData.value.imageConfig.src) {
URL.revokeObjectURL(imageCropperData.value.imageConfig.src)
}
// 2. Create the blob link to the file to optimize performance:
const blob = URL.createObjectURL(files[0])
// 3. Update the image. The type will be derived from the extension
imageCropperData.value.imageConfig = {
src: blob,
type: files[0].type,
name: files[0].name,
}
showCropper.value = true
}
})
const handleOnUploadImage = (data: Record<string, any> = {}) => {
if (imageCropperData.value.cropFor === 'banner') {
formViewData.value!.banner_image_url = stringifyProp(data) ?? ''
} else {
formViewData.value!.logo_url = stringifyProp(data) ?? ''
}
updateView()
}
onClickOutside(draggableRef, (e) => {
if (
(e.target as HTMLElement)?.closest(
'.nc-dropdown-single-select-cell, .nc-dropdown-multi-select-cell, .nc-dropdown-user-select-cell',
)
) {
return
}
activeRow.value = ''
isTabPressed.value = false
})
onMounted(async () => {
if (imageCropperData.value.src) {
URL.revokeObjectURL(imageCropperData.value.imageConfig.src)
}
isLoadingFormView.value = true
await loadFormView()
setFormData()
@ -447,6 +576,12 @@ watch(activeRow, (newValue) => {
}
})
watch([focusLabel, activeRow], () => {
if (activeRow && focusLabel.value) {
focusLabel.value?.focus()
}
})
useEventListener(
formRef,
'focusout',
@ -480,7 +615,7 @@ useEventListener(
</script>
<template>
<div class="h-full">
<div class="h-full relative">
<template v-if="isMobileMode">
<div class="pl-6 pr-[120px] py-6 bg-white flex-col justify-start items-start gap-2.5 inline-flex">
<div class="text-gray-500 text-5xl font-semibold leading-16">
@ -550,18 +685,61 @@ useEventListener(
class="flex-1 h-full overflow-auto nc-form-scrollbar p-6"
:style="{background:(formViewData?.meta as Record<string,any>).background_color || '#F9F9FA'}"
>
<div :class="isEditable ? 'min-w-[616px] overflow-x-auto nc-form-scrollbar' : ''">
<!-- for future implementation of cover image -->
<!-- Todo: cover image uploader and image cropper to crop image in fixed aspect ratio -->
<GeneralFormBanner
v-if="
formViewData.banner_image_url || !(parseProp(formViewData?.meta).hide_branding && !formViewData.banner_image_url)
"
:banner-image-url="formViewData.banner_image_url"
/>
<div class="min-w-[616px] overflow-x-auto nc-form-scrollbar">
<GeneralImageCropper
v-if="isEditable"
v-model:show-cropper="showCropper"
:image-config="imageCropperData.imageConfig"
:cropper-config="imageCropperData.cropperConfig"
:upload-config="imageCropperData.uploadConfig"
@submit="handleOnUploadImage"
></GeneralImageCropper>
<!-- cover image -->
<div class="group relative max-w-[max(33%,688px)] mx-auto">
<GeneralFormBanner :banner-image-url="formViewData.banner_image_url" />
<div class="absolute bottom-0 right-0 hidden group-hover:block">
<div class="flex items-center space-x-1 m-2">
<NcButton
type="secondary"
size="small"
class="nc-form-upload-banner-btn"
data-testid="nc-form-upload-banner-btn"
@click="openUploadImage(true)"
>
<div class="flex gap-2 items-center">
<component :is="iconMap.upload" class="w-4 h-4" />
<span>
{{ formViewData.banner_image_url ? $t('general.replace') : $t('general.upload') }}
{{ $t('general.banner') }}
</span>
</div>
</NcButton>
<NcTooltip v-if="formViewData.banner_image_url">
<template #title> {{ $t('general.delete') }} {{ $t('general.banner') }} </template>
<NcButton
type="secondary"
size="small"
class="nc-form-delete-banner-btn"
data-testid="nc-form-delete-banner-btn"
@click="
() => {
if (isEditable) {
formViewData!.banner_image_url = ''
updateView()
}
}
"
>
<div class="flex gap-2 items-center">
<component :is="iconMap.delete" class="w-4 h-4" />
</div>
</NcButton>
</NcTooltip>
</div>
</div>
</div>
<a-card
class="!py-8 !lg:py-12 !border-gray-200 !rounded-3xl !mt-6 max-w-[688px] !mx-auto"
class="!py-8 !lg:py-12 !border-gray-200 !rounded-3xl !mt-6 !max-w-[max(33%,688px)] !mx-auto"
:body-style="{
margin: '0 auto',
padding: '0px !important',
@ -571,16 +749,59 @@ useEventListener(
<!-- form header -->
<div class="flex flex-col px-4 lg:px-6">
<!-- Form logo -->
<!-- <div v-if="isEditable">
<div class="inline-block rounded-xl bg-gray-100 p-3">
<NcButton type="secondary" size="small" class="nc-form-upload-logo" data-testid="nc-form-upload-log">
<div class="flex gap-2 items-center">
<component :is="iconMap.upload" class="w-4 h-4" />
<span> Upload Logo </span>
</div>
</NcButton>
<div class="mb-4">
<div
class="nc-form-logo-wrapper mx-6 group relative rounded-xl inline-block h-56px max-w-189px overflow-hidden"
:class="formViewData.logo_url ? 'hover:(w-full bg-gray-100)' : 'bg-gray-100'"
style="transition: all 0.3s ease-in"
>
<LazyCellAttachmentImage
v-if="formViewData.logo_url"
:srcs="getPossibleAttachmentSrc(parseProp(formViewData.logo_url))"
class="nc-form-logo !object-contain object-left max-h-full max-w-full !m-0 rounded-xl"
/>
<div
class="items-center space-x-1 flex-nowrap m-3"
:class="formViewData.logo_url ? 'hidden absolute top-0 left-0 group-hover:flex' : 'flex'"
>
<NcButton
v-if="isEditable"
type="secondary"
size="small"
class="nc-form-upload-logo-btn"
data-testid="nc-form-upload-log-btn"
@click="openUploadImage(false)"
>
<div class="flex gap-2 items-center">
<component :is="iconMap.upload" class="w-4 h-4" />
<span> {{ formViewData.logo_url ? $t('general.replace') : $t('general.upload') }} Logo</span>
</div>
</NcButton>
<NcTooltip v-if="formViewData.logo_url">
<template #title> {{ $t('general.delete') }} {{ $t('general.logo') }} </template>
<NcButton
type="secondary"
size="small"
class="nc-form-delete-logo-btn"
data-testid="nc-form-delete-logo-btn"
@click="
() => {
if (isEditable) {
formViewData!.logo_url = ''
updateView()
}
}
"
>
<div class="flex gap-2 items-center">
<component :is="iconMap.delete" class="w-4 h-4" />
</div>
</NcButton>
</NcTooltip>
</div>
</div>
</div> -->
</div>
<!-- form title -->
<div
class="border-transparent px-4 lg:px-6"
@ -594,6 +815,9 @@ useEventListener(
{
'hover:bg-gray-50': activeRow !== 'nc-form-heading' && isEditable,
},
{
'bg-gray-50': activeRow === 'nc-form-heading' && isEditable,
},
{
'!hover:bg-white !ring-0 !cursor-auto': isLocked,
},
@ -641,6 +865,9 @@ useEventListener(
{
'hover:bg-gray-50': activeRow !== 'nc-form-sub-heading' && isEditable,
},
{
'bg-gray-50': activeRow === 'nc-form-sub-heading' && isEditable,
},
{
'!hover:bg-white !ring-0 !cursor-auto': isLocked,
},
@ -693,13 +920,13 @@ useEventListener(
:class="[
`nc-form-drag-${element.title.replaceAll(' ', '')}`,
{
'rounded-2xl overflow-hidden border-2 cursor-pointer my-1': isEditable,
'rounded-2xl overflow-hidden border-2 my-1': isEditable,
},
{
'p-4 lg:p-6 border-transparent my-0': !isEditable,
},
{
'nc-form-field-drag-handler border-transparent hover:(bg-gray-50) p-4 lg:p-6 ':
'nc-form-field-drag-handler border-transparent hover:(bg-gray-50) p-4 lg:p-6 cursor-pointer':
activeRow !== element.title && isEditable,
},
@ -782,7 +1009,7 @@ useEventListener(
<template v-if="activeRow === element.title">
<a-form-item class="my-0 !mb-2">
<a-textarea
:ref="focusLabel"
ref="focusLabel"
v-model:value="element.label"
:rows="1"
auto-size
@ -869,7 +1096,10 @@ useEventListener(
v-else
v-model="formState[element.title]"
class="nc-input truncate"
:class="`nc-form-input-${element.title.replaceAll(' ', '')}`"
:class="[
`nc-form-input-${element.title.replaceAll(' ', '')}`,
{ 'layout-list': element.meta.isList },
]"
:data-testid="`nc-form-input-${element.title.replaceAll(' ', '')}`"
:column="element"
:edit-enabled="true"
@ -880,19 +1110,55 @@ useEventListener(
</div>
<!-- Field Settings -->
<!-- eslint-disable vue/no-constant-condition -->
<div
v-if="activeRow === element.title && false"
class="nc-form-field-settings border-t border-gray-200 p-4 lg:p-6"
v-if="activeRow === element.title"
class="nc-form-field-settings border-t border-gray-200 p-4 lg:p-6 flex flex-col gap-3"
>
<!-- Todo: Show on conditions, options limit,... -->
<div class="flex items-start gap-3 px-3 py-2 border-1 border-gray-200 rounded-lg">
<!-- Layout -->
<div v-if="isSelectTypeCol(element.uidt)">
<div>Layout</div>
<a-radio-group
v-model:value="element.meta.isList"
class="nc-form-field-layout !mt-2"
@change="updateColMeta(element)"
>
<a-radio :value="false">{{ $t('general.dropdown') }}</a-radio>
<a-radio :value="true">{{ $t('general.list') }}</a-radio>
</a-radio-group>
</div>
<!-- Todo: Show on conditions,... -->
<!-- eslint-disable vue/no-constant-condition -->
<div v-if="false" class="flex items-start gap-3 px-3 py-2 border-1 border-gray-200 rounded-lg">
<a-switch v-e="['a:form-view:field:show-on-condition']" size="small" />
<div>
<div class="font-medium text-gray-800">{{ $t('labels.showOnConditions') }}</div>
<div class="text-gray-500">{{ $t('labels.showFieldOnConditionsMet') }}</div>
</div>
</div>
<!-- Limit options -->
<div v-if="isSelectTypeCol(element.uidt)" class="px-3 py-2 border-1 border-gray-200 rounded-lg">
<div class="flex items-center gap-3">
<a-switch
v-model:checked="element.meta.isLimitOption"
v-e="['a:form-view:field:limit-options']"
size="small"
@change="updateColMeta(element)"
/>
<div class="font-medium text-gray-800">{{ $t('labels.limitOptions') }}</div>
</div>
<div class="pl-10 mt-2 flex-1 max-w-[calc(100%_-_40px)]">
<div class="text-gray-500">{{ $t('labels.limitOptionsSubtext') }}.</div>
<div v-if="element.meta.isLimitOption" class="mt-5 max-w-[80%]">
<LazySmartsheetFormLimitOptions
v-model:model-value="element.meta.limitOptions"
:column="element"
@update:model-value="updateColMeta(element)"
></LazySmartsheetFormLimitOptions>
</div>
</div>
</div>
</div>
</div>
</template>
@ -944,8 +1210,8 @@ useEventListener(
</a-card>
</div>
</div>
<div v-if="isEditable" class="h-full flex-1 max-w-[384px] nc-form-left-drawer border-l border-gray-200">
<Splitpanes horizontal class="w-full nc-form-right-splitpane">
<div class="h-full flex-1 max-w-[384px] nc-form-left-drawer border-l border-gray-200">
<Splitpanes v-if="formViewData" horizontal class="w-full nc-form-right-splitpane">
<Pane min-size="30" size="50" class="nc-form-right-splitpane-item p-4 flex flex-col space-y-4 !min-h-200px">
<div class="flex flex-wrap justify-between items-center gap-2">
<div class="flex gap-3">
@ -958,6 +1224,7 @@ useEventListener(
</div>
<a-dropdown
v-if="isUIAllowed('fieldAdd')"
v-model:visible="showColumnDropdown"
:trigger="['click']"
overlay-class-name="nc-dropdown-form-add-column"
@ -1035,6 +1302,7 @@ useEventListener(
item-key="id"
ghost-class="nc-form-field-ghost"
:style="{ height: 'calc(100% - 64px)' }"
:disabled="isLocked || !isEditable"
@change="onMove($event)"
@start="drag = true"
@end="drag = false"
@ -1080,7 +1348,7 @@ useEventListener(
<span v-if="isRequired(field, field.required)" class="text-red-500 text-sm align-top">&nbsp;*</span>
</div>
</div>
<NcSwitch :checked="!!field.show" :disabled="field.required" />
<NcSwitch :checked="!!field.show" :disabled="field.required || isLocked || !isEditable" />
</div>
</div>
</template>
@ -1096,17 +1364,12 @@ useEventListener(
</template>
</div>
</Pane>
<Pane
v-if="isEditable && !isLocked && formViewData"
min-size="20"
size="50"
class="nc-form-right-splitpane-item !overflow-y-auto nc-form-scrollbar"
>
<Pane min-size="20" size="50" class="nc-form-right-splitpane-item !overflow-y-auto nc-form-scrollbar">
<div class="p-4 flex flex-col space-y-4 border-b border-gray-200">
<!-- Appearance Settings -->
<div class="text-base font-bold text-gray-900">{{ $t('labels.appearanceSettings') }}</div>
<div>
<div :class="isLocked || !isEditable ? 'pointer-events-none' : ''">
<div class="text-gray-800">{{ $t('labels.backgroundColor') }}</div>
<div class="flex justify-start">
<LazyGeneralColorPicker
@ -1149,8 +1412,11 @@ useEventListener(
size="small"
class="nc-form-hide-branding"
data-testid="nc-form-hide-branding"
:disabled="isLocked || !isEditable"
@change="
(value) => {
if (isLocked || !isEditable) return
(formViewData!.meta as Record<string,any>).hide_branding = value
updateView()
}
@ -1183,6 +1449,7 @@ useEventListener(
hide-details
class="nc-form-after-submit-msg !rounded-lg !px-3 !py-1"
data-testid="nc-form-after-submit-msg"
:disabled="isLocked || !isEditable"
@change="updateView"
/>
</div>
@ -1197,6 +1464,7 @@ useEventListener(
size="small"
class="nc-form-checkbox-submit-another-form"
data-testid="nc-form-checkbox-submit-another-form"
:disabled="isLocked || !isEditable"
@change="updateView"
/>
<span class="ml-4">{{ $t('msg.info.submitAnotherForm') }}</span>
@ -1210,6 +1478,7 @@ useEventListener(
size="small"
class="nc-form-checkbox-show-blank-form"
data-testid="nc-form-checkbox-show-blank-form"
:disabled="isLocked || !isEditable"
@change="updateView"
/>
@ -1223,6 +1492,7 @@ useEventListener(
size="small"
class="nc-form-checkbox-send-email"
data-testid="nc-form-checkbox-send-email"
:disabled="isLocked || !isEditable"
@change="onEmailChange"
/>
@ -1239,6 +1509,21 @@ useEventListener(
</div>
</div>
</template>
<div
v-if="user?.base_roles?.viewer || user?.base_roles?.commenter"
class="absolute inset-0 bg-black/40 z-500 grid place-items-center"
>
<div class="text-center bg-white px-6 py-8 rounded-xl max-w-lg">
<div class="text-2xl text-gray-800 font-bold">
{{ $t('msg.info.yourCurrentRoleIs') }}
'<span class="capitalize"> {{ Object.keys(user.base_roles)?.[0] ?? ProjectRoles.NO_ACCESS }}</span
>'.
</div>
<div class="text-sm text-gray-700 pt-6">
{{ $t('msg.info.pleaseRequestAccessForView', { viewName: 'form view' }) }}
</div>
</div>
</div>
</div>
</template>
@ -1250,7 +1535,13 @@ useEventListener(
}
.nc-input {
@apply appearance-none w-full !bg-white rounded-lg border-solid border-1 border-gray-200 focus-within:border-brand-500;
@apply appearance-none w-full;
&:not(.layout-list) {
@apply !bg-white rounded-lg border-solid border-1 border-gray-200 focus-within:border-brand-500;
}
&.layout-list {
@apply h-auto !pl-0 !py-1;
}
&.nc-cell-rating,
&.nc-cell-geodata {
@apply !py-1;
@ -1300,6 +1591,12 @@ useEventListener(
@apply mt-2;
}
}
:deep(.ant-form-item-has-error .ant-select:not(.ant-select-disabled) .ant-select-selector) {
border: none !important;
}
:deep(.ant-form-item-has-success .ant-select:not(.ant-select-disabled) .ant-select-selector) {
border: none !important;
}
:deep(.nc-cell-attachment) {
@apply p-0;
@ -1357,4 +1654,14 @@ useEventListener(
:deep(.nc-form-input-required + button):focus {
box-shadow: 0 0 0 2px #fff, 0 0 0 4px #3366ff;
}
.nc-form-field-layout {
@apply !flex !items-center w-full space-x-3;
:deep(.ant-radio-wrapper) {
@apply border-1 border-gray-200 rounded-lg !py-2 !px-3 basis-full !mr-0 !items-center;
.ant-radio {
@apply !top-0;
}
}
}
</style>

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

@ -232,7 +232,7 @@ async function onMoveStack(event: any, undo = false) {
const { fk_grp_col_id, meta: stack_meta } = kanbanMetaData.value
groupingFieldColOptions.value[oldIndex].order = newIndex
groupingFieldColOptions.value[newIndex].order = oldIndex
const stackMetaObj = JSON.parse(stack_meta as string) || {}
const stackMetaObj = parseProp(stack_meta) || {}
stackMetaObj[fk_grp_col_id as string] = groupingFieldColOptions.value
await updateKanbanMeta({
meta: stackMetaObj,

370
packages/nc-gui/components/smartsheet/calendar/Cell.vue

@ -0,0 +1,370 @@
<script lang="ts" setup>
import {
type BoolType,
type ColumnType,
type LookupType,
type RollupType,
dateFormats,
isCreatedOrLastModifiedByCol,
isCreatedOrLastModifiedTimeCol,
timeFormats,
} from 'nocodb-sdk'
import dayjs from 'dayjs'
import {
computed,
isBoolean,
isDate,
isDateTime,
isInt,
parseProp,
ref,
storeToRefs,
useAttachment,
useBase,
useMetas,
} from '#imports'
interface Props {
column: ColumnType
modelValue: any
bold?: BoolType
italic?: BoolType
underline?: BoolType
}
const props = defineProps<Props>()
const meta = inject(MetaInj)
const { t } = useI18n()
const { metas } = useMetas()
const column = toRef(props, 'column')
const { sqlUis } = storeToRefs(useBase())
const basesStore = useBases()
const { basesUser } = storeToRefs(basesStore)
const { isXcdbBase, isMssql, isMysql } = useBase()
const { getPossibleAttachmentSrc } = useAttachment()
const sqlUi = ref(column.value?.source_id ? sqlUis.value[column.value?.source_id] : Object.values(sqlUis.value)[0])
const abstractType = computed(() => column.value && sqlUi.value.getAbstractType(column.value))
const getCheckBoxValue = (modelValue: boolean | string | number | '0' | '1') => {
return !!modelValue && modelValue !== '0' && modelValue !== 0 && modelValue !== 'false'
}
const getMultiSelectValue = (modelValue: any, col: ColumnType): string => {
if (!modelValue) {
return ''
}
return modelValue
? Array.isArray(modelValue)
? modelValue.join(', ')
: modelValue.toString()
: isMysql(col.source_id)
? modelValue.toString().split(',').join(', ')
: modelValue.split(', ')
}
const getDateValue = (modelValue: string | null | number, col: ColumnType, isSystemCol?: boolean) => {
const dateFormat = !isSystemCol ? parseProp(col.meta)?.date_format ?? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm:ss'
if (!modelValue || !dayjs(modelValue).isValid()) {
return ''
} else {
return dayjs(/^\d+$/.test(String(modelValue)) ? +modelValue : modelValue).format(dateFormat)
}
}
const getYearValue = (modelValue: string | null) => {
if (!modelValue) {
return ''
} else if (!dayjs(modelValue).isValid()) {
return ''
} else {
return dayjs(modelValue.toString(), 'YYYY').format('YYYY')
}
}
const getDateTimeValue = (modelValue: string | null, col: ColumnType) => {
if (!modelValue || !dayjs(modelValue).isValid()) {
return ''
}
const dateFormat = parseProp(col?.meta)?.date_format ?? dateFormats[0]
const timeFormat = parseProp(col?.meta)?.time_format ?? timeFormats[0]
const dateTimeFormat = `${dateFormat} ${timeFormat}`
const isXcDB = isXcdbBase(col.source_id)
if (!isXcDB) {
return dayjs(/^\d+$/.test(modelValue) ? +modelValue : modelValue, dateTimeFormat).format(dateTimeFormat)
}
if (isMssql(col.source_id)) {
// e.g. 2023-04-29T11:41:53.000Z
return dayjs(modelValue, dateTimeFormat).format(dateTimeFormat)
} else {
return dayjs(modelValue).utc().local().format(dateTimeFormat)
}
}
const getTimeValue = (modelValue: string | null) => {
if (!modelValue) {
return ''
}
let dateTime = dayjs(modelValue)
if (!dateTime.isValid()) {
dateTime = dayjs(modelValue, 'HH:mm:ss')
}
if (!dateTime.isValid()) {
dateTime = dayjs(`1999-01-01 ${modelValue}`)
}
if (!dateTime.isValid()) {
return ''
}
return dateTime.format('HH:mm')
}
const getDurationValue = (modelValue: string | null, col: ColumnType) => {
const durationType = parseProp(col.meta)?.duration || 0
return convertMS2Duration(modelValue, durationType)
}
const getPercentValue = (modelValue: string | null) => {
return modelValue ? `${modelValue}%` : ''
}
const getCurrencyValue = (modelValue: string | number | null | undefined, col: ColumnType): string => {
const currencyMeta = {
currency_locale: 'en-US',
currency_code: 'USD',
...parseProp(col.meta),
}
try {
if (modelValue === null || modelValue === undefined || isNaN(modelValue)) {
return modelValue === null || modelValue === undefined ? '' : (modelValue as string)
}
return new Intl.NumberFormat(currencyMeta.currency_locale || 'en-US', {
style: 'currency',
currency: currencyMeta.currency_code || 'USD',
}).format(+modelValue)
} catch (e) {
return modelValue as string
}
}
const getUserValue = (modelValue: string | string[] | null | Array<any>) => {
if (!modelValue) {
return ''
}
const baseUsers = meta?.value.base_id ? basesUser.value.get(meta?.value.base_id) || [] : []
if (typeof modelValue === 'string') {
const idsOrMails = modelValue.split(',')
return idsOrMails
.map((idOrMail) => {
const user = baseUsers.find((u) => u.id === idOrMail || u.email === idOrMail)
return user ? user.display_name || user.email : idOrMail.id
})
.join(', ')
} else {
if (Array.isArray(modelValue)) {
return modelValue
.map((idOrMail) => {
const user = baseUsers.find((u) => u.id === idOrMail.id || u.email === idOrMail.email)
return user ? user.display_name || user.email : idOrMail.id
})
.join(', ')
} else {
return modelValue ? modelValue.display_name || modelValue.email : ''
}
}
}
const getDecimalValue = (modelValue: string | null | number, col: ColumnType) => {
if (!modelValue || isNaN(Number(modelValue))) {
return ''
}
const columnMeta = parseProp(col.meta)
return Number(modelValue).toFixed(columnMeta?.precision ?? 1)
}
const getIntValue = (modelValue: string | null | number) => {
if (!modelValue || isNaN(Number(modelValue))) {
return ''
}
return Number(modelValue) as unknown as string
}
const getTextAreaValue = (modelValue: string | null, col: ColumnType) => {
const isRichMode = typeof col.meta === 'string' ? JSON.parse(col.meta).richMode : col.meta?.richMode
if (isRichMode) {
return modelValue?.replace(/[*_~\[\]]|<\/?[^>]+(>|$)/g, '') || ''
}
return modelValue || ''
}
const getRollupValue = (modelValue: string | null | number, col: ColumnType) => {
const colOptions = col.colOptions as RollupType
const fns = ['count', 'avg', 'sum', 'countDistinct', 'sumDistinct', 'avgDistinct']
if (fns.includes(colOptions.rollup_function!)) {
return modelValue as string
} else {
const relationColumnOptions = colOptions.fk_relation_column_id
? meta?.value.columns?.find((c) => c.id === colOptions.fk_relation_column_id)?.colOptions
: null
const relatedTableMeta =
relationColumnOptions?.fk_related_model_id && metas.value?.[relationColumnOptions.fk_related_model_id as string]
const childColumn = relatedTableMeta?.columns.find((c: ColumnType) => c.id === colOptions.fk_rollup_column_id)
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return parseValue(modelValue, childColumn) as string
}
}
const getLookupValue = (modelValue: string | null | number | Array<any>, col: ColumnType) => {
const colOptions = col.colOptions as LookupType
const relationColumnOptions = colOptions.fk_relation_column_id
? meta?.value.columns?.find((c) => c.id === colOptions.fk_relation_column_id)?.colOptions
: null
const relatedTableMeta =
relationColumnOptions?.fk_related_model_id && metas.value?.[relationColumnOptions.fk_related_model_id as string]
const childColumn = relatedTableMeta?.columns.find((c: ColumnType) => c.id === colOptions.fk_lookup_column_id) as
| ColumnType
| undefined
if (Array.isArray(modelValue)) {
return modelValue
.map((v) => {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return parseValue(v, childColumn!)
})
.join(', ')
}
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return parseValue(modelValue, childColumn!)
}
const getAttachmentValue = (modelValue: string | null | number | Array<any>) => {
if (Array.isArray(modelValue)) {
return modelValue.map((v) => `${v.title} (${getPossibleAttachmentSrc(v).join(', ')})`).join(', ')
}
return modelValue as string
}
const getLinksValue = (modelValue: string, col: ColumnType) => {
if (typeof col.meta === 'string') {
col.meta = JSON.parse(col.meta)
}
const parsedValue = +modelValue || 0
if (!parsedValue) {
return ''
} else if (parsedValue === 1) {
return `1 ${col?.meta?.singular || t('general.link')}`
} else {
return `${parsedValue} ${col?.meta?.plural || t('general.links')}`
}
}
const parseValue = (value: any, col: ColumnType): string => {
if (!col) {
return ''
}
if (isGeoData(col)) {
const [latitude, longitude] = ((value as string) || '').split(';')
return latitude && longitude ? `${latitude}; ${longitude}` : value
}
if (isTextArea(col)) {
return getTextAreaValue(value, col)
}
if (isBoolean(col, abstractType)) {
return getCheckBoxValue(value) ? 'Checked' : 'Unchecked'
}
if (isMultiSelect(col)) {
return getMultiSelectValue(value, col)
}
if (isDate(col, abstractType)) {
return getDateValue(value, col)
}
if (isYear(col, abstractType)) {
return getYearValue(value)
}
if (isDateTime(col, abstractType)) {
return getDateTimeValue(value, col)
}
if (isTime(col, abstractType)) {
return getTimeValue(value)
}
if (isDuration(col)) {
return getDurationValue(value, col)
}
if (isPercent(col)) {
return getPercentValue(value)
}
if (isCurrency(col)) {
return getCurrencyValue(value, col)
}
if (isUser(col)) {
return getUserValue(value)
}
if (isDecimal(col)) {
return getDecimalValue(value, col)
}
if (isInt(col, abstractType)) {
return getIntValue(value)
}
if (isJSON(col)) {
return JSON.stringify(value, null, 2)
}
if (isRollup(col)) {
return getRollupValue(value, col)
}
if (isLookup(col)) {
return getLookupValue(value, col)
}
if (isCreatedOrLastModifiedTimeCol(col)) {
return getDateValue(value, col, true)
}
if (isCreatedOrLastModifiedByCol(col)) {
return getUserValue(value)
}
if (isAttachment(col)) {
return getAttachmentValue(value)
}
if (isLink(col)) {
return getLinksValue(value, col)
}
return value as unknown as string
}
</script>
<template>
<span
:class="{
'font-bold': bold,
'italic': italic,
'underline': underline,
}"
data-testid="nc-calendar-cell"
>
{{ parseValue(modelValue, column) }}
</span>
</template>
<style lang="scss" scoped></style>

58
packages/nc-gui/components/smartsheet/calendar/DayView/DateField.vue

@ -1,7 +1,7 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import { UITypes, isVirtualCol } from 'nocodb-sdk'
import { type Row, computed, ref } from '#imports'
import type { ColumnType } from 'nocodb-sdk'
import { type Row, computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { isRowEmpty } from '~/utils'
const emit = defineEmits(['expand-record', 'new-record'])
@ -15,6 +15,22 @@ const { isUIAllowed } = useRoles()
const { selectedDate, formattedData, formattedSideBarData, calendarRange, updateRowProperty, displayField } =
useCalendarViewStoreOrThrow()
const fields = inject(FieldsInj, ref())
const { fields: _fields } = useViewColumnsOrThrow()
const getFieldStyle = (field: ColumnType) => {
const fi = _fields.value.find((f) => f.title === field.title)
return {
underline: fi.underline,
bold: fi.bold,
italic: fi.italic,
}
}
const fieldsWithoutDisplay = computed(() => fields.value.filter((f) => !isPrimary(f)))
// We loop through all the records and calculate the position of each record based on the range
// We only need to calculate the top, of the record since there is no overlap in the day view of date Field
const recordsAcrossAllRange = computed<Row[]>(() => {
@ -196,27 +212,23 @@ const dropEvent = (event: DragEvent) => {
@click="emit('expand-record', record)"
>
<template v-if="!isRowEmpty(record, displayField)">
<div
:class="{
'!mt-1.5 ml-1': displayField.uidt === UITypes.SingleLineText,
'!mt-1': displayField.uidt === UITypes.MultiSelect || displayField.uidt === UITypes.SingleSelect,
}"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(displayField!)"
v-model="record.row[displayField!.title!]"
:column="displayField"
:row="record"
/>
<LazySmartsheetCell
v-else
v-model="record.row[displayField!.title!]"
:column="displayField"
:edit-enabled="false"
:read-only="true"
/>
</div>
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField!).bold"
:column="displayField!"
:italic="getFieldStyle(displayField!).italic"
:underline="getFieldStyle(displayField!).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<LazySmartsheetCalendarCell
v-model="record.row[field!.title!]"
:bold="getFieldStyle(field).bold"
:column="field"
:italic="getFieldStyle(field).italic"
:underline="getFieldStyle(field).underline"
/>
</template>
</LazySmartsheetCalendarRecordCard>
</LazySmartsheetRow>

122
packages/nc-gui/components/smartsheet/calendar/DayView/DateTimeField.vue

@ -1,12 +1,13 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import { UITypes, isVirtualCol } from 'nocodb-sdk'
import { type Row, computed, ref } from '#imports'
import type { ColumnType } from 'nocodb-sdk'
import { type Row, computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emit = defineEmits(['expandRecord', 'new-record'])
const {
// activeCalendarView,
selectedDate,
selectedTime,
formattedData,
@ -24,6 +25,23 @@ const { isUIAllowed } = useRoles()
const meta = inject(MetaInj, ref())
const fields = inject(FieldsInj, ref())
const { fields: _fields } = useViewColumnsOrThrow()
const getFieldStyle = (field: ColumnType) => {
if (!_fields.value) return { underline: false, bold: false, italic: false }
const fi = _fields.value.find((f) => f.title === field.title)
return {
underline: fi?.underline,
bold: fi?.bold,
italic: fi?.italic,
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
const hours = computed(() => {
const hours: Array<dayjs.Dayjs> = []
const _selectedDate = dayjs(selectedDate.value)
@ -38,7 +56,7 @@ const recordsAcrossAllRange = computed<{
record: Row[]
count: {
[key: string]: {
id: string
id: string[]
overflow: boolean
overflowCount: number
}
@ -149,7 +167,7 @@ const recordsAcrossAllRange = computed<{
style.display = 'none'
overlaps[timeKey].overflowCount += 1
}
_startDate = _startDate.add(15, 'minutes')
_startDate = _startDate.add(1, 'minutes')
}
// This property is used to determine which side the record should be rounded. It can be top, bottom, both or none
@ -187,16 +205,21 @@ const recordsAcrossAllRange = computed<{
const id = generateRandomNumber()
const startDate = dayjs(record.row[fromCol.title!])
const endDate = dayjs(record.row[fromCol.title!]).add(15, 'minutes')
let endDate = dayjs(record.row[fromCol.title!]).add(1, 'hour')
if (endDate.isAfter(scheduleEnd, 'minutes')) {
endDate = scheduleEnd
}
const startHour = startDate.hour()
let style: Partial<CSSStyleDeclaration> = {}
let _startDate = startDate.clone()
// We loop through every 15 minutes between the start and end date and keep track of the number of records that overlap at a given time
// We loop through every minute between the start and end date and keep track of the number of records that overlap at a given time
while (_startDate.isBefore(endDate)) {
const timeKey = _startDate.startOf('hour').format('HH:mm')
const timeKey = _startDate.format('HH:mm')
if (!overlaps[timeKey]) {
overlaps[timeKey] = {
@ -216,15 +239,20 @@ const recordsAcrossAllRange = computed<{
display: 'none',
}
}
_startDate = _startDate.add(15, 'minutes')
_startDate = _startDate.add(1, 'minute')
}
const topInPixels = (startDate.hour() + startDate.startOf('hour').minute() / 60) * 80
// The top of the record is calculated based on the start hour
// Update such that it is also based on Minutes
const minutes = startDate.minute() + startDate.hour() * 60
const updatedTopInPixels = (minutes * 80) / 60
// A minimum height of 80px is set for each record
const heightInPixels = Math.max((endDate.diff(startDate, 'minute') / 60) * 80, perRecordHeight)
const finalTopInPixels = topInPixels + startHour * 2
const finalTopInPixels = updatedTopInPixels + startHour * 2
style = {
...style,
@ -314,8 +342,9 @@ const calculateNewRow = (event: MouseEvent) => {
// It can be between 0 and 23 (inclusive)
const hour = Math.max(Math.floor(percentY * 23), 0)
const minutes = Math.min(Math.max(Math.round(Math.floor((percentY * 23 - hour) * 60) / 15) * 15, 0), 60)
// We calculate the new startDate by adding the hour to the start of the selected date
const newStartDate = dayjs(selectedDate.value).startOf('day').add(hour, 'hour')
const newStartDate = dayjs(selectedDate.value).startOf('day').add(hour, 'hour').add(minutes, 'minute')
if (!newStartDate || !fromCol) return { newRow: null, updateProperty: [] }
let endDate
@ -552,6 +581,35 @@ const dragStart = (event: MouseEvent, record: Row) => {
document.addEventListener('mouseup', onMouseUp)
}
const isOverflowAcrossHourRange = (hour: dayjs.Dayjs) => {
let startOfHour = hour.startOf('hour')
const endOfHour = hour.endOf('hour')
const ids: Array<string> = []
let isOverflow = false
let overflowCount = 0
while (startOfHour.isBefore(endOfHour, 'minute')) {
const hourKey = startOfHour.format('HH:mm')
if (recordsAcrossAllRange.value?.count?.[hourKey]?.overflow) {
isOverflow = true
recordsAcrossAllRange.value?.count?.[hourKey]?.id.forEach((id) => {
if (!ids.includes(id)) {
ids.push(id)
overflowCount += 1
}
})
}
startOfHour = startOfHour.add(1, 'minute')
}
overflowCount = overflowCount > 8 ? overflowCount - 8 : 0
return { isOverflow, overflowCount }
}
const viewMore = (hour: dayjs.Dayjs) => {
sideBarFilterOption.value = 'selectedHours'
selectedTime.value = hour
@ -662,7 +720,7 @@ const viewMore = (hour: dayjs.Dayjs) => {
</NcButton>
<NcButton
v-if="recordsAcrossAllRange?.count?.[hour.format('HH:mm')]?.overflow"
v-if="isOverflowAcrossHourRange(hour).isOverflow"
class="!absolute bottom-2 text-center w-15 mx-auto inset-x-0 z-3 text-gray-500"
size="xxsmall"
type="secondary"
@ -670,7 +728,7 @@ const viewMore = (hour: dayjs.Dayjs) => {
>
<span class="text-xs">
+
{{ recordsAcrossAllRange?.count[hour.format('HH:mm')]?.overflowCount }}
{{ isOverflowAcrossHourRange(hour).overflowCount }}
more
</span>
</NcButton>
@ -699,27 +757,23 @@ const viewMore = (hour: dayjs.Dayjs) => {
@resize-start="onResizeStart"
>
<template v-if="!isRowEmpty(record, displayField)">
<div
:class="{
'!mt-2': displayField!.uidt === UITypes.SingleLineText,
'!mt-1': displayField!.uidt === UITypes.MultiSelect || displayField!.uidt === UITypes.SingleSelect,
}"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(displayField!)"
v-model="record.row[displayField!.title!]"
:column="displayField"
:row="record"
/>
<LazySmartsheetCell
v-else
v-model="record.row[displayField!.title!]"
:column="displayField"
:edit-enabled="false"
:read-only="true"
/>
</div>
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField!).bold"
:column="displayField"
:italic="getFieldStyle(displayField!).italic"
:underline="getFieldStyle(displayField!).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<LazySmartsheetCalendarCell
v-model="record.row[field!.title!]"
:bold="getFieldStyle(field).bold"
:column="field"
:italic="getFieldStyle(field).italic"
:underline="getFieldStyle(field).underline"
/>
</template>
</LazySmartsheetCalendarVRecordCard>
</LazySmartsheetRow>

94
packages/nc-gui/components/smartsheet/calendar/MonthView.vue

@ -1,8 +1,7 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import { UITypes, isVirtualCol } from 'nocodb-sdk'
import type { Row } from '#imports'
import type { ColumnType } from 'nocodb-sdk'
import { type Row, computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emit = defineEmits(['new-record', 'expandRecord'])
@ -61,6 +60,23 @@ const resizeDirection = ref<'right' | 'left'>()
const resizeRecord = ref<Row>()
const fields = inject(FieldsInj, ref())
const { fields: _fields } = useViewColumnsOrThrow()
const getFieldStyle = (field: ColumnType | undefined) => {
if (!field) return { underline: false, bold: false, italic: false }
const fi = _fields.value?.find((f) => f.title === field.title)
return {
underline: fi?.underline,
bold: fi?.bold,
italic: fi?.italic,
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
const dates = computed(() => {
const startOfMonth = selectedMonth.value.startOf('month')
const endOfMonth = selectedMonth.value.endOf('month')
@ -331,8 +347,8 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean) => {
const percentY = (event.clientY - top - window.scrollY) / height
const percentX = (event.clientX - left - window.scrollX) / width
const fromCol = dragRecord.value.rowMeta.range?.fk_from_col
const toCol = dragRecord.value.rowMeta.range?.fk_to_col
const fromCol = dragRecord.value?.rowMeta.range?.fk_from_col
const toCol = dragRecord.value?.rowMeta.range?.fk_to_col
const week = Math.floor(percentY * dates.value.length)
const day = Math.floor(percentX * 7)
@ -345,7 +361,7 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean) => {
const newRow = {
...dragRecord.value,
row: {
...dragRecord.value.row,
...dragRecord.value?.row,
[fromCol!.title!]: dayjs(newStartDate).format('YYYY-MM-DD HH:mm:ssZ'),
},
}
@ -353,8 +369,8 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean) => {
const updateProperty = [fromCol!.title!]
if (toCol) {
const fromDate = dragRecord.value.row[fromCol!.title!] ? dayjs(dragRecord.value.row[fromCol!.title!]) : null
const toDate = dragRecord.value.row[toCol!.title!] ? dayjs(dragRecord.value.row[toCol!.title!]) : null
const fromDate = dragRecord.value?.row[fromCol!.title!] ? dayjs(dragRecord.value.row[fromCol!.title!]) : null
const toDate = dragRecord.value?.row[toCol!.title!] ? dayjs(dragRecord.value?.row[toCol!.title!]) : null
if (fromDate && toDate) {
endDate = dayjs(newStartDate).add(toDate.diff(fromDate, 'day'), 'day')
@ -366,7 +382,6 @@ const calculateNewRow = (event: MouseEvent, updateSideBar?: boolean) => {
endDate = newStartDate.clone()
}
dragRecord.value = undefined
newRow.row[toCol!.title!] = dayjs(endDate).format('YYYY-MM-DD HH:mm:ssZ')
updateProperty.push(toCol!.title!)
}
@ -440,7 +455,7 @@ const onResize = (event: MouseEvent) => {
[toCol!.title!]: dayjs(newEndDate).format('YYYY-MM-DD HH:mm:ssZ'),
},
}
} else if (resizeDirection.value === 'left') {
} else {
let newStartDate = dates.value[week] ? dayjs(dates.value[week][day]) : null
updateProperty = [fromCol!.title!]
@ -465,7 +480,9 @@ const onResize = (event: MouseEvent) => {
return pk === newPk ? newRow : r
})
useDebouncedRowUpdate(newRow, updateProperty, false)
if (newRow) {
useDebouncedRowUpdate(newRow, updateProperty, false)
}
}
const onResizeEnd = () => {
@ -480,7 +497,7 @@ const onResizeEnd = () => {
const onResizeStart = (direction: 'right' | 'left', event: MouseEvent, record: Row) => {
if (!isUIAllowed('dataEdit') || draggingId.value) return
selectedDate.value = null
// selectedDate.value = null
resizeInProgress.value = true
resizeDirection.value = direction
resizeRecord.value = record
@ -490,11 +507,10 @@ const onResizeStart = (direction: 'right' | 'left', event: MouseEvent, record: R
}
const stopDrag = (event: MouseEvent) => {
clearTimeout(dragTimeout.value)
if (!isUIAllowed('dataEdit') || !dragRecord.value || !isDragging.value) return
event.preventDefault()
clearTimeout(dragTimeout.value)
dragElement.value!.style.boxShadow = 'none'
const { newRow, updateProperty } = calculateNewRow(event, false)
@ -540,7 +556,7 @@ const dragStart = (event: MouseEvent, record: Row) => {
})
dragRecord.value = record
selectedDate.value = null
// selectedDate.value = null
isDragging.value = true
dragElement.value = target
@ -613,7 +629,7 @@ const isDateSelected = (date: dayjs.Dayjs) => {
<div
v-for="(day, index) in days"
:key="index"
class="text-center bg-gray-50 py-1 text-sm border-b-1 border-r-1 last:border-r-0 border-gray-200 font-semibold text-gray-500"
class="text-center bg-gray-50 py-1 text-sm border-b-1 border-r-1 last:border-r-0 border-gray-100 font-semibold text-gray-500"
>
{{ day }}
</div>
@ -637,7 +653,7 @@ const isDateSelected = (date: dayjs.Dayjs) => {
isDateSelected(day) || (focusedDate && dayjs(day).isSame(focusedDate, 'day')),
'!text-gray-400': !isDayInPagedMonth(day),
}"
class="text-right relative group last:border-r-0 text-sm h-full border-r-1 border-b-1 border-gray-200 font-medium hover:bg-gray-50 text-gray-800 bg-white"
class="text-right relative group last:border-r-0 text-sm h-full border-r-1 border-b-1 border-gray-100 font-medium hover:bg-gray-50 text-gray-800 bg-white"
data-testid="nc-calendar-month-day"
@click="selectDate(day)"
>
@ -769,30 +785,25 @@ const isDateSelected = (date: dayjs.Dayjs) => {
: false
"
@resize-start="onResizeStart"
@dblclick.stop="emit('expand-record', record)"
@dblclick.stop="emit('expandRecord', record)"
>
<template v-if="!isRowEmpty(record, displayField)">
<div
:class="{
'mt-1.4': displayField!.uidt === UITypes.SingleLineText,
'mt-1': displayField!.uidt === UITypes.MultiSelect || displayField!.uidt === UITypes.SingleSelect,
}"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(displayField!)"
v-model="record.row[displayField!.title!]"
:column="displayField"
:row="record"
/>
<LazySmartsheetCell
v-else
v-model="record.row[displayField!.title!]"
:column="displayField"
:edit-enabled="false"
:read-only="true"
/>
</div>
<LazySmartsheetCalendarCell
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
:italic="getFieldStyle(displayField).italic"
:underline="getFieldStyle(displayField).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<LazySmartsheetCalendarCell
v-model="record.row[field!.title!]"
:bold="getFieldStyle(field).bold"
:column="field"
:italic="getFieldStyle(field).italic"
:underline="getFieldStyle(field).underline"
/>
</template>
</LazySmartsheetCalendarRecordCard>
</LazySmartsheetRow>
@ -802,11 +813,6 @@ const isDateSelected = (date: dayjs.Dayjs) => {
</template>
<style lang="scss" scoped>
.hide {
transition: 0.01s;
transform: translateX(-9999px);
}
.prevent-select {
-webkit-user-select: none; /* Safari */
-ms-user-select: none; /* IE 10 and IE 11 */

19
packages/nc-gui/components/smartsheet/calendar/RecordCard.vue

@ -28,8 +28,8 @@ const emit = defineEmits(['resize-start'])
:class="{
'min-h-9': size === 'small',
'h-full': size === 'auto',
'rounded-l-lg ml-1': position === 'leftRounded',
'rounded-r-lg mr-1': position === 'rightRounded',
'rounded-l-lg': position === 'leftRounded',
'rounded-r-lg': position === 'rightRounded',
'rounded-lg mx-1': position === 'rounded',
'rounded-none': position === 'none',
'bg-maroon-50': color === 'maroon',
@ -53,10 +53,10 @@ const emit = defineEmits(['resize-start'])
'bg-pink-500': color === 'pink',
'bg-purple-500': color === 'purple',
}"
class="block h-full min-h-5 w-1 rounded"
class="w-1 min-h-5 bg-blue-500 rounded-x rounded-y-sm"
></div>
<div v-if="(position === 'leftRounded' || position === 'rounded') && resize" class="mt-0.1 h-7.1 absolute -left-4 resize">
<div v-if="(position === 'leftRounded' || position === 'rounded') && resize" class="mt-0.7 h-7.1 absolute -left-4 resize">
<NcButton
:class="{
'!block z-1 !border-brand-500': selected || hover,
@ -70,15 +70,20 @@ const emit = defineEmits(['resize-start'])
</NcButton>
</div>
<div class="overflow-hidden ml-2 h-8 absolute">
<div class="overflow-hidden items-center flex w-full ml-2 h-8">
<span v-if="position === 'rightRounded' || position === 'none'" class="mr-1"> .... </span>
<span class="text-sm !w-[80%] text-gray-800">
<span
:class="{
'pr-7': position === 'leftRounded',
}"
class="text-sm pr-3 mr-3 break-word space-x-2 whitespace-nowrap gap-2 overflow-hidden text-ellipsis w-full truncate text-gray-800"
>
<slot />
</span>
<span v-if="position === 'leftRounded' || position === 'none'" class="absolute my-0 right-5"> .... </span>
</div>
<div v-if="(position === 'rightRounded' || position === 'rounded') && resize" class="absolute mt-0.1 z-1 -right-4 resize">
<div v-if="(position === 'rightRounded' || position === 'rounded') && resize" class="absolute mt-0.3 z-1 -right-4 resize">
<NcButton
:class="{
'!block !border-brand-500': selected || hover,

27
packages/nc-gui/components/smartsheet/calendar/VRecordCard.vue

@ -26,14 +26,14 @@ const emit = defineEmits(['resize-start'])
>
<NcButton
:class="{
'!flex border-1 rounded-lg border-brand-500': selected || hover,
'!flex rounded-lg border-brand-500': selected || hover,
}"
class="!group-hover:(border-brand-500) !border-1 cursor-ns-resize"
class="!group-hover:(border-brand-500) !border-1 text-gray-400 cursor-ns-resize"
size="xsmall"
type="secondary"
@mousedown.stop="emit('resize-start', 'left', $event, record)"
>
<component :is="iconMap.drag" class="text-gray-400"></component>
<component :is="iconMap.drag" class="mt-0.5" />
</NcButton>
</div>
<div
@ -51,9 +51,9 @@ const emit = defineEmits(['resize-start'])
'group-hover:(border-brand-500)': resize,
'!border-brand-500 border-1': selected || hover,
}"
class="relative h-full ml-0.25 border-1 border-gray-50"
class="relative flex items-center h-full ml-0.25 border-1 border-transparent"
>
<div class="h-full absolute py-2">
<div class="h-full py-1">
<div
:class="{
'bg-maroon-500': color === 'maroon',
@ -63,17 +63,18 @@ const emit = defineEmits(['resize-start'])
'bg-pink-500': color === 'pink',
'bg-purple-500': color === 'purple',
}"
class="block h-full min-h-5 ml-1 w-1 rounded mr-2"
class="block h-full min-h-5 ml-1 w-1 rounded"
></div>
</div>
<div v-if="position === 'bottomRounded' || position === 'none'" class="ml-3">....</div>
<div class="ml-3 pr-3 text-ellipsis overflow-hidden w-full h-8 absolute">
<span class="text-sm text-gray-800">
<slot />
</span>
</div>
<span
class="pl-1 pr-1 text-sm h-[80%] text-gray-800 leading-7 space-x-2 break-all whitespace-normal truncate w-full overflow-y-hidden"
>
<slot />
</span>
<div v-if="position === 'topRounded' || position === 'none'" class="h-full pb-7 flex items-end ml-3">....</div>
</div>
<div
@ -84,12 +85,12 @@ const emit = defineEmits(['resize-start'])
:class="{
'!flex border-1 rounded-lg z-1 cursor-ns-resize border-brand-500': selected || hover,
}"
class="!group-hover:(border-brand-500) !border-1"
class="!group-hover:(border-brand-500) text-gray-400 !border-1"
size="xsmall"
type="secondary"
@mousedown.stop="emit('resize-start', 'right', $event, record)"
>
<component :is="iconMap.drag" class="text-gray-400"></component>
<component :is="iconMap.drag" class="mt-0.5" />
</NcButton>
</div>
</template>

67
packages/nc-gui/components/smartsheet/calendar/WeekView/DateField.vue

@ -1,8 +1,8 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import { UITypes, isVirtualCol } from 'nocodb-sdk'
import { type ColumnType } from 'nocodb-sdk'
import type { Row } from '~/lib'
import { ref } from '#imports'
import { computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emits = defineEmits(['expandRecord'])
@ -18,14 +18,30 @@ const { isUIAllowed } = useRoles()
const meta = inject(MetaInj, ref())
const fields = inject(FieldsInj, ref())
const { fields: _fields } = useViewColumnsOrThrow()
const getFieldStyle = (field: ColumnType | undefined) => {
const fi = _fields.value?.find((f) => f.title === field.title)
return {
underline: fi?.underline,
bold: fi?.bold,
italic: fi?.italic,
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
// Calculate the dates of the week
const weekDates = computed(() => {
const startOfWeek = new Date(selectedDateRange.value.start!)
const endOfWeek = new Date(selectedDateRange.value.end!)
let startOfWeek = dayjs(selectedDateRange.value.start)
const endOfWeek = dayjs(selectedDateRange.value.end)
const datesArray = []
while (startOfWeek.getTime() <= endOfWeek.getTime()) {
datesArray.push(new Date(startOfWeek))
startOfWeek.setDate(startOfWeek.getDate() + 1)
while (startOfWeek.isBefore(endOfWeek) || startOfWeek.isSame(endOfWeek, 'day')) {
datesArray.push(dayjs(startOfWeek))
startOfWeek = startOfWeek.add(1, 'day')
}
return datesArray
})
@ -567,27 +583,22 @@ const dropEvent = (event: DragEvent) => {
@resize-start="onResizeStart"
>
<template v-if="!isRowEmpty(record, displayField)">
<div
:class="{
'mt-2': displayField.uidt === UITypes.SingleLineText,
'mt-1': displayField.uidt === UITypes.MultiSelect || displayField.uidt === UITypes.SingleSelect,
}"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(displayField)"
v-model="record.row[displayField.title]"
:column="displayField"
:row="record"
/>
<LazySmartsheetCell
v-else
v-model="record.row[displayField.title]"
:column="displayField"
:edit-enabled="false"
:read-only="true"
/>
</div>
<LazySmartsheetCalendarCell
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
:italic="getFieldStyle(displayField).italic"
:underline="getFieldStyle(displayField).underline"
/>
</template>
<template v-for="(field, index) in fieldsWithoutDisplay" :key="index">
<LazySmartsheetCalendarCell
v-model="record.row[field!.title!]"
:bold="getFieldStyle(field).bold"
:column="field"
:italic="getFieldStyle(field).italic"
:underline="getFieldStyle(field).underline"
/>
</template>
</LazySmartsheetCalendarRecordCard>
</LazySmartsheetRow>

205
packages/nc-gui/components/smartsheet/calendar/WeekView/DateTimeField.vue

@ -1,8 +1,8 @@
<script lang="ts" setup>
import dayjs from 'dayjs'
import { UITypes, isVirtualCol } from 'nocodb-sdk'
import { type ColumnType } from 'nocodb-sdk'
import type { Row } from '~/lib'
import { computed, ref } from '#imports'
import { computed, isPrimary, ref, useViewColumnsOrThrow } from '#imports'
import { generateRandomNumber, isRowEmpty } from '~/utils'
const emits = defineEmits(['expandRecord'])
@ -30,6 +30,23 @@ const { isUIAllowed } = useRoles()
const meta = inject(MetaInj, ref())
const fields = inject(FieldsInj, ref())
const { fields: _fields } = useViewColumnsOrThrow()
const getFieldStyle = (field: ColumnType | undefined) => {
if (!field) return { underline: false, bold: false, italic: false }
const fi = _fields.value?.find((f) => f.title === field.title)
return {
underline: fi?.underline,
bold: fi?.bold,
italic: fi?.italic,
}
}
const fieldsWithoutDisplay = computed(() => fields.value?.filter((f) => !isPrimary(f)))
// Since it is a datetime Week view, we need to create a 2D array of dayjs objects to represent the hours in a day for each day in the week
const datesHours = computed(() => {
const datesHours: Array<Array<dayjs.Dayjs>> = []
@ -68,7 +85,11 @@ const recordsAcrossAllRange = computed<{
}
}
}>(() => {
if (!formattedData.value || !calendarRange.value || !container.value) return { records: [], count: {} }
if (!formattedData.value || !calendarRange.value || !container.value || !scrollContainer.value)
return {
records: [],
count: {},
}
const { scrollHeight } = scrollContainer.value
@ -78,7 +99,7 @@ const recordsAcrossAllRange = computed<{
const scheduleStart = dayjs(selectedDateRange.value.start).startOf('day')
const scheduleEnd = dayjs(selectedDateRange.value.end).endOf('day')
// We need to keep track of the overlaps for each day and hour in the week to calculate the width and left position of each record
// We need to keep track of the overlaps for each day and hour, minute in the week to calculate the width and left position of each record
// The first key is the date, the second key is the hour, and the value is an object containing the ids of the records that overlap
// The key is in the format YYYY-MM-DD and the hour is in the format HH:mm
const overlaps: {
@ -116,61 +137,83 @@ const recordsAcrossAllRange = computed<{
sortedFormattedData.forEach((record: Row) => {
if (!toCol && fromCol) {
// If there is no toColumn chosen in the range
const startDate = record.row[fromCol.title!] ? dayjs(record.row[fromCol.title!]) : null
if (!startDate) return
const ogStartDate = record.row[fromCol.title!] ? dayjs(record.row[fromCol.title!]) : null
if (!ogStartDate) return
// Hour Key currently is set as start of the hour
// TODO: Need to work on the granularity of the hour
const dateKey = startDate?.format('YYYY-MM-DD')
const hourKey = startDate?.startOf('hour').format('HH:mm')
let endDate = ogStartDate.clone().add(1, 'hour')
if (endDate.isAfter(scheduleEnd, 'minutes')) {
endDate = scheduleEnd
}
const id = record.rowMeta.id ?? generateRandomNumber()
let startDate = ogStartDate.clone()
let style: Partial<CSSStyleDeclaration> = {}
// If the dateKey and hourKey are valid, we add the id to the overlaps object
if (dateKey && hourKey) {
if (!overlaps[dateKey]) {
overlaps[dateKey] = {}
}
if (!overlaps[dateKey][hourKey]) {
overlaps[dateKey][hourKey] = {
id: [],
overflow: false,
overflowCount: 0,
while (startDate.isBefore(endDate, 'minutes')) {
const dateKey = startDate?.format('YYYY-MM-DD')
const hourKey = startDate?.format('HH:mm')
// If the dateKey and hourKey are valid, we add the id to the overlaps object
if (dateKey && hourKey) {
if (!overlaps[dateKey]) {
overlaps[dateKey] = {}
}
if (!overlaps[dateKey][hourKey]) {
overlaps[dateKey][hourKey] = {
id: [],
overflow: false,
overflowCount: 0,
}
}
overlaps[dateKey][hourKey].id.push(id)
}
overlaps[dateKey][hourKey].id.push(id)
}
// If the number of records that overlap in a single hour is more than 4, we hide the record and set the overflow flag to true
// We also keep track of the number of records that overflow
if (overlaps[dateKey][hourKey].id.length > 4) {
overlaps[dateKey][hourKey].overflow = true
style.display = 'none'
overlaps[dateKey][hourKey].overflowCount += 1
// If the number of records that overlap in a single hour is more than 4, we hide the record and set the overflow flag to true
// We also keep track of the number of records that overflow
if (overlaps[dateKey][hourKey].id.length > 4) {
overlaps[dateKey][hourKey].overflow = true
style.display = 'none'
overlaps[dateKey][hourKey].overflowCount += 1
}
// TODO: dayIndex is not calculated perfectly
// Should revisit this part in next iteration
let dayIndex = dayjs(dateKey).day() - 1
if (dayIndex === -1) {
dayIndex = 6
}
startDate = startDate.add(1, 'minute')
}
// TODO: dayIndex is not calculated perfectly
// Should revisit this part in next iteration
let dayIndex = dayjs(dateKey).day() - 1
let dayIndex = ogStartDate.day() - 1
if (dayIndex === -1) {
dayIndex = 6
}
const hourKey = ogStartDate.format('HH:mm')
// We calculate the index of the hour in the day and set the top and height of the record
const hourIndex = Math.min(
Math.max(
datesHours.value[dayIndex].findIndex((h) => h.startOf('hour').format('HH:mm') === hourKey),
datesHours.value[dayIndex]?.findIndex((h) => h.startOf('hour').format('HH:mm') === hourKey),
0,
),
23,
)
const minutes = ogStartDate.minute() + ogStartDate.hour() * 60
const topPx = (minutes * perHeight) / 60
style = {
...style,
top: `${hourIndex * perHeight - hourIndex - hourIndex * 0.15}px`,
height: `${perHeight - 2}px`,
top: `${topPx - hourIndex - hourIndex * 0.15 + 0.7}px`,
height: `${perHeight - 4}px`,
}
recordsToDisplay.push({
@ -332,14 +375,14 @@ const recordsAcrossAllRange = computed<{
overlapIndex = Math.max(overlapIndex, overlaps[dateKey][hours].id.indexOf(record.rowMeta.id!))
}
}
const spacing = 1
const spacing = 0.1
const widthPerRecord = (100 - spacing * (maxOverlaps - 1)) / maxOverlaps / 7
const leftPerRecord = widthPerRecord * overlapIndex
record.rowMeta.style = {
...record.rowMeta.style,
left: `calc(${dayIndex * perWidth}px + ${leftPerRecord}%)`,
width: `calc(${widthPerRecord}%)`,
left: `calc(${dayIndex * perWidth}px + ${leftPerRecord}% )`,
width: `calc(${widthPerRecord - 0.1}%)`,
}
return record
})
@ -483,7 +526,7 @@ const calculateNewRow = (
const { scrollHeight } = container.value
const percentX = (event.clientX - left - window.scrollX) / width
const percentY = (event.clientY - top + container.value.scrollTop) / scrollHeight
const percentY = (event.clientY - top + container.value.scrollTop - 36.8) / scrollHeight
const fromCol = dragRecord.value.rowMeta.range?.fk_from_col
const toCol = dragRecord.value.rowMeta.range?.fk_to_col
@ -493,7 +536,9 @@ const calculateNewRow = (
const day = Math.max(0, Math.min(6, Math.floor(percentX * 7)))
const hour = Math.max(0, Math.min(23, Math.floor(percentY * 24)))
const newStartDate = dayjs(selectedDateRange.value.start).add(day, 'day').add(hour, 'hour')
const minutes = Math.round(((percentY * 24 * 60) % 60) / 15) * 15
const newStartDate = dayjs(selectedDateRange.value.start).add(day, 'day').add(hour, 'hour').add(minutes, 'minute')
if (!newStartDate) return { newRow: null, updatedProperty: [] }
let endDate
@ -552,9 +597,9 @@ const onDrag = (event: MouseEvent) => {
const scrollBottomThreshold = 20
if (event.clientY > containerRect.bottom - scrollBottomThreshold) {
scrollContainer.value.scrollTop += 10
scrollContainer.value.scrollTop += 20
} else if (event.clientY < containerRect.top + scrollBottomThreshold) {
scrollContainer.value.scrollTop -= 10
scrollContainer.value.scrollTop -= 20
}
calculateNewRow(event)
@ -657,6 +702,36 @@ const viewMore = (hour: dayjs.Dayjs) => {
selectedTime.value = hour
showSideMenu.value = true
}
const isOverflowAcrossHourRange = (hour: dayjs.Dayjs) => {
let startOfHour = hour.startOf('hour')
const endOfHour = hour.endOf('hour')
const ids: Array<string> = []
let isOverflow = false
let overflowCount = 0
while (startOfHour.isBefore(endOfHour, 'minute')) {
const dateKey = startOfHour.format('YYYY-MM-DD')
const hourKey = startOfHour.format('HH:mm')
if (recordsAcrossAllRange.value?.count?.[dateKey]?.[hourKey]?.overflow) {
isOverflow = true
recordsAcrossAllRange.value?.count?.[dateKey]?.[hourKey]?.id.forEach((id) => {
if (!ids.includes(id)) {
ids.push(id)
overflowCount += 1
}
})
}
startOfHour = startOfHour.add(1, 'minute')
}
overflowCount = overflowCount > 4 ? overflowCount - 4 : 0
return { isOverflow, overflowCount }
}
</script>
<template>
@ -673,7 +748,7 @@ const viewMore = (hour: dayjs.Dayjs) => {
:class="{
'text-brand-500': date[0].isSame(dayjs(), 'date'),
}"
class="w-1/7 text-center text-sm text-gray-500 w-full py-1 border-gray-200 last:border-r-0 border-b-0 border-l-1 border-r-0 bg-gray-50"
class="w-1/7 text-center text-sm text-gray-500 w-full py-1 border-gray-100 last:border-r-0 border-b-0 border-l-1 border-r-0 bg-gray-50"
>
{{ dayjs(date[0]).format('DD ddd') }}
</div>
@ -688,14 +763,14 @@ const viewMore = (hour: dayjs.Dayjs) => {
</div>
</div>
<div ref="container" class="absolute ml-16 flex w-[calc(100%-64px)]">
<div v-for="(date, index) in datesHours" :key="index" class="h-full w-1/7" data-testid="nc-calendar-week-day">
<div v-for="(date, index) in datesHours" :key="index" class="h-full w-1/7 mt-7.1" data-testid="nc-calendar-week-day">
<div
v-for="(hour, hourIndex) in date"
:key="hourIndex"
:class="{
'border-1 !border-brand-500 bg-gray-50': hour.isSame(selectedTime, 'hour'),
}"
class="text-center relative first:mt-7.1 h-20 text-sm text-gray-500 w-full hover:bg-gray-50 py-1 border-transparent border-1 border-x-gray-200 border-t-gray-200"
class="text-center relative h-20 text-sm text-gray-500 w-full hover:bg-gray-50 py-1 border-transparent border-1 border-x-gray-100 border-t-gray-100"
data-testid="nc-calendar-week-hour"
@click="
() => {
@ -705,7 +780,7 @@ const viewMore = (hour: dayjs.Dayjs) => {
"
>
<NcButton
v-if="recordsAcrossAllRange?.count?.[hour.format('YYYY-MM-DD')]?.[hour.format('HH:mm')]?.overflow"
v-if="isOverflowAcrossHourRange(hour).isOverflow"
class="!absolute bottom-1 text-center w-15 ml-auto inset-x-0 z-3 text-gray-500"
size="xxsmall"
type="secondary"
@ -713,7 +788,7 @@ const viewMore = (hour: dayjs.Dayjs) => {
>
<span class="text-xs">
+
{{ recordsAcrossAllRange?.count[hour.format('YYYY-MM-DD')][hour.format('HH:mm')]?.overflowCount }}
{{ isOverflowAcrossHourRange(hour).overflowCount }}
more
</span>
</NcButton>
@ -746,27 +821,23 @@ const viewMore = (hour: dayjs.Dayjs) => {
@resize-start="onResizeStart"
>
<template v-if="!isRowEmpty(record, displayField)">
<div
:class="{
'!mt-2': displayField!.uidt === UITypes.SingleLineText,
'!mt-1': displayField!.uidt === UITypes.MultiSelect || displayField!.uidt === UITypes.SingleSelect,
}"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(displayField!)"
v-model="record.row[displayField!.title!]"
:column="displayField"
:row="record"
/>
<LazySmartsheetCell
v-else
v-model="record.row[displayField!.title!]"
:column="displayField"
:edit-enabled="false"
:read-only="true"
/>
</div>
<LazySmartsheetCalendarCell
v-if="!isRowEmpty(record, displayField!)"
v-model="record.row[displayField!.title!]"
:bold="getFieldStyle(displayField).bold"
:column="displayField"
:italic="getFieldStyle(displayField).italic"
:underline="getFieldStyle(displayField).underline"
/>
</template>
<template v-for="(field, id) in fieldsWithoutDisplay" :key="id">
<LazySmartsheetCalendarCell
v-model="record.row[field!.title!]"
:bold="getFieldStyle(field).bold"
:column="field"
:italic="getFieldStyle(field).italic"
:underline="getFieldStyle(field).underline"
/>
</template>
</LazySmartsheetCalendarVRecordCard>
</LazySmartsheetRow>

15
packages/nc-gui/components/smartsheet/calendar/index.vue

@ -41,6 +41,7 @@ provide(IsKanbanInj, ref(false))
provide(IsCalendarInj, ref(true))
const {
activeCalendarView,
calendarRange,
calDataType,
loadCalendarMeta,
@ -53,7 +54,6 @@ const {
pageDate,
showSideMenu,
selectedDateRange,
activeCalendarView,
paginateCalendarView,
} = useCalendarViewStoreOrThrow()
@ -140,6 +140,11 @@ const goToToday = () => {
start: dayjs().startOf('week'),
end: dayjs().endOf('week'),
}
document?.querySelector('.nc-calendar-today')?.scrollIntoView({
behavior: 'smooth',
block: 'center',
})
}
const headerText = computed(() => {
@ -181,8 +186,8 @@ const headerText = computed(() => {
</NcTooltip>
<NcDropdown v-model:visible="calendarRangeDropdown" :auto-close="false" :trigger="['click']">
<NcButton :class="{ '!w-24': activeCalendarView === 'year' }" class="w-45" full-width size="small" type="secondary">
<div class="flex w-full px-3 py-1 w-full items-center justify-between">
<NcButton :class="{ '!w-22': activeCalendarView === 'year' }" class="w-45" full-width size="small" type="secondary">
<div class="flex px-2 w-full items-center justify-between">
<span class="font-bold text-center text-brand-500" data-testid="nc-calendar-active-date">{{ headerText }}</span>
<component :is="iconMap.arrowDown" class="h-4 w-4 text-gray-700" />
</div>
@ -237,7 +242,9 @@ const headerText = computed(() => {
type="secondary"
@click="goToToday"
>
{{ $t('activity.goToToday') }}
<span class="text-gray-700">
{{ $t('activity.goToToday') }}
</span>
</NcButton>
<span class="opacity-0" data-testid="nc-active-calendar-view">
{{ activeCalendarView }}

293
packages/nc-gui/components/smartsheet/form/LimitOptions.vue

@ -0,0 +1,293 @@
<script setup lang="ts">
import Draggable from 'vuedraggable'
import tinycolor from 'tinycolor2'
import type { ColumnType, SelectOptionType, SelectOptionsType, UserFieldRecordType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import type { FormFieldsLimitOptionsType } from '~/lib'
import { MetaInj, iconMap } from '#imports'
const props = defineProps<{
modelValue: FormFieldsLimitOptionsType[]
column: ColumnType
}>()
const emit = defineEmits(['update:modelValue'])
const meta = inject(MetaInj)!
const column = toRef(props, 'column')
const basesStore = useBases()
const { basesUser } = storeToRefs(basesStore)
const baseUsers = computed(() => (meta.value.base_id ? basesUser.value.get(meta.value.base_id) || [] : []))
const searchQuery = ref('')
const drag = ref(false)
const vModel = computed({
get: () => {
let order = 1
const limitOptionsById =
(props.modelValue || []).reduce((o: Record<string, FormFieldsLimitOptionsType>, f: FormFieldsLimitOptionsType) => {
if (order < (f?.order ?? 0)) {
order = f.order
}
return {
...o,
[f.id]: f,
}
}, {} as Record<string, FormFieldsLimitOptionsType>) ?? {}
if (UITypes.User === column.value.uidt) {
const collaborators = ((baseUsers.value || []) as UserFieldRecordType[])
.filter((user) => !user?.deleted)
.map((user: any) => ({
id: user.id,
email: user.email,
display_name: user.display_name,
order: user.id && limitOptionsById[user.id] ? limitOptionsById[user.id]?.order ?? user.order : order++,
show: user.id && limitOptionsById[user.id] ? limitOptionsById[user.id]?.show : !(props.modelValue || []).length,
}))
.sort((a, b) => a.order - b.order)
if ((props.modelValue || []).length !== collaborators.length) {
emit(
'update:modelValue',
collaborators.map((o) => ({ id: o.id, order: o.order, show: o.show })),
)
}
return collaborators
} else if ([UITypes.SingleSelect, UITypes.MultiSelect].includes(column.value.uidt as UITypes)) {
const updateModelValue = ((column.value.colOptions as SelectOptionsType)?.options || [])
.map((c) => {
return {
...c,
order: c.id && limitOptionsById[c.id] ? limitOptionsById[c.id]?.order ?? c.order : order++,
show: c.id && limitOptionsById[c.id] ? limitOptionsById[c.id]?.show : !(props.modelValue || []).length,
} as SelectOptionType & { show?: boolean }
})
.sort((a, b) => {
if (a.order !== undefined && b.order !== undefined) {
return a.order - b.order
}
return 0
})
if ((props.modelValue || []).length !== ((column.value.colOptions as SelectOptionsType)?.options || []).length) {
emit(
'update:modelValue',
updateModelValue.map((o) => ({ id: o.id, order: o.order, show: o.show })),
)
}
return updateModelValue
}
return []
},
set: (val) => {
emit(
'update:modelValue',
val.map((o) => ({ id: o.id, order: o.order, show: o.show })),
)
},
})
async function onMove(_event: { moved: { newIndex: number; oldIndex: number; element: any } }) {
const {
moved: { newIndex = 0, oldIndex = 0, element },
} = _event
let nextOrder: number
// set new order value based on the new order of the items
if (!vModel.value.length || vModel.value.length === 1) {
nextOrder = 1
} else if (vModel.value.length - 1 === newIndex) {
// If moving to the end, set nextOrder greater than the maximum order in the list
nextOrder = Math.max(...vModel.value.map((item) => item?.order ?? 0)) + 1
} else if (newIndex === 0) {
// If moving to the beginning, set nextOrder smaller than the minimum order in the list
nextOrder = Math.min(...vModel.value.map((item) => item?.order ?? 0)) / 2
} else {
nextOrder =
(parseFloat(String(vModel.value[newIndex - 1]?.order ?? 0)) + parseFloat(String(vModel.value[newIndex + 1]?.order ?? 0))) /
2
}
const _nextOrder = !isNaN(Number(nextOrder)) ? nextOrder : oldIndex
element.order = _nextOrder
vModel.value = [...vModel.value]
}
</script>
<template>
<div class="w-full h-full nc-col-select-option nc-form-scrollbar">
<div v-if="vModel.length > 12">
<a-input
v-model:value="searchQuery"
class="!h-9 !px-3 !py-1 !rounded-lg mb-2"
:placeholder="`${$t('placeholder.searchOptions')}...`"
name="nc-form-field-limit-option-search-input"
data-testid="nc-form-field-limit-option-search-input"
>
<template #prefix>
<GeneralIcon icon="search" class="mr-2 h-4 w-4 text-gray-500 group-hover:text-black" />
</template>
<template #suffix>
<GeneralIcon
v-if="searchQuery.length > 0"
icon="close"
class="ml-2 h-4 w-4 text-gray-500 group-hover:text-black"
data-testid="nc-form-field-clear-search"
@click="searchQuery = ''"
/>
</template>
</a-input>
</div>
<Draggable
v-if="vModel.length"
:model-value="vModel"
item-key="id"
handle=".nc-child-draggable-icon"
ghost-class="nc-form-field-limit-option-ghost"
class="rounded-lg border-1 border-gray-200 !max-h-[224px] overflow-y-auto nc-form-scrollbar"
@change="onMove($event)"
@start="drag = true"
@end="drag = false"
>
<template #item="{ element }">
<div
v-if="
column.uidt === UITypes.User
? (element?.display_name?.trim() || element?.email)?.toLowerCase().includes(searchQuery.toLowerCase())
: element.title?.toLowerCase().includes(searchQuery.toLowerCase())
"
:key="element.id"
class="w-full h-10 px-2 py-1.5 flex flex-row items-center gap-3 border-b-1 last:border-none border-gray-200"
:class="[
`nc-form-field-${column.title?.replaceAll(' ', '')}-limit-option-${element.title?.replaceAll(' ', '')}`,
`${element.show ? 'hover:bg-gray-50' : 'bg-gray-100'}`,
]"
:data-testid="`nc-form-field-${column.title?.replaceAll(' ', '')}-limit-option-${element.title?.replaceAll(' ', '')}`"
>
<component :is="iconMap.drag" class="nc-child-draggable-icon flex-none cursor-move !h-4 !w-4 text-gray-600" />
<div
@click="
() => {
element.show = !element.show
vModel = [...vModel]
}
"
>
<component
:is="element.show ? iconMap.eye : iconMap.eyeSlash"
class="flex-none cursor-pointer !h-4 !w-4 text-gray-600"
/>
</div>
<a-tag v-if="column.uidt === UITypes.User" class="rounded-tag max-w-[calc(100%_-_70px)] !pl-0" color="'#ccc'">
<span
:style="{
'color': tinycolor.isReadable('#ccc' || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable('#ccc' || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
class="flex items-stretch gap-2"
>
<div>
<GeneralUserIcon
size="auto"
:name="element.display_name?.trim() ? element.display_name?.trim() : ''"
:email="element.email"
class="!text-[0.65rem]"
/>
</div>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ element.display_name?.trim() || element?.email }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ element.display_name?.trim() || element?.email }}
</span>
</NcTooltip>
</span>
</a-tag>
<a-tag v-else class="rounded-tag max-w-[calc(100%_-_70px)]" :color="element.color">
<span
:style="{
'color': tinycolor.isReadable(element.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(element.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ element.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ element.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</div>
</template>
<template v-if="!vModel.length" #footer
><div class="px-0.5 py-2 text-gray-500 text-center">{{ $t('title.noOptionsFound') }}</div></template
>
<template
v-else-if="
vModel.length &&
searchQuery &&
!vModel?.filter((element) => {
return column.uidt === UITypes.User
? (element?.display_name?.trim() || element?.email)?.toLowerCase().includes(searchQuery.toLowerCase())
: element.title?.toLowerCase().includes(searchQuery.toLowerCase())
})?.length
"
#footer
>
<div class="px-0.5 py-2 text-gray-500 text-center">{{ $t('title.noOptionsFound') }} with title `{{ searchQuery }}`</div>
</template>
</Draggable>
</div>
</template>
<style scoped lang="scss">
.nc-form-scrollbar {
@apply scrollbar scrollbar-thin scrollbar-thumb-gray-200 scrollbar-track-transparent;
&::-webkit-scrollbar-thumb:hover {
@apply !scrollbar-thumb-gray-300;
}
}
.rounded-tag {
@apply py-0 px-[12px] rounded-[12px];
}
:deep(.ant-tag) {
@apply rounded-tag my-[2px];
}
.nc-form-field-limit-option-ghost {
@apply bg-gray-50;
}
</style>

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

@ -50,6 +50,7 @@ const {
saveOrUpdate,
metaColumnById,
loadViewColumns,
toggleFieldStyles,
toggleFieldVisibility,
} = useViewColumnsOrThrow()
@ -396,7 +397,41 @@ useMenuCloseOnEsc(open)
</template>
<template #default>{{ field.title }}</template>
</NcTooltip>
<div v-if="activeView.type === ViewTypes.CALENDAR" class="flex mr-2">
<NcButton
:class="{
'!bg-gray-800 !text-white': field.bold,
}"
class="!rounded-r-none"
size="xxsmall"
type="secondary"
@click.stop="toggleFieldStyles(field, 'bold', !field.bold)"
>
<component :is="iconMap.bold" />
</NcButton>
<NcButton
:class="{
'!bg-gray-800 !text-white': field.italic,
}"
class="!rounded-x-none !border-x-0"
size="xxsmall"
type="secondary"
@click.stop="toggleFieldStyles(field, 'italic', !field.italic)"
>
<component :is="iconMap.italic" />
</NcButton>
<NcButton
:class="{
'!bg-gray-800 !text-white': field.underline,
}"
class="!rounded-l-none"
size="xxsmall"
type="secondary"
@click.stop="toggleFieldStyles(field, 'underline', !field.underline)"
>
<component :is="iconMap.underline" />
</NcButton>
</div>
<NcSwitch :checked="field.show" :disabled="field.isViewEssentialField" @change="$t('a:fields:show-hide')" />
</div>

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

@ -188,7 +188,7 @@ const linkedShortcuts = (e: KeyboardEvent) => {
try {
e.target?.previousElementSibling?.focus()
} catch (e) {}
} else if (e.key !== 'Tab' && e.key !== 'Shift' && e.key !== 'Enter' && e.key !== ' ') {
} else if (!expandedFormDlg.value && e.key !== 'Tab' && e.key !== 'Shift' && e.key !== 'Enter' && e.key !== ' ') {
try {
filterQueryRef.value?.focus()
} catch (e) {}
@ -200,6 +200,7 @@ onMounted(() => {
})
onUnmounted(() => {
childrenListPagination.query = ''
window.removeEventListener('keydown', linkedShortcuts)
})
</script>

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

@ -230,7 +230,7 @@ const linkedShortcuts = (e: KeyboardEvent) => {
try {
e.target?.previousElementSibling?.focus()
} catch (e) {}
} else if (e.key !== 'Tab' && e.key !== 'Shift' && e.key !== 'Enter' && e.key !== ' ') {
} else if (!expandedFormDlg.value && e.key !== 'Tab' && e.key !== 'Shift' && e.key !== 'Enter' && e.key !== ' ') {
try {
filterQueryRef.value?.focus()
} catch (e) {}
@ -242,6 +242,7 @@ onMounted(() => {
})
onUnmounted(() => {
childrenExcludedListPagination.query = ''
window.removeEventListener('keydown', linkedShortcuts)
})
</script>

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

@ -211,7 +211,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
const { fk_grp_col_id, meta: stack_meta } = kanbanMetaData.value
stackMetaObj.value = stack_meta ? JSON.parse(stack_meta as string) : {}
stackMetaObj.value = parseProp(stack_meta) || {}
if (stackMetaObj.value && fk_grp_col_id && stackMetaObj.value[fk_grp_col_id]) {
// keep the existing order (index of the array) but update the values done outside kanban

32
packages/nc-gui/composables/useMultiSelect/convertCellData.ts

@ -1,6 +1,6 @@
import dayjs from 'dayjs'
import type { AttachmentType, ColumnType, LinkToAnotherRecordType, SelectOptionsType } from 'nocodb-sdk'
import { UITypes, populateUniqueFileName } from 'nocodb-sdk'
import { UITypes, getDateFormat, getDateTimeFormat, populateUniqueFileName } from 'nocodb-sdk'
import type { AppInfo } from '~/composables/useGlobal'
import { isBt, isMm, parseProp } from '#imports'
@ -55,30 +55,24 @@ export default function convertCellData(
if (strval === 'false' || strval === '0' || strval === '') return false
}
return null
case UITypes.Date: {
const parsedDate = dayjs(value, parseProp(column?.meta)?.date_format ?? 'YYYY-MM-DD')
if (!parsedDate.isValid()) {
if (isMultiple) {
return null
} else {
throw new Error('Not a valid date')
}
}
return parsedDate.format('YYYY-MM-DD')
}
case UITypes.Date:
case UITypes.DateTime: {
const parsedDateTime = dayjs(
value,
`${parseProp(column?.meta)?.date_format ?? 'YYYY-MM-DD'} ${parseProp(column?.meta)?.time_format ?? 'HH:mm'}`,
)
if (!parsedDateTime.isValid()) {
let parsedDateOrDateTime = dayjs(value, getDateTimeFormat(value))
if (!parsedDateOrDateTime.isValid()) {
parsedDateOrDateTime = dayjs(value, getDateFormat(value))
}
if (!parsedDateOrDateTime.isValid()) {
if (isMultiple) {
return null
} else {
throw new Error('Not a valid datetime value')
throw new Error(`Not a valid '${to}' value`)
}
}
return parsedDateTime.utc().format('YYYY-MM-DD HH:mm:ssZ')
return to === UITypes.Date
? parsedDateOrDateTime.format('YYYY-MM-DD')
: parsedDateOrDateTime.utc().format('YYYY-MM-DD HH:mm:ssZ')
}
case UITypes.Time: {
let parsedTime = dayjs(value)

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

@ -785,7 +785,7 @@ export function useMultiSelect(
if (columnObj.uidt === UITypes.LongText) {
if (rowObj.row[columnObj.title] === '<br />') {
rowObj.row[columnObj.title] = e.key
} else {
} else if (parseProp(columnObj.meta).richMode) {
rowObj.row[columnObj.title] = rowObj.row[columnObj.title] ? rowObj.row[columnObj.title] + e.key : e.key
}
} else {

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

@ -109,6 +109,7 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share
columns.value = viewMeta.model?.columns?.map((c) => ({
...c,
meta: { ...parseProp(fieldById[c.id].meta), ...parseProp(c.meta) },
description: fieldById[c.id].description,
}))

12
packages/nc-gui/composables/useViewColumns.ts

@ -1,8 +1,8 @@
import { ViewTypes, isHiddenCol, isSystemColumn } from 'nocodb-sdk'
import type { ColumnType, GridColumnReqType, GridColumnType, MapType, TableType, ViewType } from 'nocodb-sdk'
import { ViewTypes, isHiddenCol, isSystemColumn } from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue'
import { computed, ref, storeToRefs, useBase, useNuxtApp, useRoles, useUndoRedo, watch } from '#imports'
import type { Field } from '#imports'
import { computed, ref, storeToRefs, useBase, useNuxtApp, useRoles, useUndoRedo, watch } from '#imports'
const [useProvideViewColumns, useViewColumns] = useInjectionState(
(
@ -278,6 +278,13 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
saveOrUpdate(field, fieldIndex)
}
const toggleFieldStyles = (field: any, style: 'underline' | 'bold' | 'italic', status: boolean) => {
const fieldIndex = fields.value?.findIndex((f) => f.fk_column_id === field.fk_column_id)
if (!fieldIndex && fieldIndex !== 0) return
field[style] = status
saveOrUpdate(field, fieldIndex, true)
}
// reload view columns when active view changes
// or when columns changes(delete/add)
watch(
@ -351,6 +358,7 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
showSystemFields,
metaColumnById,
toggleFieldVisibility,
toggleFieldStyles,
isViewColumnsLoading,
updateGridViewColumn,
gridViewCols,

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

@ -297,6 +297,7 @@ export function useViewData(
fk_column_id: c.id,
fk_view_id: viewMeta.value?.id,
...(fieldById[c.id!] ? fieldById[c.id!] : {}),
meta: { ...parseProp(fieldById[c.id!]?.meta), ...parseProp(c.meta) }, // TODO: discuss with @pranav
order: (fieldById[c.id!] && fieldById[c.id!].order) || order++,
id: fieldById[c.id!] && fieldById[c.id!].id,
}))

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "الوصول مقيد بكلمة مرور",
"privateLink": "تتم مشاركة هذا العرض عبر رابط خاص",
"privateLinkAdditionalInfo": "يمكن للأشخاص الذين لديهم رابط خاص رؤية الخلايا المرئية فقط في طريقة العرض هذه",
"afterFormSubmitted": "بعد تقديم النموذج",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "الوصول للمشروع عبر",
"submitAnotherForm": "إظهار زر 'إرسال نموذج آخر'",
"showBlankForm": "إظهار نموذج فارغ بعد 5 ثوان",
"emailForm": "راسلني بالبريد عبر",
"showSysFields": "إظهار حقول النظام",
"filterAutoApply": "تطبيق تلقائي",
"showMessage": "اعرض هذه الرسالة",
"formDisplayMessage": "Display Message",
"viewNotShared": "لم تتم مشاركة العرض الحالي!",
"showAllViews": "عرض جميع المشاهدات المشتركة لهذا الجدول",
"collabView": "يمكن للمتعاونين الذين لديهم أذونات تحرير أو أعلى تغيير تكوين العرض.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "تصدير البيانات الوصفية للمشروع بنجاح",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "অস পসওযড সবদধ",
"privateLink": "এই ভিউটি একটিযকিগত লির মযমগ কর হয",
"privateLinkAdditionalInfo": "বযকিগত লিকযত লবল এই দষগিযমন দখত",
"afterFormSubmitted": "ফরম জমওযর পর",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "মযমস পরকলপ",
"submitAnotherForm": "অনয ফরম জমিন' বমটিন",
"showBlankForm": "5 সড পর একটি ফরম দন",
"emailForm": "আম ইমল করন",
"showSysFields": "সিম করগিন",
"filterAutoApply": "অটরযগ",
"showMessage": "এই বি",
"formDisplayMessage": "Display Message",
"viewNotShared": "বরতমন ভিউ ভগ কর হয!",
"showAllViews": "এই টির সমসত ভগ কর দরশন দন",
"collabView": "সমদন অনমতি উচচতর সহ সহযিউ কনফিশন পরিবরতন করত।",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "পরকলপ ম সফলভ রফতি কর",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Přepnout Mobilní režim",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Přístup je omezen heslem",
"privateLink": "Tento pohled je sdílen prostřednictvím soukromého odkazu",
"privateLinkAdditionalInfo": "Lidé se soukromým odkazem mohou vidět pouze buňky viditelné v tomto zobrazení.",
"afterFormSubmitted": "Po odeslání formuláře",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Přístup k projektu přes",
"submitAnotherForm": "Zobrazit tlačítko \"Odeslat další formulář",
"showBlankForm": "Zobrazení prázdného formuláře po 5 sekundách",
"emailForm": "Pošlete mi e-mail na adresu",
"showSysFields": "Zobrazit systémová pole",
"filterAutoApply": "Automatické použití",
"showMessage": "Zobrazit tuto zprávu",
"formDisplayMessage": "Display Message",
"viewNotShared": "Současný pohled není sdílený!",
"showAllViews": "Zobrazit všechna sdílená zobrazení této tabulky",
"collabView": "Spolupracovníci s oprávněním k úpravám nebo vyšším mohou měnit konfiguraci zobrazení.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Úspěšný export metadat projektu",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Skift Mobil Tilstand",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Adgang er adgangskode begrænset",
"privateLink": "Denne visning deles via et privat link",
"privateLinkAdditionalInfo": "Folk med privat link kan kun se celler synlige i denne opfattelse",
"afterFormSubmitted": "Efter formularen er indsendt",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Access Project Via.",
"submitAnotherForm": "Vis 'Indsend en anden formular' -knap",
"showBlankForm": "Vis en blank form efter 5 sekunder",
"emailForm": "E-mail mig på",
"showSysFields": "Vis systemfelter",
"filterAutoApply": "Auto Application",
"showMessage": "Vis denne besked",
"formDisplayMessage": "Display Message",
"viewNotShared": "Nuværende visning er ikke delt!",
"showAllViews": "Vis alle fælles visninger af denne tabel",
"collabView": "Samarbejdspartnere med redigeringstilladelser eller højere kan ændre visningskonfigurationen.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Project Metadata eksporteres med succes",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Mobilen Modus umschalten",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Zugriff ist Passwort-geschützt",
"privateLink": "Diese Ansicht wird durch einen persönlichen Link geteilt",
"privateLinkAdditionalInfo": "Personen mit einem persönlichen Link können nur Zellen sehen, die in dieser Ansicht angezeigt werden",
"afterFormSubmitted": "Nachdem das Formular übermittelt wurde",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Zugriff auf das Projekt via",
"submitAnotherForm": "Weiteres Formular übermitteln'-Button anzeigen",
"showBlankForm": "Ein leeres Formular nach 5 Sekunden anzeigen",
"emailForm": "E-Mail an mich unter",
"showSysFields": "Systemfelder anzeigen",
"filterAutoApply": "Automatisch anwenden",
"showMessage": "Diese Nachricht anzeigen",
"formDisplayMessage": "Display Message",
"viewNotShared": "Aktuelle Ansicht wird nicht geteilt!",
"showAllViews": "Alle geteilten Ansichten dieser Tabelle anzeigen",
"collabView": "Mitarbeitern mit Bearbeitungsberechtigung oder höher können die Ansichtenkonfiguration ändern",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Projektmetadaten erfolgreich exportiert",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -422,7 +427,8 @@
"setNull": "Set NULL",
"setDefault": "Set Default"
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here"
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -685,11 +691,14 @@
"selectField": "Select a field",
"selectFieldLabel": "Make changes to field properties by selecting a field from the list"
},
"appearanceSettings":"Appearance Settings",
"backgroundColor":"Background Color",
"hideNocodbBranding":"Hide NocoDB Branding",
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet":"Shows field only when conditions are met"
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit ptions",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
@ -999,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Looks like you haven’t generated any API tokens yet.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Fast track your projects by collaborating on them with your team!"
"inviteYourTeamLabel": "Fast track your projects by collaborating on them with your team!",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1107,7 +1117,7 @@
"tooLargeFieldEntity": "The field is too large to be converted to {entity}",
"roleRequired": "Role required",
"warning": {
"calendarNoFields": "Calendar view requires a date or date time field to be setup. Try setting up a calendar view after adding a date / date time field!",
"calendarNoFields": "Calendar view requires a date or date time field to be setup. Try setting up a calendar view after adding a date/ date time field!",
"kanbanNoFields": "Kanban view requires a single select field to be setup. Try setting up a kanban view after adding a single select field!",
"mapNoFields": "Map view requires a geo data field to be setup. Try setting up a map view after adding a geo data field!",
"dbValid": "Please make sure database you are trying to connect is valid! This operation can cause schema loss!!",
@ -1294,7 +1304,9 @@
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}"
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
@ -1382,7 +1394,7 @@
"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",
"fieldRequired": "{value} cannot be empty.",
"projectNotAccessible": "Base not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -192,13 +192,18 @@
"enter": "Enter",
"seconds": "Segundos",
"paste": "Pegar",
"restore": "Restaurar"
"restore": "Restaurar",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
"week": "Week",
"month": "Month",
"year": "Year",
"day": "Día",
"week": "Semana",
"month": "Mes",
"year": "Año",
"workspace": "Espacio de trabajo",
"workspaces": "Espacios de trabajo",
"project": "Proyecto",
@ -305,7 +310,7 @@
"isNotNull": "no es nulo"
},
"title": {
"sso": "Authentication (SSO)",
"sso": "Autenticación (SSO)",
"docs": "Documentos",
"forum": "Foro",
"parameter": "Parámetro",
@ -336,7 +341,7 @@
"virtualRelation": "Relación virtual",
"linkMore": "Enlace más",
"linkMoreRecords": "Vincular más registros",
"linkRecords": "Link Records",
"linkRecords": "Registros de Enlaces",
"downloadFile": "Descargar archivo",
"renameTable": "Renombrar tabla",
"renamingTable": "Renombrar tabla",
@ -403,7 +408,7 @@
"findRowByScanningCode": "Find row by scanning a QR or Barcode",
"tokenManagement": "Gestión de Token",
"addNewToken": "Añadir nuevo token",
"createNewToken": "Create new token",
"createNewToken": "Crear nuevo token",
"accountSettings": "Configuración de la cuenta",
"resetPasswordMenu": "Restablecer contraseña",
"tokens": "Tokens",
@ -421,80 +426,82 @@
"restrict": "Restringir",
"setNull": "Establecer NULL",
"setDefault": "Establecer por defecto"
}
},
"selectFieldsFromRightPannelToAddHere": "Selecciona los campos del panel derecho para añadirlos aquí",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
"save": "Save",
"cancel": "Cancel",
"metadataUrl": "Metadata URL",
"audience-entityId": "Audience/ Entity ID",
"redirectUrl": "Redirect URL",
"selectYear": "Seleccionar Año",
"save": "Guardar",
"cancel": "Cancelar",
"metadataUrl": "URL de metadatos",
"audience-entityId": "Audiencia/ Entidad ID",
"redirectUrl": "URL de redirección",
"oidc": "OpenID Connect (OIDC)",
"saml": "Security Assertion Markup Language (SAML)",
"newProvider": "New Provider",
"generalSettings": "General Settings",
"ssoSettings": "SSO Settings",
"organizeBy": "Organize by",
"previous": "Previous",
"nextMonth": "Next Month",
"previousMonth": "Previous Month",
"next": "Next",
"organiseBy": "Organise by",
"newProvider": "Nuevo proveedor",
"generalSettings": "Ajustes Generales",
"ssoSettings": "Ajustes SSO",
"organizeBy": "Organizar por",
"previous": "Anterior",
"nextMonth": "Mes siguiente",
"previousMonth": "Mes anterior",
"next": "Siguiente",
"organiseBy": "Organizar por",
"heading1": "Encabezado 1",
"heading2": "Encabezado 2",
"heading3": "Heading 3",
"bold": "Bold",
"italic": "Italic",
"underline": "Underline",
"strike": "Strike",
"taskList": "Task List",
"bulletList": "Bullet List",
"numberedList": "Numbered List",
"downloadData": "Download Data",
"blockQuote": "Block Quote",
"noToken": "No Token",
"tokenLimit": "Only one token per user is allowed",
"duplicateAttachment": "File with name {filename} already attached",
"heading3": "Encabezado 3",
"bold": "Negrita",
"italic": "Cursiva",
"underline": "Subrayado",
"strike": "Tachado",
"taskList": "Lista de Tareas",
"bulletList": "Lista con viñetas",
"numberedList": "Lista numerada",
"downloadData": "Descargar Datos",
"blockQuote": "Bloque de cita",
"noToken": "Sin Token",
"tokenLimit": "Sólo se permite un token por usuario",
"duplicateAttachment": "Archivo con el nombre {filename} ya adjuntado",
"viewIdColon": "VIEW ID: {viewId}",
"toAddress": "To Address",
"subject": "Subject",
"body": "Body",
"toAddress": "A Dirección",
"subject": "Asunto",
"body": "Cuerpo",
"commaSeparatedMobileNumber": "Comma separated Mobile #",
"headerName": "Header Name",
"icon": "Icon",
"max": "Max",
"enableRichText": "Enable Rich Text",
"headerName": "Nombre del encabezado",
"icon": "Icono",
"max": "Máximo",
"enableRichText": "Activar Texto Enriquecido",
"idColon": "Id:",
"copiedRecordURL": "Copied Record URL",
"copyRecordURL": "Copy Record URL",
"duplicateRecord": "Duplicate record",
"binaryEncodingFormat": "Binary encoding format",
"syntax": "Syntax",
"examples": "Examples",
"durationInfo": "A duration of time in minutes or seconds (e.g. 1:23).",
"addHeader": "Add Header",
"enterDefaultUrlOptional": "Enter default URL (Optional)",
"negative": "Negative",
"discard": "Discard",
"default": "Default",
"defaultNumberPercent": "Default Number (%)",
"durationFormat": "Duration Format",
"dateFormat": "Date Format",
"timeFormat": "Time Format",
"singularLabel": "Singular Label",
"pluralLabel": "Plural Label",
"selectDateField": "Select a date field",
"endDateField": "End date field",
"optional": "(Optional)",
"clickToMake": "Click to make",
"visibleForRole": "visible for role:",
"copiedRecordURL": "URL del registro copiado",
"copyRecordURL": "Copiar URL de registro",
"duplicateRecord": "Duplicar registro",
"binaryEncodingFormat": "Formato de codificación binaria",
"syntax": "Sintaxis",
"examples": "Ejemplos",
"durationInfo": "Una duración de tiempo en minutos o segundos (por ejemplo, 1:23).",
"addHeader": "Añadir Encabezado",
"enterDefaultUrlOptional": "Introdcir URL predeterminada (Opcional)",
"negative": "Negativo",
"discard": "Descartar",
"default": "Por defecto",
"defaultNumberPercent": "Número por defecto (%)",
"durationFormat": "Formato de la duración",
"dateFormat": "Formato de fecha",
"timeFormat": "Formato de hora",
"singularLabel": "Etiqueta Singular",
"pluralLabel": "Etiqueta Plural",
"selectDateField": "Seleccionar un campo de fecha",
"endDateField": "Campo fecha de fin",
"optional": "(Opcional)",
"clickToMake": "Pulsar para hacer",
"visibleForRole": "visible para el rol:",
"inUI": "in UI Dashboard",
"projectSettings": "Base Settings",
"clickToHide": "Click to hide",
"clickToDownload": "Click to download",
"forRole": "for role",
"clickToCopyViewID": "Click to copy View ID",
"projectSettings": "Ajustes básicos",
"clickToHide": "Clic para ocultar",
"clickToDownload": "Clic para descargar",
"forRole": "para el rol",
"clickToCopyViewID": "Clic para copiar View ID",
"viewMode": "Modo solo lectura",
"searchUsers": "Buscar usuarios",
"superAdmin": "Super Admin",
@ -528,9 +535,9 @@
"duplicateFormView": "Duplicar vista de formulario",
"createFormView": "Crear vista de formulario",
"duplicateKanbanView": "Duplicar vista Kanban",
"duplicateCalendarView": "Duplicate Calendar View",
"duplicateCalendarView": "Duplicar vista de calendario",
"createKanbanView": "Crear vista Kanban",
"createCalendarView": "Create Calendar View",
"createCalendarView": "Crear vista de calendario",
"viewName": "Nombre de la vista",
"viewLink": "Ver enlace",
"columnName": "Nombre de columna",
@ -683,18 +690,27 @@
"incompleteConfiguration": "Configuración incompleta",
"selectField": "Seleccione un campo",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Ajustes de apariencia",
"backgroundColor": "Color de Fondo",
"hideNocodbBranding": "Ocultar marca NocoDB",
"showOnConditions": "Mostrar en condiciones",
"showFieldOnConditionsMet": "Muestra el campo sólo cuando se cumplen las condiciones",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
"withEndDate": "with end date",
"calendar": "Calendar",
"viewSettings": "View settings",
"noRange": "La vista del calendario requiere un rango de fechas",
"goToToday": "Ir a Hoy",
"toggleSidebar": "Alternar Barra Lateral",
"addEndDate": "Añadir fecha final",
"withEndDate": "con fecha de fin",
"calendar": "Calendario",
"viewSettings": "Ver ajustes",
"googleOAuth": "Google OAuth",
"registerOIDC": "Register OIDC Identity Provider",
"registerSAML": "Register SAML Identity Provider",
"registerOIDC": "Registrar proveedor de identidad OIDC",
"registerSAML": "Registrar proveedor de identidad SAML",
"openInANewTab": "Abrir en una nueva pestaña",
"copyIFrameCode": "Copiar código IFrame",
"onCondition": "En Condición",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Activar el modo móvil",
"startCommenting": "¡Empieza a comentar!"
"startCommenting": "¡Empieza a comentar!",
"clearForm": "Limpiar formulario",
"addFieldFromFormView": "Añadir Campo",
"selectAllFields": "Seleccionar todos los campos"
},
"tooltip": {
"reachedSourceLimit": "Limitado a una única fuente de datos por el momento",
@ -952,7 +971,7 @@
"selectGroupField": "Seleccione un campo de agrupación",
"selectGroupFieldNotFound": "No se encuentra ningún campo de selección único. Por favor, cree uno primero.",
"selectGeoField": "Seleccione un campo de datos geográficos",
"notSelected": "-not selected-",
"notSelected": "-no seleccionado-",
"selectGeoFieldNotFound": "No se encuentra ningún campo de datos geográficos. Por favor, cree uno primero.",
"password": {
"enter": "Ingresa la contraseña",
@ -962,7 +981,7 @@
"confirm": "Confirmar nueva contraseña"
},
"selectAColumnForTheQRCodeValue": "Select a field for the QR code value",
"allowNegativeNumbers": "Allow negative numbers",
"allowNegativeNumbers": "Permitir números negativos",
"searchProjectTree": "Buscar tablas",
"searchFields": "Buscar campos",
"searchColumn": "Buscar columna {search}",
@ -973,7 +992,7 @@
"filterByEmail": "Filtrar por correo electrónico",
"filterQuery": "Filtrar consulta",
"selectField": "Seleccionar campo",
"precision": "Precision",
"precision": "Precisión",
"decimal1": "1.0",
"decimal2": "1.00",
"decimal3": "1.000",
@ -982,21 +1001,22 @@
"decimal6": "1.000000",
"decimal7": "1.0000000",
"decimal8": "1.00000000",
"value": "Value",
"key": "Key",
"value": "Valor",
"key": "Clave",
"createTable": "Create your First Table!",
"createTableLabel": "Create your first table effortlessly, from scratch, or by importing/connecting to an external database.",
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
"enterPassword": "Enter password",
"enterPassword": "Introducir la contraseña",
"bySigningUp": "By signing up, you agree to the",
"subscribeToOurWeeklyNewsletter": "Subscribe to our weekly newsletter",
"verifyingPassword": "Verifying Password",
"verifyingPassword": "Verificando contraseña",
"thisSharedViewIsProtected": "This shared view is protected",
"successfullySubmittedFormData": "Successfully submitted form data",
"formViewNotSupportedOnMobile": "Form view is not supported on mobile",
@ -1004,19 +1024,19 @@
"optimizedQueryDisabled": "Optimized query is disabled",
"optimizedQueryEnabled": "Optimized query is enabled",
"lookupNonBtWarning": "Lookup field is not supported for non-Belongs to relation",
"invalidTime": "Invalid Time",
"invalidTime": "Hora no válida",
"linkColumnClearNotSupportedYet": "You don't have any supported links for Lookup",
"recordCouldNotBeFound": "Record could not be found",
"invalidPhoneNumber": "Invalid phone number",
"pageSizeChanged": "Page size changed",
"errorLoadingData": "Error loading data",
"pageSizeChanged": "Tamaño de página modificado",
"errorLoadingData": "Error al cargar datos",
"webhookBodyMsg1": "Use context variable",
"webhookBodyMsg2": "body",
"webhookBodyMsg2": "cuerpo",
"webhookBodyMsg3": "to refer the record under consideration",
"formula": {
"hintStart": "Hint: Use {placeholder1} to reference fields, e.g: {placeholder2}. For more, please check out",
"hintEnd": "Formulas.",
"noSuggestedFormulaFound": "No suggested formula found",
"hintEnd": "Fórmulas.",
"noSuggestedFormulaFound": "Fórmula sugerida no encontrada",
"typeIsExpected": "{calleeName} requires a {type} at position {position}",
"numericTypeIsExpected": "Numeric type is expected",
"stringTypeIsExpected": "String type is expected",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Restricción mediante contraseña",
"privateLink": "Esta vista es compartida por link privado",
"privateLinkAdditionalInfo": "Las personas con el link privado podrán únicamente ver celdas visibles de esta vista",
"afterFormSubmitted": "Después de enviar el formulario",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Accede al proyecto a través de",
"submitAnotherForm": "Mostrar el botón 'Presentar otro formulario'",
"showBlankForm": "Muestra un formulario en blanco después de 5 segundos.",
"emailForm": "Envíame un correo electrónico a",
"showSysFields": "Mostrar campos del sistema",
"filterAutoApply": "Aplicar automáticamente",
"showMessage": "Mostrar este mensaje",
"formDisplayMessage": "Display Message",
"viewNotShared": "La vista actual no está compartida!",
"showAllViews": "Mostrar todas las vistas compartidas de esta tabla",
"collabView": "Los colaboradores con permisos de edición o superior pueden cambiar la configuración de la vista.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Metadatos del proyecto exportados con éxito.",

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

@ -192,7 +192,12 @@
"enter": "Sartu",
"seconds": "Seconds",
"paste": "Itsatsi",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"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",
"postFormSubmissionSettings": "Post Form Submission Settings",
"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",
"formDisplayMessage": "Display 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.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Project metadata exported successfully",

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

@ -192,7 +192,12 @@
"enter": "وارد کردن",
"seconds": "ثانیه ها",
"paste": "جای گذاری",
"restore": "بازیابی"
"restore": "بازیابی",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "تغییر وضعیت حالت موبایل",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "دسترسی با لزوم ورود کلمه عبور محدود شده",
"privateLink": "این نمایش از طریق لینک خصوصی به اشتراک گذاشته شده",
"privateLinkAdditionalInfo": "افراد با لینک خصوصی تنها میتوانند سلولهایی که در این نمایش قابل مشاهده است را ببینند",
"afterFormSubmitted": "بعد از ارسال فرم",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "دسترسی به پروژه از طریق",
"submitAnotherForm": "نمایش دکمه \"ارسال فرمی دیگر\"",
"showBlankForm": "نمایش فرم خالی پس از 5 ثانیه",
"emailForm": "به این آدرس پست الکترونیکی من پیام ارسال کنید",
"showSysFields": "نمایش فیلدهای سیستم",
"filterAutoApply": "اعمال خودکار",
"showMessage": "نمایش این پیام",
"formDisplayMessage": "Display Message",
"viewNotShared": "نمایش فعلی به اشتراک گذاشته نشده!",
"showAllViews": "مشاهده تمام نمایش های به اشتراک گذاشته شده از این جدول",
"collabView": "همکاران با دسترسی ویرایش یا فراتر میتوانند پیکربندی نمایش را تغییر دهند.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "فراداده پروژه با موفقیت خارج شد",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Pääsy on salasana rajoitettu",
"privateLink": "Tämä näkymä on jaettu yksityisen linkin kautta",
"privateLinkAdditionalInfo": "Ihmiset, joilla on oma linkki, voivat nähdä vain tässä näkymässä näkyviä soluja",
"afterFormSubmitted": "Lomakkeen jälkeen",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Access Project kautta",
"submitAnotherForm": "Näytä \"Lähetä toinen lomake\" -painike",
"showBlankForm": "Näytä tyhjä lomake 5 sekunnin kuluttua",
"emailForm": "Lähetä minulle sähköpostia",
"showSysFields": "Näytä järjestelmäkenttiä",
"filterAutoApply": "Auto Apply",
"showMessage": "Näytä tämä viesti",
"formDisplayMessage": "Display Message",
"viewNotShared": "Nykyistä näkymää ei ole jaettu!",
"showAllViews": "Näytä kaikki tämän taulukon yhteiset näkymät",
"collabView": "Yhteistyökumppanit, joissa on muokkausoikeudet tai uudempi, voivat muuttaa näkymäasetusta.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Project Metadata viedään onnistuneesti",

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

@ -192,7 +192,12 @@
"enter": "Entrée",
"seconds": "Secondes",
"paste": "Coller",
"restore": "Restaurer"
"restore": "Restaurer",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "(Dés-)activer le mode Mobile",
"startCommenting": "Commencez à commenter !"
"startCommenting": "Commencez à commenter !",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limité à une seule source de données pour le moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Cliquer pour copier l'ID du champ",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "L’accès est restreint par un mot de passe",
"privateLink": "Cette vue est partagée avec un lien privé",
"privateLinkAdditionalInfo": "Les personnes ayant le lien privé peuvent voir uniquement les cellules visibles de cette vue",
"afterFormSubmitted": "Après que le formulaire a été soumis",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Accéder au projet via",
"submitAnotherForm": "Afficher le bouton \"Soumettre un autre formulaire\"",
"showBlankForm": "Montrer un formulaire vierge après 5 secondes",
"emailForm": "Écrivez-moi à",
"showSysFields": "Afficher les champs système",
"filterAutoApply": "Appliquer automatiquement",
"showMessage": "Montrer ce message ",
"formDisplayMessage": "Display Message",
"viewNotShared": "La vue actuelle n'est pas partagée!",
"showAllViews": "Montrer toutes les vues partagées sur cette table",
"collabView": "Les collaborateurs avec des autorisations d'édition ou plus peuvent modifier la configuration de la vue.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Les métadonnées de projet sont exportées avec succès",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "הגישה היא מוגבלת בסיסמה",
"privateLink": "תצוגה זו משותפת דרך קישור פרטי",
"privateLinkAdditionalInfo": "אנשים עם קישור פרטי יכולים לראות רק תאים גלוי בתצוגה זו",
"afterFormSubmitted": "לאחר הטופס מוגשת",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "גישה לפרויקט דרך",
"submitAnotherForm": "הצג 'שלח עוד כפתור' טופס '",
"showBlankForm": "הצג טופס ריק לאחר 5 שניות",
"emailForm": "דואר אלקטרוני לי ב",
"showSysFields": "הצג שדות מערכת",
"filterAutoApply": "החל אוטומטי",
"showMessage": "הצג הודעה זו",
"formDisplayMessage": "Display Message",
"viewNotShared": "התצוגה הנוכחית אינה משותפת!",
"showAllViews": "הצג את כל הנופים המשותפים של השולחן הזה",
"collabView": "משתפי פעולה עם הרשאות עריכה או גבוה יותר יכולים לשנות את תצורת התצוגה.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "פרויקט Metadata מיוצא בהצלחה",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "एकस पसवरड परतिित ह",
"privateLink": "यह दय एक नििक कयम सि गय",
"privateLinkAdditionalInfo": "नििक वग कवल इस दय मिई दिख सकत",
"afterFormSubmitted": "फम कद परसत कि",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "कयम सट",
"submitAnotherForm": "एक और फम सबमिट कर' बटन दि",
"showBlankForm": "5 सड कद एक खम दि",
"emailForm": "म ई-मल कर",
"showSysFields": "सिटम फड दि",
"filterAutoApply": "ऑट कर",
"showMessage": "यह सश दि",
"formDisplayMessage": "Display Message",
"viewNotShared": "वरतमन दय स नह!",
"showAllViews": "इस ति सभिर दि",
"collabView": "सदन अनमति उचचतर कथ सहयय किगरशन क बदल सकत।",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "परिजन सफलतवक नित क गई",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Preklopi na način za mobilne uređaje",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Pristup je ograničen lozinkom",
"privateLink": "Ovaj prikaz se dijeli putem privatne veze",
"privateLinkAdditionalInfo": "Osobe s privatnom vezom mogu vidjeti samo ćelije vidljive u ovom pogledu",
"afterFormSubmitted": "Nakon podnošenja obrasca",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Projekt pristupa putem",
"submitAnotherForm": "Prikaži \"Pošalji još jedan obrazac\"",
"showBlankForm": "Pokažite prazan obrazac nakon 5 sekundi",
"emailForm": "E-mail me na",
"showSysFields": "Prikaži polja sustava",
"filterAutoApply": "Automatsko primjenjivanje",
"showMessage": "Pokažite ovu poruku",
"formDisplayMessage": "Display Message",
"viewNotShared": "Trenutni prikaz se ne dijeli!",
"showAllViews": "Prikaži sve zajedničke poglede na ovu tablicu",
"collabView": "Suradnici s uređivanjem dopuštenja ili više mogu promijeniti konfiguraciju prikaza.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Projektni metapodaci su uspješno izvozili",

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

@ -192,7 +192,12 @@
"enter": "Masuk",
"seconds": "Detik",
"paste": "Tempel",
"restore": "Pulihkan"
"restore": "Pulihkan",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Akses dibatasi kata sandi",
"privateLink": "Tampilan ini dibagikan melalui tautan pribadi",
"privateLinkAdditionalInfo": "Orang dengan tautan pribadi hanya dapat melihat sel yang terlihat dalam pandangan ini",
"afterFormSubmitted": "Setelah formulir dikirimkan",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "PROYEK AKSES VIA.",
"submitAnotherForm": "Tampilkan tombol 'Kirim formulir lain'",
"showBlankForm": "Tampilkan formulir kosong setelah 5 detik",
"emailForm": "E-mail saya di",
"showSysFields": "Tampilkan bidang sistem",
"filterAutoApply": "Terapkan secara otomatis",
"showMessage": "Tampilkan pesan ini",
"formDisplayMessage": "Display Message",
"viewNotShared": "Tampilan saat ini tidak dibagikan!",
"showAllViews": "Tampilkan semua tampilan bersama dari tabel ini",
"collabView": "Kolaborator dengan izin edit atau lebih tinggi dapat mengubah konfigurasi tampilan.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Metadata proyek berhasil diekspor",

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

@ -192,7 +192,12 @@
"enter": "Invio",
"seconds": "Secondi",
"paste": "Incolla",
"restore": "Ripristino"
"restore": "Ripristino",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Limita",
"setNull": "Imposta NULL",
"setDefault": "Imposta default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Configurazione incompleta",
"selectField": "Seleziona un campo",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Attiva/Disattiva Modalità Mobile",
"startCommenting": "Inizi a commentare!"
"startCommenting": "Inizi a commentare!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limitato a una sola sorgente dati per il momento",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Fare clic per copiare l'Id del campo",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "L'accesso è protetto da una password",
"privateLink": "Questa vista è condivisa tramite un collegamento privato",
"privateLinkAdditionalInfo": "Le persone con collegamento privato possono vedere solo le celle visibili in questa vista",
"afterFormSubmitted": "Dopo che il modulo è stato inviato",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Accedi al progetto tramite",
"submitAnotherForm": "Mostra \"Invia un altro modulo\"",
"showBlankForm": "Mostra un modulo vuoto dopo 5 secondi",
"emailForm": "Mandami un'e-mail a",
"showSysFields": "Mostra campi di sistema",
"filterAutoApply": "Auto Apply.",
"showMessage": "Mostra questo messaggio",
"formDisplayMessage": "Display Message",
"viewNotShared": "La vista corrente non è condivisa!",
"showAllViews": "Mostra tutte le viste condivise di questa tabella",
"collabView": "I collaboratori con autorizzazioni di modifica o superiore possono modificare la configurazione della vista",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "La modifica della chiave di sistema non è supportata",
"notAvailableAtTheMoment": "Non disponibile al momento",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Si prega di completare la configurazione di tutti i campi prima di salvare",
"somethingWentWrong": "Qualcosa è andato storto",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Metadati del progetto esportati con successo",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "アクセスするにはパスワードが必要です",
"privateLink": "このビューはプライベートリンクを介して共有されています",
"privateLinkAdditionalInfo": "プライベートリンクを持つ人々は、このビューで表示されているセルのみを見ることができます",
"afterFormSubmitted": "フォーム送信後の操作",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "プロジェクトへのアクセス: ",
"submitAnotherForm": "「他の回答を送信」ボタンを表示",
"showBlankForm": "5秒後に空白のフォームを表示",
"emailForm": "次のアドレスへメールを送る",
"showSysFields": "システムフィールドを表示",
"filterAutoApply": "自動適用",
"showMessage": "このメッセージを表示",
"formDisplayMessage": "Display Message",
"viewNotShared": "共有されているビューはありません!",
"showAllViews": "このテーブルのすべての共有されているビューを表示する",
"collabView": "編集権限を持つコラボレータは、ビュー構成を変更できます。",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "プロジェクトメタデータは正常にエクスポートされました",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "초",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "제한",
"setNull": "null 설정",
"setDefault": "기본값 설정"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "모바일 모드 전환",
"startCommenting": "댓글 달기"
"startCommenting": "댓글 달기",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "데이터 소스 제한에 도달했습니다.",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "클릭하여 필드 ID 복사",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "엑세스 비밀번호 제한",
"privateLink": "비공개 링크로 현재 뷰 공유",
"privateLinkAdditionalInfo": "비공개 링크가 있는 사용자는 현재 보기에서 표시되는 셀만 볼 수 있습니다.",
"afterFormSubmitted": "양식이 제출 된 후",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "API 옵션",
"submitAnotherForm": "다른 양식 제출",
"showBlankForm": "5 초 후에 빈 양식을 보여줍니다",
"emailForm": "이메일로 공유",
"showSysFields": "시스템 필드 표시",
"filterAutoApply": "자동 적용",
"showMessage": "아래 메시지 표시",
"formDisplayMessage": "Display Message",
"viewNotShared": "현재 뷰가 공유되지 않습니다!",
"showAllViews": "테이블의 공유된 모든 뷰 표시",
"collabView": "편집 권한 이상의 권한을 보유한 공동 작업자는 뷰 구성을 변경할 수 있습니다.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "프로젝트 메타 데이터를 성공적으로 내보냈습니다.",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Piekļuve ir ierobežota ar paroli",
"privateLink": "Šis skats ir koplietots izmantojot privātu saiti",
"privateLinkAdditionalInfo": "Cilvēkiar privātu saiti var redzēt tikai šūnas šajā skatā",
"afterFormSubmitted": "Pēc formas iesniegšanas",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Piekļūt projektam caur",
"submitAnotherForm": "Parādīt 'Iesniegt vēl vienu formu' pogu",
"showBlankForm": "Parādīt tukšu formu pēc 5 sekundēm",
"emailForm": "Nosūtīt epastu man uz",
"showSysFields": "Parādīt sistēmas laukus",
"filterAutoApply": "Automātiski pielietot",
"showMessage": "Parādīt šo ziņojumu",
"formDisplayMessage": "Display Message",
"viewNotShared": "Esošais skats nav koplietots!",
"showAllViews": "Parādīt visus šīs tabulas koplietotos skatus",
"collabView": "Līdzautori ar rediģēšanas vai augstākām atļaujām var mainīt šī skata konfigurāciju.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Projekta metadati eksportēti veiksmīgi",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Toegang is wachtwoord beperkt",
"privateLink": "Deze weergave wordt gedeeld via een privélink",
"privateLinkAdditionalInfo": "Mensen met privélink kunnen alleen cellen zien die zichtbaar zijn in deze weergave",
"afterFormSubmitted": "Nadat het formulier ingediend wordt",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Krijg toegang tot het project via",
"submitAnotherForm": "Toon 'Stuur een nieuwe inzending' in",
"showBlankForm": "Toon een leeg formulier na 5 seconden",
"emailForm": "E-mail me op",
"showSysFields": "Toon systeemvelden",
"filterAutoApply": "Automatisch toepassen",
"showMessage": "Toon dit bericht",
"formDisplayMessage": "Display Message",
"viewNotShared": "Huidige weergave is niet gedeeld!",
"showAllViews": "Toon alle gedeelde weergaven van deze tabel",
"collabView": "Collaborators met bewerkingsmachtigingen of hoger kunnen de weergaveconfiguratie wijzigen.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Project metadata met succes geëxporteerd",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Tilgang er passordbegrenset",
"privateLink": "Denne visningen deles via en privat lenke",
"privateLinkAdditionalInfo": "Personer med privat kobling kan bare se celler synlige i denne visningen",
"afterFormSubmitted": "Etter skjema er sendt inn",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Tilgang til prosjekt via",
"submitAnotherForm": "Vis 'Send inn en annen form' -knapp",
"showBlankForm": "Vis et tomt skjema etter 5 sekunder",
"emailForm": "E-post meg på",
"showSysFields": "Vis systemfelt",
"filterAutoApply": "Auto gjelder",
"showMessage": "Vis denne meldingen",
"formDisplayMessage": "Display Message",
"viewNotShared": "Nåværende visning er ikke delt!",
"showAllViews": "Vis alle felles syn på dette bordet",
"collabView": "Samarbeidspartnere med redigeringsrettigheter eller høyere kan endre visningskonfigurasjonen.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Prosjektmetadata eksporteres vellykket",

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

@ -192,7 +192,12 @@
"enter": "Wprowadź",
"seconds": "Sekundy",
"paste": "Wklej",
"restore": "Przywróć"
"restore": "Przywróć",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Ogranicz",
"setNull": "Ustaw NULL",
"setDefault": "Ustaw domyślne"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Niekompletna konfiguracja",
"selectField": "Wybierz pole",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "Otwórz w OpenStreetMap"
},
"toggleMobileMode": "Przełącz tryb mobilny",
"startCommenting": "Rozpocznij komentowanie"
"startCommenting": "Rozpocznij komentowanie",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Ograniczenie do jednego źródła danych w tej chwili",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Kliknij, aby skopiować Identyfikator Pola",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Dostęp jest ograniczony hasłem",
"privateLink": "Ten widok jest współdzielony przez prywatny link",
"privateLinkAdditionalInfo": "Ludzie z prywatnym ogniwem mogą widzieć tylko komórki widoczne w tym widoku",
"afterFormSubmitted": "Po złożeniu formularza",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Dostęp do projektu przez",
"submitAnotherForm": "Pokaż przycisk \"Prześlij inny formularz\"",
"showBlankForm": "Pokaż pustą formę po 5 sekundach",
"emailForm": "E-mail mnie",
"showSysFields": "Pokaż pola systemowe.",
"filterAutoApply": "Automatyczne zastosowanie",
"showMessage": "Pokaż tę wiadomość",
"formDisplayMessage": "Display Message",
"viewNotShared": "Aktualny widok nie jest udostępniany!",
"showAllViews": "Pokaż wszystkie wspólne widoki na tę tabelę",
"collabView": "Współpracownicy z uprawnieniami edycji lub wyższe mogą zmienić konfigurację widoku.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Edycja klucza systemowego nie jest obsługiwana",
"notAvailableAtTheMoment": "Obecnie niedostępne",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Proszę zakończyć konfigurację wszystkich pól przed zapisaniem",
"somethingWentWrong": "Coś poszło nie tak",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Pomyślnie wyeksportowano metadane projektu",

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

@ -35,7 +35,7 @@
"heatmap_chart": "Gráfico de mapa de calor",
"treemap_chart": "Gráfico em árvore",
"box_plot_chart": "Gráfico de caixas",
"candlestick_chart": "Candlestick Chart"
"candlestick_chart": "Gráfico castiçal"
}
},
"general": {
@ -65,7 +65,7 @@
"saving": "Gravando",
"cancel": "Cancelar",
"null": "Nulo",
"escape": "Escape",
"escape": "Sair",
"hex": "Hex",
"clear": "Limpar",
"slack": "Slack",
@ -75,39 +75,39 @@
"matterMost": "Mattermost",
"twilio": "Twilio",
"whatsappTwilio": "WhatsApp Twilio",
"quote": "Quote",
"quote": "Citar",
"submit": "Enviar",
"create": "Criar",
"createEntity": "Create {entity}",
"creating": "Creating",
"creatingEntity": "Creating {entity}",
"details": "Details",
"skip": "Skip",
"code": "Code",
"createEntity": "Criar {entity}",
"creating": "Criando",
"creatingEntity": "Criando {entity}",
"details": "Detalhes",
"skip": "Saltar",
"code": "Código",
"duplicate": "Duplicado",
"duplicating": "Duplicating",
"activate": "Activate",
"action": "Action",
"duplicating": "Duplicando",
"activate": "Ativar",
"action": "Ação",
"insert": "Inserir",
"delete": "Excluir",
"deleteEntity": "Delete {entity}",
"bulkInsert": "Bulk Insert",
"bulkDelete": "Bulk Delete",
"bulkUpdate": "Bulk Update",
"deleting": "Deleting",
"deleteEntity": "Eliminar {entity}",
"bulkInsert": "Inserção em massa",
"bulkDelete": "Excluir em massa",
"bulkUpdate": "Atualização em massa",
"deleting": "Apagando",
"update": "Atualizar",
"rename": "Renomear",
"reload": "recarregar",
"reset": "Redefinir",
"install": "Instalar",
"show": "Mostrar",
"access": "Access",
"visibility": "Visibility",
"access": "Acesso",
"visibility": "Visibilidade",
"hide": "Esconder",
"deprecated": "Deprecated",
"deprecated": "Descontinuado",
"showAll": "Mostre tudo",
"hideAll": "Esconda tudo",
"notFound": "Not found",
"notFound": "Não encontrado",
"showMore": "Mostre mais",
"showOptions": "Mostrar opções",
"hideOptions": "Ocultar opções",
@ -119,7 +119,7 @@
"signIn": "AUTENTIQUE-SE",
"signOut": "Sair",
"required": "Obrigatório",
"enableScanner": "Enable Scanner for filling",
"enableScanner": "Ativar scanner para preenchimento",
"preferred": "Preferido",
"mandatory": "Obrigatoriedade",
"loading": "Carregando ...",
@ -127,8 +127,8 @@
"upload": "Carregar",
"download": "Descarregar",
"default": "Predefinição",
"base": "Source",
"datasource": "Data Source",
"base": "Origem",
"datasource": "Origem dos dados",
"more": "Mais",
"less": "Menos",
"event": "Evento",
@ -136,7 +136,7 @@
"after": "Depois de",
"before": "Antes de",
"search": "Procurar",
"searchIn": "Search In",
"searchIn": "Pesquisar em",
"notification": "Notificação",
"reference": "Referência",
"function": "Função",
@ -157,25 +157,25 @@
"groupingField": "Campo de Agrupamento",
"insertAfter": "Inserir depois",
"insertBefore": "Inserir Antes",
"insertAbove": "Insert above",
"insertBelow": "Insert below",
"insertAbove": "Inserir acima",
"insertBelow": "Inserir abaixo",
"hideField": "Ocultar Campo",
"sortAsc": "Ordenar Ascendente",
"sortDesc": "Ordenar Descendente",
"move": "Move",
"geoDataField": "GeoData Field",
"type": "Type",
"name": "Name",
"changes": "Changes",
"new": "New",
"old": "Old",
"data": "Data",
"source": "Source",
"destination": "Destination",
"active": "Active",
"inactive": "Inactive",
"linked": "linked",
"finish": "Finish",
"move": "Mover",
"geoDataField": "Campo de dados geográficos",
"type": "Tipo",
"name": "Nome",
"changes": "Alterações",
"new": "Novo",
"old": "Antigo",
"data": "Dados",
"source": "Origem",
"destination": "Destino",
"active": "Ativo",
"inactive": "Inativo",
"linked": "vinculado",
"finish": "Concluir",
"min": "Min",
"max": "Máximo",
"avg": "Média",
@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Segundos",
"paste": "Colar",
"restore": "Restaurar"
"restore": "Restaurar",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -395,17 +400,17 @@
"quickImportExcel": "Quick Import - Excel",
"quickImportJSON": "Quick Import - JSON",
"jsonEditor": "JSON Editor",
"comingSoon": "Coming Soon",
"comingSoon": "Brevemente",
"advancedSettings": "Configurações avançadas",
"codeSnippet": "Código Snippet",
"keyboardShortcut": "Atalhos de teclado",
"generateRandomName": "Generate Random Name",
"generateRandomName": "Gerar nome aleatório",
"findRowByScanningCode": "Find row by scanning a QR or Barcode",
"tokenManagement": "Token Management",
"addNewToken": "Add new token",
"createNewToken": "Create new token",
"accountSettings": "Account Settings",
"resetPasswordMenu": "Reset Password",
"tokenManagement": "Gestão de tokens",
"addNewToken": "Adicionar novo token",
"createNewToken": "Criar novo token",
"accountSettings": "Configurações da conta",
"resetPasswordMenu": "Repor a palavra-passe",
"tokens": "Tokens",
"userManagement": "Gestão de utilizadores",
"accountManagement": "Gestão de contas",
@ -418,29 +423,31 @@
"links": {
"noAction": "Sem ação",
"cascade": "Cascata",
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
"restrict": "Restringir",
"setNull": "Definir NULL",
"setDefault": "Definir como padrão"
},
"selectFieldsFromRightPannelToAddHere": "Seleccione campos do painel direito para adicionar aqui",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
"selectYear": "Selecionar ano",
"save": "Guardar",
"cancel": "Cancelar",
"metadataUrl": "URL de metadados",
"audience-entityId": "Audience/ Entity ID",
"audience-entityId": "Público-alvo/Entidade ID",
"redirectUrl": "URL de redirecionamento",
"oidc": "OpenID Connect (OIDC)",
"oidc": "Ligação OpenID (OIDC)",
"saml": "Security Assertion Markup Language (SAML)",
"newProvider": "Novo provedor",
"generalSettings": "Configurações gerais",
"ssoSettings": "Configurações SSO",
"organizeBy": "Organize by",
"previous": "Previous",
"nextMonth": "Next Month",
"previousMonth": "Previous Month",
"next": "Next",
"organiseBy": "Organise by",
"organizeBy": "Organizar por",
"previous": "Anterior",
"nextMonth": "Próximo mês",
"previousMonth": "Mês anterior",
"next": "Próximo",
"organiseBy": "Organizar por",
"heading1": "Cabeçalho 1",
"heading2": "Cabeçalho 2",
"heading3": "Cabeçalho 3",
@ -452,36 +459,36 @@
"bulletList": "Lista com marcadores",
"numberedList": "Lista numerada",
"downloadData": "Transferir dados",
"blockQuote": "Block Quote",
"noToken": "No Token",
"blockQuote": "Bloco de citação",
"noToken": "Nenhum Token",
"tokenLimit": "Só é permitido um token por utilizador",
"duplicateAttachment": "Arquivo com o nome {filename} já está anexado",
"viewIdColon": "VIEW ID: {viewId}",
"toAddress": "To Address",
"subject": "Subject",
"viewIdColon": "ID DE VISUALIZAÇÃO: {viewId}",
"toAddress": "Para o endereço",
"subject": "Assunto",
"body": "Body",
"commaSeparatedMobileNumber": "Comma separated Mobile #",
"headerName": "Header Name",
"icon": "Icon",
"headerName": "Nome do cabeçalho",
"icon": "Ícone",
"max": "Max",
"enableRichText": "Enable Rich Text",
"enableRichText": "Ativar texto rico",
"idColon": "Id:",
"copiedRecordURL": "Copied Record URL",
"copyRecordURL": "Copy Record URL",
"duplicateRecord": "Duplicate record",
"binaryEncodingFormat": "Binary encoding format",
"syntax": "Syntax",
"examples": "Examples",
"durationInfo": "A duration of time in minutes or seconds (e.g. 1:23).",
"addHeader": "Add Header",
"enterDefaultUrlOptional": "Enter default URL (Optional)",
"negative": "Negative",
"discard": "Discard",
"default": "Default",
"defaultNumberPercent": "Default Number (%)",
"durationFormat": "Duration Format",
"dateFormat": "Date Format",
"timeFormat": "Time Format",
"duplicateRecord": "Duplicar registo",
"binaryEncodingFormat": "Formato de codificação binária",
"syntax": "Sintaxe",
"examples": "Exemplos",
"durationInfo": "Duração de tempo em minutos ou segundos (exp. 1:23).",
"addHeader": "Adicionar cabeçalho",
"enterDefaultUrlOptional": "Introduzir URL predefinido (opcional)",
"negative": "Negativo",
"discard": "Descartar",
"default": "Padrão",
"defaultNumberPercent": "Número padrão (%)",
"durationFormat": "Formato de duração",
"dateFormat": "Formato da data",
"timeFormat": "Formato da hora",
"singularLabel": "Singular Label",
"pluralLabel": "Plural Label",
"selectDateField": "Select a date field",
@ -530,7 +537,7 @@
"duplicateKanbanView": "Duplicate Kanban View",
"duplicateCalendarView": "Duplicate Calendar View",
"createKanbanView": "Create Kanban View",
"createCalendarView": "Create Calendar View",
"createCalendarView": "Criar visualização de calendário",
"viewName": "Visualizar nome",
"viewLink": "View link.",
"columnName": "Nome da coluna",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "O acesso está protegido por uma palavra-passe",
"privateLink": "Esta vista é partilhada através de uma ligação privada",
"privateLinkAdditionalInfo": "As pessoas com acesso à ligação privada só podem ver as células visíveis nesta vista",
"afterFormSubmitted": "Após o formulário é submetido",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Aceder ao Projecto por",
"submitAnotherForm": "Mostrar 'enviar outro formulário' botão",
"showBlankForm": "Mostre um formulário em branco após 5 segundos",
"emailForm": "E-mail para",
"showSysFields": "Mostrar campos do sistema",
"filterAutoApply": "Aplicar automaticamente",
"showMessage": "Mostre esta mensagem",
"formDisplayMessage": "Display Message",
"viewNotShared": "A visão atual não é compartilhada!",
"showAllViews": "Mostrar todas as vistas compartilhadas desta mesa",
"collabView": "Colaboradores com permissões de edição ou maiores podem alterar a configuração da visualização.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Metadados do projeto exportado com sucesso",

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

@ -1,28 +1,28 @@
{
"dashboards": {
"create_new_dashboard_project": "Create New Interface",
"connect_data_sources": "Connect data sources",
"create_new_dashboard_project": "Criar nova interface",
"connect_data_sources": "Conectar fontes de dados",
"alert": "Alert",
"alert-message": "No databases have been connected. Connect database bases to build interfaces. Skip this step and add databases from the base home page later.",
"select_database_projects_that_you_want_to_link_to_this_dashboard_projects": "Select Database Bases that you want to link to this Interface.",
"create_interface": "Create interface",
"select_database_projects_that_you_want_to_link_to_this_dashboard_projects": "Selecione as bases de dados que você deseja vincular a esta interface.",
"create_interface": "Criar interface",
"project_name": "Base Name",
"connect": "Connect",
"connect": "Conectar",
"buttonActionTypes": {
"open_external_url": "Open external link",
"delete_record": "Delete record",
"update_record": "Update record",
"open_layout": "Open layout"
"open_external_url": "Abrir link externo",
"delete_record": "Excluir registro",
"update_record": "Atualizar registro",
"open_layout": "Abrir layout"
},
"widgets": {
"static_text": "Text",
"chart": "Chart",
"table": "Table",
"image": "Image",
"static_text": "Texto",
"chart": "Gráfico",
"table": "Tabela",
"image": "Imagem",
"map": "Map",
"button": "Button",
"number": "Number",
"bar_chart": "Bar Chart",
"button": "Botão",
"number": "Número",
"bar_chart": "Gráfico de barras",
"line_chart": "Line Chart",
"area_chart": "Area Chart",
"pie_chart": "Pie Chart",
@ -39,7 +39,7 @@
}
},
"general": {
"quit": "Quit",
"quit": "Sair",
"home": "Início",
"load": "Carregar",
"open": "Abrir",
@ -47,7 +47,7 @@
"yes": "Sim",
"no": "Não",
"ok": "OK",
"back": "Back",
"back": "Voltar",
"and": "E",
"or": "Ou",
"add": "Adicionar",
@ -55,16 +55,16 @@
"link": "Link",
"links": "Links",
"remove": "Remover",
"import": "Import",
"logout": "Log Out",
"import": "Importar",
"logout": "Encerrar Sessão",
"empty": "Empty",
"changeIcon": "Change Icon",
"changeIcon": "Alterar Ícone",
"save": "Salvar",
"available": "Available",
"abort": "Abort",
"available": "Disponível",
"abort": "Abortar",
"saving": "Saving",
"cancel": "Cancelar",
"null": "Null",
"null": "Nulo",
"escape": "Escape",
"hex": "Hex",
"clear": "Clear",
@ -164,17 +164,17 @@
"sortDesc": "Ordenar Descendente",
"move": "Move",
"geoDataField": "Campo GeoData",
"type": "Type",
"name": "Name",
"changes": "Changes",
"new": "New",
"old": "Old",
"data": "Data",
"source": "Source",
"destination": "Destination",
"active": "Active",
"inactive": "Inactive",
"linked": "linked",
"type": "Tipo",
"name": "Nome",
"changes": "Mudanças",
"new": "Novo",
"old": "Antigo",
"data": "Dados",
"source": "Fonte",
"destination": "Destino",
"active": "Ativo",
"inactive": "Inativo",
"linked": "vinculado",
"finish": "Finish",
"min": "Min",
"max": "Max",
@ -190,15 +190,20 @@
"useSurveyMode": "Use Survey Mode",
"shift": "Shift",
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"seconds": "Segundos",
"paste": "Colar",
"restore": "Restaurar",
"replace": "Substituir",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
"week": "Week",
"month": "Month",
"year": "Year",
"day": "Dia",
"week": "Semana",
"month": "Mês",
"year": "Ano",
"workspace": "Workspace",
"workspaces": "Workspaces",
"project": "Projeto",
@ -217,7 +222,7 @@
"webhooks": "WebHooks.",
"view": "Visualizar",
"views": "Vizualizações",
"sidebar": "Sidebar",
"sidebar": "Barra lateral",
"viewType": {
"grid": "Grade",
"gallery": "Galeria",
@ -230,7 +235,7 @@
"users": "Usuários",
"role": "Função",
"roles": "Funções",
"developer": "Developer",
"developer": "Desenvolvedor",
"roleType": {
"owner": "Proprietário",
"creator": "Criador",
@ -238,7 +243,7 @@
"commenter": "Comentarista",
"viewer": "Visualizador",
"noaccess": "No Access",
"superAdmin": "Super Admin",
"superAdmin": "Super Administrador",
"orgLevelCreator": "Criador de Nível da Organização",
"orgLevelViewer": "Visualizador de nível da organização"
},
@ -250,7 +255,7 @@
"tall": "Tall",
"extra": "Extra"
},
"externalDb": "External Database"
"externalDb": "Banco de Dados externo"
},
"datatype": {
"ID": "ID",
@ -305,7 +310,7 @@
"isNotNull": "não é nulo"
},
"title": {
"sso": "Authentication (SSO)",
"sso": "Autenticação (SSO)",
"docs": "Docs",
"forum": "Forum",
"parameter": "Parameter",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Alternar o modo móvel",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "O acesso está protegido por uma senha",
"privateLink": "Esta vizualização é compartilhada através de uma conexão privada",
"privateLinkAdditionalInfo": "As pessoas com acesso a conexão privada só podem ver as células visíveis nesta vizualização",
"afterFormSubmitted": "Após o formulário é submetido",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Acesse o projeto via",
"submitAnotherForm": "Mostrar 'enviar outro formulário' botão",
"showBlankForm": "Mostre um formulário em branco após 5 segundos",
"emailForm": "E-mail para",
"showSysFields": "Mostrar campos do sistema",
"filterAutoApply": "Aplicar automaticamente",
"showMessage": "Mostre esta mensagem",
"formDisplayMessage": "Display Message",
"viewNotShared": "A visão atual não é compartilhada!",
"showAllViews": "Mostrar todas as vistas compartilhadas desta mesa",
"collabView": "Colaboradores com permissões de edição ou maiores podem alterar a configuração da visualização.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Metadados do projeto exportado com sucesso",

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

@ -192,7 +192,12 @@
"enter": "Вход",
"seconds": "Секунды",
"paste": "Вставить",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Установить в NULL",
"setDefault": "Установить по умолчанию"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Выбрать поле",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Переключить мобильный режим",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Доступ защищенный паролем",
"privateLink": "Это представление передано личной ссылкой.",
"privateLinkAdditionalInfo": "Люди с личной ссыкой могу видеть только ячейки видимые в этом представлении",
"afterFormSubmitted": "После отправки формы",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Доступ проекта через",
"submitAnotherForm": "Показать кнопку «Отправить другую форму»",
"showBlankForm": "Показать пустую форму через 5 секунд",
"emailForm": "Напишите мне на",
"showSysFields": "Показать системные поля",
"filterAutoApply": "Применять автоматически",
"showMessage": "Покажите это сообщение",
"formDisplayMessage": "Display Message",
"viewNotShared": "Текущим представлением не поделились",
"showAllViews": "Показать все общие представление этой таблицы",
"collabView": "Сотрудники с разрешениями редактирования или выше могут изменить конфигурацию представления",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Метаданные проекта успешно экспортированы",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Prístup je obmedzený heslom",
"privateLink": "Tento pohľad sa zdieľa prostredníctvom súkromného prepojenia",
"privateLinkAdditionalInfo": "Ľudia so súkromným prepojením môžu vidieť iba bunky viditeľné v tomto zobrazení",
"afterFormSubmitted": "Po odoslaní formulára",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Prístup k projektu cez",
"submitAnotherForm": "Zobrazenie tlačidla Odoslať ďalší formulár",
"showBlankForm": "Zobrazenie prázdneho formulára po 5 sekundách",
"emailForm": "Napíšte mi na e-mailovú adresu",
"showSysFields": "Zobrazenie systémových polí",
"filterAutoApply": "Automatická aplikácia",
"showMessage": "Zobraziť túto správu",
"formDisplayMessage": "Display Message",
"viewNotShared": "Súčasný pohľad nie je zdieľaný!",
"showAllViews": "Zobrazenie všetkých zdieľaných zobrazení tejto tabuľky",
"collabView": "Spolupracovníci s oprávneniami na úpravu alebo vyššími môžu zmeniť konfiguráciu zobrazenia.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Úspešný export metadát projektu",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Za dostop je potrebno geslo",
"privateLink": "Ta pogled je v skupni rabi prek zasebne povezave",
"privateLinkAdditionalInfo": "Ljudje z zasebno povezavo lahko vidijo le celice, ki so vidne v tem pogledu",
"afterFormSubmitted": "Po obrazec",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Dostopaj projekt prek",
"submitAnotherForm": "Pokaži gumb \"Pošljite gumb\"",
"showBlankForm": "Po 5 sekundah pokažite prazno obliko",
"emailForm": "Pošlji mi e-pošto",
"showSysFields": "Pokaži sistemska polja",
"filterAutoApply": "Auto Nanesite",
"showMessage": "Pokaži to sporočilo",
"formDisplayMessage": "Display Message",
"viewNotShared": "Trenutni pogled ni v skupni rabi!",
"showAllViews": "Pokaži vse skupne poglede na to tabelo",
"collabView": "Sodelavci z dovoljenji za urejanje ali višje lahko spremenijo konfiguracijo pogleda.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Projekt Metapodatki se je uspešno izvozil",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "Åtkomst är lösenordsbegränsad",
"privateLink": "Denna uppfattning delas via en privat länk",
"privateLinkAdditionalInfo": "Människor med privat länk kan bara se celler synliga i den här vyn",
"afterFormSubmitted": "Efter formuläret skickas in",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Åtkomstprojekt via",
"submitAnotherForm": "Visa \"Skicka en annan formulär\" -knapp",
"showBlankForm": "Visa en tom form efter 5 sekunder",
"emailForm": "E-posta mig på",
"showSysFields": "Visa systemfält",
"filterAutoApply": "Auto ansöker",
"showMessage": "Visa det här meddelandet",
"formDisplayMessage": "Display Message",
"viewNotShared": "Aktuell vy är inte delad!",
"showAllViews": "Visa alla delade utsikt över denna tabell",
"collabView": "Samarbetare med redigeringsbehörigheter eller högre kan ändra visningskonfigurationen.",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "Projektmetadata exporterades framgångsrikt",

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

@ -192,7 +192,12 @@
"enter": "Enter",
"seconds": "Seconds",
"paste": "Paste",
"restore": "Restore"
"restore": "Restore",
"replace": "Replace",
"banner": "Banner",
"logo": "Logo",
"dropdown": "Dropdown",
"list": "List"
},
"objects": {
"day": "Day",
@ -421,7 +426,9 @@
"restrict": "Restrict",
"setNull": "Set NULL",
"setDefault": "Set Default"
}
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found"
},
"labels": {
"selectYear": "Select Year",
@ -683,9 +690,18 @@
"incompleteConfiguration": "Incomplete configuration",
"selectField": "Select a field",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
}
},
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Clear selection"
},
"activity": {
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
@ -907,7 +923,10 @@
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode",
"startCommenting": "Start commenting!"
"startCommenting": "Start commenting!",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields"
},
"tooltip": {
"reachedSourceLimit": "Limited to only one data source for the moment",
@ -989,7 +1008,8 @@
"noTokenCreated": "No API Tokens created",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace."
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
},
"msg": {
"clickToCopyFieldId": "Click to copy Field Id",
@ -1166,14 +1186,14 @@
"afterEnablePwd": "การเขาถงคอรหสผานท จำกด",
"privateLink": "มมมองนใชวมกนผานลงควนตว",
"privateLinkAdditionalInfo": "ผงควนตวสามารถเหนเซลลมองเหนไดในมมมองนเทานน",
"afterFormSubmitted": "หลงจากสงแบบฟอรมแล",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "เขาถงโครงการผานทาง",
"submitAnotherForm": "แสดงปม 'สงฟอรมอน'",
"showBlankForm": "แสดงแบบฟอรมเปลาหลงจาก 5 วนาท",
"emailForm": "สงอเมลถงฉนท",
"showSysFields": "แสดงฟลดระบบ",
"filterAutoApply": "ใชตโนม",
"showMessage": "แสดงขอความน",
"formDisplayMessage": "Display Message",
"viewNotShared": "มมมองปจจนไมไดแชร!",
"showAllViews": "แสดงมมมองทแชรงหมดของตารางน",
"collabView": "ผทำงานรวมกนททธแกไขหรอสงกวาสามารถเปลยนการกำหนดคามมมอง",
@ -1283,9 +1303,14 @@
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"groupPasteIsNotSupportedOnLinksColumn": "Group paste operation is not supported on Links/LinkToAnotherRecord column",
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column"
"groupClearIsNotSupportedOnLinksColumn": "Group clear operation is not supported on Links/LinkToAnotherRecord column",
"upgradeToEnterpriseEdition": "Upgrade to Enterprise Edition {extraInfo}",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}"
},
"error": {
"fetchingCalendarData": "Error fetching calendar data",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
@ -1376,7 +1401,8 @@
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data"
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
},
"toast": {
"exportMetadata": "ขอมลเมตาของโครงการสงออกเรยบรอยแลว",

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

Loading…
Cancel
Save