Browse Source

Merge branch 'develop' into test/fix-multi-field-editor-test

pull/8522/head
Raju Udava 6 months ago
parent
commit
584dbda697
  1. 6
      packages/nc-gui/components/project/AllTables.vue
  2. 4
      packages/nc-gui/components/project/View.vue
  3. 2
      packages/nc-gui/components/shared-view/Calendar.vue
  4. 2
      packages/nc-gui/components/shared-view/Gallery.vue
  5. 1
      packages/nc-gui/components/shared-view/Grid.vue
  6. 2
      packages/nc-gui/components/shared-view/Kanban.vue
  7. 2
      packages/nc-gui/components/shared-view/Map.vue
  8. 8
      packages/nc-gui/components/smartsheet/expanded-form/Comments.vue
  9. 52
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  10. 3
      packages/nc-gui/components/smartsheet/grid/Table.vue
  11. 6
      packages/nc-gui/components/smartsheet/header/Cell.vue
  12. 4
      packages/nc-gui/components/smartsheet/header/VirtualCell.vue
  13. 246
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  14. 1
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilterMenu.vue
  15. 9
      packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue
  16. 11
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  17. 4
      packages/nc-gui/components/tabs/Smartsheet.vue
  18. 14
      packages/nc-gui/composables/useViewColumns.ts
  19. 2
      packages/nc-gui/composables/useViewFilters.ts
  20. 7
      packages/nc-gui/lang/ar.json
  21. 7
      packages/nc-gui/lang/bn_IN.json
  22. 5
      packages/nc-gui/lang/cs.json
  23. 7
      packages/nc-gui/lang/da.json
  24. 7
      packages/nc-gui/lang/de.json
  25. 12
      packages/nc-gui/lang/en.json
  26. 11
      packages/nc-gui/lang/es.json
  27. 9
      packages/nc-gui/lang/eu.json
  28. 7
      packages/nc-gui/lang/fa.json
  29. 7
      packages/nc-gui/lang/fi.json
  30. 351
      packages/nc-gui/lang/fr.json
  31. 7
      packages/nc-gui/lang/he.json
  32. 7
      packages/nc-gui/lang/hi.json
  33. 7
      packages/nc-gui/lang/hr.json
  34. 7
      packages/nc-gui/lang/id.json
  35. 9
      packages/nc-gui/lang/it.json
  36. 7
      packages/nc-gui/lang/ja.json
  37. 5
      packages/nc-gui/lang/ko.json
  38. 7
      packages/nc-gui/lang/lv.json
  39. 7
      packages/nc-gui/lang/nl.json
  40. 7
      packages/nc-gui/lang/no.json
  41. 5
      packages/nc-gui/lang/pl.json
  42. 9
      packages/nc-gui/lang/pt.json
  43. 7
      packages/nc-gui/lang/pt_BR.json
  44. 7
      packages/nc-gui/lang/ru.json
  45. 7
      packages/nc-gui/lang/sk.json
  46. 7
      packages/nc-gui/lang/sl.json
  47. 7
      packages/nc-gui/lang/sv.json
  48. 7
      packages/nc-gui/lang/th.json
  49. 5
      packages/nc-gui/lang/tr.json
  50. 7
      packages/nc-gui/lang/uk.json
  51. 7
      packages/nc-gui/lang/vi.json
  52. 21
      packages/nc-gui/lang/zh-Hans.json
  53. 7
      packages/nc-gui/lang/zh-Hant.json
  54. 2
      packages/nocodb/src/app.module.ts
  55. 6
      packages/nocodb/src/controllers/auth/ui/emailTemplates/invite.ts
  56. 4
      packages/nocodb/src/controllers/auth/ui/emailTemplates/verify.ts
  57. 4
      packages/nocodb/src/filters/global-exception/global-exception.filter.ts
  58. 3
      packages/nocodb/src/helpers/isDisposableEmail.ts
  59. 13
      packages/nocodb/src/interface/Jobs.ts
  60. 6
      packages/nocodb/src/modules/global/global.module.ts
  61. 6
      packages/nocodb/src/modules/jobs/fallback/fallback-queue.service.ts
  62. 13
      packages/nocodb/src/modules/jobs/jobs-service.interface.ts
  63. 5
      packages/nocodb/src/modules/jobs/jobs.controller.ts
  64. 2
      packages/nocodb/src/modules/jobs/jobs.module.ts
  65. 5
      packages/nocodb/src/modules/jobs/jobs/at-import/at-import.controller.ts
  66. 3
      packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts
  67. 13
      packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.processor.ts
  68. 64
      packages/nocodb/src/modules/jobs/jobs/export-import/import.service.ts
  69. 8
      packages/nocodb/src/modules/jobs/jobs/health-check.processor.ts
  70. 5
      packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.controller.ts
  71. 5
      packages/nocodb/src/modules/jobs/jobs/source-create/source-create.controller.ts
  72. 3
      packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.controller.ts
  73. 24
      packages/nocodb/src/modules/jobs/jobs/webhook-handler/webhook-handler.processor.ts
  74. 6
      packages/nocodb/src/services/base-users/ui/emailTemplates/invite.ts
  75. 4
      packages/nocodb/src/services/base-users/ui/emailTemplates/verify.ts
  76. 10
      packages/nocodb/src/services/columns.service.ts
  77. 61
      packages/nocodb/src/services/hook-handler.service.ts
  78. 2
      tests/playwright/pages/Dashboard/ViewSidebar/index.ts
  79. 9
      tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts

6
packages/nc-gui/components/project/AllTables.vue

@ -105,7 +105,7 @@ const onCreateBaseClick = () => {
<GeneralIcon icon="download" />
<div class="label">{{ $t('activity.import') }} {{ $t('general.data') }}</div>
</div>
<!-- <component :is="isDataSourceLimitReached ? NcTooltip : 'div'" v-if="isUIAllowed('sourceCreate')">
<!-- <component :is="isDataSourceLimitReached ? NcTooltip : 'div'" v-if="isUIAllowed('sourceCreate')">
<template #title>
<div>
{{ $t('tooltip.reachedSourceLimit') }}
@ -124,7 +124,7 @@ const onCreateBaseClick = () => {
<GeneralIcon icon="dataSource" />
<div class="label">{{ $t('labels.connectDataSource') }}</div>
</div>
</component>-->
</component> -->
</div>
<div
v-if="base?.isLoading"
@ -191,7 +191,7 @@ const onCreateBaseClick = () => {
</div>
<ProjectImportModal v-if="defaultBase" v-model:visible="isImportModalOpen" :source="defaultBase" />
<!-- <LazyDashboardSettingsDataSourcesCreateBase v-model:open="isNewBaseModalOpen" />-->
<!-- <LazyDashboardSettingsDataSourcesCreateBase v-model:open="isNewBaseModalOpen" /> -->
</div>
</template>

4
packages/nc-gui/components/project/View.vue

@ -162,7 +162,7 @@ watch(
</template>
<ProjectAccessSettings :base-id="currentBase?.id" />
</a-tab-pane>
<!-- <a-tab-pane v-if="isUIAllowed('sourceCreate')" key="data-source">
<!-- <a-tab-pane v-if="isUIAllowed('sourceCreate')" key="data-source">
<template #tab>
<div class="tab-title" data-testid="proj-view-tab__data-sources">
<GeneralIcon icon="database" />
@ -180,7 +180,7 @@ watch(
</div>
</template>
<DashboardSettingsDataSources v-model:state="baseSettingsState" />
</a-tab-pane>-->
</a-tab-pane> -->
</a-tabs>
</div>
</div>

2
packages/nc-gui/components/shared-view/Calendar.vue

@ -11,8 +11,6 @@ provide(MetaInj, meta)
provide(ActiveViewInj, sharedView)
provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)

2
packages/nc-gui/components/shared-view/Gallery.vue

@ -11,8 +11,6 @@ provide(MetaInj, meta)
provide(ActiveViewInj, sharedView)
provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)

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

@ -18,7 +18,6 @@ provide(ReloadViewDataHookInj, reloadEventHook)
provide(ReadonlyInj, ref(true))
provide(MetaInj, meta)
provide(ActiveViewInj, sharedView)
provide(FieldsInj, columns)
provide(IsPublicInj, ref(true))
provide(IsLockedInj, isLocked)

2
packages/nc-gui/components/shared-view/Kanban.vue

@ -11,8 +11,6 @@ provide(MetaInj, meta)
provide(ActiveViewInj, sharedView)
provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)

2
packages/nc-gui/components/shared-view/Map.vue

@ -11,8 +11,6 @@ provide(MetaInj, meta)
provide(ActiveViewInj, sharedView)
provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)

8
packages/nc-gui/components/smartsheet/expanded-form/Comments.vue

@ -166,10 +166,10 @@ watch(commentsWrapperEl, () => {
<div v-else ref="commentsWrapperEl" class="flex flex-col h-full py-1 nc-scrollbar-thin">
<div v-for="log of comments" :key="log.id">
<div class="group gap-3 overflow-hidden hover:bg-gray-200 flex items-start px-3 pt-3 pb-4">
<GeneralUserIcon size="medium" :name="log.display_name" :email="log.user" class="mt-0.5" />
<div class="flex-1 flex flex-col gap-1 max-w-[calc(100%_-_24px)]">
<GeneralUserIcon size="medium" :name="log.display_name" :email="log.user" class="mt-0.7" />
<div class="flex-1 flex flex-col gap-0.5 max-w-[calc(100%_-_24px)]">
<div class="w-full flex justify-between gap-3 min-h-7">
<div class="flex items-start max-w-[calc(100%_-_40px)]">
<div class="flex items-center max-w-[calc(100%_-_40px)]">
<div class="w-full flex flex-wrap items-center">
<NcTooltip class="truncate max-w-42 mr-2" show-on-truncate-only>
<template #title>
@ -389,7 +389,7 @@ watch(commentsWrapperEl, () => {
.ant-tabs-nav {
@apply px-3;
.ant-tabs-nav-list {
@apply w-[calc(100%_-_24px)] gap-6;
@apply w-full gap-6;
.ant-tabs-tab {
@apply flex-1 flex items-center justify-center pt-3 pb-2.5;

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

@ -562,7 +562,7 @@ export default {
<div
class="flex min-h-7 flex-shrink-0 w-full items-center nc-expanded-form-header relative p-4 xs:(px-2 py-0 min-h-[48px]) justify-between"
>
<div class="flex-1 flex gap-3 lg:w-100 <lg:max-w-[calc(100%_-_178px)] xs:(max-w-[calc(100%_-_44px)])">
<div class="flex-1 flex gap-4 lg:w-100 <lg:max-w-[calc(100%_-_178px)] xs:(max-w-[calc(100%_-_44px)])">
<div class="flex gap-2">
<NcTooltip v-if="props.showNextPrevIcons">
<template #title> {{ renderAltOrOptlKey() }} + </template>
@ -601,13 +601,13 @@ export default {
}"
>
<div v-if="meta.title" class="flex items-center gap-2 px-2 py-1 rounded-lg bg-gray-100 text-gray-800">
<GeneralTableIcon :meta="meta" class="!text-gray-800" />
<GeneralTableIcon :meta="meta" class="!text-gray-800 !mx-0" />
<NcTooltip class="truncate max-w-[100px] xs:(max-w-[82px]) h-5" show-on-truncate-only>
<NcTooltip class="truncate text-sm max-w-[100px] xs:(max-w-[82px]) align-middle" show-on-truncate-only>
<template #title>
{{ meta.title }}
</template>
<span class="font-weight-500 truncate text-sm"> {{ meta.title }} </span>
<span class="font-weight-500 truncate text-sm">{{ meta.title }}</span>
</NcTooltip>
</div>
<div
@ -627,6 +627,21 @@ export default {
</div>
</div>
<div class="flex gap-2">
<NcTooltip v-if="!isMobileMode && isUIAllowed('dataEdit')">
<template #title> {{ renderAltOrOptlKey() }} + S </template>
<NcButton
v-e="['c:row-expand:save']"
:disabled="changedColumns.size === 0 && !isUnsavedFormExist"
:loading="isSaving"
class="nc-expand-form-save-btn !xs:(text-base) !h-7 !px-2"
data-testid="nc-expanded-form-save"
type="primary"
size="xsmall"
@click="save"
>
<div class="xs:px-1">{{ newRecordSubmitBtnText ?? 'Save Record' }}</div>
</NcButton>
</NcTooltip>
<NcButton
v-if="!isNew && rowId && !isMobileMode"
:disabled="isLoading"
@ -645,21 +660,6 @@ export default {
{{ isRecordLinkCopied ? $t('labels.copiedRecordURL') : $t('labels.copyRecordURL') }}
</div>
</NcButton>
<NcTooltip v-if="!isMobileMode && isUIAllowed('dataEdit')">
<template #title> {{ renderAltOrOptlKey() }} + S </template>
<NcButton
v-e="['c:row-expand:save']"
:disabled="changedColumns.size === 0 && !isUnsavedFormExist"
:loading="isSaving"
class="nc-expand-form-save-btn !xs:(text-base) !h-7 !px-2"
data-testid="nc-expanded-form-save"
type="primary"
size="xsmall"
@click="save"
>
<div class="xs:px-1">{{ newRecordSubmitBtnText ?? 'Save Record' }}</div>
</NcButton>
</NcTooltip>
<NcDropdown v-if="!isNew && rowId && !isMobileMode" placement="bottomRight">
<NcButton type="text" size="xsmall" class="nc-expand-form-more-actions !w-7 !h-7" :disabled="isLoading">
<GeneralIcon icon="threeDotVertical" class="text-md" :class="isLoading ? 'text-gray-300' : 'text-gray-700'" />
@ -730,7 +730,7 @@ export default {
>
<div
ref="expandedFormScrollWrapper"
class="flex flex-col flex-grow gap-3 h-full max-h-full nc-scrollbar-thin items-center w-full p-4 xs:(px-4 pt-4 pb-2 gap-6) children:max-w-[588px] <lg:(children:max-w-[450px])"
class="flex flex-col flex-grow gap-4 h-full max-h-full nc-scrollbar-thin items-center w-full p-4 xs:(px-4 pt-4 pb-2 gap-6) children:max-w-[588px] <lg:(children:max-w-[450px])"
>
<div
v-for="(col, i) of fields"
@ -1024,14 +1024,18 @@ export default {
}
.nc-data-cell {
box-shadow: 0 0 1px rgba(0, 0, 0, 0.1);
&:hover,
@apply !rounded-lg;
transition: all 0.3s;
&:hover {
@apply !border-1 !border-brand-400;
}
&:focus-within {
box-shadow: 0 0 3px rgba(0, 0, 0, 0.1) !important;
box-shadow: 0px 0px 0px 2px rgba(51, 102, 255, 0.24) !important;
}
}
.nc-data-cell:focus-within {
@apply !border-1 !border-brand-500 !rounded-lg;
@apply !border-1 !border-brand-500;
}
:deep(.nc-system-field input) {

3
packages/nc-gui/components/smartsheet/grid/Table.vue

@ -1136,6 +1136,9 @@ const calculateSlices = () => {
start: 0,
end: 0,
}
// try again until the grid is rendered
setTimeout(calculateSlices, 100)
return
}

6
packages/nc-gui/components/smartsheet/header/Cell.vue

@ -99,7 +99,7 @@ const onClick = (e: Event) => {
:class="{
'h-full': column,
'!text-gray-400': isKanban,
'flex-col !items-start justify-center': isExpandedForm && !isMobileMode,
'flex-col !items-start justify-center pt-0.5': isExpandedForm && !isMobileMode,
'cursor-pointer hover:bg-gray-100': isExpandedForm && !isMobileMode && isUIAllowed('fieldEdit'),
'bg-gray-100': isExpandedForm ? editColumnDropdown || isDropDownOpen : false,
}"
@ -138,7 +138,7 @@ const onClick = (e: Event) => {
<NcTooltip
v-if="column"
:class="{
'cursor-pointer pt-0.25': !isForm && isUIAllowed('fieldEdit') && !hideMenu,
'cursor-pointer': !isForm && isUIAllowed('fieldEdit') && !hideMenu,
'cursor-default': isForm || !isUIAllowed('fieldEdit') || hideMenu,
'truncate': !isForm,
}"
@ -164,7 +164,7 @@ const onClick = (e: Event) => {
<GeneralIcon
v-if="isExpandedForm && !isMobileMode && isUIAllowed('fieldEdit')"
icon="arrowDown"
class="flex-none text-grey h-full text-grey cursor-pointer ml-1 group-hover:visible"
class="flex-none cursor-pointer ml-1 group-hover:visible w-4 h-4"
:class="{
visible: editColumnDropdown || isDropDownOpen,
invisible: !(editColumnDropdown || isDropDownOpen),

4
packages/nc-gui/components/smartsheet/header/VirtualCell.vue

@ -179,7 +179,7 @@ const onClick = (e: Event) => {
<div
class="flex items-center w-full h-full text-small text-gray-500 font-weight-medium group"
:class="{
'flex-col !items-start justify-center': isExpandedForm,
'flex-col !items-start justify-center pt-0.5': isExpandedForm && !isMobileMode,
'bg-gray-100': isExpandedForm ? editColumnDropdown || isDropDownOpen : false,
'cursor-pointer hover:bg-gray-100': isExpandedForm && !isMobileMode && isUIAllowed('fieldEdit'),
}"
@ -220,7 +220,7 @@ const onClick = (e: Event) => {
<GeneralIcon
v-if="isExpandedForm && !isMobileMode && isUIAllowed('fieldEdit')"
icon="arrowDown"
class="flex-none h-full cursor-pointer ml-1 group-hover:visible"
class="flex-none cursor-pointer ml-1 group-hover:visible w-4 h-4"
:class="{
visible: editColumnDropdown || isDropDownOpen,
invisible: !(editColumnDropdown || isDropDownOpen),

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

@ -11,6 +11,7 @@ interface Props {
modelValue?: undefined | Filter[]
webHook?: boolean
draftFilter?: Partial<FilterType>
isOpen?: boolean
}
const props = withDefaults(defineProps<Props>(), {
@ -27,6 +28,7 @@ const emit = defineEmits(['update:filtersLength', 'update:draftFilter', 'update:
const excludedFilterColUidt = [UITypes.QrCode, UITypes.Barcode]
const draftFilter = useVModel(props, 'draftFilter', emit)
const modelValue = useVModel(props, 'modelValue', emit)
const { nestedLevel, parentId, autoSave, hookId, showLoading, webHook } = toRefs(props)
@ -386,6 +388,15 @@ watch(
immediate: true,
},
)
const addFilterBtnRef = ref()
watchEffect(() => {
if (props.isOpen && !nested.value && addFilterBtnRef.value) {
setTimeout(() => {
addFilterBtnRef.value?.$el?.focus()
}, 10)
}
})
</script>
<template>
@ -394,13 +405,63 @@ watch(
:class="{
'max-h-[max(80vh,500px)] min-w-112 py-2 pl-4': !nested,
'w-full ': nested,
'py-4': !filters.length,
}"
>
<div v-if="nested" class="flex w-full items-center mb-2">
<div :class="[`nc-filter-logical-op-level-${nestedLevel}`]"><slot name="start"></slot></div>
<div class="flex-grow"></div>
<NcDropdown :trigger="['hover']" overlay-class-name="nc-dropdown-filter-group-sub-menu">
<GeneralIcon icon="plus" class="cursor-pointer" />
<template #overlay>
<NcMenu>
<template v-if="isEeUI && !isPublic">
<template v-if="filtersCount < getPlanLimit(PlanLimitTypes.FILTER_LIMIT)">
<NcMenuItem @click.stop="addFilter()">
<div class="flex items-center gap-1">
<component :is="iconMap.plus" />
<!-- Add Filter -->
{{ $t('activity.addFilter') }}
</div>
</NcMenuItem>
<NcMenuItem v-if="nestedLevel < 5" @click.stop="addFilterGroup()">
<div class="flex items-center gap-1">
<!-- Add Filter Group -->
<component :is="iconMap.plusSquare" />
{{ $t('activity.addFilterGroup') }}
</div>
</NcMenuItem>
</template>
</template>
<template v-else>
<NcMenuItem @click.stop="addFilter()">
<div class="flex items-center gap-1">
<component :is="iconMap.plus" />
<!-- Add Filter -->
{{ $t('activity.addFilter') }}
</div>
</NcMenuItem>
<NcMenuItem v-if="!webHook && nestedLevel < 5" @click.stop="addFilterGroup()">
<div class="flex items-center gap-1">
<!-- Add Filter Group -->
<component :is="iconMap.plusSquare" />
{{ $t('activity.addFilterGroup') }}
</div>
</NcMenuItem>
</template>
</NcMenu>
</template>
</NcDropdown>
<div>
<slot name="end"></slot>
</div>
</div>
<div
v-if="filters && filters.length"
ref="wrapperDomRef"
class="flex flex-col gap-y-3 nc-filter-grid w-full"
class="flex flex-col gap-y-1.5 nc-filter-grid w-full"
:class="{ 'max-h-420px nc-scrollbar-thin nc-filter-top-wrapper pr-4 my-2 py-1': !nested }"
@click.stop
>
@ -408,17 +469,29 @@ watch(
<template v-if="filter.status !== 'delete'">
<template v-if="filter.is_group">
<div class="flex flex-col w-full gap-y-2">
<div class="flex flex-row w-full justify-between items-center">
<span v-if="!i" class="flex items-center ml-2">{{ $t('labels.where') }}</span>
<div class="flex rounded-lg p-2 w-full border-1" :class="[`nc-filter-nested-level-${nestedLevel}`]">
<LazySmartsheetToolbarColumnFilter
v-if="filter.id || filter.children || !autoSave"
:key="filter.id ?? i"
ref="localNestedFilters"
v-model="filter.children"
:nested-level="nestedLevel + 1"
:parent-id="filter.id"
:auto-save="autoSave"
:web-hook="webHook"
>
<template #start>
<span v-if="!i" class="flex items-center nc-filter-where-label ml-1">{{ $t('labels.where') }}</span>
<div v-else :key="`${i}nested`" class="flex nc-filter-logical-op">
<NcSelect
v-model:value="filter.logical_op"
v-e="['c:filter:logical-op:select']"
:dropdown-match-select-width="false"
class="min-w-20 capitalize"
class="min-w-18 max-w-18 capitalize"
placeholder="Group op"
dropdown-class-name="nc-dropdown-filter-logical-op-group"
:disabled="visibleFilters.indexOf(filter) > 1 && !isLogicalOpChangeAllowed"
:disabled="i > 1 && !isLogicalOpChangeAllowed"
:class="{ 'nc-disabled-logical-op': filter.readOnly || (i > 1 && !isLogicalOpChangeAllowed) }"
@click.stop
@change="onLogicalOpUpdate(filter, i)"
>
@ -435,6 +508,8 @@ watch(
</a-select-option>
</NcSelect>
</div>
</template>
<template #end>
<NcButton
v-if="!filter.readOnly"
:key="i"
@ -446,33 +521,29 @@ watch(
>
<component :is="iconMap.deleteListItem" />
</NcButton>
</div>
<div class="flex border-1 rounded-lg p-2 w-full" :class="nestedLevel % 2 !== 0 ? 'bg-white' : 'bg-gray-100'">
<LazySmartsheetToolbarColumnFilter
v-if="filter.id || filter.children || !autoSave"
:key="filter.id ?? i"
ref="localNestedFilters"
v-model="filter.children"
:nested-level="nestedLevel + 1"
:parent-id="filter.id"
:auto-save="autoSave"
:web-hook="webHook"
/>
</template>
</LazySmartsheetToolbarColumnFilter>
</div>
</div>
</template>
<div v-else class="flex flex-row gap-x-2 w-full" :class="`nc-filter-wrapper-${filter.fk_column_id}`">
<span v-if="!i" class="flex items-center ml-2 mr-7.35">{{ $t('labels.where') }}</span>
<div v-else class="flex flex-row gap-x-0 w-full nc-filter-wrapper" :class="`nc-filter-wrapper-${filter.fk_column_id}`">
<div v-if="!i" class="flex items-center !min-w-18 !max-w-18 pl-3 nc-filter-where-label">
{{ $t('labels.where') }}
</div>
<NcSelect
v-else
v-model:value="filter.logical_op"
v-e="['c:filter:logical-op:select']"
:dropdown-match-select-width="false"
class="h-full !min-w-20 !max-w-20 capitalize"
class="h-full !min-w-18 !max-w-18 capitalize"
hide-details
:disabled="filter.readOnly || (visibleFilters.indexOf(filter) > 1 && !isLogicalOpChangeAllowed)"
dropdown-class-name="nc-dropdown-filter-logical-op"
:class="{
'nc-disabled-logical-op': filter.readOnly || (visibleFilters.indexOf(filter) > 1 && !isLogicalOpChangeAllowed),
}"
@change="onLogicalOpUpdate(filter, i)"
@click.stop
>
@ -488,6 +559,7 @@ watch(
</div>
</a-select-option>
</NcSelect>
<SmartsheetToolbarFieldListAutoCompleteDropdown
:key="`${i}_6`"
v-model="filter.fk_column_id"
@ -497,6 +569,7 @@ watch(
@click.stop
@change="selectFilterField(filter, i)"
/>
<NcSelect
v-model:value="filter.comparison_op"
v-e="['c:filter:comparison-op:select']"
@ -529,6 +602,7 @@ watch(
</NcSelect>
<div v-if="['blank', 'notblank'].includes(filter.comparison_op)" class="flex flex-grow"></div>
<NcSelect
v-else-if="isDateType(types[filter.fk_column_id])"
v-model:value="filter.comparison_sub_op"
@ -567,6 +641,7 @@ watch(
</a-select-option>
</template>
</NcSelect>
<a-checkbox
v-if="filter.field && types[filter.field] === 'boolean'"
v-model:checked="filter.value"
@ -583,6 +658,7 @@ watch(
@update-filter-value="(value) => updateFilterValue(value, filter, i)"
@click.stop
/>
<div v-else-if="!isDateType(types[filter.fk_column_id])" class="flex-grow"></div>
<NcButton
@ -600,16 +676,16 @@ watch(
</template>
</div>
<template v-if="!nested">
<template v-if="isEeUI && !isPublic">
<div
v-if="filtersCount < getPlanLimit(PlanLimitTypes.FILTER_LIMIT)"
ref="addFiltersRowDomRef"
class="flex gap-2"
:class="{
'mt-1 mb-2': filters.length,
}"
>
<NcButton size="small" type="text" class="!text-brand-500" @click.stop="addFilter()">
<NcButton :ref="addFilterBtnRef" size="small" type="text" class="nc-btn-focus" @click.stop="addFilter()">
<div class="flex items-center gap-1">
<component :is="iconMap.plus" />
<!-- Add Filter -->
@ -617,7 +693,7 @@ watch(
</div>
</NcButton>
<NcButton v-if="nestedLevel < 5" type="text" size="small" @click.stop="addFilterGroup()">
<NcButton v-if="nestedLevel < 5" class="nc-btn-focus" type="text" size="small" @click.stop="addFilterGroup()">
<div class="flex items-center gap-1">
<!-- Add Filter Group -->
<component :is="iconMap.plus" />
@ -626,6 +702,7 @@ watch(
</NcButton>
</div>
</template>
<template v-else>
<div
ref="addFiltersRowDomRef"
@ -634,7 +711,7 @@ watch(
'mt-1 mb-2': filters.length,
}"
>
<NcButton size="small" type="text" class="!text-brand-500" @click.stop="addFilter()">
<NcButton ref="addFilterBtnRef" class="nc-btn-focus" size="small" type="text" @click.stop="addFilter()">
<div class="flex items-center gap-1">
<component :is="iconMap.plus" />
<!-- Add Filter -->
@ -642,7 +719,13 @@ watch(
</div>
</NcButton>
<NcButton v-if="!webHook && nestedLevel < 5" type="text" size="small" @click.stop="addFilterGroup()">
<NcButton
v-if="!webHook && nestedLevel < 5"
class="nc-btn-focus"
type="text"
size="small"
@click.stop="addFilterGroup()"
>
<div class="flex items-center gap-1">
<!-- Add Filter Group -->
<component :is="iconMap.plus" />
@ -651,6 +734,7 @@ watch(
</NcButton>
</div>
</template>
</template>
<div
v-if="!filters.length"
class="flex flex-row text-gray-400 mt-2"
@ -666,7 +750,7 @@ watch(
</div>
</template>
<style scoped>
<style scoped lang="scss">
.nc-filter-item-remove-btn {
@apply text-gray-600 hover:text-gray-800;
}
@ -680,6 +764,112 @@ watch(
}
:deep(.ant-select-selector) {
@apply !min-h-8.25;
@apply !min-h-8;
}
.nc-disabled-logical-op :deep(.ant-select-arrow) {
@apply hidden;
}
.nc-filter-wrapper {
@apply bg-white !rounded-lg border-1px border-[#E7E7E9];
& > * {
@apply !border-none;
}
& > * > :deep(.ant-select-selector) {
border: none !important;
box-shadow: none !important;
}
& > :not(:last-child):not(:empty) {
border-right: 1px solid #eee !important;
border-bottom-right-radius: 0 !important;
border-top-right-radius: 0 !important;
}
& > :not(:first-child) {
border-bottom-left-radius: 0 !important;
border-top-left-radius: 0 !important;
}
& > :last-child {
@apply relative;
&::after {
content: '';
@apply absolute h-full w-1px bg-[#eee] -left-1px top-0;
}
}
:deep(::placeholder) {
@apply text-sm tracking-normal;
}
:deep(::-ms-input-placeholder) {
@apply text-sm tracking-normal;
}
:deep(input) {
@apply text-sm;
}
:deep(.nc-select:not(.nc-disabled-logical-op):hover) {
&,
.ant-select-selector {
@apply bg-gray-50;
}
}
}
.nc-filter-nested-level-0 {
@apply bg-[#f9f9fa];
}
.nc-filter-nested-level-1,
.nc-filter-nested-level-3 {
@apply bg-gray-[#f4f4f5];
}
.nc-filter-nested-level-2,
.nc-filter-nested-level-4 {
@apply bg-gray-[#e7e7e9];
}
.nc-filter-logical-op-level-3,
.nc-filter-logical-op-level-5 {
:deep(.nc-select.ant-select .ant-select-selector) {
@apply border-[#d9d9d9];
}
}
.nc-filter-where-label {
@apply text-gray-400;
}
:deep(.ant-select-disabled.ant-select:not(.ant-select-customize-input) .ant-select-selector) {
@apply bg-transparent text-gray-400;
}
:deep(.nc-filter-logical-op .nc-select.ant-select .ant-select-selector) {
@apply shadow-none;
}
:deep(.nc-select-expand-btn) {
@apply text-gray-500;
}
.menu-filter-dropdown {
input:not(:disabled),
select:not(:disabled),
.ant-select:not(.ant-select-disabled) {
@apply text-[#4A5268];
}
}
.nc-filter-input-wrapper :deep(input) {
@apply !px-2;
}
.nc-btn-focus:focus {
@apply !text-brand-500 !shadow-none;
}
</style>

1
packages/nc-gui/components/smartsheet/toolbar/ColumnFilterMenu.vue

@ -86,6 +86,7 @@ eventBus.on(async (event, column: ColumnType) => {
:auto-save="true"
data-testid="nc-filter-menu"
@update:filters-length="filtersLength = $event"
:is-open="open"
>
</SmartsheetToolbarColumnFilter>
</template>

9
packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue

@ -63,14 +63,15 @@ const options = computed<SelectProps['options']>(() =>
return !isVirtualSystemField
}
})
)?.map((c: ColumnType) => ({
)
// sort and keep system columns at the end
?.sort((field1, field2) => +isSystemColumn(field2) - +isSystemColumn(field1))
?.map((c: ColumnType) => ({
value: c.id,
label: c.title,
icon: h(
isVirtualCol(c) ? resolveComponent('SmartsheetHeaderVirtualCellIcon') : resolveComponent('SmartsheetHeaderCellIcon'),
{
columnMeta: c,
},
{ columnMeta: c },
),
c,
})),

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

@ -11,8 +11,6 @@ const reloadViewMetaHook = inject(ReloadViewMetaHookInj, undefined)!
const reloadViewDataHook = inject(ReloadViewDataHookInj, undefined)!
const rootFields = inject(FieldsInj)
const { isMobileMode } = useGlobal()
const isLocked = inject(IsLockedInj, ref(false))
@ -23,7 +21,6 @@ const { $api, $e } = useNuxtApp()
const {
showSystemFields,
sortedAndFilteredFields,
fields,
filteredFieldList,
filterQuery,
@ -48,14 +45,6 @@ eventBus.on((event) => {
}
})
watch(
sortedAndFilteredFields,
(v) => {
if (rootFields) rootFields.value = v || []
},
{ immediate: true },
)
const numberOfHiddenFields = computed(() => filteredFieldList.value?.filter((field) => !field.show)?.length)
const gridDisplayValueField = computed(() => {

4
packages/nc-gui/components/tabs/Smartsheet.vue

@ -16,8 +16,6 @@ useSidebar('nc-right-sidebar')
const activeTab = toRef(props, 'activeTab')
const fields = ref<ColumnType[]>([])
const route = useRoute()
const meta = computed<TableType | undefined>(() => {
@ -50,7 +48,6 @@ provide(IsLockedInj, isLocked)
provide(ReloadViewDataHookInj, reloadViewDataEventHook)
provide(ReloadViewMetaHookInj, reloadViewMetaEventHook)
provide(OpenNewRecordFormHookInj, openNewRecordFormHook)
provide(FieldsInj, fields)
provide(IsFormInj, isForm)
provide(TabMetaInj, activeTab)
provide(
@ -60,6 +57,7 @@ provide(
useExpandedFormDetachedProvider()
useProvideViewColumns(activeView, meta, () => reloadViewDataEventHook?.trigger())
useProvideViewGroupBy(activeView, meta, xWhere)
useProvideSmartsheetLtarHelpers(meta)

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

@ -6,9 +6,11 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
(
view: Ref<ViewType | undefined>,
meta: Ref<TableType | undefined> | ComputedRef<TableType | undefined>,
reloadData?: () => void,
reloadData?: (params?: { shouldShowLoading?: boolean }) => void,
isPublic = false,
) => {
const rootFields = ref<ColumnType[]>([])
const fields = ref<Field[]>()
const filterQuery = ref('')
@ -356,6 +358,16 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
}
}
watch(
sortedAndFilteredFields,
(v) => {
if (rootFields) rootFields.value = v || []
},
{ immediate: true },
)
provide(FieldsInj, rootFields)
return {
fields,
loadViewColumns,

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

@ -188,7 +188,7 @@ export function useViewFilters(
comparison_op: comparisonOpList(options.value?.[0].uidt as UITypes).filter((compOp) =>
isComparisonOpAllowed({ fk_column_id: options.value?.[0].id }, compOp),
)?.[0].value as FilterType['comparison_op'],
value: '',
value: null,
status: 'create',
logical_op: logicalOps.size === 1 ? logicalOps.values().next().value : 'and',
}

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "اسم الجدول",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Table name",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Akceptované typy souborů jsou .xls, .xlsx, .xlsm, .ods, .ots.",
"parameterKeyCannotBeEmpty": "Klíč parametru nesmí být prázdný",
"duplicateParameterKeysAreNotAllowed": "Duplicitní klíče parametrů nejsou povoleny",
"fieldRequired": "{value} nemůže být prázdný.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projekt není přístupný",
"copyToClipboardError": "Nepodařilo se zkopírovat do schránky",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tabelnavn.",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "De accepterede filtyper er .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameternøglen kan ikke være tom",
"duplicateParameterKeysAreNotAllowed": "Det er ikke tilladt at duplikere parameternøgler",
"fieldRequired": "{value} kan ikke være tom.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projektet er ikke tilgængeligt",
"copyToClipboardError": "Kopiering til udklipsholderen mislykkedes",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tabellenname",
"dashboardName": "Dashboard name",
"createView": "Neue Ansicht erstellen",
"createView": "Ansicht erstellen",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Die akzeptierten Dateitypen sind .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameterschlüssel darf nicht leer sein",
"duplicateParameterKeysAreNotAllowed": "Doppelte Parameterschlüssel sind nicht erlaubt",
"fieldRequired": "{value} kann nicht leer sein.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projekt nicht zugänglich",
"copyToClipboardError": "Kopieren in die Zwischenablage fehlgeschlagen",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -589,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Table name",
"dashboardName": "Dashboard name",
"createView": "Create view",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -756,7 +756,7 @@
"selectField": "Select a field",
"selectFieldLabel": "Make changes to field properties by selecting a field from the list"
},
"appearanceSettings": "Appearance settings",
"appearanceSettings": "Appearance Settings",
"backgroundColor": "Background Color",
"hideNocodbBranding": "Hide NocoDB Branding",
"showOnConditions": "Show on condtions",
@ -919,7 +919,7 @@
"clearMetadata": "Clear Metadata",
"exportToFile": "Export to file",
"changePwd": "Change Password",
"createView": "Create a View",
"createView": "Create View",
"shareView": "Share View",
"findRowByCodeScan": "Find record by scan",
"fillByCodeScan": "Fill by scan",
@ -1015,7 +1015,7 @@
"group": "Group"
},
"tooltip": {
"reachedSourceLimit": "Limited to 10 data sources per base",
"reachedSourceLimit": "Limited to only one data source for the moment",
"saveChanges": "Save changes",
"xcDB": "Create a new base",
"extDB": "Supports MySQL, PostgreSQL, SQL Server & SQLite",
@ -1286,7 +1286,7 @@
"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",
"postFormSubmissionSettings": "Post form submission settings",
"postFormSubmissionSettings": "Post Form Submission Settings",
"apiOptions": "Access Base via",
"submitAnotherForm": "Show 'Submit Another Form' button",
"showBlankForm": "Show a blank form after 5 seconds",
@ -1498,7 +1498,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": "This field cannot be empty.",
"fieldRequired": "{value} cannot be empty.",
"projectNotAccessible": "Base not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Token sin título",
"tableName": "Nombre de la tabla",
"dashboardName": "Nombre del panel",
"createView": "Crear una vista",
"createView": "Crear Vista",
"creatingView": "Creando Vista",
"duplicateView": "Duplicar vista",
"duplicateGridView": "Duplicar vista en cuadrcula",
@ -917,7 +919,7 @@
"clearMetadata": "Limpiar metadatos",
"exportToFile": "Exportar a archivo",
"changePwd": "Cambia la contraseña",
"createView": "Crear una Vista",
"createView": "Crear vista",
"shareView": "Compartir vista",
"findRowByCodeScan": "Find row by scan",
"fillByCodeScan": "Rellenar por escaneo",
@ -1013,7 +1015,7 @@
"group": "Group"
},
"tooltip": {
"reachedSourceLimit": "Limited to 10 data sources per base",
"reachedSourceLimit": "Limitado a una única fuente de datos por el momento",
"saveChanges": "Guardar cambios",
"xcDB": "Crear un nuevo proyecto",
"extDB": "Soporta MySQL, PostgreSQL, SQL Server y SQLite",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Los tipos de archivo aceptados son .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "La clave del parámetro no puede estar vacía",
"duplicateParameterKeysAreNotAllowed": "No se permiten claves de parámetros duplicadas",
"fieldRequired": "{value} no puede estar vacía.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Proyecto no accesible",
"copyToClipboardError": "Fallo al copiar al portapapeles",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Taularen izena",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -917,7 +919,7 @@
"clearMetadata": "Clear Metadata",
"exportToFile": "Export to file",
"changePwd": "Change Password",
"createView": "Create a View",
"createView": "Create View",
"shareView": "Share View",
"findRowByCodeScan": "Find row by scan",
"fillByCodeScan": "Fill by scan",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "نام جدول",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "نوع فایل های مورد قبول .xls, .xlsx, .xlm, .ods, .ots هستند",
"parameterKeyCannotBeEmpty": "کلید پارامتر نمیتواند خالی باشد",
"duplicateParameterKeysAreNotAllowed": "کلید های پارامتر تکراری مجاز نیستند",
"fieldRequired": "{value} نمیتواند خالی باشد.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "کپی به کلیپ برد ناموفق",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Taulukon nimi",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Hyväksytyt tiedostotyypit ovat .xls, .xlsx, .xlsm, .ods, .ots ja .xlsx.",
"parameterKeyCannotBeEmpty": "Parametriavain ei voi olla tyhjä",
"duplicateParameterKeysAreNotAllowed": "Parametrin kaksoisavaimet eivät ole sallittuja",
"fieldRequired": "{value} ei voi olla tyhjä.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Hankkeeseen ei pääse käsiksi",
"copyToClipboardError": "Kopiointi leikepöydälle epäonnistui",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -10,7 +10,7 @@
"connect": "Connecter",
"buttonActionTypes": {
"open_external_url": "Ouvrir le lien externe",
"delete_record": "Supprimer la ligne",
"delete_record": "Supprimer l'enregistrement",
"update_record": "Mettre à jour l'enregistrement",
"open_layout": "Ouvrir la mise en page"
},
@ -39,7 +39,7 @@
}
},
"general": {
"role": "Role",
"role": "Rôle",
"general": "Général",
"quit": "Quitter",
"home": "Accueil",
@ -197,7 +197,7 @@
"paste": "Coller",
"restore": "Restaurer",
"replace": "Remplacer",
"banner": "Banner",
"banner": "Bandeau",
"logo": "Logo",
"dropdown": "Liste déroulante",
"list": "Liste",
@ -293,7 +293,7 @@
"Formula": "Formule",
"Rollup": "Synthèse",
"Count": "Compteur",
"Lookup": "Consulter",
"Lookup": "Lookup",
"DateTime": "Date et heure",
"CreatedTime": "Date de création",
"LastModifiedTime": "Dernière modification",
@ -320,9 +320,9 @@
"isNotNull": "est non null"
},
"title": {
"renameBase": "Rename Base",
"renameBase": "Renommer la Base",
"renameWorkspace": "Renommer l'espace de travail",
"renamingWorkspace": "Renaming Workspace",
"renamingWorkspace": "Renommer l'espace de travail",
"renamingBase": "Renommer la Base",
"sso": "Authentification (SSO)",
"docs": "Documents",
@ -354,7 +354,7 @@
"manyToMany": "Plusieurs à plusieurs",
"oneToOne": "Un à un",
"virtualRelation": "Virtual Relation",
"linkMore": "Link More",
"linkMore": "Lier plus",
"linkMoreRecords": "Lier plus d'enregistrements",
"linkRecords": "Lier les enregistrements",
"downloadFile": "Télécharger le fichier",
@ -378,7 +378,7 @@
"formTitle": "Intitulé du formulaire",
"collaborative": "Collaboratif",
"locked": "Verrouillé",
"personal": "Personal",
"personal": "Personnels",
"appStore": "Magasin d'applications",
"teamAndAuth": "Équipe & Authentification",
"rolesUserMgmt": "Gestion des utilisateurs & rôles",
@ -436,54 +436,56 @@
"switchLanguage": "Changer de langue",
"renameFile": "Renommer le fichier",
"links": {
"noAction": "No Action",
"noAction": "Aucune action",
"cascade": "Cascade",
"restrict": "Restrict",
"restrict": "Restreindre",
"setNull": "Définir NULL",
"setDefault": "Définir à la valeur par défaut"
},
"selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here",
"noOptionsFound": "No options found",
"surveyFormSubmitConfirmMsg": "Are you sure you want to submit this form?",
"selectFieldsFromRightPannelToAddHere": "Sélectionnez les champs du panneau de droite à ajouter ici",
"noOptionsFound": "Aucune option trouvée",
"surveyFormSubmitConfirmMsg": "Êtes-vous sûr de vouloir envoyer ce formulaire ?",
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"today": "Today",
"workspace": "Workspace",
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Aujourd'hui",
"workspace": "Espace de travail",
"txt": "TXT Record value",
"transferOwnership": "Transfer Ownership",
"recentActivity": "Recent Activity",
"goToMembers": "Go to Members",
"transferOwnership": "Définir un nouveau propriétaire",
"recentActivity": "Activité récente",
"goToMembers": "Aller aux membres",
"addMember": "Ajouter un membre",
"numberOfMembers": "No. Members",
"numberOfBases": "No. Bases",
"numberOfRecords": "No. Records",
"workspaceName": "Workspace Name",
"workspaceWithoutOwner": "Workspace without Owners",
"inviteUsersToWorkspace": "Invite Users to Workspace",
"numberOfMembers": "Nombre de membres",
"numberOfBases": "Nombre de bases",
"numberOfRecords": "Nombre d'enregistrements",
"workspaceName": "Nom de l'espace de travail",
"workspaceWithoutOwner": "Espace de travail sans propriétaire",
"inviteUsersToWorkspace": "Inviter des utilisateurs à l'espace de travail",
"selectWorkspace": "-select workspaces to invite to-",
"addMembersToOrganization": "Ajouter des membres à l'organisation",
"memberIn": "Member in:",
"assignAs": "Assign as",
"signOutUser": "Sign out user",
"signOutUsers": "Sign out users",
"deactivateUser": "Deactivate User",
"deactivateUsers": "Deactivate Users",
"signOutUser": "Déconnecter l'utilisateur",
"signOutUsers": "Déconnecter les utilisateurs",
"deactivateUser": "Désactiver l'utilisateur",
"deactivateUsers": "Désactiver les utilisateurs",
"lastActive": "Last Active",
"dateAdded": "Date ajoutée",
"uploadImage": "Upload Image",
"organizationProfile": "Organisation Profile",
"organizationImage": "Organisation Image",
"organizationName": "Organisation Name",
"uploadImage": "Charger une image",
"organizationProfile": "Profil de l'organisation",
"organizationImage": "Image de l'organisation",
"organizationName": "Nom de l'organisation",
"activeDomains": "Active Domains",
"domains": "Domains",
"disablePublicSharing": "Disable Public Sharing",
"shareSettings": "Share Settings",
"deleteUserAndData": "Delete User and their data",
"userOptions": "User Options",
"deleteThisOrganization": "Delete this Organisation",
"disablePublicSharing": "Désactiver le partage public",
"shareSettings": "Partager les paramètres",
"deleteUserAndData": "Supprimer l'utilisateur et ses données",
"userOptions": "Options de l'utilisateur",
"deleteThisOrganization": "Supprimer cette organisation",
"dangerZone": "Dangerzone",
"selectYear": "Select Year",
"selectYear": "Sélectionnez une Année",
"save": "Enregistrer",
"cancel": "Annuler",
"metadataUrl": "URL des métadonnées",
@ -496,13 +498,13 @@
"adminPanel": "Panneau d'administration",
"moveWorkspaceToOrg": "Déplacer l'espace de travail vers l'organisation",
"ssoSettings": "Paramètres SSO",
"addDomain": "Add Domain",
"domain": "Domain",
"addDomain": "Ajouter le domaine",
"domain": "Domaine",
"settings": "Réglages",
"workspaces": "Espaces de travail",
"back": "Précédent",
"dashboard": "Tableau de bord",
"organizeBy": "Organize by",
"organizeBy": "Organiser en fonction de",
"previous": "Précédent",
"nextMonth": "Mois suivant",
"previousMonth": "Mois précédent",
@ -587,7 +589,7 @@
"untitledToken": "Jeton sans titre",
"tableName": "Nom du tableau",
"dashboardName": "Nom du tableau de bord",
"createView": "Créer une vue",
"createView": "Créer vue",
"creatingView": "Création de la vue",
"duplicateView": "Dupliquer la vue",
"duplicateGridView": "Dupliquer la vue Grille",
@ -717,7 +719,7 @@
"hasMany": "a plusieurs",
"belongsTo": "appartient à",
"manyToMany": "ont des relations nombreuses et variées",
"oneToOne": "have one to one relation",
"oneToOne": "a une relation 1-1",
"extraConnectionParameters": "Paramètres de connexion supplémentaires",
"commentsOnly": "Commentaires uniquement",
"documentation": "Documentation",
@ -738,7 +740,7 @@
"includeView": "Inclure la vue",
"includeWebhook": "Inclure le Webhook",
"zoomInToViewColumns": "Zoom in to view columns",
"embedInSite": "Embed this view in your site",
"embedInSite": "Intégrer cette vue dans votre site",
"titleRequired": "le titre est obligatoire.",
"sourceNameRequired": "Le nom de la source est obligatoire",
"changeWsName": "Changer le nom de l'espace de travail",
@ -750,7 +752,7 @@
"saveChanges": "Enregistrer les modifications",
"updatedField": "Champ mis à jour",
"deletedField": "Champ supprimé",
"incompleteConfiguration": "Incomplete configuration",
"incompleteConfiguration": "Configuration incomplète",
"selectField": "Sélectionner un champ",
"selectFieldLabel": "Begin by selecting a field to customise its properties and structure."
},
@ -758,8 +760,8 @@
"backgroundColor": "Couleur d'arrière-plan",
"hideNocodbBranding": "Masquer la marque NocoDB",
"showOnConditions": "Show on conditions",
"showFieldOnConditionsMet": "Shows field only when conditions are met",
"limitOptions": "Limit options",
"showFieldOnConditionsMet": "Montre le champ uniquement lorsque les conditions sont réunies",
"limitOptions": "Limiter les options",
"limitOptionsSubtext": "Limit options visible to users by selecting available options",
"clearSelection": "Effacer la sélection"
},
@ -771,17 +773,17 @@
"newWorkspace": "Nouvel espace de travail",
"addDomain": "Add Domain",
"addMembers": "Ajouter des membres",
"enterEmail": "Enter email addresses",
"inviteToBase": "Invite to Base",
"inviteToWorkspace": "Invite to Workspace",
"addMember": "Add Member to Base",
"noRange": "Calendar view requires a date range",
"goToToday": "Go to Today",
"toggleSidebar": "Toggle Sidebar",
"addEndDate": "Add end date",
"withEndDate": "with end date",
"enterEmail": "Entrez les adresses e-mail",
"inviteToBase": "Inviter à la base",
"inviteToWorkspace": "Inviter à l'espace de travail",
"addMember": "Ajouter un membre à la Base",
"noRange": "La vue calendrier nécessite une plage de dates",
"goToToday": "Aller à aujourd'hui",
"toggleSidebar": "Activer/désactiver la barre latérale",
"addEndDate": "Ajouter une date de fin",
"withEndDate": "avec la date de fin",
"calendar": "Calendrier",
"viewSettings": "View settings",
"viewSettings": "Afficher les paramètres",
"googleOAuth": "Google OAuth",
"registerOIDC": "Register OIDC Identity Provider",
"registerSAML": "Register SAML Identity Provider",
@ -789,27 +791,27 @@
"copyIFrameCode": "Copier le code IFrame",
"onCondition": "On Condition",
"bulkDownload": "Bulk Download",
"attachFile": "Attach File",
"viewAttachment": "View Attachments",
"attachFile": "Joindre un fichier",
"viewAttachment": "Voir les pièces jointes",
"attachmentDrop": "Cliquez ou déposez un fichier dans la cellule",
"addFiles": "Ajouter un ou des fichier(s)",
"hideInUI": "Masquer dans l'interface",
"addBase": "Add Base",
"addBase": "Ajouter une base",
"addParameter": "Ajouter un paramètre",
"submitAnotherForm": "Soumettre un autre formulaire",
"dragAndDropFieldsHereToAdd": "Drag and drop fields here to add",
"editSource": "Edit Data Source",
"enterText": "Enter text",
"dragAndDropFieldsHereToAdd": "Glissez et déposez les champs ici pour ajouter",
"editSource": "Modifier la source de données",
"enterText": "Saisir texte",
"okEditBase": "Ok & Edit Base",
"showInUI": "Afficher dans l'interface utilisateur",
"outOfSync": "Out of sync",
"newSource": "Nouvelle source de données",
"newWebhook": "New Webhook",
"newWebhook": "Nouveau Webhook",
"enablePublicAccess": "Activer l'accès public",
"doYouWantToSaveTheChanges": "Voulez-vous enregistrer les modifications ?",
"editingAccess": "Accès en modification",
"enabledPublicViewing": "Activer l'affichage anonyme",
"restrictAccessWithPassword": "Restrict access with password",
"restrictAccessWithPassword": "Restreindre l'accès avec un mot de passe",
"manageProjectAccess": "Gérer l'accès à la base",
"allowDownload": "Autoriser le téléchargement",
"surveyMode": "Mode Sondage",
@ -887,7 +889,7 @@
"previousRecord": "Ligne précédente",
"copyApiURL": "Copier l'URL de l'API",
"createTable": "Créer une nouvelle table",
"createDashboard": "Create Dashboard",
"createDashboard": "Créer un tableau de bord",
"createWorkspace": "Créer un espace de travail",
"refreshTable": "Actualiser le tableau",
"renameTable": "Renommer la table",
@ -895,7 +897,7 @@
"deleteTable": "Supprimer la table",
"addField": "Ajouter un nouveau champ à ce tableau",
"setDisplay": "Définir comme valeur d'affichage",
"addRow": "Ajouter une nouvelle ligne",
"addRow": "Ajouter un nouvel enregistrement",
"saveRow": "Enregistrer",
"saveAndExit": "Enregistrer et quitter",
"saveAndStay": "Enregistrer et rester",
@ -917,7 +919,7 @@
"clearMetadata": "Effacer les métadonnées",
"exportToFile": "Exporter vers le fichier",
"changePwd": "Changer le mot de passe",
"createView": "Créer une vue",
"createView": "Créer vue",
"shareView": "Partager la vue",
"findRowByCodeScan": "Find row by scan",
"fillByCodeScan": "Remplir avec un scanner",
@ -972,10 +974,10 @@
"markAllAsRead": "Tout marquer comme lu",
"column": {
"delete": "Supprimer le champ",
"addNumber": "Add Number Field",
"addSingleLineText": "Add SingleLineText Field",
"addLongText": "Add LongText Field",
"addOther": "Add Other Field"
"addNumber": "Ajouter un champ de type numérique",
"addSingleLineText": "Ajouter un champ de type texte sur une ligne",
"addLongText": "Ajouter un champ de type texte long",
"addOther": "Ajouter un autre champ"
},
"erd": {
"showColumns": "Afficher les colonnes",
@ -999,17 +1001,17 @@
},
"toggleMobileMode": "(Dés-)activer le mode Mobile",
"startCommenting": "Commencez à commenter !",
"clearForm": "Clear Form",
"addFieldFromFormView": "Add Field",
"selectAllFields": "Select all fields",
"clearForm": "Vider le formulaire",
"addFieldFromFormView": "Ajouter un champ",
"selectAllFields": "Sélectionner tous les champs",
"preFilledFields": {
"title": "Enable Pre-fill",
"default": "Default",
"locked": "Lock pre-filled fields as read-only",
"hidden": "Hide pre-filled fields",
"lockedFieldTooltip": "Pre-filled value"
"title": "Autoriser le pré-remplissage",
"default": "Valeur par défaut",
"locked": "Mettre les champs préremplis en lecture seule",
"hidden": "Masquer les champs préremplis",
"lockedFieldTooltip": "Valeur préremplie"
},
"getPreFilledLink": "Get Pre-filled Link",
"getPreFilledLink": "Obtenir un lien prérempli",
"group": "Grouper par"
},
"tooltip": {
@ -1024,7 +1026,7 @@
"light": "Jour (^⇧B)"
},
"addTable": "Ajouter un nouveau tableau",
"addDashboard": "Add new Dashboard",
"addDashboard": "Ajouter un nouveau tableau de bord",
"inviteMore": "Inviter plus d'utilisateurs",
"toggleNavDraw": "Afficher ou masquer le panneau de navigation",
"reloadApiToken": "Recharger les jetons API",
@ -1041,9 +1043,9 @@
"clientKey": "Selectionner un fichier .key",
"clientCert": "Selectionner un fichier .cert",
"clientCA": "Selectionner un fichier d'authentification",
"changeIconColour": "Change icon colour",
"changeIconColour": "Changer la couleur de l'icône",
"preFillFormInfo": "Generate share form URL with pre-filled field data. To get a pre-filled link, make sure you’ve filled the necessary fields in the form view builder.",
"surveyFormInfo": "Form mode with one field per page"
"surveyFormInfo": "Mode formulaire avec un champ par page (enquête)"
},
"placeholder": {
"selectSlackChannels": "Sélectionnez les canaux Slack",
@ -1052,14 +1054,14 @@
"selectMattermostChannels": "Sélectionnez les canaux Mattermost",
"webhookTitle": "Titre du Webhook",
"barcodeColumn": "Sélectionnez un champ pour la valeur du code-barres",
"notFoundContent": "No valid field Type can be found.",
"selectBarcodeFormat": "Select a Barcode format",
"notFoundContent": "Aucun type de champ valide ne peut être trouvé.",
"selectBarcodeFormat": "Sélectionnez un format de code-barres",
"projName": "Saisir le nom du projet",
"selectGroupField": "Choisir un champ de regroupement",
"selectGroupFieldNotFound": "No Single Select Field can be found. Please create one first.",
"selectGeoField": "Select a GeoData Field",
"notSelected": "-not selected-",
"selectGeoFieldNotFound": "No GeoData Field can be found. Please create one first.",
"selectGroupFieldNotFound": "Aucun champ de sélection en liste ne peut être trouvé. Veuillez en créer un d'abord.",
"selectGeoField": "Sélectionnez un champ de type GeoData",
"notSelected": "-non sélectionné-",
"selectGeoFieldNotFound": "Aucun champ de type GeoData n'a été trouvé. Veuillez en créer un d'abord.",
"password": {
"enter": "Saisir le mot de passe",
"current": "Mot de passe actuel",
@ -1067,8 +1069,8 @@
"save": "Enregistrer le mot de passe",
"confirm": "Confirmer le nouveau mot de passe"
},
"selectAColumnForTheQRCodeValue": "Select a field for the QR code value",
"allowNegativeNumbers": "Allow negative numbers",
"selectAColumnForTheQRCodeValue": "Sélectionnez un champ contenant la valeur du QR code",
"allowNegativeNumbers": "Autoriser les nombres négatifs",
"searchProjectTree": "Chercher un tableau",
"searchFields": "Champ de recherche",
"searchColumn": "Recherche {recherche} colonne",
@ -1090,20 +1092,21 @@
"decimal8": "1,00000000",
"value": "Valeur",
"key": "Clé",
"createTable": "Create your First Table!",
"createTable": "Créez votre première table !",
"createTableLabel": "Create your first table effortlessly, from scratch, or by importing/connecting to an external database.",
"noTokenCreated": "No API Tokens created",
"noTokenCreated": "Aucun jeton d'API créé",
"noTokenCreatedLabel": "Begin by creating API tokens to unlock advanced functionalities.",
"inviteYourTeam": "Invite your team",
"inviteYourTeam": "Invitez votre équipe",
"inviteYourTeamLabel": "Streamline collaboration and productivity with your team – start by inviting them to join your workspace.",
"searchOptions": "Search options"
"searchOptions": "Options de recherche"
},
"msg": {
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Contrôlez le nom et l'apparence de vos organisations.",
"addCompanyDomains": "Ajoutez des domaines pour restreindre l'accès aux utilisateurs non souhaités.",
"restrictUsersFromSharing": "Empêcher les utilisateurs de partager leurs bases publiquement.",
"selectUsersToBeRemoved": "Select users to be removed and deleted from all organisation workspaces.",
"deleteOrganization": "Delete all users, bases and data related to this organization",
"selectUsersToBeRemoved": "Sélectionnez les utilisateurs à supprimer et à supprimer de tous les espaces de travail de l'organisation.",
"deleteOrganization": "Supprimer tous les utilisateurs, bases et données liées à cette organisation",
"clickToCopyFieldId": "Cliquer pour copier l'ID du champ",
"enterPassword": "Saisir le mot de passe",
"bySigningUp": "En vous inscrivant, vous acceptez les",
@ -1112,79 +1115,79 @@
"thisSharedViewIsProtected": "Cette vue partagée est protégée",
"successfullySubmittedFormData": "Données du formulaire soumises avec succès",
"formViewNotSupportedOnMobile": "L'affichage des formulaires n'est pas pris en charge sur les téléphones portables",
"newFormWillBeLoaded": "New form will be loaded after {seconds} seconds",
"newFormWillBeLoaded": "Un nouveau formulaire sera chargé après {seconds} secondes",
"optimizedQueryDisabled": "Optimized query is disabled",
"optimizedQueryEnabled": "Optimized query is enabled",
"lookupNonBtWarning": "Lookup field is not supported for non-Belongs to relation",
"invalidTime": "Invalid Time",
"linkColumnClearNotSupportedYet": "You don't have any supported links for Lookup",
"recordCouldNotBeFound": "Record could not be found",
"linkColumnClearNotSupportedYet": "Vous n'avez aucun lien défini pour ajouter un champ Lookup",
"recordCouldNotBeFound": "L'enregistrement n'a pas pu être trouvé",
"invalidPhoneNumber": "Numéro de téléphone invalide",
"pageSizeChanged": "Page size changed",
"pageSizeChanged": "Taille de la page modifiée",
"errorLoadingData": "Erreur de chargement des données",
"webhookBodyMsg1": "Use context variable",
"webhookBodyMsg2": "body",
"webhookBodyMsg1": "Utiliser une variable de contexte",
"webhookBodyMsg2": "corps du message",
"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",
"hintStart": "Astuce : Utilisez {placeholder1} pour référencer des champs, par exemple: {placeholder2}. Pour en savoir plus, veuillez vérifier",
"hintEnd": "Expressions.",
"noSuggestedFormulaFound": "Aucune formule suggérée trouvée",
"typeIsExpected": "{calleeName} requires a {type} at position {position}",
"numericTypeIsExpected": "Numeric type is expected",
"stringTypeIsExpected": "String type is expected",
"operationNotAvailable": "{operation} operation not available",
"numericTypeIsExpected": "Un type numérique est attendu",
"stringTypeIsExpected": "Un type texte est attendu",
"operationNotAvailable": "Opération {operation} non disponible",
"cantSaveFieldFormulaInvalid": "Impossible d'enregistrer le champ car la formule n'est pas valide",
"notSupportedToReferenceColumn": "Not supported to reference field {columnName}",
"typeIsExpectedButFound": "Le type {type} est attendu, mais le type {found} est trouvé",
"requiredArgumentsFormula": "{calleeName} requires {requiredArguments} arguments",
"requiredArgumentsFormula": "{calleeName} nécessite les arguments {requiredArguments}",
"minRequiredArgumentsFormula": "{calleeName} required minimum {minRequiredArguments} arguments",
"maxRequiredArgumentsFormula": "{calleeName} required maximum {maxRequiredArguments} arguments",
"functionNotAvailable": "La fonction {function} n'est pas disponible",
"firstParamWeekDayHaveDate": "The first parameter of WEEKDAY() should have date value",
"secondParamWeekDayHaveDate": "The second parameter of WEEKDAY() should have the value either \"sunday\", \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\" or \"saturday\"",
"firstParamDateAddHaveDate": "The first parameter of DATEADD() should have date value",
"secondParamDateAddHaveNumber": "The second parameter of DATEADD() should have numeric value",
"thirdParamDateAddHaveDate": "The third parameter of DATEADD() should have the value either \"day\", \"week\", \"month\" or \"year\"",
"firstParamDateDiffHaveDate": "The first parameter of DATEDIFF() should have date value",
"secondParamDateDiffHaveDate": "The second parameter of DATEDIFF() should have date value",
"thirdParamDateDiffHaveDate": "The third parameter of DATETIME_DIFF() should have value either \"milliseconds\", \"ms\", \"seconds\", \"s\", \"minutes\", \"m\", \"hours\", \"h\", \"days\", \"d\", \"weeks\", \"w\", \"months\", \"M\", \"quarters\", \"Q\", \"years\", or \"y\"",
"columnNotAvailable": "Field {columnName} is not available",
"cantSaveCircularReference": "Can’t save field because it causes a circular reference",
"columnWithTypeFoundButExpected": "Field {columnName} with {columnType} type is found but {expectedType} type is expected",
"columnNotMatchedWithType": "{columnName} is not matched with {columnType}"
"firstParamWeekDayHaveDate": "Le premier paramètre de la fonction WEEKDAY() doit avoir une valeur de type date",
"secondParamWeekDayHaveDate": "Le second paramètre de WEEKDAY() doit avoir la valeur \"dimanche\", \"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\" ou \"samedi\"",
"firstParamDateAddHaveDate": "Le premier paramètre de la fonction WEEKDAY() doit avoir une valeur de type date",
"secondParamDateAddHaveNumber": "Le deuxième paramètre de la fonction DATEADD() doit avoir une valeur numérique",
"thirdParamDateAddHaveDate": "Le troisième paramètre de DATEADD() doit avoir la valeur \"day\", \"week\", \"month\" ou \"year\"",
"firstParamDateDiffHaveDate": "Le premier paramètre de la fonction DATEDIFF() doit avoir une valeur de type date",
"secondParamDateDiffHaveDate": "Le second paramètre de la fonction DATEDIFF() doit avoir une valeur de type date",
"thirdParamDateDiffHaveDate": "Le troisième paramètre de la fonction DATETIME_DIFF() doit avoir la valeur \"millisecondes\", \"ms\", \"secondes\", \"s\", \"s\", \"s\", \"minutes\", \"m\", \"hours\", \"h\", \"days\", \"d\", \"weeks\", \"w\", \"months\", \"M\", \"quarters\", \"Q\", \"years\", ou \"y\"",
"columnNotAvailable": "Le champ {columnName} n'est pas disponible",
"cantSaveCircularReference": "Impossible d'enregistrer le champ car il provoque une référence circulaire",
"columnWithTypeFoundButExpected": "Le champ {columnName} avec le type {columnType} est trouvé mais le type {expectedType} est attendu",
"columnNotMatchedWithType": "{columnName} ne correspond pas au type {columnType}"
},
"selectOption": {
"cantBeNull": "Select options can't be null",
"multiSelectCantHaveCommas": "MultiSelect fields can't have commas(',')",
"cantHaveDuplicates": "Select options can't have duplicates",
"createNewOptionNamed": "Create new option named"
"createNewOptionNamed": "Créer une nouvelle option nommée"
},
"plsEnterANumber": "Veuillez saisir un nombre",
"plsInputEmail": "Veuillez saisir un e-mail",
"invalidDate": "Invalid date",
"invalidLocale": "Invalid locale",
"invalidDate": "Date non valide",
"invalidLocale": "Langue invalide",
"invalidCurrencyCode": "Code de devise invalide",
"postgresHasItsOwnCurrencySettings": "Le type 'money' de PostgreSQL a ses propres paramètres de devise",
"validColumnsForBarCode": "The valid Field Types for a Barcode Field are: Number, Single Line Text, Long Text, Phone Number, URL, Email, Decimal. Please create one first.",
"validColumnsForBarCode": "Les types de champs valides pour un champ de code-barres sont : Numéro, Texte à une seule ligne, Texte Long, Numéro de Téléphone, URL, Email, Décimal. Veuillez en créer un d'abord.",
"hm": {
"title": "Has Many Relation",
"tooltip_desc": "A single record from table ",
"title": "Relation 1-n",
"tooltip_desc": "Un seul enregistrement de la table ",
"tooltip_desc2": " peut être lié avec plusieurs enregistrements de la table "
},
"mm": {
"title": "Many to Many Relation",
"tooltip_desc": "Multiple records from table ",
"tooltip_desc2": " can be linked with multiple records from table "
"title": "Relation n-n",
"tooltip_desc": "Plusieurs enregistrements de la table ",
"tooltip_desc2": " peut être lié avec plusieurs enregistrements de la table "
},
"bt": {
"title": "Belongs to Relation",
"tooltip_desc": "A single record from table ",
"tooltip_desc2": " can be linked with a record from table "
"title": "Relation appartient à",
"tooltip_desc": "Un seul enregistrement de la table ",
"tooltip_desc2": " peut être lié avec un enregistrement de la table "
},
"oo": {
"title": "One to One Relation",
"tooltip_desc": "A single record from table ",
"tooltip_desc2": " can be linked with a single record from table "
"tooltip_desc2": " peut être lié à un seul enregistrement de la table "
},
"clickLinkRecordsToAddLinkFromTable": "Il semble qu'aucun enregistrement n'ait encore été lié.",
"noRecordsLinked": "Aucun enregistrement lié",
@ -1202,17 +1205,17 @@
"idColumnRequired": "ID field is required, you can rename this later if required.",
"length59Required": "The length exceeds the max 59 characters",
"noNewNotifications": "You have no new notifications",
"noRecordFound": "Record not found",
"noRecordFound": "Enregistrement non trouvé",
"noRecordsFound": "Aucun enregistrement trouvé",
"noRecordsMatchYourSearchQuery": "Aucun enregistrement ne correspond à votre recherche",
"rowDeleted": "Record deleted",
"saveChanges": "Do you want to save the changes?",
"tooLargeFieldEntity": "The field is too large to be converted to {entity}",
"rowDeleted": "Enregistrement supprimé",
"saveChanges": "Voulez-vous enregistrer les modifications ?",
"tooLargeFieldEntity": "Le champ est trop grand pour être converti en {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!",
"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!",
"mapNoFields": "La vue cartographique nécessite un champ de données géographiques pour être configuré. Essayez de configurer une vue cartographique après avoir ajouté un champ de données géographiques !",
"dbValid": "Veuillez vous assurer que la base de données à laquelle vous essayez de vous connecter est valide ! Cette opération peut provoquer une perte de schéma !!",
"barcode": {
"renderError": "Erreur de code-barres - veuillez vérifier la compatibiltié entre la donnée d'entrée et le type de code-barres"
@ -1220,24 +1223,24 @@
"nonEditableFields": {
"computedFieldUnableToClear": "Avertissement : Champ calculé - impossible d'effacer le texte",
"qrFieldsCannotBeDirectlyChanged": "Attention : les champs QR code ne peuvent pas être modifiés directement.",
"barcodeFieldsCannotBeDirectlyChanged": "Warning: Barcode fields cannot be directly changed."
"barcodeFieldsCannotBeDirectlyChanged": "Attention : les champs code-barres ne peuvent pas être modifiés directement."
},
"duplicateProject": "Are you sure you want to duplicate the base?",
"duplicateProject": "Êtes-vous sûr de vouloir dupliquer la base ?",
"duplicateTable": "Êtes-vous sûr de vouloir dupliquer la table ?",
"multiField": {
"fieldVisibility": "You cannot change visibility of a field that is being edited. Please save or discard changes first.",
"moveEditedField": "You cannot move field that is being edited. Either save or discard changes first",
"moveDeletedField": "You cannot move field that is deleted. Either save or discard changes first"
"fieldVisibility": "Vous ne pouvez pas modifier la visibilité d'un champ en cours de modification. Veuillez d'abord enregistrer ou annuler les modifications.",
"moveEditedField": "Vous ne pouvez pas déplacer un champ en cours d'édition. Enregistrez ou annulez d'abord les modifications",
"moveDeletedField": "Vous ne pouvez pas déplacer un champ supprimé. Enregistrez ou annulez d'abord les modifications"
}
},
"info": {
"enterWorkspaceName": "Enter workspace name",
"enterBaseName": "Enter base name",
"enterWorkspaceName": "Entrez le nom de l'espace de travail",
"enterBaseName": "Entrez le nom de base",
"idpPaste": "Paste these URL in your Identity Providers console",
"noSaml": "There are no configured SAML authentications.",
"noOIDC": "There are no configured OpenID authentications.",
"noSaml": "Il n'y a aucune authentification SAML configurée.",
"noOIDC": "Il n'y a aucune authentification OpenID configurée.",
"disabledAsViewLocked": "Désactivé car la vue est verrouillée",
"basesMigrated": "Bases are migrated. Please try again.",
"basesMigrated": "Les bases sont migrées. Veuillez réessayer.",
"pasteNotSupported": "L'opération de collage n'est pas prise en charge sur la cellule active",
"roles": {
"orgCreator": "Le créateur peut créer de nouveaux projets et accéder à tout projet invité.",
@ -1277,7 +1280,7 @@
"formInput": "Entrer le libellé du formulaire",
"formHelpText": "Ajouter un texte d'aide",
"onlyCreator": "Visible uniquement pour les créateurs",
"formTitle": "Add form Title",
"formTitle": "Ajouter un titre au formulaire",
"formDesc": "Ajouter une description au formulaire",
"beforeEnablePwd": "Restreindre l’accès à l’aide d’un mot de passe",
"afterEnablePwd": "L’accès est restreint par un mot de passe",
@ -1290,7 +1293,7 @@
"emailForm": "Écrivez-moi à",
"showSysFields": "Afficher les champs système",
"filterAutoApply": "Appliquer automatiquement",
"formDisplayMessage": "Display Message",
"formDisplayMessage": "Afficher le 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.",
@ -1344,8 +1347,8 @@
"addMultipleUsers": "Vous pouvez ajouter plusieurs courriels séparés par des virgules (,)",
"enterTableName": "Entrez le nom du tableau",
"enterLayoutName": "Enter Layout name",
"enterDashboardName": "Enter Dashboard name",
"defaultColumns": "Default fields",
"enterDashboardName": "Entrez le nom du tableau de bord",
"defaultColumns": "Champs par défaut",
"addDefaultColumns": "Ajouter des colonnes par défaut",
"tableNameInDb": "Nom de la table tel qu'enregistré dans la base de données",
"airtable": {
@ -1385,8 +1388,8 @@
"noMoreRecords": "Plus d'enregistrements",
"tokenNameNotEmpty": "Token name should not be empty",
"tokenNameMaxLength": "Token name should not be more than 255 characters",
"dbNameRequired": "Database name is required",
"wsNameRequired": "Workspace name required",
"dbNameRequired": "Le nom de la base de données est requis",
"wsNameRequired": "Nom de l'espace de travail requis",
"wsNameMinLength": "Le nom de l'espace de travail doit comporter au moins 3 caractères",
"wsNameMaxLength": "Le nom de l'espace de travail doit comporter au plus 50 caractères",
"wsDeleteDlg": "Supprimez cet espace de travail et tout son contenu.",
@ -1398,25 +1401,25 @@
"thankYou": "Merci !",
"submittedFormData": "Vous avez soumis les données du formulaire avec succès.",
"editingSystemKeyNotSupported": "Editing system key not supported",
"notAvailableAtTheMoment": "Not available at the moment",
"notAvailableAtTheMoment": "Non disponible pour le 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}",
"thisFeatureIsOnlyAvailableInEnterpriseEdition": "This feature is only available in enterprise edition",
"yourCurrentRoleIs": "Your current role is",
"pleaseRequestAccessForView": "Please request for higher permission from the Admin / Base owner / Workspace owner to get access to this {viewName}",
"yourCurrentRoleIs": "Votre rôle actuel est",
"pleaseRequestAccessForView": "Veuillez demander des droits plus élevés au propriétaire de l’Admin / Base / Espace de travail pour avoir accès à cette {viewName}",
"preventHideAllOptions": "You cannot hide all options if field is required"
},
"error": {
"fetchingCalendarData": "Erreur lors de la récupération des données du calendrier",
"fetchingActiveDates": "Error fetching active dates",
"scopesRequired": "Scopes required",
"domainRequired": "Domain name is required",
"domainRequired": "Le nom de domaine est requis",
"authUrlRequired": "Auth URL is required",
"userNameAttributeRequired": "Username attribute is required",
"clientIdRequired": "Client ID is required",
"clientIdRequired": "L'ID du client est requis",
"issuerRequired": "Issuer is required",
"clientSecretRequired": "Client Secret is required",
"clientSecretRequired": "Le client secret est requis",
"jwkUrlRequired": "JWK URL is required",
"tokenUrlRequired": "Token URL is required",
"userInfoUrlRequired": "UserInfo URL is required",
@ -1449,8 +1452,8 @@
"atLeastOneNumber": "Un chiffre",
"atLeastOneSpecialChar": "Un caractère spécial",
"allowedSpecialCharList": "Liste des caractères spéciaux autorisés",
"invalidEmails": "Invalid emails",
"invalidEmail": "Invalid Email"
"invalidEmails": "E-mails non valides",
"invalidEmail": "Email non valide"
},
"invalidXml": "Invalid XML",
"invalidURL": "URL invalide",
@ -1483,7 +1486,7 @@
"followingCharactersAreNotAllowed": "Les caractères suivants ne sont pas autorisés",
"columnNameRequired": "Nom de la colonne requis",
"duplicateColumnName": "Duplicate field name",
"duplicateSystemColumnName": "Name already used for system field",
"duplicateSystemColumnName": "Nom déjà utilisé par un champ système",
"uiDataTypeRequired": "UI data type is required",
"columnNameExceedsCharacters": "The length of column name exceeds the max {value} characters",
"projectNameExceeds50Characters": "Le nom du projet dépasse les 50 caractères",
@ -1495,15 +1498,15 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Les types de fichiers acceptés sont .xls, .xlsx, .xlsm, .ods, .ots.",
"parameterKeyCannotBeEmpty": "La clé de paramètre ne peut pas être vide",
"duplicateParameterKeysAreNotAllowed": "Les doublons de clés de paramètres ne sont pas autorisés",
"fieldRequired": "{value} ne peut pas être vide.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projet non accessible",
"copyToClipboardError": "Échec de la copie dans le presse-papiers",
"pasteFromClipboardError": "Failed to paste from clipboard",
"pasteFromClipboardError": "Échec du collage à partir du presse-papiers",
"multiFieldSaveValidation": "Please complete the configuration of all fields before saving",
"somethingWentWrong": "Something went wrong",
"somethingWentWrong": "Quelque chose n'a pas fonctionné",
"draggedContentIsNotTypeOfImage": "Dragged content is not type of image",
"fieldToParseImageData": "Field to parse image data",
"someOfTheRequiredFieldsAreEmpty": "Some of the required fields are empty"
"someOfTheRequiredFieldsAreEmpty": "Certains des champs requis sont vides"
},
"toast": {
"exportMetadata": "Les métadonnées de projet sont exportées avec succès",
@ -1523,9 +1526,9 @@
"futureRelease": "Bientôt disponible !"
},
"success": {
"licenseKeyUpdated": "License Key Updated",
"licenseKeyUpdated": "Clé de licence mise à jour",
"columnDuplicated": "Colonne dupliquée avec succès",
"rowDuplicatedWithoutSavedYet": "Row duplicated (not saved)",
"rowDuplicatedWithoutSavedYet": "Enregistrement en double (non enregistré)",
"updatedUIACL": "Mise à jour réussie de l'ACL de l'interface utilisateur pour les tables",
"pluginUninstalled": "Le plugin a été désinstallé avec succès",
"pluginSettingsSaved": "Les paramètres du plugin ont été enregistrés avec succès",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "שם שולחן",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Table name",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tablica",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Dozvoljeni tipovi datoteka su .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Ključ parametra ne može biti prazan",
"duplicateParameterKeysAreNotAllowed": "Duplicirani ključevi parametara nisu dopušteni",
"fieldRequired": "{value} ne može biti prazno.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Kopiranje u međuspremnik nije uspjelo",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Nama meja",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Jenis file yang diterima adalah .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Kunci parameter tidak boleh kosong",
"duplicateParameterKeysAreNotAllowed": "Kunci parameter duplikat tidak diperbolehkan",
"fieldRequired": "{value} tidak boleh kosong.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Proyek tidak dapat diakses",
"copyToClipboardError": "Gagal menyalin ke papan klip",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Token senza titolo",
"tableName": "Nome della tabella",
"dashboardName": "Nome dashboard",
"createView": "Crea una vista",
"createView": "Crea vista",
"creatingView": "Creazione vista",
"duplicateView": "Duplica vista",
"duplicateGridView": "Duplica Visualizzazione Griglia",
@ -917,7 +919,7 @@
"clearMetadata": "Cancella metadati",
"exportToFile": "Esporta su file",
"changePwd": "Cambia password",
"createView": "Crea una vista",
"createView": "Crea vista",
"shareView": "Condividi vista",
"findRowByCodeScan": "Find row by scan",
"fillByCodeScan": "Riempi per scansione",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "I tipi di file accettati sono .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "La chiave del parametro non può essere vuota",
"duplicateParameterKeysAreNotAllowed": "Le chiavi dei parametri duplicate non sono consentite",
"fieldRequired": "{value} non può essere vuoto.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Progetto non accessibile",
"copyToClipboardError": "Non è riuscito a copiare negli appunti",
"pasteFromClipboardError": "Impossibile incollare dagli appunti",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "テーブルの名前",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "使用可能なファイル形式は、.xls、.xlsx、.xlsm、.ods、.ots です。",
"parameterKeyCannotBeEmpty": "パラメータキーは空にできません",
"duplicateParameterKeysAreNotAllowed": "パラメータキーの重複は許可されていません",
"fieldRequired": "{value} を空にすることはできません。",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "このプロジェクトにはアクセスできません",
"copyToClipboardError": "クリップボードへのコピーに失敗しました",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "허용되는 파일 형식은 .xls, .xlsx, .xlsm, .ods, .ots입니다",
"parameterKeyCannotBeEmpty": "매개 변수 키는 비워 둘 수 없습니다.",
"duplicateParameterKeysAreNotAllowed": "중복 매개 변수 키는 허용되지 않습니다.",
"fieldRequired": "{value}은(는) 비워 둘 수 없습니다.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "프로젝트에 액세스할 수 없습니다.",
"copyToClipboardError": "클립 보드에 복사할 수 없습니다.",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tabulas nosaukums",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Pieņemtie failu tipi ir .xls, .xlsx, .xlsm, .ods, .ots.",
"parameterKeyCannotBeEmpty": "Parametra atslēga nedrīkst būt tukša",
"duplicateParameterKeysAreNotAllowed": "Parametru taustiņu dublēšanās nav atļauta",
"fieldRequired": "{value} nevar būt tukšs.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projekts nav pieejams",
"copyToClipboardError": "Neizdevās kopēt uz starpliktuvi",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tabelnaam",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "De geaccepteerde bestandstypen zijn .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parametersleutel kan niet leeg zijn",
"duplicateParameterKeysAreNotAllowed": "Dubbele parametersleutels zijn niet toegestaan",
"fieldRequired": "{value} kan niet leeg zijn.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Project niet toegankelijk",
"copyToClipboardError": "Kopiëren naar klembord mislukt",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tabellnavn",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Dziś",
"workspace": "Obszar roboczy",
"txt": "Wartość rekordu TXT",
@ -1099,6 +1101,7 @@
"searchOptions": "Opcje wyszukiwania"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Kontroluj nazwę i wygląd organizacji.",
"addCompanyDomains": "Dodaj domeny firmy, aby ograniczyć dostęp od niechcianych użytkowników.",
"restrictUsersFromSharing": "Ogranicz użytkowników z możliwości publicznego udostępniania baz danych.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Akceptowane typy plików to: .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Klucz parametru nie może być pusty",
"duplicateParameterKeysAreNotAllowed": "Zduplikowane klucze parametrów są niedozwolone",
"fieldRequired": "{value} nie może być puste.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projekt niedostępny",
"copyToClipboardError": "Nie udało się skopiować do schowka",
"pasteFromClipboardError": "Nie udało się wkleić ze schowka",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Token sem título",
"tableName": "Nome da tabela",
"dashboardName": "Nome do painel",
"createView": "Criar uma vista",
"createView": "Criar Vista",
"creatingView": "Criando visualização",
"duplicateView": "Vista duplicada",
"duplicateGridView": "Vista duplicada em grelha",
@ -917,7 +919,7 @@
"clearMetadata": "Limpar Metadados",
"exportToFile": "Exportar para ficheiro",
"changePwd": "Alterar a senha",
"createView": "Criar uma vista",
"createView": "Criar Vista",
"shareView": "Partilhar Vista",
"findRowByCodeScan": "Find row by scan",
"fillByCodeScan": "Fill by scan",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Os tipos de ficheiro aceites são .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "A chave do parâmetro não pode estar vazia",
"duplicateParameterKeysAreNotAllowed": "Não são permitidas chaves de parâmetros duplicadas",
"fieldRequired": "{value} não pode estar vazio.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projecto não acessível",
"copyToClipboardError": "Falha na cópia para a prancheta",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Nome da tabela",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Os tipos de ficheiro aceites são .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "A chave do parâmetro não pode estar vazia",
"duplicateParameterKeysAreNotAllowed": "Não são permitidas chaves de parâmetros duplicadas",
"fieldRequired": "{value} não pode estar vazio.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projecto não acessível",
"copyToClipboardError": "Falha na cópia para a prancheta",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Название таблицы",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Допустимые типы файлов: .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Ключ параметра не может быть пустым",
"duplicateParameterKeysAreNotAllowed": "Дублирование ключей параметров не допускается",
"fieldRequired": "{value} не может быть пустым.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Проект недоступен",
"copyToClipboardError": "Не удалось скопировать в буфер обмена",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Názov tabuľky",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Akceptované typy súborov sú .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Kľúč parametra nemôže byť prázdny",
"duplicateParameterKeysAreNotAllowed": "Duplicitné kľúče parametrov nie sú povolené",
"fieldRequired": "{value} nemôže byť prázdny.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projekt nie je prístupný",
"copyToClipboardError": "Nepodarilo sa skopírovať do schránky",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Ime tabele",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Sprejete vrste datotek so .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Ključ parametra ne more biti prazen",
"duplicateParameterKeysAreNotAllowed": "Podvojeni ključi parametrov niso dovoljeni",
"fieldRequired": "{value} ne more biti prazen.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projekt ni dostopen",
"copyToClipboardError": "Neuspešno kopiranje v odložišče",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tabellnamn",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "De accepterade filtyperna är .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parameternyckeln kan inte vara tom",
"duplicateParameterKeysAreNotAllowed": "Dubbla parameternycklar är inte tillåtna",
"fieldRequired": "{value} får inte vara tom.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Projektet är inte tillgängligt",
"copyToClipboardError": "Kopiering till urklipp misslyckades",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "ชอตาราง",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Kabul edilen dosya türleri .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Parametre anahtarı boş olamaz",
"duplicateParameterKeysAreNotAllowed": "Yinelenen parametre anahtarlarına izin verilmez",
"fieldRequired": "{value} boş olamaz.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Proje erişilebilir değil",
"copyToClipboardError": "Panoya kopyalanamadı",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Назва таблиці",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "Дозволені типи файлів: .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "Ключ параметра не може бути порожнім",
"duplicateParameterKeysAreNotAllowed": "Дублювання ключів параметрів неприпустимо",
"fieldRequired": "{value} не може бути порожнім.",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Проєкт недоступний",
"copyToClipboardError": "Не вдалося скопіювати в буфер обміну",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "Tên bảng.",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,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": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "Failed to copy to clipboard",
"pasteFromClipboardError": "Failed to paste from clipboard",

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

@ -162,7 +162,7 @@
"insertAbove": "将上方内容插入",
"insertBelow": "将下方内容插入",
"hideField": "隐藏字段",
"showField": "Show Field",
"showField": "显示字段",
"sortAsc": "升序",
"sortDesc": "降序",
"move": "移动",
@ -448,16 +448,18 @@
"noResultsMatchedYourSearch": "您的搜索没有任何匹配结果"
},
"labels": {
"today": "Today",
"workspace": "Workspace",
"connectionDetails": "链接明细",
"metaSync": "元同步",
"today": "今天",
"workspace": "工作区",
"txt": "TXT 记录值",
"transferOwnership": "转让所有权",
"recentActivity": "最近动态",
"goToMembers": "转到成员",
"addMember": "添加成员",
"numberOfMembers": "No. Members",
"numberOfBases": "No. Bases",
"numberOfRecords": "No. Records",
"numberOfMembers": "工作区序号",
"numberOfBases": "项目序号",
"numberOfRecords": "记录序号",
"workspaceName": "工作区名称",
"workspaceWithoutOwner": "工作区(无所有者)",
"inviteUsersToWorkspace": "邀请用户访问工作区",
@ -469,7 +471,7 @@
"signOutUsers": "注销用户",
"deactivateUser": "停用用户",
"deactivateUsers": "停用用户",
"lastActive": "Last Active",
"lastActive": "最近活动",
"dateAdded": "日期已添加",
"uploadImage": "上传图片",
"organizationProfile": "组织简介",
@ -482,7 +484,7 @@
"deleteUserAndData": "删除用户及其数据",
"userOptions": "用户选项",
"deleteThisOrganization": "删除该组织",
"dangerZone": "Dangerzone",
"dangerZone": "危险区",
"selectYear": "选择年份",
"save": "保存",
"cancel": "取消",
@ -1099,6 +1101,7 @@
"searchOptions": "搜索选项"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "控制您的组织名称和外观。",
"addCompanyDomains": "添加公司域,限制不需要的用户访问。",
"restrictUsersFromSharing": "限制用户公开共享项目 。",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "可接受的文件类型是 .xls, .xlsx, .xlsm, .ods, .ots",
"parameterKeyCannotBeEmpty": "参数键不能为空",
"duplicateParameterKeysAreNotAllowed": "不允许重复的参数键",
"fieldRequired": "{value} 不能为空。",
"fieldRequired": "此字段不能为空。",
"projectNotAccessible": "无权访问此项目",
"copyToClipboardError": "未能复制到剪贴板",
"pasteFromClipboardError": "从剪贴板粘贴失败",

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

@ -448,6 +448,8 @@
"noResultsMatchedYourSearch": "Your search did not yield any matching results."
},
"labels": {
"connectionDetails": "Connection Details",
"metaSync": "Meta Sync",
"today": "Today",
"workspace": "Workspace",
"txt": "TXT Record value",
@ -587,7 +589,7 @@
"untitledToken": "Untitled token",
"tableName": "表名稱",
"dashboardName": "Dashboard name",
"createView": "Create a View",
"createView": "Create View",
"creatingView": "Creating View",
"duplicateView": "Duplicate View",
"duplicateGridView": "Duplicate Grid View",
@ -1099,6 +1101,7 @@
"searchOptions": "Search options"
},
"msg": {
"formulaNotSupported": "This function is unavailable for your database",
"controlOrgAppearance": "Control your organisations name and appearance.",
"addCompanyDomains": "Add company domains to restrict access to unwanted users.",
"restrictUsersFromSharing": "Restrict users from being able to share bases publicly.",
@ -1495,7 +1498,7 @@
"theAcceptedFileTypesAreXlsXlsxXlsmOdsOts": "受支持的檔案類型包括 .xls、.xlsx、.xlsm、.ods 和 .ots",
"parameterKeyCannotBeEmpty": "參數鍵不可為空",
"duplicateParameterKeysAreNotAllowed": "不允許重複的參數鍵",
"fieldRequired": "{value} 不能為空",
"fieldRequired": "This field cannot be empty.",
"projectNotAccessible": "Project not accessible",
"copyToClipboardError": "複製到剪貼簿失敗",
"pasteFromClipboardError": "Failed to paste from clipboard",

2
packages/nocodb/src/app.module.ts

@ -21,7 +21,6 @@ import { JobsModule } from '~/modules/jobs/jobs.module';
import appConfig from '~/app.config';
import { ExtractIdsMiddleware } from '~/middlewares/extract-ids/extract-ids.middleware';
import { HookHandlerService } from '~/services/hook-handler.service';
import { BasicStrategy } from '~/strategies/basic.strategy/basic.strategy';
import { UsersModule } from '~/modules/users/users.module';
import { AuthModule } from '~/modules/auth/auth.module';
@ -66,7 +65,6 @@ export const ceModuleConfig = {
LocalStrategy,
AuthTokenStrategy,
BaseViewStrategy,
HookHandlerService,
BasicStrategy,
],
};

6
packages/nocodb/src/controllers/auth/ui/emailTemplates/invite.ts

@ -132,8 +132,8 @@ export default `<!doctype html>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Hi,</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
I invited you to be "<%- roles -%>" of the NocoDB base "<%- baseName %>".
Click the button below to to accept my invitation.</p>
You have been invited to become "<%- roles -%>" of the NocoDB base "<%- baseName %>".
Click the button below to accept the invitation.</p>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"
class="btn btn-primary"
style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; box-sizing: border-box; width: 100%;"
@ -161,7 +161,7 @@ export default `<!doctype html>
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Thanks regards <%- adminEmail %>.</p>
Have a nice day,<br><%- adminEmail %></p>
</td>
</tr>
</table>

4
packages/nocodb/src/controllers/auth/ui/emailTemplates/verify.ts

@ -132,7 +132,7 @@ export default `<!doctype html>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Hi,</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Please verify your email address by clicking the following button.</p>
Please verify your e-mail address by clicking the following button.</p>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"
class="btn btn-primary"
style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; box-sizing: border-box; width: 100%;"
@ -160,7 +160,7 @@ export default `<!doctype html>
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Thanks regards NocoDB.</p>
Thank you and have a nice day,<br><%- adminEmail %></p>
</td>
</tr>
</table>

4
packages/nocodb/src/filters/global-exception/global-exception.filter.ts

@ -10,6 +10,7 @@ import {
ExternalError,
extractDBError,
Forbidden,
NcBaseError,
NcBaseErrorv2,
NotFound,
SsoError,
@ -39,7 +40,8 @@ export class GlobalExceptionFilter implements ExceptionFilter {
exception = new NcBaseErrorv2(NcErrorType.BAD_JSON);
}
const dbError = extractDBError(exception);
// try to extract db error for unknown errors
const dbError = !(exception instanceof NcBaseError) ? extractDBError(exception) : null;
// skip unnecessary error logging
if (

3
packages/nocodb/src/helpers/isDisposableEmail.ts

@ -3503,9 +3503,6 @@ const disposableEmailDomains = [
'xrap.de',
'xrho.com',
'xvx.us',
'xwaretech.com',
'xwaretech.info',
'xwaretech.net',
'xww.ro',
'xxhamsterxx.ga',
'xxi2.com',

13
packages/nocodb/src/interface/Jobs.ts

@ -1,3 +1,5 @@
import type { UserType } from 'nocodb-sdk';
export const JOBS_QUEUE = 'jobs';
export enum JobTypes {
@ -12,6 +14,7 @@ export enum JobTypes {
UpdateWsStat = 'update-ws-stats',
UpdateSrcStat = 'update-source-stat',
HealthCheck = 'health-check',
HandleWebhook = 'handle-webhook',
}
export enum JobStatus {
@ -40,3 +43,13 @@ export enum InstanceCommands {
RESET = 'reset',
RELEASE = 'release',
}
export interface HandleWebhookJobData {
hookName: string;
prevData;
newData;
user: UserType;
viewId: string;
modelId: string;
tnPath: string;
}

6
packages/nocodb/src/modules/global/global.module.ts

@ -12,7 +12,9 @@ import { JwtStrategy } from '~/strategies/jwt.strategy';
import { UsersService } from '~/services/users/users.service';
import { TelemetryService } from '~/services/telemetry.service';
import { AppHooksListenerService } from '~/services/app-hooks-listener.service';
import { HookHandlerService } from '~/services/hook-handler.service';
import { UsersModule } from '~/modules/users/users.module';
import { JobsModule } from '~/modules/jobs/jobs.module';
export const JwtStrategyProvider: Provider = {
provide: JwtStrategy,
@ -36,7 +38,7 @@ export const JwtStrategyProvider: Provider = {
};
export const globalModuleMetadata = {
imports: [EventEmitterModule, forwardRef(() => UsersModule)],
imports: [EventEmitterModule, forwardRef(() => UsersModule), JobsModule],
providers: [
InitMetaServiceProvider,
AppHooksService,
@ -46,6 +48,7 @@ export const globalModuleMetadata = {
AppHooksService,
AppHooksListenerService,
TelemetryService,
HookHandlerService,
],
exports: [
MetaService,
@ -54,6 +57,7 @@ export const globalModuleMetadata = {
AppHooksService,
AppHooksListenerService,
TelemetryService,
HookHandlerService,
...(process.env.NC_WORKER_CONTAINER !== 'true' ? [SocketGateway] : []),
],
};

6
packages/nocodb/src/modules/jobs/fallback/fallback-queue.service.ts

@ -6,6 +6,7 @@ import { AtImportProcessor } from '~/modules/jobs/jobs/at-import/at-import.proce
import { MetaSyncProcessor } from '~/modules/jobs/jobs/meta-sync/meta-sync.processor';
import { SourceCreateProcessor } from '~/modules/jobs/jobs/source-create/source-create.processor';
import { SourceDeleteProcessor } from '~/modules/jobs/jobs/source-delete/source-delete.processor';
import { WebhookHandlerProcessor } from '~/modules/jobs/jobs/webhook-handler/webhook-handler.processor';
import { JobsEventService } from '~/modules/jobs/fallback/jobs-event.service';
import { JobStatus, JobTypes } from '~/interface/Jobs';
@ -31,6 +32,7 @@ export class QueueService {
protected readonly metaSyncProcessor: MetaSyncProcessor,
protected readonly sourceCreateProcessor: SourceCreateProcessor,
protected readonly sourceDeleteProcessor: SourceDeleteProcessor,
protected readonly webhookHandlerProcessor: WebhookHandlerProcessor,
) {
this.emitter.on(JobStatus.ACTIVE, (data: { job: Job }) => {
const job = this.queueMemory.find((job) => job.id === data.job.id);
@ -88,6 +90,10 @@ export class QueueService {
this: this.sourceDeleteProcessor,
fn: this.sourceDeleteProcessor.job,
},
[JobTypes.HandleWebhook]: {
this: this.webhookHandlerProcessor,
fn: this.webhookHandlerProcessor.job,
},
};
async jobWrapper(job: Job) {

13
packages/nocodb/src/modules/jobs/jobs-service.interface.ts

@ -0,0 +1,13 @@
import type Bull from 'bull';
import type { JobStatus } from '~/interface/Jobs';
export interface IJobsService {
jobsQueue: Bull.Queue;
toggleQueue(): Promise<void>;
add(name: string, data: any): Promise<Bull.Job<any>>;
jobStatus(jobId: string): Promise<JobStatus>;
jobList(): Promise<Bull.Job<any>[]>;
getJobWithData(data: any): Promise<Bull.Job<any>>;
resumeQueue(): Promise<void>;
pauseQueue(): Promise<void>;
}

5
packages/nocodb/src/modules/jobs/jobs.controller.ts

@ -21,6 +21,7 @@ import { GlobalGuard } from '~/guards/global/global.guard';
import NocoCache from '~/cache/NocoCache';
import { CacheGetType, CacheScope } from '~/utils/globals';
import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
const nanoidv2 = customAlphabet('1234567890abcdefghijklmnopqrstuvwxyz', 14);
const POLLING_INTERVAL = 30000;
@ -31,7 +32,7 @@ export class JobsController implements OnModuleInit {
jobsRedisService: JobsRedisService;
constructor(
@Inject('JobsService') private readonly jobsService,
@Inject('JobsService') private readonly jobsService: IJobsService,
private moduleRef: ModuleRef,
) {}
@ -168,7 +169,7 @@ export class JobsController implements OnModuleInit {
const job = await this.jobsService.getJobWithData(data);
if (job) {
res = {};
res.id = job.id;
res.id = `${job.id}`;
res.status = await this.jobsService.jobStatus(data.id);
}
}

2
packages/nocodb/src/modules/jobs/jobs.module.ts

@ -14,6 +14,7 @@ import { SourceCreateController } from '~/modules/jobs/jobs/source-create/source
import { SourceCreateProcessor } from '~/modules/jobs/jobs/source-create/source-create.processor';
import { SourceDeleteController } from '~/modules/jobs/jobs/source-delete/source-delete.controller';
import { SourceDeleteProcessor } from '~/modules/jobs/jobs/source-delete/source-delete.processor';
import { WebhookHandlerProcessor } from '~/modules/jobs/jobs/webhook-handler/webhook-handler.processor';
// Jobs Module Related
import { JobsLogService } from '~/modules/jobs/jobs/jobs-log.service';
@ -77,6 +78,7 @@ export const JobsModuleMetadata = {
MetaSyncProcessor,
SourceCreateProcessor,
SourceDeleteProcessor,
WebhookHandlerProcessor,
],
exports: ['JobsService'],
};

5
packages/nocodb/src/modules/jobs/jobs/at-import/at-import.controller.ts

@ -13,11 +13,14 @@ import { SyncSource } from '~/models';
import { NcError } from '~/helpers/catchError';
import { JobTypes } from '~/interface/Jobs';
import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
@Controller()
@UseGuards(MetaApiLimiterGuard, GlobalGuard)
export class AtImportController {
constructor(@Inject('JobsService') private readonly jobsService) {}
constructor(
@Inject('JobsService') private readonly jobsService: IJobsService,
) {}
@Post([
'/api/v1/db/meta/syncs/:syncId/trigger',

3
packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.controller.ts

@ -17,12 +17,13 @@ import { Base, Column, Model, Source } from '~/models';
import { generateUniqueName } from '~/helpers/exportImportHelpers';
import { JobTypes } from '~/interface/Jobs';
import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
@Controller()
@UseGuards(MetaApiLimiterGuard, GlobalGuard)
export class DuplicateController {
constructor(
@Inject('JobsService') protected readonly jobsService,
@Inject('JobsService') protected readonly jobsService: IJobsService,
protected readonly basesService: BasesService,
) {}

13
packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.processor.ts

@ -205,12 +205,12 @@ export class DuplicateProcessor {
(c.colOptions.type === RelationTypes.BELONGS_TO ||
(c.colOptions.type === RelationTypes.ONE_TO_ONE &&
c.meta?.bt)) &&
c.colOptions.fk_related_model_id === modelId,
c.colOptions.fk_related_model_id === sourceModel.id,
)
.map((c) => c.id);
if (bts.length > 0) {
fields[md.id] = [md.primaryKey.id];
fields[md.id] = fields[md.id] ? fields[md.id] : [md.primaryKey.id];
fields[md.id].push(...bts);
}
}
@ -294,14 +294,6 @@ export class DuplicateProcessor {
throw new Error(`Export failed for model '${sourceModel.id}'`);
}
exportedModel.model.columns = exportedModel.model.columns.filter((c) =>
c.id.includes(columnId),
);
if (exportedModel.model.columns.length !== 1) {
throw new Error(`There was an error duplicating column!`);
}
const replacedColumn = exportedModel.model.columns.find((c) =>
c.id.includes(columnId),
);
@ -325,6 +317,7 @@ export class DuplicateProcessor {
req,
externalModels: relatedModels,
existingModel: sourceModel,
importColumnIds: [columnId],
});
elapsedTime(hrTime, 'import model schema', 'duplicateColumn');

64
packages/nocodb/src/modules/jobs/jobs/export-import/import.service.ts

@ -81,6 +81,7 @@ export class ImportService {
req: NcRequest;
externalModels?: Model[];
existingModel?: Model;
importColumnIds?: string[];
}) {
const hrTime = initTime();
@ -143,7 +144,12 @@ export class ImportService {
const modelData = data.model;
const reducedColumnSet = modelData.columns.filter(
(a) => !isVirtualCol(a) && a.uidt !== UITypes.ForeignKey,
(a) =>
!isVirtualCol(a) &&
a.uidt !== UITypes.ForeignKey &&
(param.importColumnIds
? param.importColumnIds.includes(getEntityIdentifier(a.id))
: true),
);
// create table with static columns
@ -228,7 +234,14 @@ export class ImportService {
const modelData = data.model;
const table = tableReferences.get(modelData.id);
const linkedColumnSet = modelData.columns.filter((a) => isLinksOrLTAR(a));
const linkedColumnSet = modelData.columns.filter(
(a) =>
isLinksOrLTAR(a) &&
!a.system &&
(param.importColumnIds
? param.importColumnIds.includes(getEntityIdentifier(a.id))
: true),
);
for (const col of linkedColumnSet) {
if (col.colOptions) {
@ -299,9 +312,8 @@ export class ImportService {
colOptions.fk_mm_model_id && a.id !== col.id,
);
// referencing the same model
if (colOptions.fk_related_model_id === modelData.id) {
continue;
childColumn.title = `${childColumn.title} copy`;
}
for (const nColumn of childModel.columns) {
@ -391,31 +403,8 @@ export class ImportService {
a.id !== col.id,
);
// referencing the same model
if (colOptions.fk_related_model_id === modelData.id) {
const counterRelationType =
colOptions.type === 'hm' ? 'bt' : 'oo';
const oldCol = childModel.columns.find(
(oColumn) =>
oColumn.colOptions?.fk_parent_column_id ===
getEntityIdentifier(colOptions.fk_parent_column_id) &&
oColumn.colOptions?.fk_child_column_id ===
getEntityIdentifier(colOptions.fk_child_column_id) &&
oColumn.colOptions?.type === counterRelationType,
);
const col = childModel.columns.find(
(nColumn) =>
nColumn.colOptions?.fk_parent_column_id ===
getIdOrExternalId(colOptions.fk_parent_column_id) &&
nColumn.colOptions?.fk_child_column_id ===
getIdOrExternalId(colOptions.fk_child_column_id) &&
nColumn.colOptions?.type === counterRelationType,
);
idMap.set(
`${oldCol.base_id}::${oldCol.source_id}::${oldCol.fk_model_id}::${oldCol.id}`,
col.id,
);
continue;
childColumn.title = `${childColumn.title} copy`;
}
for (const nColumn of childModel.columns) {
@ -520,6 +509,10 @@ export class ImportService {
a.id !== getEntityIdentifier(col.id)),
);
if (colOptions.fk_related_model_id === modelData.id) {
childColumn.title = `${childColumn.title} copy`;
}
for (const nColumn of childModel.columns) {
if (
nColumn?.colOptions?.fk_mm_model_id ===
@ -643,6 +636,10 @@ export class ImportService {
a.id !== getEntityIdentifier(col.id)),
);
if (colOptions.fk_related_model_id === modelData.id) {
childColumn.title = `${childColumn.title} copy`;
}
for (const nColumn of childModel.columns) {
if (
nColumn.id !== getIdOrExternalId(col.id) &&
@ -768,6 +765,10 @@ export class ImportService {
a.id !== getEntityIdentifier(col.id)),
);
if (colOptions.fk_related_model_id === modelData.id) {
childColumn.title = `${childColumn.title} copy`;
}
for (const nColumn of childModel.columns) {
if (
nColumn.id !== getIdOrExternalId(col.id) &&
@ -815,7 +816,7 @@ export class ImportService {
referencedColumnSet.push(
...modelData.columns.filter(
(a) =>
a.uidt === UITypes.Lookup ||
(a.uidt === UITypes.Lookup ||
a.uidt === UITypes.Rollup ||
a.uidt === UITypes.Formula ||
a.uidt === UITypes.QrCode ||
@ -823,7 +824,10 @@ export class ImportService {
a.uidt === UITypes.LastModifiedTime ||
a.uidt === UITypes.CreatedBy ||
a.uidt === UITypes.LastModifiedBy ||
a.uidt === UITypes.Barcode,
a.uidt === UITypes.Barcode) &&
(param.importColumnIds
? param.importColumnIds.includes(getEntityIdentifier(a.id))
: true),
),
);
}

8
packages/nocodb/src/modules/jobs/jobs/health-check.processor.ts

@ -1,17 +1,19 @@
import { Process, Processor } from '@nestjs/bull';
import { Inject, Logger } from '@nestjs/common';
import type { Queue } from 'bull';
import { JOBS_QUEUE, JobTypes } from '~/interface/Jobs';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
@Processor(JOBS_QUEUE)
export class HealthCheckProcessor {
private logger = new Logger(HealthCheckProcessor.name);
constructor(@Inject('JobsService') protected readonly jobsService) {}
constructor(
@Inject('JobsService') protected readonly jobsService: IJobsService,
) {}
@Process(JobTypes.HealthCheck)
async healthCheck() {
const queue = this.jobsService.jobsQueue as Queue;
const queue = this.jobsService.jobsQueue;
if (queue) {
queue

5
packages/nocodb/src/modules/jobs/jobs/meta-sync/meta-sync.controller.ts

@ -13,11 +13,14 @@ import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware';
import { NcError } from '~/helpers/catchError';
import { JobTypes } from '~/interface/Jobs';
import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
@Controller()
@UseGuards(MetaApiLimiterGuard, GlobalGuard)
export class MetaSyncController {
constructor(@Inject('JobsService') private readonly jobsService) {}
constructor(
@Inject('JobsService') private readonly jobsService: IJobsService,
) {}
@Post([
'/api/v1/db/meta/projects/:baseId/meta-diff',

5
packages/nocodb/src/modules/jobs/jobs/source-create/source-create.controller.ts

@ -15,11 +15,14 @@ import { Acl } from '~/middlewares/extract-ids/extract-ids.middleware';
import { NcError } from '~/helpers/catchError';
import { JobTypes } from '~/interface/Jobs';
import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
@Controller()
@UseGuards(MetaApiLimiterGuard, GlobalGuard)
export class SourceCreateController {
constructor(@Inject('JobsService') private readonly jobsService) {}
constructor(
@Inject('JobsService') private readonly jobsService: IJobsService,
) {}
@Post([
'/api/v1/db/meta/projects/:baseId/bases',

3
packages/nocodb/src/modules/jobs/jobs/source-delete/source-delete.controller.ts

@ -13,12 +13,13 @@ import { NcError } from '~/helpers/catchError';
import { JobTypes } from '~/interface/Jobs';
import { SourcesService } from '~/services/sources.service';
import { MetaApiLimiterGuard } from '~/guards/meta-api-limiter.guard';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
@Controller()
@UseGuards(MetaApiLimiterGuard, GlobalGuard)
export class SourceDeleteController {
constructor(
@Inject('JobsService') private readonly jobsService,
@Inject('JobsService') private readonly jobsService: IJobsService,
private readonly sourcesService: SourcesService,
) {}

24
packages/nocodb/src/modules/jobs/jobs/webhook-handler/webhook-handler.processor.ts

@ -0,0 +1,24 @@
import { Process, Processor } from '@nestjs/bull';
import { forwardRef, Inject, Logger } from '@nestjs/common';
import { Job } from 'bull';
import {
type HandleWebhookJobData,
JOBS_QUEUE,
JobTypes,
} from '~/interface/Jobs';
import { HookHandlerService } from '~/services/hook-handler.service';
@Processor(JOBS_QUEUE)
export class WebhookHandlerProcessor {
private logger = new Logger(WebhookHandlerProcessor.name);
constructor(
@Inject(forwardRef(() => HookHandlerService))
private readonly hookHandlerService: HookHandlerService,
) {}
@Process(JobTypes.HandleWebhook)
async job(job: Job<HandleWebhookJobData>) {
await this.hookHandlerService.handleHooks(job.data);
}
}

6
packages/nocodb/src/services/base-users/ui/emailTemplates/invite.ts

@ -132,8 +132,8 @@ export default `<!doctype html>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Hi,</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
I invited you to be "<%- roles -%>" of the NocoDB base "<%- baseName %>".
Click the button below to to accept my invitation.</p>
You have been invited to become "<%- roles -%>" of the NocoDB base "<%- baseName %>".
Click the button below to accept the invitation.</p>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"
class="btn btn-primary"
style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; box-sizing: border-box; width: 100%;"
@ -161,7 +161,7 @@ export default `<!doctype html>
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Thanks regards <%- adminEmail %>.</p>
Have a nice day,<br><%- adminEmail %></p>
</td>
</tr>
</table>

4
packages/nocodb/src/services/base-users/ui/emailTemplates/verify.ts

@ -132,7 +132,7 @@ export default `<!doctype html>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Hi,</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Please verify your email address by clicking the following button.</p>
Please verify your e-mail address by clicking the following button.</p>
<table role="presentation" border="0" cellpadding="0" cellspacing="0"
class="btn btn-primary"
style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; box-sizing: border-box; width: 100%;"
@ -160,7 +160,7 @@ export default `<!doctype html>
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; margin-bottom: 15px;">
Thanks regards NocoDB.</p>
Thank you and have a nice day,<br><%- adminEmail %>
</td>
</tr>
</table>

10
packages/nocodb/src/services/columns.service.ts

@ -452,10 +452,16 @@ export class ColumnsService {
}),
);
const data = await sqlClient.raw('SELECT DISTINCT ?? FROM ??', [
const data = await baseModel.execAndParse(
baseModel.dbDriver.raw('SELECT DISTINCT ?? FROM ??', [
column.column_name,
baseModel.getTnPath(table.table_name),
]);
]),
null,
{
raw: true,
},
);
if (data.length) {
const existingOptions = colBody.colOptions.options.map(

61
packages/nocodb/src/services/hook-handler.service.ts

@ -1,8 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { UITypes, ViewTypes } from 'nocodb-sdk';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { type HookType, UITypes, ViewTypes } from 'nocodb-sdk';
import ejs from 'ejs';
import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import type { UserType } from 'nocodb-sdk';
import NcPluginMgrv2 from '~/helpers/NcPluginMgrv2';
import {
_transformSubmittedFormDataForEmail,
@ -11,18 +10,22 @@ import {
import { IEventEmitter } from '~/modules/event-emitter/event-emitter.interface';
import formSubmissionEmailTemplate from '~/utils/common/formSubmissionEmailTemplate';
import { FormView, Hook, Model, View } from '~/models';
import { type HandleWebhookJobData, JobTypes } from '~/interface/Jobs';
import { IJobsService } from '~/modules/jobs/jobs-service.interface';
export const HANDLE_WEBHOOK = '__nc_handleHooks';
@Injectable()
export class HookHandlerService implements OnModuleInit, OnModuleDestroy {
private logger = new Logger(HookHandlerService.name);
private unsubscribe: () => void;
constructor(
@Inject('IEventEmitter') private readonly eventEmitter: IEventEmitter,
@Inject('JobsService') private readonly jobsService: IJobsService,
) {}
private async handleHooks({
public async handleHooks({
hookName,
prevData,
newData,
@ -30,15 +33,7 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy {
viewId,
modelId,
tnPath,
}: {
hookName;
prevData;
newData;
user: UserType;
viewId: string;
modelId: string;
tnPath: string;
}): Promise<void> {
}: HandleWebhookJobData): Promise<void> {
const view = await View.get(viewId);
const model = await Model.get(modelId);
@ -111,7 +106,11 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy {
});
}
} catch (e) {
console.log(e);
this.logger.error({
error: e,
details: 'Error while sending form submission email',
hookName,
});
}
}
@ -119,23 +118,47 @@ export class HookHandlerService implements OnModuleInit, OnModuleDestroy {
const [event, operation] = hookName.split('.');
const hooks = await Hook.list({
fk_model_id: modelId,
event,
operation,
event: event as HookType['event'],
operation: operation as HookType['operation'],
});
for (const hook of hooks) {
if (hook.active) {
invokeWebhook(hook, model, view, prevData, newData, user);
await invokeWebhook(hook, model, view, prevData, newData, user);
}
}
} catch (e) {
console.log('hooks :: error', hookName, e);
this.logger.error({
error: e,
details: 'Error while handling webhook',
hookName,
});
}
}
private async triggerHook({
hookName,
prevData,
newData,
user,
viewId,
modelId,
tnPath,
}: HandleWebhookJobData) {
await this.jobsService.add(JobTypes.HandleWebhook, {
hookName,
prevData,
newData,
user,
viewId,
modelId,
tnPath,
});
}
onModuleInit(): any {
this.unsubscribe = this.eventEmitter.on(
HANDLE_WEBHOOK,
this.handleHooks.bind(this),
this.triggerHook.bind(this),
);
}

2
tests/playwright/pages/Dashboard/ViewSidebar/index.ts

@ -161,7 +161,7 @@ export class ViewSidebarPage extends BasePage {
force: true,
});
const submitAction = () =>
this.rootPage.locator('.ant-modal-content').locator('button:has-text("Create view"):visible').click();
this.rootPage.locator('.ant-modal-content').locator('button:has-text("Create View"):visible').click();
await this.waitForResponse({
httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: '/api/v1/db/meta/tables/',

9
tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts

@ -65,7 +65,14 @@ export class ToolbarFilterPage extends BasePage {
await this.get().locator(`button:has-text("Add Filter Group")`).last().click();
const filterDropdown = this.get().locator('.menu-filter-dropdown').nth(filterGroupIndex);
await filterDropdown.waitFor({ state: 'visible' });
await filterDropdown.locator(`button:has-text("Add Filter")`).first().click();
const ADD_BUTTON_SELECTOR = `span:has-text("add")`;
const FILTER_GROUP_SUB_MENU_SELECTOR = `.nc-dropdown-filter-group-sub-menu`;
const ADD_FILTER_SELECTOR = `.nc-menu-item:has-text("Add Filter")`;
await filterDropdown.locator(ADD_BUTTON_SELECTOR).first().click();
const filterGroupSubMenu = this.rootPage.locator(FILTER_GROUP_SUB_MENU_SELECTOR).last();
await filterGroupSubMenu.waitFor({ state: 'visible' });
await filterGroupSubMenu.locator(ADD_FILTER_SELECTOR).first().click();
const selectField = filterDropdown.locator('.nc-filter-field-select').last();
const selectOperation = filterDropdown.locator('.nc-filter-operation-select').last();
const selectValue = filterDropdown.locator('.nc-filter-value-select > input').last();

Loading…
Cancel
Save