Browse Source

Merge branch 'develop' into fix/group-by-menu-ui

pull/7173/head
աɨռɢӄաօռɢ 9 months ago
parent
commit
69d84bcecd
  1. 9
      packages/nc-gui/assets/style.scss
  2. 1
      packages/nc-gui/components/api-client/Headers.vue
  3. 23
      packages/nc-gui/components/cell/DatePicker.vue
  4. 6
      packages/nc-gui/components/cell/DateTimePicker.vue
  5. 2
      packages/nc-gui/components/cell/GeoData.vue
  6. 9
      packages/nc-gui/components/cell/Json.vue
  7. 9
      packages/nc-gui/components/cell/RichText.vue
  8. 16
      packages/nc-gui/components/cell/TextArea.vue
  9. 2
      packages/nc-gui/components/cell/TimePicker.vue
  10. 2
      packages/nc-gui/components/cell/YearPicker.vue
  11. 1
      packages/nc-gui/components/dashboard/Sidebar/UserInfo.vue
  12. 1
      packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue
  13. 5
      packages/nc-gui/components/dashboard/TreeView/TableNode.vue
  14. 14
      packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue
  15. 3
      packages/nc-gui/components/dashboard/settings/AuditTab.vue
  16. 11
      packages/nc-gui/components/dashboard/settings/BaseAudit.vue
  17. 6
      packages/nc-gui/components/dashboard/settings/UIAcl.vue
  18. 2
      packages/nc-gui/components/dlg/share-and-collaborate/ShareBase.vue
  19. 2
      packages/nc-gui/components/dlg/share-and-collaborate/SharePage.vue
  20. 2
      packages/nc-gui/components/general/language/index.vue
  21. 2
      packages/nc-gui/components/nc/Dropdown.vue
  22. 14
      packages/nc-gui/components/nc/Modal.vue
  23. 10
      packages/nc-gui/components/nc/Select.vue
  24. 11
      packages/nc-gui/components/nc/Tooltip.vue
  25. 2
      packages/nc-gui/components/notification/Item/Wrapper.vue
  26. 13
      packages/nc-gui/components/project/AccessSettings.vue
  27. 47
      packages/nc-gui/components/project/View.vue
  28. 2
      packages/nc-gui/components/smartsheet/column/AdvancedOptions.vue
  29. 7
      packages/nc-gui/components/smartsheet/column/DateOptions.vue
  30. 3
      packages/nc-gui/components/smartsheet/column/DateTimeOptions.vue
  31. 4
      packages/nc-gui/components/smartsheet/column/EditOrAdd.vue
  32. 92
      packages/nc-gui/components/smartsheet/column/FormulaOptions.vue
  33. 2
      packages/nc-gui/components/smartsheet/column/LinkedToAnotherRecordOptions.vue
  34. 4
      packages/nc-gui/components/smartsheet/column/RichLongTextDefaultValue.vue
  35. 67
      packages/nc-gui/components/smartsheet/column/RollupOptions.vue
  36. 2
      packages/nc-gui/components/smartsheet/column/SelectOptions.vue
  37. 2
      packages/nc-gui/components/smartsheet/details/Fields.vue
  38. 3
      packages/nc-gui/components/smartsheet/expanded-form/Comments.vue
  39. 4
      packages/nc-gui/components/smartsheet/grid/Table.vue
  40. 5
      packages/nc-gui/components/smartsheet/header/Cell.vue
  41. 2
      packages/nc-gui/components/smartsheet/header/Menu.vue
  42. 2
      packages/nc-gui/components/smartsheet/header/VirtualCell.vue
  43. 33
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  44. 6
      packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue
  45. 5
      packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue
  46. 8
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  47. 2
      packages/nc-gui/components/smartsheet/toolbar/OpenedViewAction.vue
  48. 2
      packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue
  49. 4
      packages/nc-gui/components/smartsheet/toolbar/SearchData.vue
  50. 10
      packages/nc-gui/components/template/Editor.vue
  51. 3
      packages/nc-gui/components/virtual-cell/Formula.vue
  52. 41
      packages/nc-gui/components/virtual-cell/Rollup.vue
  53. 3
      packages/nc-gui/components/webhook/CallLog.vue
  54. 4
      packages/nc-gui/components/workspace/CollaboratorsList.vue
  55. 3
      packages/nc-gui/components/workspace/ProjectList.vue
  56. 1
      packages/nc-gui/composables/useAttachment.ts
  57. 8
      packages/nc-gui/composables/useColumnCreateStore.ts
  58. 27
      packages/nc-gui/composables/useMultiSelect/index.ts
  59. 4
      packages/nc-gui/composables/useViewColumns.ts
  60. 5
      packages/nc-gui/helpers/parsers/CSVTemplateAdapter.ts
  61. 3
      packages/nc-gui/helpers/parsers/ExcelTemplateAdapter.ts
  62. 4
      packages/nc-gui/lang/ar.json
  63. 4
      packages/nc-gui/lang/bn_IN.json
  64. 4
      packages/nc-gui/lang/cs.json
  65. 4
      packages/nc-gui/lang/da.json
  66. 4
      packages/nc-gui/lang/de.json
  67. 4
      packages/nc-gui/lang/en.json
  68. 4
      packages/nc-gui/lang/es.json
  69. 4
      packages/nc-gui/lang/eu.json
  70. 4
      packages/nc-gui/lang/fa.json
  71. 4
      packages/nc-gui/lang/fi.json
  72. 4
      packages/nc-gui/lang/fr.json
  73. 4
      packages/nc-gui/lang/he.json
  74. 4
      packages/nc-gui/lang/hi.json
  75. 4
      packages/nc-gui/lang/hr.json
  76. 4
      packages/nc-gui/lang/id.json
  77. 4
      packages/nc-gui/lang/it.json
  78. 52
      packages/nc-gui/lang/ja.json
  79. 4
      packages/nc-gui/lang/ko.json
  80. 4
      packages/nc-gui/lang/lv.json
  81. 4
      packages/nc-gui/lang/nl.json
  82. 4
      packages/nc-gui/lang/no.json
  83. 4
      packages/nc-gui/lang/pl.json
  84. 4
      packages/nc-gui/lang/pt.json
  85. 4
      packages/nc-gui/lang/pt_BR.json
  86. 4
      packages/nc-gui/lang/ru.json
  87. 4
      packages/nc-gui/lang/sk.json
  88. 4
      packages/nc-gui/lang/sl.json
  89. 4
      packages/nc-gui/lang/sv.json
  90. 4
      packages/nc-gui/lang/th.json
  91. 4
      packages/nc-gui/lang/tr.json
  92. 4
      packages/nc-gui/lang/uk.json
  93. 4
      packages/nc-gui/lang/vi.json
  94. 4
      packages/nc-gui/lang/zh-Hans.json
  95. 4
      packages/nc-gui/lang/zh-Hant.json
  96. 2
      packages/nc-gui/store/bases.ts
  97. 89
      packages/nc-gui/utils/dateTimeUtils.ts
  98. 413
      packages/nc-gui/utils/filterUtils.ts
  99. 1
      packages/nc-gui/utils/index.ts
  100. 3
      packages/nocodb-sdk/package.json
  101. Some files were not shown because too many files have changed in this diff Show More

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

@ -225,6 +225,10 @@ a {
@apply !rounded-md;
}
}
// select dropdown border style
.ant-select-dropdown {
@apply border-1 border-gray-200
}
// menu item styling
.nc-menu-item {
@ -426,7 +430,10 @@ a {
.ant-dropdown-menu-submenu {
@apply !py-0;
&.ant-dropdown-menu-submenu-popup{
@apply border-1 border-gray-200
}
.ant-dropdown-menu,
.ant-menu {
@apply m-0 p-0;

1
packages/nc-gui/components/api-client/Headers.vue

@ -91,6 +91,7 @@ const filterOption = (input: string, option: Option) => option.value.toUpperCase
:options="headerList"
:placeholder="$t('placeholder.key')"
:filter-option="filterOption"
dropdown-class-name="border-1 border-gray-200"
/>
</a-form-item>
</td>

23
packages/nc-gui/components/cell/DatePicker.vue

@ -1,5 +1,6 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import { isDateMonthFormat } from 'nocodb-sdk'
import {
ActiveCellInj,
CellClickHookInj,
@ -10,8 +11,13 @@ import {
computed,
inject,
isDrawerOrModalExist,
onClickOutside,
onMounted,
onUnmounted,
parseProp,
ref,
useGlobal,
useI18n,
useSelectedCellKeyupListener,
watch,
} from '#imports'
@ -43,6 +49,8 @@ const isDateInvalid = ref(false)
const dateFormat = computed(() => parseProp(columnMeta?.value?.meta)?.date_format ?? 'YYYY-MM-DD')
const picker = computed(() => (isDateMonthFormat(dateFormat.value) ? 'month' : ''))
const localState = computed({
get() {
if (!modelValue) {
@ -54,7 +62,9 @@ const localState = computed({
return undefined
}
return /^\d+$/.test(modelValue) ? dayjs(+modelValue) : dayjs(modelValue)
const format = picker.value === 'month' ? dateFormat : 'YYYY-MM-DD'
return dayjs(/^\d+$/.test(modelValue) ? +modelValue : modelValue, format)
},
set(val?: dayjs.Dayjs) {
if (!val) {
@ -62,6 +72,11 @@ const localState = computed({
return
}
if (picker.value === 'month') {
// reset day to 1st
val = dayjs(val).date(1)
}
if (val.isValid()) {
emit('update:modelValue', val?.format('YYYY-MM-DD'))
}
@ -198,12 +213,15 @@ const updateOpen = (next: boolean) => {
}
const cellClickHook = inject(CellClickHookInj, null)
const cellClickHandler = () => {
open.value = (active.value || editable.value) && !open.value
}
onMounted(() => {
cellClickHook?.on(cellClickHandler)
})
onUnmounted(() => {
cellClickHook?.on(cellClickHandler)
})
@ -219,6 +237,7 @@ const clickHandler = () => {
<template>
<a-date-picker
v-model:value="localState"
:picker="picker"
:bordered="false"
class="!w-full !px-1 !border-none"
:class="{ 'nc-null': modelValue === null && showNull }"
@ -226,7 +245,7 @@ const clickHandler = () => {
:placeholder="placeholder"
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:dropdown-class-name="`${randomClass} nc-picker-date ${open ? 'active' : ''}`"
:dropdown-class-name="`${randomClass} nc-picker-date children:border-1 children:border-gray-200 ${open ? 'active' : ''} `"
:open="isOpen"
@click="clickHandler"
@update:open="updateOpen"

6
packages/nc-gui/components/cell/DateTimePicker.vue

@ -1,18 +1,16 @@
<script setup lang="ts">
import dayjs from 'dayjs'
import { isSystemColumn } from 'nocodb-sdk'
import { dateFormats, isSystemColumn, timeFormats } from 'nocodb-sdk'
import {
ActiveCellInj,
CellClickHookInj,
ColumnInj,
EditColumnInj,
ReadonlyInj,
dateFormats,
inject,
isDrawerOrModalExist,
parseProp,
ref,
timeFormats,
useBase,
useSelectedCellKeyupListener,
watch,
@ -278,7 +276,7 @@ const isColDisabled = computed(() => {
:placeholder="placeholder"
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:dropdown-class-name="`${randomClass} nc-picker-datetime ${open ? 'active' : ''}`"
:dropdown-class-name="`${randomClass} nc-picker-datetime children:border-1 children:border-gray-200 ${open ? 'active' : ''}`"
:open="isOpen"
@click="clickHandler"
@ok="open = !open"

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

@ -100,7 +100,7 @@ const openInOSM = () => {
</div>
<div v-else data-testid="nc-geo-data-lat-long-set">{{ latLongStr }}</div>
<template #overlay>
<a-form :model="formState" class="flex flex-col w-max-64" @finish="handleFinish">
<a-form :model="formState" class="flex flex-col w-max-64 border-1 border-gray-200" @finish="handleFinish">
<a-form-item>
<div class="flex mt-4 items-center mx-2">
<div class="mr-2">{{ $t('labels.lat') }}:</div>

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

@ -150,7 +150,14 @@ watch(isExpanded, () => {
</script>
<template>
<component :is="isExpanded ? NcModal : 'div'" v-model:visible="isExpanded" :closable="false" centered :footer="null">
<component
:is="isExpanded ? NcModal : 'div'"
v-model:visible="isExpanded"
:closable="false"
centered
:footer="null"
:wrap-class-name="isExpanded ? '!z-1051' : null"
>
<div v-if="editEnabled && !readonly" class="flex flex-col w-full" @mousedown.stop @mouseup.stop @click.stop>
<div class="flex flex-row justify-between pt-1 pb-2 nc-json-action" @mousedown.stop>
<a-button type="text" size="small" @click="isExpanded = !isExpanded">

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

@ -148,7 +148,7 @@ watch(editorDom, () => {
class="h-full"
:class="{
'flex flex-col flex-grow nc-rich-text-full': props.fullMode,
'nc-rich-text-embed': !props.fullMode,
'nc-rich-text-embed flex flex-col pl-1 w-full': !props.fullMode,
}"
>
<div v-if="props.showMenu" class="absolute top-0 right-0.5">
@ -159,9 +159,10 @@ watch(editorDom, () => {
<EditorContent
ref="editorDom"
:editor="editor"
class="flex flex-col nc-textarea-rich-editor w-full flex-grow"
class="flex flex-col nc-textarea-rich-editor w-full"
:class="{
'ml-1 mt-2.5': props.fullMode,
'ml-1 mt-2.5 flex-grow': props.fullMode,
'nc-scrollbar-md': !props.fullMode && !props.readonly,
}"
/>
</div>
@ -181,7 +182,7 @@ watch(editorDom, () => {
.nc-rich-text-embed {
.ProseMirror {
@apply !border-transparent;
@apply !border-transparent max-h-full;
}
}

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

@ -120,8 +120,8 @@ const onMouseMove = (e: MouseEvent) => {
e.stopPropagation()
position.value = {
top: e.clientY - 22,
left: e.clientX - 46,
top: e.clientY - 30,
left: e.clientX - 120,
}
}
@ -149,7 +149,7 @@ watch(position, () => {
dom.style.left = `${position.value.left}px`
dom.style.top = `${position.value.top}px`
}, 100)
}, 1)
})
const dragStart = () => {
@ -175,7 +175,7 @@ watch(editEnabled, () => {
:overlay-class-name="isVisible ? 'nc-textarea-dropdown-active' : undefined"
>
<div
class="flex flex-row pt-0.5 w-full"
class="flex flex-row pt-0.5 w-full rich-wrapper"
:class="{
'min-h-10': rowHeight !== 1,
'min-h-6.5': rowHeight === 1,
@ -191,7 +191,7 @@ watch(editEnabled, () => {
}"
@dblclick="onExpand"
>
<LazyCellRichText v-model:value="vModel" sync-value-change readonly class="!pointer-events-none" />
<LazyCellRichText v-model:value="vModel" sync-value-change readonly />
</div>
<textarea
v-else-if="editEnabled && !isVisible"
@ -239,7 +239,7 @@ watch(editEnabled, () => {
<NcTooltip
v-if="!isVisible"
placement="bottom"
class="!absolute right-0 bottom-1 !hidden nc-text-area-expand-btn"
class="!absolute right-0 bottom-1 nc-text-area-expand-btn"
:class="{ 'right-0 bottom-1': editEnabled, '!bottom-0': !isRichMode }"
>
<template #title>{{ $t('title.expand') }}</template>
@ -296,8 +296,10 @@ watch(editEnabled, () => {
textarea:focus {
box-shadow: none;
}
</style>
:deep(.nc-text-area-expand-btn) {
<style lang="scss">
.cell:hover .nc-text-area-expand-btn {
@apply !block;
}
</style>

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

@ -136,7 +136,7 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
:allow-clear="!readOnly && !localState && !isPk"
:input-read-only="true"
:open="isOpen"
:popup-class-name="`${randomClass} nc-picker-time ${open ? 'active' : ''}`"
:popup-class-name="`${randomClass} nc-picker-time children:border-1 children:border-gray-200 ${open ? 'active' : ''}`"
@click="open = (active || editable) && !open"
@ok="open = !open"
>

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

@ -121,7 +121,7 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
:allow-clear="(!readOnly && !localState && !isPk) || isEditColumn"
:input-read-only="true"
:open="isOpen"
:dropdown-class-name="`${randomClass} nc-picker-year ${open ? 'active' : ''}`"
:dropdown-class-name="`${randomClass} nc-picker-year children:border-1 children:border-gray-200 ${open ? 'active' : ''}`"
@click="open = (active || editable) && !open"
@change="open = (active || editable) && !open"
@ok="open = !open"

1
packages/nc-gui/components/dashboard/Sidebar/UserInfo.vue

@ -1,5 +1,4 @@
<script lang="ts" setup>
import GithubButton from 'vue-github-button'
import {
computed,
message,

1
packages/nc-gui/components/dashboard/TreeView/ProjectNode.vue

@ -429,6 +429,7 @@ const projectDelete = () => {
class="nc-sidebar-node-title capitalize text-ellipsis overflow-hidden select-none"
:style="{ wordBreak: 'keep-all', whiteSpace: 'nowrap', display: 'inline' }"
:class="{ 'text-black font-semibold': activeProjectId === base.id && baseViewOpen }"
show-on-truncate-only
>
<template #title>{{ base.title }}</template>
<span @click="onProjectClick(base)">

5
packages/nc-gui/components/dashboard/TreeView/TableNode.vue

@ -231,7 +231,10 @@ const isTableOpened = computed(() => {
</div>
</div>
</div>
<NcTooltip class="nc-tbl-title nc-sidebar-node-title text-ellipsis w-full overflow-hidden select-none">
<NcTooltip
class="nc-tbl-title nc-sidebar-node-title text-ellipsis w-full overflow-hidden select-none"
show-on-truncate-only
>
<template #title>{{ table.title }}</template>
<span
:class="{

14
packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue

@ -128,6 +128,16 @@ onKeyStroke('Enter', (event) => {
}
})
const onRenameMenuClick = () => {
if (isMobileMode.value || !isUIAllowed('viewCreateOrEdit')) return
if (!isEditing.value) {
isEditing.value = true
_title.value = vModel.value.title
$e('c:view:rename', { view: vModel.value?.type })
}
}
const focusInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
/** Rename a view */
@ -232,7 +242,7 @@ watch(isDropdownOpen, async () => {
@blur="onRename"
@keydown.stop="onKeyDown($event)"
/>
<NcTooltip v-else class="nc-sidebar-node-title text-ellipsis overflow-hidden select-none w-full">
<NcTooltip v-else class="nc-sidebar-node-title text-ellipsis overflow-hidden select-none w-full" show-on-truncate-only>
<template #title> {{ vModel.alias || vModel.title }}</template>
<div
data-testid="sidebar-view-title"
@ -268,7 +278,7 @@ watch(isDropdownOpen, async () => {
:table="table"
in-sidebar
@close-modal="isDropdownOpen = false"
@rename="onRename"
@rename="onRenameMenuClick"
@delete="onDelete"
/>
</template>

3
packages/nc-gui/components/dashboard/settings/AuditTab.vue

@ -1,7 +1,8 @@
<script setup lang="ts">
import { Tooltip as ATooltip, Empty } from 'ant-design-vue'
import type { AuditType } from 'nocodb-sdk'
import { ProjectIdInj, h, iconMap, onMounted, storeToRefs, timeAgo, useBase, useGlobal, useI18n, useNuxtApp } from '#imports'
import { timeAgo } from 'nocodb-sdk'
import { ProjectIdInj, h, iconMap, onMounted, storeToRefs, useBase, useGlobal, useI18n, useNuxtApp } from '#imports'
const { $api } = useNuxtApp()

11
packages/nc-gui/components/dashboard/settings/BaseAudit.vue

@ -1,7 +1,8 @@
<script setup lang="ts">
import { Tooltip as ATooltip, Empty } from 'ant-design-vue'
import type { AuditType } from 'nocodb-sdk'
import { h, iconMap, onMounted, storeToRefs, timeAgo, useBase, useGlobal, useI18n, useNuxtApp } from '#imports'
import { timeAgo } from 'nocodb-sdk'
import { h, iconMap, onMounted, storeToRefs, useBase, useGlobal, useI18n, useNuxtApp } from '#imports'
interface Props {
sourceId: string
@ -135,13 +136,14 @@ const columns = [
v-model:page-size="currentLimit"
:total="+totalRows"
show-less-items
class="pagination"
@change="loadAudits"
/>
</div>
</div>
</template>
<style lang="scss">
<style lang="scss" scoped>
.nc-audit-table pre {
display: table;
table-layout: fixed;
@ -150,4 +152,9 @@ const columns = [
font-size: unset;
font-family: unset;
}
.pagination {
.ant-select-dropdown {
@apply !border-1 !border-gray-200;
}
}
</style>

6
packages/nc-gui/components/dashboard/settings/UIAcl.vue

@ -147,7 +147,7 @@ const toggleSelectAll = (role: Role) => {
<template>
<div class="flex flex-row w-full items-center justify-center">
<div class="flex flex-col w-[900px]">
<NcTooltip class="mb-4 first-letter:capital font-bold max-w-100 truncate">
<NcTooltip class="mb-4 first-letter:capital font-bold max-w-100 truncate" show-on-truncate-only>
<template #title>{{ base.title }}</template>
<span> UI ACL : {{ base.title }} </span>
</NcTooltip>
@ -211,7 +211,7 @@ const toggleSelectAll = (role: Role) => {
<div class="min-w-5 flex items-center justify-center">
<GeneralTableIcon :meta="{ meta: record.table_meta, type: record.ptype }" class="text-gray-500" />
</div>
<NcTooltip class="overflow-ellipsis min-w-0 shrink-1 truncate">
<NcTooltip class="overflow-ellipsis min-w-0 shrink-1 truncate" show-on-truncate-only>
<template #title>{{ record._ptn }}</template>
<span>{{ record._ptn }}</span>
</NcTooltip>
@ -223,7 +223,7 @@ const toggleSelectAll = (role: Role) => {
<div class="min-w-5 flex items-center justify-center">
<GeneralViewIcon :meta="record" class="text-gray-500"></GeneralViewIcon>
</div>
<NcTooltip class="overflow-ellipsis min-w-0 shrink-1 truncate">
<NcTooltip class="overflow-ellipsis min-w-0 shrink-1 truncate" show-on-truncate-only>
<template #title>{{ record.title }}</template>
<span>{{ record.title }}</span>
</NcTooltip>

2
packages/nc-gui/components/dlg/share-and-collaborate/ShareBase.vue

@ -148,7 +148,7 @@ const onRoleToggle = async () => {
<div class="flex flex-col py-2 px-3 gap-2 w-full" data-testid="nc-share-base-sub-modal">
<div class="flex flex-col w-full p-3 border-1 border-gray-100 rounded-md">
<div class="flex flex-row w-full justify-between">
<div class="text-black font-medium">{{ $t('activity.enablePublicAccess') }}</div>
<div class="text-gray-900 font-medium">{{ $t('activity.enablePublicAccess') }}</div>
<a-switch
v-e="['c:share:base:enable:toggle']"
:checked="isSharedBaseEnabled"

2
packages/nc-gui/components/dlg/share-and-collaborate/SharePage.vue

@ -277,7 +277,7 @@ const isPublicShared = computed(() => {
<div class="flex flex-col py-2 px-3 mb-1">
<div class="flex flex-col w-full mt-2.5 px-3 py-2.5 border-gray-200 border-1 rounded-md gap-y-2">
<div class="flex flex-row w-full justify-between py-0.5">
<div class="flex" :style="{ fontWeight: 500 }">{{ $t('activity.enabledPublicViewing') }}</div>
<div class="text-gray-900 font-medium">{{ $t('activity.enabledPublicViewing') }}</div>
<a-switch
v-e="['c:share:view:enable:toggle']"
data-testid="share-view-toggle"

2
packages/nc-gui/components/general/language/index.vue

@ -9,7 +9,7 @@
</div>
<template #overlay>
<a-menu class="nc-scrollbar-dark-md min-w-50 max-h-90vh overflow-auto !p-1 m-1 rounded-md">
<a-menu class="nc-scrollbar-dark-md min-w-50 max-h-90vh overflow-auto !p-1 m-1 rounded-md border-1 border-gray-200">
<GeneralLanguageMenu />
</a-menu>
</template>

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

@ -25,7 +25,7 @@ const overlayClassName = toRef(props, 'overlayClassName')
const autoClose = computed(() => props.autoClose)
const overlayClassNameComputed = computed(() => {
let className = 'nc-dropdown bg-white rounded-lg border-1 border-gray-100 shadow-lg'
let className = 'nc-dropdown bg-white rounded-lg border-1 border-gray-200 shadow-lg'
if (overlayClassName.value) {
className += ` ${overlayClassName.value}`
}

14
packages/nc-gui/components/nc/Modal.vue

@ -6,17 +6,19 @@ const props = withDefaults(
size?: 'small' | 'medium' | 'large'
destroyOnClose?: boolean
maskClosable?: boolean
wrapClassName?: string
}>(),
{
size: 'medium',
destroyOnClose: true,
maskClosable: true,
wrapClassName: '',
},
)
const emits = defineEmits(['update:visible'])
const { width: propWidth, destroyOnClose, maskClosable } = props
const { width: propWidth, destroyOnClose, maskClosable, wrapClassName: _wrapClassName } = props
const { isMobileMode } = useGlobal()
@ -64,6 +66,14 @@ const height = computed(() => {
return 'auto'
})
const newWrapClassName = computed(() => {
let className = 'nc-modal-wrapper'
if (_wrapClassName) {
className += ` ${_wrapClassName}`
}
return className
})
const visible = useVModel(props, 'visible', emits)
const slots = useSlots()
@ -76,7 +86,7 @@ const slots = useSlots()
:width="width"
:centered="true"
:closable="false"
wrap-class-name="nc-modal-wrapper"
:wrap-class-name="newWrapClassName"
:footer="null"
:mask-closable="maskClosable"
:destroy-on-close="destroyOnClose"

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

@ -15,7 +15,13 @@ const emits = defineEmits(['update:value', 'change'])
const placeholder = computed(() => props.placeholder)
const dropdownClassName = computed(() => props.dropdownClassName)
const dropdownClassName = computed(() => {
let className = 'nc-select-dropdown'
if (props.dropdownClassName) {
className += ` ${props.dropdownClassName}`
}
return className
})
const showSearch = computed(() => props.showSearch)
@ -37,7 +43,7 @@ const onChange = (value: string) => {
v-model:value="vModel"
:placeholder="placeholder"
class="nc-select"
:dropdown-class-name="dropdownClassName ? `nc-select-dropdown ${dropdownClassName}` : 'nc-select-dropdown'"
:dropdown-class-name="dropdownClassName"
:show-search="showSearch"
:filter-option="filterOption"
:dropdown-match-select-width="dropdownMatchSelectWidth"

11
packages/nc-gui/components/nc/Tooltip.vue

@ -11,6 +11,7 @@ interface Props {
// force disable tooltip
disabled?: boolean
placement?: TooltipPlacement | undefined
showOnTruncateOnly?: boolean
hideOnClick?: boolean
overlayClassName?: string
}
@ -20,6 +21,7 @@ const props = defineProps<Props>()
const modifierKey = computed(() => props.modifierKey)
const tooltipStyle = computed(() => props.tooltipStyle)
const disabled = computed(() => props.disabled)
const showOnTruncateOnly = computed(() => props.showOnTruncateOnly)
const hideOnClick = computed(() => props.hideOnClick)
const placement = computed(() => props.placement ?? 'top')
@ -65,6 +67,15 @@ onKeyStroke(
)
watch([isHovering, () => modifierKey.value, () => disabled.value], ([hovering, key, isDisabled]) => {
if (showOnTruncateOnly?.value) {
const targetElement = el?.value
const isElementTruncated = targetElement && targetElement.scrollWidth > targetElement.clientWidth
if (!isElementTruncated) {
showTooltip.value = false
return
}
}
if (!hovering || isDisabled) {
showTooltip.value = false
return

2
packages/nc-gui/components/notification/Item/Wrapper.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
import { timeAgo } from '#imports'
import { timeAgo } from 'nocodb-sdk'
const props = defineProps<{
item: {

13
packages/nc-gui/components/project/AccessSettings.vue

@ -1,8 +1,15 @@
<script lang="ts" setup>
import {
OrderedProjectRoles,
OrgUserRoles,
ProjectRoles,
WorkspaceRolesToProjectRoles,
extractRolesObj,
timeAgo,
} from 'nocodb-sdk'
import type { WorkspaceUserRoles } from 'nocodb-sdk'
import { OrderedProjectRoles, OrgUserRoles, ProjectRoles, WorkspaceRolesToProjectRoles, extractRolesObj } from 'nocodb-sdk'
import InfiniteLoading from 'v3-infinite-loading'
import { isEeUI, storeToRefs, timeAgo } from '#imports'
import { isEeUI, storeToRefs } from '#imports'
const basesStore = useBases()
const { getProjectUsers, createProjectUser, updateProjectUser, removeProjectUser } = basesStore
@ -177,7 +184,7 @@ onMounted(async () => {
</div>
<div v-else class="nc-collaborators-list mt-6 h-full">
<div class="flex flex-col rounded-lg overflow-hidden border-1 max-w-350 max-h-[calc(100%-8rem)]">
<div class="flex flex-row bg-gray-50 min-h-12 items-center">
<div class="flex flex-row bg-gray-50 min-h-12 items-center border-b-1">
<div class="text-gray-700 users-email-grid">{{ $t('objects.users') }}</div>
<div class="text-gray-700 date-joined-grid">{{ $t('title.dateJoined') }}</div>
<div class="text-gray-700 user-access-grid">{{ $t('general.access') }}</div>

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

@ -1,7 +1,13 @@
<script lang="ts" setup>
import { useTitle } from '@vueuse/core'
import NcLayout from '~icons/nc-icons/layout'
const { openedProject } = storeToRefs(useBases())
import { isEeUI } from '#imports'
const basesStore = useBases()
const { getProjectUsers } = basesStore
const { openedProject, activeProjectId, baseUserCount } = storeToRefs(basesStore)
const { activeTables } = storeToRefs(useTablesStore())
const { activeWorkspace, workspaceUserCount } = storeToRefs(useWorkspace())
@ -26,6 +32,25 @@ const { isMobileMode } = useGlobal()
const baseSettingsState = ref('')
const userCount = isEeUI ? workspaceUserCount : baseUserCount
const updateBaseUserCount = async () => {
if (!baseUserCount) return
try {
const { totalRows } = await getProjectUsers({
baseId: activeProjectId.value!,
page: 1,
searchText: undefined,
limit: 20,
})
baseUserCount.value = totalRows
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
watch(
() => route.value.query?.page,
(newVal, oldVal) => {
@ -57,6 +82,16 @@ watch(projectPageTab, () => {
}
})
watch(
() => route.value.params.baseId,
(newVal, oldVal) => {
if (newVal && oldVal === undefined) {
updateBaseUserCount()
}
},
{ immediate: true },
)
watch(
() => openedProject.value?.title,
() => {
@ -75,7 +110,7 @@ watch(
<GeneralOpenLeftSidebarBtn />
<div class="flex flex-row items-center h-full gap-x-2.5">
<GeneralProjectIcon :type="openedProject?.type" />
<NcTooltip class="flex font-medium text-sm capitalize truncate max-w-150">
<NcTooltip class="flex font-medium text-sm capitalize truncate max-w-150" show-on-truncate-only>
<template #title> {{ openedProject?.title }}</template>
<span class="truncate">
{{ openedProject?.title }}
@ -119,14 +154,14 @@ watch(
<GeneralIcon icon="users" class="!h-3.5 !w-3.5" />
<div>{{ $t('labels.members') }}</div>
<div
v-if="workspaceUserCount"
v-if="userCount"
class="tab-info"
:class="{
'bg-primary-selected': projectPageTab === 'data-source',
'bg-gray-50': projectPageTab !== 'data-source',
'bg-primary-selected': projectPageTab === 'collaborator',
'bg-gray-50': projectPageTab !== 'collaborator',
}"
>
{{ workspaceUserCount }}
{{ userCount }}
</div>
</div>
</template>

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

@ -73,7 +73,7 @@ vModel.value.au = !!vModel.value.au */
</div>
<a-form-item :label="$t('labels.databaseType')" v-bind="validateInfos.dt">
<a-select v-model:value="vModel.dt" dropdown-class-name="nc-dropdown-db-type" @change="onDataTypeChange">
<a-select v-model:value="vModel.dt" dropdown-class-name="nc-dropdown-db-type " @change="onDataTypeChange">
<a-select-option v-for="type in dataTypes" :key="type" :value="type">
{{ type }}
</a-select-option>

7
packages/nc-gui/components/smartsheet/column/DateOptions.vue

@ -1,5 +1,6 @@
<script setup lang="ts">
import { dateFormats, useVModel } from '#imports'
import { dateFormats, dateMonthFormats } from 'nocodb-sdk'
import { useVModel } from '#imports'
const props = defineProps<{
value: any
@ -17,8 +18,8 @@ if (!vModel.value.meta?.date_format) {
<template>
<a-form-item :label="$t('labels.dateFormat')">
<a-select v-model:value="vModel.meta.date_format" dropdown-class-name="nc-dropdown-date-format">
<a-select-option v-for="(format, i) of dateFormats" :key="i" :value="format">
<a-select v-model:value="vModel.meta.date_format" class="nc-date-select" dropdown-class-name="nc-dropdown-date-format">
<a-select-option v-for="(format, i) of [...dateFormats, ...dateMonthFormats]" :key="i" :value="format">
<div class="flex flex-row items-center">
<div class="text-xs">
{{ format }}

3
packages/nc-gui/components/smartsheet/column/DateTimeOptions.vue

@ -1,5 +1,6 @@
<script setup lang="ts">
import { dateFormats, timeFormats, useVModel } from '#imports'
import { dateFormats, timeFormats } from 'nocodb-sdk'
import { useVModel } from '#imports'
const props = defineProps<{
value: any

4
packages/nc-gui/components/smartsheet/column/EditOrAdd.vue

@ -226,7 +226,7 @@ if (props.fromTableExplorer) {
'!w-146': isTextArea(formState) && formState.meta.richMode,
'!w-[600px]': formState.uidt === UITypes.Formula && !props.embedMode,
'!w-[500px]': formState.uidt === UITypes.Attachment && !props.embedMode && !appInfo.ee,
'shadow-lg border-1 border-gray-100 shadow-gray-300 rounded-xl p-6': !embedMode,
'shadow-lg border-1 border-gray-200 shadow-gray-300 rounded-xl p-6': !embedMode,
}"
@keydown="handleEscape"
@click.stop
@ -274,7 +274,7 @@ if (props.fromTableExplorer) {
show-search
class="nc-column-type-input !rounded"
:disabled="isKanban || readOnly"
dropdown-class-name="nc-dropdown-column-type "
dropdown-class-name="nc-dropdown-column-type border-1 border-gray-200"
@change="onUidtOrIdTypeChange"
@dblclick="showDeprecated = !showDeprecated"
>

92
packages/nc-gui/components/smartsheet/column/FormulaOptions.vue

@ -2,23 +2,40 @@
import type { Ref } from 'vue'
import type { ListItem as AntListItem } from 'ant-design-vue'
import jsep from 'jsep'
import type { ColumnType, FormulaType } from 'nocodb-sdk'
import { UITypes, jsepCurlyHook, substituteColumnIdWithAliasInFormula } from 'nocodb-sdk'
import type { ColumnType, FormulaType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import {
UITypes,
isLinksOrLTAR,
isNumericCol,
isSystemColumn,
jsepCurlyHook,
substituteColumnIdWithAliasInFormula,
validateDateWithUnknownFormat,
} from 'nocodb-sdk'
import {
MetaInj,
NcAutocompleteTree,
computed,
formulaList,
formulaTypes,
formulas,
getUIDTIcon,
getWordUntilCaret,
iconMap,
inject,
insertAtCursor,
isDate,
nextTick,
onMounted,
ref,
storeToRefs,
useBase,
useColumnCreateStoreOrThrow,
useDebounceFn,
useI18n,
useMetas,
useNocoEe,
useVModel,
validateDateWithUnknownFormat,
} from '#imports'
const props = defineProps<{
@ -35,6 +52,10 @@ const { setAdditionalValidations, validateInfos, sqlUi, column } = useColumnCrea
const { t } = useI18n()
const baseStore = useBase()
const { tables } = storeToRefs(baseStore)
const { predictFunction: _predictFunction } = useNocoEe()
enum JSEPNode {
@ -54,6 +75,23 @@ const meta = inject(MetaInj, ref())
const supportedColumns = computed(
() => meta?.value?.columns?.filter((col) => !uiTypesNotSupportedInFormulas.includes(col.uidt as UITypes)) || [],
)
const { metas } = useMetas()
const refTables = computed(() => {
if (!tables.value || !tables.value.length || !meta.value || !meta.value.columns) {
return []
}
const _refTables = meta.value.columns
.filter((column) => isLinksOrLTAR(column) && !column.system && column.source_id === meta.value?.source_id)
.map((column) => ({
col: column.colOptions,
column,
...tables.value.find((table) => table.id === (column.colOptions as LinkToAnotherRecordType).fk_related_model_id),
}))
.filter((table) => (table.col as LinkToAnotherRecordType)?.fk_related_model_id === table.id && !table.mm)
return _refTables as Required<TableType & { column: ColumnType; col: Required<LinkToAnotherRecordType> }>[]
})
const validators = {
formula_raw: [
@ -501,6 +539,53 @@ function validateAgainstType(parsedTree: any, expectedType: string, func: any, t
}
break
case UITypes.Rollup: {
const rollupFunction = col.colOptions.rollup_function
if (['count', 'avg', 'sum', 'countDistinct', 'sumDistinct', 'avgDistinct'].includes(rollupFunction)) {
// these functions produce a numeric value, which can be used in numeric functions
if (expectedType !== formulaTypes.NUMERIC) {
typeErrors.add(
t('msg.formula.columnWithTypeFoundButExpected', {
columnName: parsedTree.name,
columnType: formulaTypes.NUMERIC,
expectedType,
}),
)
}
} else {
// the value is based on the foreign rollup column type
const selectedTable = refTables.value.find((t) => t.column.id === col.colOptions.fk_relation_column_id)
const refTableColumns = metas.value[selectedTable.id].columns.filter(
(c: ColumnType) =>
vModel.value.fk_lookup_column_id === c.id ||
(!isSystemColumn(c) && c.id !== vModel.value.id && c.uidt !== UITypes.Links),
)
const childFieldColumn = refTableColumns.find(
(column: ColumnType) => column.id === col.colOptions.fk_rollup_column_id,
)
const abstractType = sqlUi.value.getAbstractType(childFieldColumn)
if (expectedType === formulaTypes.DATE && !isDate(childFieldColumn, sqlUi.value.getAbstractType(childFieldColumn))) {
typeErrors.add(
t('msg.formula.columnWithTypeFoundButExpected', {
columnName: parsedTree.name,
columnType: abstractType,
expectedType,
}),
)
} else if (expectedType === formulaTypes.NUMERIC && !isNumericCol(childFieldColumn)) {
typeErrors.add(
t('msg.formula.columnWithTypeFoundButExpected', {
columnName: parsedTree.name,
columnType: abstractType,
expectedType,
}),
)
}
}
break
}
// not supported
case UITypes.ForeignKey:
case UITypes.Attachment:
@ -508,7 +593,6 @@ function validateAgainstType(parsedTree: any, expectedType: string, func: any, t
case UITypes.Time:
case UITypes.Percent:
case UITypes.Duration:
case UITypes.Rollup:
case UITypes.Lookup:
case UITypes.Barcode:
case UITypes.Button:

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

@ -82,7 +82,7 @@ const isLinks = computed(() => vModel.value.uidt === UITypes.Links)
<div class="min-w-5 flex items-center justify-center">
<GeneralTableIcon :meta="table" class="text-gray-500" />
</div>
<NcTooltip class="flex-1 truncate">
<NcTooltip class="flex-1 truncate" show-on-truncate-only>
<template #title>{{ table.title }}</template>
<span>{{ table.title }}</span>
</NcTooltip>

4
packages/nc-gui/components/smartsheet/column/RichLongTextDefaultValue.vue

@ -18,8 +18,8 @@ const cdfValue = computed({
<div>
<div class="!my-3 text-xs">{{ $t('placeholder.defaultValue') }}</div>
<div class="flex flex-row gap-2">
<div class="border-1 relative pt-11 flex items-center w-full px-0 my-[-4px] border-gray-300 rounded-md !max-h-70 !pb-2.5">
<LazyCellRichText v-model:value="cdfValue" class="border-t-1 border-gray-100" show-menu full-mode />
<div class="border-1 relative pt-11 flex items-center w-full px-0 border-gray-300 rounded-md max-h-70 pb-1">
<LazyCellRichText v-model:value="cdfValue" class="border-t-1 border-gray-100 !max-h-80 !min-h-30" show-menu />
</div>
</div>
</div>

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

@ -1,8 +1,23 @@
<script setup lang="ts">
import { onMounted } from '@vue/runtime-core'
import type { ColumnType, LinkToAnotherRecordType, TableType, UITypes } from 'nocodb-sdk'
import { isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { MetaInj, inject, ref, storeToRefs, useBase, useColumnCreateStoreOrThrow, useMetas, useVModel } from '#imports'
import { isLinksOrLTAR, isNumericCol, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import type { Ref } from '#imports'
import {
MetaInj,
computed,
h,
inject,
ref,
resolveComponent,
storeToRefs,
useBase,
useColumnCreateStoreOrThrow,
useI18n,
useMetas,
useVModel,
watch,
} from '#imports'
const props = defineProps<{
value: any
@ -17,6 +32,7 @@ const meta = inject(MetaInj, ref())
const { setAdditionalValidations, validateInfos, onDataTypeChange, isEdit } = useColumnCreateStoreOrThrow()
const baseStore = useBase()
const { tables } = storeToRefs(baseStore)
const { metas } = useMetas()
@ -29,17 +45,6 @@ setAdditionalValidations({
rollup_function: [{ required: true, message: t('general.required') }],
})
const aggrFunctionsList = [
{ text: t('datatype.Count'), value: 'count' },
{ text: t('general.min'), value: 'min' },
{ text: t('general.max'), value: 'max' },
{ text: t('general.avg'), value: 'avg' },
{ text: t('general.sum'), value: 'sum' },
{ text: t('general.countDistinct'), value: 'countDistinct' },
{ text: t('general.sumDistinct'), value: 'sumDistinct' },
{ text: t('general.avgDistinct'), value: 'avgDistinct' },
]
if (!vModel.value.fk_relation_column_id) vModel.value.fk_relation_column_id = null
if (!vModel.value.fk_rollup_column_id) vModel.value.fk_rollup_column_id = null
if (!vModel.value.rollup_function) vModel.value.rollup_function = null
@ -94,6 +99,40 @@ const cellIcon = (column: ColumnType) =>
h(isVirtualCol(column) ? resolveComponent('SmartsheetHeaderVirtualCellIcon') : resolveComponent('SmartsheetHeaderCellIcon'), {
columnMeta: column,
})
const aggFunctionsList: Ref<Record<string, string>[]> = ref([])
watch(
() => vModel.value.fk_rollup_column_id,
() => {
const childFieldColumn = columns.value?.find((column: ColumnType) => column.id === vModel.value.fk_rollup_column_id)
const showNumericFunctions = isNumericCol(childFieldColumn)
const nonNumericFunctions = [
// functions for non-numeric types,
// e.g. count / min / max / countDistinct date field
{ text: t('datatype.Count'), value: 'count' },
{ text: t('general.min'), value: 'min' },
{ text: t('general.max'), value: 'max' },
{ text: t('general.countDistinct'), value: 'countDistinct' },
]
const numericFunctions = showNumericFunctions
? [
{ text: t('general.avg'), value: 'avg' },
{ text: t('general.sum'), value: 'sum' },
{ text: t('general.sumDistinct'), value: 'sumDistinct' },
{ text: t('general.avgDistinct'), value: 'avgDistinct' },
]
: []
aggFunctionsList.value = [...nonNumericFunctions, ...numericFunctions]
if (!showNumericFunctions && ['avg', 'sum', 'sumDistinct', 'avgDistinct'].includes(vModel.value.rollup_function)) {
// when the previous roll up function was numeric type and the current child field is non-numeric
// reset rollup function with a non-numeric type
vModel.value.rollup_function = aggFunctionsList.value[0].value
}
},
)
</script>
<template>
@ -141,7 +180,7 @@ const cellIcon = (column: ColumnType) =>
dropdown-class-name="nc-dropdown-rollup-function"
@change="onDataTypeChange"
>
<a-select-option v-for="(func, index) of aggrFunctionsList" :key="index" :value="func.value">
<a-select-option v-for="(func, index) of aggFunctionsList" :key="index" :value="func.value">
{{ func.text }}
</a-select-option>
</a-select>

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

@ -339,7 +339,7 @@ const loadListData = async ($state: any) => {
<a-dropdown
v-model:visible="colorMenus[index]"
:trigger="['click']"
overlay-class-name="nc-dropdown-select-color-options"
overlay-class-name="nc-dropdown-select-color-options rounded-md overflow-hidden border-1 border-gray-200 "
>
<template #overlay>
<LazyGeneralColorPicker

2
packages/nc-gui/components/smartsheet/details/Fields.vue

@ -819,6 +819,7 @@ const onFieldOptionUpdate = () => {
'text-brand-500': compareCols(field, activeField),
}"
class="truncate flex-1"
show-on-truncate-only
>
<template #title> {{ fieldState(field)?.title || field.title }} </template>
<span>
@ -978,6 +979,7 @@ const onFieldOptionUpdate = () => {
:class="{
'text-brand-500': compareCols(displayColumn, activeField),
}"
show-on-truncate-only
>
<template #title> {{ fieldState(displayColumn)?.title || displayColumn.title }} </template>
<span>

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

@ -1,8 +1,9 @@
<script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core'
import type { AuditType } from 'nocodb-sdk'
import { timeAgo } from 'nocodb-sdk'
import { Icon } from '@iconify/vue'
import { ref, timeAgo, useExpandedFormStoreOrThrow, useGlobal, useRoles, watch } from '#imports'
import { ref, useExpandedFormStoreOrThrow, useGlobal, useRoles, watch } from '#imports'
const props = defineProps<{
loading: boolean

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

@ -1806,7 +1806,7 @@ onKeyStroke('ArrowDown', onDown)
<template #overlay>
<div class="relative overflow-visible min-h-17 w-10">
<div
class="absolute -top-19 flex flex-col h-34.5 w-70 bg-white rounded-lg justify-start overflow-hidden"
class="absolute -top-19 flex flex-col h-34.5 w-70 bg-white rounded-lg border-1 border-gray-200 justify-start overflow-hidden"
style="box-shadow: 0px 4px 6px -2px rgba(0, 0, 0, 0.06), 0px -12px 16px -4px rgba(0, 0, 0, 0.1)"
:class="{
'-left-44': !isAddNewRecordGridMode,
@ -1849,7 +1849,7 @@ onKeyStroke('ArrowDown', onDown)
</div>
</template>
<template #icon>
<component :is="iconMap.arrowUp" class="text-gray-600 h-4" />
<component :is="iconMap.arrowUp" class="text-gray-600 h-4 w-4" />
</template>
</a-dropdown-button>
</div>

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

@ -99,12 +99,13 @@ const onClick = (e: Event) => {
}"
class="name pl-1"
placement="bottom"
show-on-truncate-only
>
<template #title> {{ column.title }} </template>
<div :class="{ truncate: !isForm }" :data-test-id="column.title">
<span :data-test-id="column.title">
{{ column.title }}
</div>
</span>
</NcTooltip>
<span v-if="(column.rqd && !column.cdf) || required" class="text-red-500">&nbsp;*</span>

2
packages/nc-gui/components/smartsheet/header/Menu.vue

@ -291,7 +291,7 @@ const onInsertAfter = () => {
<GeneralIcon icon="arrowDown" class="text-grey h-full text-grey nc-ui-dt-dropdown cursor-pointer outline-0 mr-2" />
</div>
<template #overlay>
<a-menu class="shadow bg-white nc-column-options">
<a-menu class="shadow bg-white border-1 border-gray-200 nc-column-options">
<a-menu-item @click="onEditPress">
<div class="nc-column-edit nc-header-menu-item">
<component :is="iconMap.edit" class="text-gray-700 mx-0.65 my-0.75" />

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

@ -154,7 +154,7 @@ const openDropDown = (e: Event) => {
>
<LazySmartsheetHeaderVirtualCellIcon v-if="column && !props.hideIcon" />
<NcTooltip placement="bottom" class="truncate name pl-1">
<NcTooltip placement="bottom" class="truncate name pl-1" show-on-truncate-only>
<template #title>
{{ tooltipMsg }}
</template>

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

@ -107,12 +107,16 @@ const isFilterDraft = (filter: Filter, col: ColumnType) => {
if (
filter.comparison_op &&
comparisonSubOpList(filter.comparison_op).find((compOp) => compOp.value === filter.comparison_sub_op)?.ignoreVal
comparisonSubOpList(filter.comparison_op, col?.meta?.date_format).find((compOp) => compOp.value === filter.comparison_sub_op)
?.ignoreVal
) {
return false
}
if (comparisonOpList(col.uidt as UITypes).find((compOp) => compOp.value === filter.comparison_op)?.ignoreVal) {
if (
comparisonOpList(col.uidt as UITypes, col?.meta?.date_format).find((compOp) => compOp.value === filter.comparison_op)
?.ignoreVal
) {
return false
}
@ -145,7 +149,7 @@ const filterUpdateCondition = (filter: FilterType, i: number) => {
// hence remove the previous value
filter.value = null
if (
!comparisonSubOpList(filter.comparison_op!)
!comparisonSubOpList(filter.comparison_op!, col?.meta?.date_format)
.map((op) => op.value)
.includes(filter.comparison_sub_op!)
) {
@ -224,8 +228,9 @@ const selectFilterField = (filter: Filter, index: number) => {
// since the existing one may not be supported for the new field
// e.g. `eq` operator is not supported in checkbox field
// hence, get the first option of the supported operators of the new field
filter.comparison_op = comparisonOpList(col.uidt as UITypes).find((compOp) => isComparisonOpAllowed(filter, compOp))
?.value as FilterType['comparison_op']
filter.comparison_op = comparisonOpList(col.uidt as UITypes, col?.meta?.date_format).find((compOp) =>
isComparisonOpAllowed(filter, compOp),
)?.value as FilterType['comparison_op']
if ([UITypes.Date, UITypes.DateTime].includes(col.uidt as UITypes) && !['blank', 'notblank'].includes(filter.comparison_op!)) {
if (filter.comparison_op === 'isWithin') {
@ -297,12 +302,16 @@ const addFilterGroup = async () => {
}
const showFilterInput = (filter: Filter) => {
const col = getColumn(filter)
if (!filter.comparison_op) return false
if (filter.comparison_sub_op) {
return !comparisonSubOpList(filter.comparison_op).find((op) => op.value === filter.comparison_sub_op)?.ignoreVal
return !comparisonSubOpList(filter.comparison_op, getColumn(filter)?.meta?.date_format).find(
(op) => op.value === filter.comparison_sub_op,
)?.ignoreVal
} else {
return !comparisonOpList(getColumn(filter)?.uidt as UITypes).find((op) => op.value === filter.comparison_op)?.ignoreVal
return !comparisonOpList(col?.uidt as UITypes, col?.meta?.date_format).find((op) => op.value === filter.comparison_op)
?.ignoreVal
}
}
@ -427,7 +436,10 @@ onBeforeUnmount(() => {
dropdown-class-name="nc-dropdown-filter-comp-op"
@change="filterUpdateCondition(filter, i)"
>
<template v-for="compOp of comparisonOpList(getColumn(filter)?.uidt)" :key="compOp.value">
<template
v-for="compOp of comparisonOpList(getColumn(filter)?.uidt, getColumn(filter)?.meta?.date_format)"
:key="compOp.value"
>
<a-select-option v-if="isComparisonOpAllowed(filter, compOp)" :value="compOp.value">
{{ compOp.text }}
</a-select-option>
@ -450,7 +462,10 @@ onBeforeUnmount(() => {
dropdown-class-name="nc-dropdown-filter-comp-sub-op"
@change="filterUpdateCondition(filter, i)"
>
<template v-for="compSubOp of comparisonSubOpList(filter.comparison_op)" :key="compSubOp.value">
<template
v-for="compSubOp of comparisonSubOpList(filter.comparison_op, getColumn(filter)?.meta?.date_format)"
:key="compSubOp.value"
>
<a-select-option v-if="isComparisonSubOpAllowed(filter, compSubOp)" :value="compSubOp.value">
{{ compSubOp.text }}
</a-select-option>

6
packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue

@ -104,11 +104,11 @@ const onArrowUp = () => {
@click="onClick(option)"
>
<SmartsheetHeaderIcon :column="option" />
<NcTooltip class="truncate">
<NcTooltip class="truncate" show-on-truncate-only>
<template #title> {{ option.title }}</template>
<span>
<template #default>
{{ option.title }}
</span>
</template>
</NcTooltip>
</div>
</div>

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

@ -85,11 +85,12 @@ if (!localValue.value && allowEmpty !== true) {
<NcTooltip
:style="{ wordBreak: 'keep-all', whiteSpace: 'nowrap', display: 'inline' }"
class="max-w-[15rem] truncate select-none"
show-on-truncate-only
>
<template #title> {{ option.label }}</template>
<span>
<template #default>
{{ option.label }}
</span>
</template>
</NcTooltip>
</div>
</a-select-option>

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

@ -380,11 +380,11 @@ useMenuCloseOnEsc(open)
"
>
<component :is="getIcon(metaColumnById[field.fk_column_id])" />
<NcTooltip :disabled="field.title.length < 30" class="flex-1 px-1 truncate">
<NcTooltip show-on-truncate-only class="flex-1 px-1 truncate">
<template #title>
{{ field.title }}
</template>
<span>{{ field.title }}</span>
<template #default>{{ field.title }}</template>
</NcTooltip>
<NcSwitch v-e="['a:fields:show-hide']" :checked="field.show" :disabled="field.isViewEssentialField" />
@ -406,9 +406,9 @@ useMenuCloseOnEsc(open)
@click.stop
>
<component :is="getIcon(metaColumnById[filteredFieldList[0].fk_column_id as string])" />
<NcTooltip :disabled="filteredFieldList?.[0]?.title?.length < 30" class="px-1 flex-1 truncate">
<NcTooltip show-on-truncate-only class="px-1 flex-1 truncate">
<template #title>{{ filteredFieldList[0].title }}</template>
<span>{{ filteredFieldList[0].title }}</span>
<template #default>{{ filteredFieldList[0].title }}</template>
</NcTooltip>
<NcSwitch v-e="['a:fields:show-hide']" :checked="true" :disabled="true" />

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

@ -182,7 +182,7 @@ function openDeleteDialog() {
'text-gray-800 font-medium': !activeView?.is_default,
}"
>
<NcTooltip class="truncate xs:pl-1.25 flex-1 text-inherit">
<NcTooltip class="truncate xs:pl-1.25 flex-1 text-inherit" show-on-truncate-only>
<template #title>{{ activeView?.is_default ? $t('title.defaultView') : activeView?.title }} </template>
<span
:class="{

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

@ -65,7 +65,7 @@ useMenuCloseOnEsc(open)
</div>
<template #overlay>
<div
class="w-full bg-white shadow-lg menu-filter-dropdown border-1 border-gray-50 rounded-md overflow-hidden"
class="w-full bg-white shadow-lg menu-filter-dropdown border-1 border-gray-200 rounded-md overflow-hidden"
data-testid="nc-height-menu"
>
<div class="flex flex-col w-full text-sm" @click.stop>

4
packages/nc-gui/components/smartsheet/toolbar/SearchData.vue

@ -114,9 +114,9 @@ watch(columns, () => {
<a-select-option v-for="op of columns" :key="op.value" v-e="['c:search:field:select']" :value="op.value">
<div class="text-[0.75rem] flex items-center -ml-1 gap-2">
<SmartsheetHeaderIcon class="text-sm" :column="op.column" />
<NcTooltip class="truncate" placement="top">
<NcTooltip class="truncate" placement="top" show-on-truncate-only>
<template #title>{{ op.label }}</template>
<span>{{ op.label }}</span>
<template #default>{{ op.label }}</template>
</NcTooltip>
</div>
</a-select-option>

10
packages/nc-gui/components/template/Editor.vue

@ -2,7 +2,7 @@
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import type { ColumnType, TableType } from 'nocodb-sdk'
import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { UITypes, getDateFormat, getDateTimeFormat, isSystemColumn, isVirtualCol, parseStringDate } from 'nocodb-sdk'
import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface'
import { srcDestMappingColumns, tableColumns } from './utils'
import {
@ -18,15 +18,12 @@ import {
extractSdkResponseErrorMsg,
fieldLengthValidator,
fieldRequiredValidator,
getDateFormat,
getDateTimeFormat,
getUIDTIcon,
iconMap,
inject,
message,
nextTick,
onMounted,
parseStringDate,
reactive,
ref,
storeToRefs,
@ -131,10 +128,7 @@ const validators = computed(() =>
hasSelectColumn.value[tableIdx] = false
table.columns?.forEach((column, columnIdx) => {
acc[`tables.${tableIdx}.columns.${columnIdx}.title`] = [
fieldRequiredValidator(),
fieldLengthValidator(),
]
acc[`tables.${tableIdx}.columns.${columnIdx}.title`] = [fieldRequiredValidator(), fieldLengthValidator()]
acc[`tables.${tableIdx}.columns.${columnIdx}.uidt`] = [fieldRequiredValidator()]
if (isSelect(column)) {
hasSelectColumn.value[tableIdx] = true

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

@ -1,7 +1,8 @@
<script lang="ts" setup>
import { handleTZ } from 'nocodb-sdk'
import type { ColumnType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { CellValueInj, ColumnInj, computed, handleTZ, inject, renderValue, replaceUrlsWithLink, useBase } from '#imports'
import { CellValueInj, ColumnInj, computed, inject, renderValue, replaceUrlsWithLink, useBase } from '#imports'
// todo: column type doesn't have required property `error` - throws in typecheck
const column = inject(ColumnInj) as Ref<ColumnType & { colOptions: { error: any } }>

41
packages/nc-gui/components/virtual-cell/Rollup.vue

@ -1,18 +1,51 @@
<script setup lang="ts">
import { CellValueInj, inject, useShowNotEditableWarning } from '#imports'
import type { ColumnType, LinkToAnotherRecordType, RollupType } from 'nocodb-sdk'
import { CellValueInj, ColumnInj, MetaInj, computed, inject, isRollup, ref, useMetas, useShowNotEditableWarning } from '#imports'
const { metas } = useMetas()
const value = inject(CellValueInj)
const column = inject(ColumnInj)!
const meta = inject(MetaInj, ref())
const { showEditNonEditableFieldWarning, showClearNonEditableFieldWarning, activateShowEditNonEditableFieldWarning } =
useShowNotEditableWarning()
const relationColumnOptions = computed<LinkToAnotherRecordType | null>(() => {
if ((column?.value?.colOptions as RollupType)?.fk_relation_column_id) {
return meta?.value?.columns?.find((c) => c.id === (column?.value?.colOptions as RollupType)?.fk_relation_column_id)
?.colOptions as LinkToAnotherRecordType
}
return null
})
const relatedTableMeta = computed(
() =>
relationColumnOptions.value?.fk_related_model_id && metas.value?.[relationColumnOptions.value?.fk_related_model_id as string],
)
const colOptions = computed(() => column.value?.colOptions)
const childColumn = computed(() => {
if (relatedTableMeta.value?.columns) {
if (isRollup(column.value)) {
return relatedTableMeta.value?.columns.find(
(c: ColumnType) => c.id === (colOptions.value as RollupType).fk_rollup_column_id,
)
}
}
return ''
})
</script>
<template>
<div @dblclick="activateShowEditNonEditableFieldWarning">
<span class="text-center pl-3">
<div v-if="['count', 'avg', 'sum', 'countDistinct', 'sumDistinct', 'avgDistinct'].includes(colOptions.rollup_function)">
{{ value }}
</span>
</div>
<LazySmartsheetCell v-else v-model="value" :column="childColumn" :edit-enabled="false" :read-only="true" />
<div>
<div v-if="showEditNonEditableFieldWarning" class="text-left text-wrap mt-2 text-[#e65100] text-xs">
{{ $t('msg.info.computedFieldEditWarning') }}

3
packages/nc-gui/components/webhook/CallLog.vue

@ -1,6 +1,7 @@
<script setup lang="ts">
import type { HookLogType, HookType } from 'nocodb-sdk'
import { AutomationLogLevel, extractSdkResponseErrorMsg, onBeforeMount, parseProp, timeAgo, useApi, useGlobal } from '#imports'
import { timeAgo } from 'nocodb-sdk'
import { AutomationLogLevel, extractSdkResponseErrorMsg, onBeforeMount, parseProp, useApi, useGlobal } from '#imports'
interface Props {
hook: HookType

4
packages/nc-gui/components/workspace/CollaboratorsList.vue

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { OrderedWorkspaceRoles, WorkspaceUserRoles } from 'nocodb-sdk'
import { storeToRefs, timeAgo, useWorkspace } from '#imports'
import { OrderedWorkspaceRoles, WorkspaceUserRoles, timeAgo } from 'nocodb-sdk'
import { storeToRefs, useWorkspace } from '#imports'
const { workspaceRoles, loadRoles } = useRoles()

3
packages/nc-gui/components/workspace/ProjectList.vue

@ -1,7 +1,7 @@
<script lang="ts" setup>
import { Empty } from 'ant-design-vue'
import type { BaseType } from 'nocodb-sdk'
import { ProjectRoles, ProjectStatus, WorkspaceUserRoles } from 'nocodb-sdk'
import { ProjectRoles, ProjectStatus, WorkspaceUserRoles, timeAgo } from 'nocodb-sdk'
import { nextTick } from '@vue/runtime-core'
import {
NcProjectType,
@ -12,7 +12,6 @@ import {
navigateTo,
ref,
storeToRefs,
timeAgo,
useBases,
useGlobal,
useNuxtApp,

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

@ -6,6 +6,7 @@ const useAttachment = () => {
const getPossibleAttachmentSrc = (item: Record<string, any>) => {
const res: string[] = []
if (item?.data) res.push(item.data)
if (item?.file) res.push(window.URL.createObjectURL(item.file))
if (item?.signedPath) res.push(`${appInfo.value.ncSiteUrl}/${item.signedPath}`)
if (item?.signedUrl) res.push(item.signedUrl)
if (item?.path) res.push(`${appInfo.value.ncSiteUrl}/${item.path}`)

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

@ -40,8 +40,6 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
const { sqlUis } = storeToRefs(baseStore)
const { bases } = storeToRefs(useBases())
const { $api } = useNuxtApp()
const { getMeta } = useMetas()
@ -66,12 +64,6 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
isXcdbBaseFunc(meta.value?.source_id ? meta.value?.source_id : Object.keys(sqlUis.value)[0]),
)
const source = computed(() =>
meta.value && meta.value.source_id && meta.value.base_id
? bases.value.get(meta.value?.base_id as string)?.sources?.find((s) => s.id === meta.value!.source_id)
: undefined,
)
const idType = null
const additionalValidations = ref<ValidationsObj>({})

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

@ -3,14 +3,13 @@ import dayjs from 'dayjs'
import type { Ref } from 'vue'
import type { MaybeRef } from '@vueuse/core'
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { RelationTypes, UITypes, dateFormats, isDateMonthFormat, isSystemColumn, isVirtualCol, timeFormats } from 'nocodb-sdk'
import { parse } from 'papaparse'
import type { Cell } from './cellRange'
import { CellRange } from './cellRange'
import convertCellData from './convertCellData'
import type { Nullable, Row } from '#imports'
import {
dateFormats,
extractPkFromRow,
extractSdkResponseErrorMsg,
isDrawerOrModalExist,
@ -20,7 +19,6 @@ import {
message,
reactive,
ref,
timeFormats,
unref,
useBase,
useCopy,
@ -155,6 +153,20 @@ export function useMultiSelect(
}
}
if (columnObj.uidt === UITypes.Date) {
const dateFormat = columnObj.meta?.date_format
if (dateFormat && isDateMonthFormat(dateFormat)) {
// any date month format (e.g. YYYY-MM) couldn't be stored in database
// with date type since it is not a valid date
// therefore, we reformat the value here to display with the formatted one
// e.g. 2023-06-03 -> 2023-06
textToCopy = dayjs(textToCopy, dateFormat).format(dateFormat)
} else {
// e.g. 2023-06-03 (in DB) -> 03/06/2023 (in UI)
textToCopy = dayjs(textToCopy, 'YYYY-MM-DD').format(dateFormat)
}
}
if (columnObj.uidt === UITypes.Time) {
// remove `"`
// e.g. "2023-05-12T08:03:53.000Z" -> 2023-05-12T08:03:53.000Z
@ -752,11 +764,13 @@ export function useMultiSelect(
const clipboardMatrix = parsedClipboard.data as string[][]
const pasteMatrixRows = clipboardMatrix.length
const selectionRowCount = Math.max(clipboardMatrix.length, selectedRange.end.row - selectedRange.start.row + 1)
const pasteMatrixRows = selectionRowCount
const pasteMatrixCols = clipboardMatrix[0].length
const colsToPaste = unref(fields).slice(activeCell.col, activeCell.col + pasteMatrixCols)
const rowsToPaste = unref(data).slice(activeCell.row, activeCell.row + pasteMatrixRows)
const rowsToPaste = unref(data).slice(activeCell.row, activeCell.row + selectionRowCount)
const propsToPaste: string[] = []
let pastedRows = 0
@ -780,7 +794,8 @@ export function useMultiSelect(
const pasteValue = convertCellData(
{
value: clipboardMatrix[i][j],
// Repeat the clipboard data array if the matrix is smaller than the selection
value: clipboardMatrix[i % clipboardMatrix.length][j],
to: pasteCol.uidt as UITypes,
column: pasteCol,
appInfo: unref(appInfo),

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

@ -275,9 +275,9 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState(
}
// reload view columns when active view changes
// or when columns count changes(delete/add)
// or when columns changes(delete/add)
watch(
[() => view?.value?.id, () => meta.value?.columns?.length],
[() => view?.value?.id, () => meta.value?.columns],
async ([newViewId]) => {
// reload only if view belongs to current table
if (newViewId && view.value?.fk_model_id === meta.value?.id) {

5
packages/nc-gui/helpers/parsers/CSVTemplateAdapter.ts

@ -1,7 +1,6 @@
import { parse } from 'papaparse'
import type { UploadFile } from 'ant-design-vue'
import { UITypes } from 'nocodb-sdk'
import { getDateFormat, validateDateWithUnknownFormat } from '../../utils/dateTimeUtils'
import { UITypes, getDateFormat, validateDateWithUnknownFormat } from 'nocodb-sdk'
import {
extractMultiOrSingleSelectProps,
getCheckboxValue,
@ -58,7 +57,7 @@ export default class CSVTemplateAdapter {
this.tables[tableIdx] = []
for (const [columnIdx, columnName] of columnNames.entries()) {
let title = ((columnNameRowExist && columnName.toString().trim()) || `Field ${columnIdx + 1}`).trim()
const title = ((columnNameRowExist && columnName.toString().trim()) || `Field ${columnIdx + 1}`).trim()
let cn: string = ((columnNameRowExist && columnName.toString().trim()) || `field_${columnIdx + 1}`)
.replace(/[` ~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/g, '_')
.trim()

3
packages/nc-gui/helpers/parsers/ExcelTemplateAdapter.ts

@ -1,5 +1,4 @@
import { UITypes } from 'nocodb-sdk'
import { getDateFormat } from '../../utils/dateTimeUtils'
import { UITypes, getDateFormat } from 'nocodb-sdk'
import TemplateGenerator from './TemplateGenerator'
import {
extractMultiOrSingleSelectProps,

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "تعطيل قاعدة مشتركة",
"enable": "أي شخص لديه الرابط",
"link": "رابط قاعدة مشتركة"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "ভগ করস অকষম করন",
"enable": "লিক সহ যউ",
"link": "ভগ করস লিক"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Povolit veřejný přístup",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Správa přístupu k projektu",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Seskupit dle",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Sdílet projekt",
"label": "Share Base",
"disable": "Zakázat sdílenou základnu",
"enable": "Kdokoli s odkazem",
"link": "Sdílený základní odkaz"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Deaktiver delt base",
"enable": "Nogen med linket",
"link": "Shared Base Link."

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Freigegebene Datenbank deaktivieren",
"enable": "Jeder mit dem Link",
"link": "Freigegebene Datenbank-Link"

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

@ -667,7 +667,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -720,7 +720,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Disable shared base",
"enable": "Anyone with the link",
"link": "Shared base link"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Deshabilitar la base compartida",
"enable": "Cualquiera con el link",
"link": "Enlace de base compartida"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Disable shared base",
"enable": "Anyone with the link",
"link": "Shared base link"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "غیرفعال کردن پایگاه مشترک",
"enable": "هر کسی لینک را داشته باشد",
"link": "لینک پایگاه مشترک"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Poista jaettu pohja",
"enable": "Jokainen, jolla on linkki",
"link": "Jaettu peruslinkki"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Désactiver la base partagée",
"enable": "N'importe qui disposant du lien",
"link": "Partager le lien de la base"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "השבת בסיס משותף",
"enable": "כל אחד עם הקישור",
"link": "קישור בסיס משותף"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "स आधर अकषम कर",
"enable": "कई भयकििसकस लिक ह",
"link": "स आधर लिक"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Onemogući zajedničku bazu",
"enable": "Bilo tko s linkom",
"link": "Zajednička baza veza"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Nonaktifkan basis bersama",
"enable": "Siapa pun dengan tautannya",
"link": "Tautan dasar bersama"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Disabilitare la base condivisa",
"enable": "Chiunque con il link",
"link": "Collegamento base condiviso"

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

@ -1,32 +1,32 @@
{
"dashboards": {
"create_new_dashboard_project": "Create New Interface",
"connect_data_sources": "Connect data sources",
"alert": "Alert",
"alert-message": "No databases have been connected. Connect database bases to build interfaces. Skip this step and add databases from the base home page later.",
"select_database_projects_that_you_want_to_link_to_this_dashboard_projects": "Select Database Bases that you want to link to this Interface.",
"create_interface": "Create interface",
"project_name": "Base Name",
"connect": "Connect",
"create_new_dashboard_project": "インターフェースを作成",
"connect_data_sources": "データソースに接続",
"alert": "アラート",
"alert-message": "データベースが接続されていません。DBベースを接続してインターフェースを構成してください。スキップして後でベースのホームページを追加することもできます。",
"select_database_projects_that_you_want_to_link_to_this_dashboard_projects": "このインターフェースに接続するプロジェクトを選択します。",
"create_interface": "インターフェースを作成",
"project_name": "プロジェクト名",
"connect": "接続",
"buttonActionTypes": {
"open_external_url": "Open external link",
"delete_record": "Delete record",
"update_record": "Update record",
"open_layout": "Open layout"
"open_external_url": "外部リンクを開く",
"delete_record": "レコードを削除",
"update_record": "レコードを更新",
"open_layout": "レイアウトを開く"
},
"widgets": {
"static_text": "Text",
"chart": "Chart",
"table": "Table",
"static_text": "テキスト",
"chart": "チャート",
"table": "",
"image": "Image",
"map": "Map",
"button": "Button",
"number": "Number",
"bar_chart": "Bar Chart",
"line_chart": "Line Chart",
"area_chart": "Area Chart",
"pie_chart": "Pie Chart",
"donut_chart": "Donut Chart",
"map": "マップ",
"button": "ボタン",
"number": "ナンバー",
"bar_chart": "棒グラフ",
"line_chart": "折れ線グラフ",
"area_chart": "面グラフ",
"pie_chart": "円グラフ",
"donut_chart": "ドーナツグラフ",
"scatter_plot": "Scatter Plot",
"bubble_chart": "Bubble Chart",
"radar_chart": "Radar Chart",
@ -39,7 +39,7 @@
}
},
"general": {
"quit": "Quit",
"quit": "終了",
"home": "ホーム",
"load": "読み込み",
"open": "開く",
@ -47,7 +47,7 @@
"yes": "はい",
"no": "いいえ",
"ok": "OK",
"back": "Back",
"back": "戻る",
"and": "と",
"or": "または",
"add": "追加",
@ -78,7 +78,7 @@
"quote": "Quote",
"submit": "送信",
"create": "作成",
"createEntity": "Create {entity}",
"createEntity": "{entity}を作成",
"creating": "Creating",
"creatingEntity": "Creating {entity}",
"details": "Details",

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

@ -666,7 +666,7 @@
"enablePublicAccess": "전체 공개",
"doYouWantToSaveTheChanges": "바뀐 내용을 저장할까요?",
"editingAccess": "수정 권한",
"enabledPublicViewing": "공개 보기 사용 설정",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "비밀번호로 액세스 제한",
"manageProjectAccess": "프로젝트 접근 권한",
"allowDownload": "다운로드 허용",
@ -719,7 +719,7 @@
"groupBy": "분류 기준",
"addSubGroup": "하위 그룹 추가",
"shareBase": {
"label": "프로젝트 공유",
"label": "Share Base",
"disable": "공유 베이스 비활성화",
"enable": "링크가 있는 모든 사용자",
"link": "공유 링크"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Atspējot koplietošanu",
"enable": "Jebkurš ar saiti",
"link": "Koplietota pamatsaite"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Schakel de gedeelde database uit",
"enable": "Iedereen met de link",
"link": "Gedeelde databaselink"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Deaktiver delt base",
"enable": "Alle med linken",
"link": "Delt grunnlinje"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Wyłącz wspólną bazę",
"enable": "Każdy z linkiem",
"link": "Wspólny link bazowy."

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Desativar a base compartilhada",
"enable": "Alguém com o link",
"link": "Link base compartilhada"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Desativar a base compartilhada",
"enable": "Qualquer um com o link",
"link": "Link da base compartilhada"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Отключить общую базу",
"enable": "Включить общую базу",
"link": "Ссылка на общую базу"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Zakázanie zdieľanej základne",
"enable": "Ktokoľvek s odkazom",
"link": "Spoločné základné prepojenie"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Onemogoči skupno bazo",
"enable": "Kdorkoli s povezavo",
"link": "Skupna bazna povezava"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Inaktivera delad bas",
"enable": "Någon med länken",
"link": "Delad baslänk"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "ปดใชงานฐานทใชวมกน",
"enable": "ทกคนทงค",
"link": "ลงคฐานทใชวมกน"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Paylaşılan bağlantıyı devre dışı bırak",
"enable": "Bağlantıya sahip olan herkes",
"link": "Paylaşılan bağlantı"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Вимкнути спільну базу",
"enable": "Будь-хто, хто має посилання",
"link": "Посилання на спільну базу"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "Vô hiệu hóa cơ sở chia sẻ",
"enable": "Bất cứ ai có liên kết",
"link": "Liên kết cơ sở chia sẻ"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "启用公共访问",
"doYouWantToSaveTheChanges": "您要保存这些更改吗?",
"editingAccess": "编辑访问权限",
"enabledPublicViewing": "启用公开查看",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "使用密码限制访问",
"manageProjectAccess": "管理项目访问",
"allowDownload": "允许下载",
@ -719,7 +719,7 @@
"groupBy": "分组",
"addSubGroup": "添加子分组",
"shareBase": {
"label": "分享项目",
"label": "Share Base",
"disable": "停止分享项目",
"enable": "任何有链接的人",
"link": "分享项目链接"

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

@ -666,7 +666,7 @@
"enablePublicAccess": "Enable Public Access",
"doYouWantToSaveTheChanges": "Do you want to save the changes ?",
"editingAccess": "Editing access",
"enabledPublicViewing": "Enable public viewing",
"enabledPublicViewing": "Enable Public Viewing",
"restrictAccessWithPassword": "Restrict access with password",
"manageProjectAccess": "Manage Base Access",
"allowDownload": "Allow Download",
@ -719,7 +719,7 @@
"groupBy": "Group By",
"addSubGroup": "Add subgroup",
"shareBase": {
"label": "Share base",
"label": "Share Base",
"disable": "停用共享資料庫",
"enable": "任何有連結的人",
"link": "共享資料庫連結"

2
packages/nc-gui/store/bases.ts

@ -12,6 +12,7 @@ export const useBases = defineStore('basesStore', () => {
const bases = ref<Map<string, NcProject>>(new Map())
const basesList = computed<NcProject[]>(() => Array.from(bases.value.values()).sort((a, b) => a.updated_at - b.updated_at))
const baseUserCount = ref<number | undefined>(undefined)
const router = useRouter()
const route = router.currentRoute
@ -294,6 +295,7 @@ export const useBases = defineStore('basesStore', () => {
return {
bases,
basesList,
baseUserCount,
loadProjects,
loadProject,
getSqlUi,

89
packages/nc-gui/utils/dateTimeUtils.ts

@ -1,89 +0,0 @@
import dayjs from 'dayjs'
export const timeAgo = (date: any) => {
if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(date)) {
// if there is no timezone info, consider as UTC
// e.g. 2023-01-01 08:00:00 (MySQL)
date += '+00:00'
}
// show in local time
return dayjs(date).fromNow()
}
export const dateFormats = [
'YYYY-MM-DD',
'YYYY/MM/DD',
'DD-MM-YYYY',
'MM-DD-YYYY',
'DD/MM/YYYY',
'MM/DD/YYYY',
'DD MM YYYY',
'MM DD YYYY',
'YYYY MM DD',
]
export const timeFormats = ['HH:mm', 'HH:mm:ss']
export const handleTZ = (val: any) => {
if (val === undefined || val === null) {
return
}
if (typeof val !== 'string') {
return val
}
return val.replace(
/((?:-?(?:[1-9][0-9]*)?[0-9]{4})-(?:1[0-2]|0[1-9])-(?:3[01]|0[1-9]|[12][0-9])T(?:2[0-3]|[01][0-9]):(?:[0-5][0-9]):(?:[0-5][0-9])(?:\.[0-9]+)?(?:Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9]))/g,
(i, v) => {
return dayjs(v).format('YYYY-MM-DD HH:mm')
},
)
}
export function validateDateFormat(v: string) {
return dateFormats.includes(v)
}
export function validateDateWithUnknownFormat(v: string) {
for (const format of dateFormats) {
if (dayjs(v, format, true).isValid() as any) {
return true
}
for (const timeFormat of ['HH:mm', 'HH:mm:ss', 'HH:mm:ss.SSS']) {
if (dayjs(v, `${format} ${timeFormat}`, true).isValid() as any) {
return true
}
}
}
return false
}
export function getDateFormat(v: string) {
for (const format of dateFormats) {
if (dayjs(v, format, true).isValid()) {
return format
}
}
return 'YYYY/MM/DD'
}
export function getDateTimeFormat(v: string) {
for (const format of dateFormats) {
for (const timeFormat of timeFormats) {
const dateTimeFormat = `${format} ${timeFormat}`
if (dayjs(v, dateTimeFormat, true).isValid() as any) {
return dateTimeFormat
}
}
}
return 'YYYY/MM/DD'
}
export function parseStringDate(v: string, dateFormat: string) {
const dayjsObj = dayjs(v)
if (dayjsObj.isValid()) {
v = dayjsObj.format('YYYY-MM-DD')
} else {
v = dayjs(v, dateFormat).format('YYYY-MM-DD')
}
return v
}

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

@ -1,4 +1,4 @@
import { UITypes, isNumericCol, numericUITypes } from 'nocodb-sdk'
import { UITypes, isDateMonthFormat, isNumericCol, numericUITypes } from 'nocodb-sdk'
const getEqText = (fieldUiType: UITypes) => {
if (isNumericCol(fieldUiType) || fieldUiType === UITypes.Time) {
@ -70,210 +70,215 @@ const getLteText = (fieldUiType: UITypes) => {
export const comparisonOpList = (
fieldUiType: UITypes,
dateFormat?: string,
): {
text: string
value: string
ignoreVal: boolean
includedTypes?: UITypes[]
excludedTypes?: UITypes[]
}[] => [
{
text: 'is checked',
value: 'checked',
ignoreVal: true,
includedTypes: [UITypes.Checkbox],
},
{
text: 'is not checked',
value: 'notchecked',
ignoreVal: true,
includedTypes: [UITypes.Checkbox],
},
{
text: getEqText(fieldUiType),
value: 'eq',
ignoreVal: false,
excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.Attachment],
},
{
text: getNeqText(fieldUiType),
value: 'neq',
ignoreVal: false,
excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.Attachment],
},
{
text: getLikeText(fieldUiType),
value: 'like',
ignoreVal: false,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: getNotLikeText(fieldUiType),
value: 'nlike',
ignoreVal: false,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: 'is empty',
value: 'empty',
ignoreVal: true,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: 'is not empty',
value: 'notempty',
ignoreVal: true,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: 'is null',
value: 'null',
ignoreVal: true,
excludedTypes: [
...numericUITypes,
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
],
},
{
text: 'is not null',
value: 'notnull',
ignoreVal: true,
excludedTypes: [
...numericUITypes,
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
],
},
{
text: 'contains all of',
value: 'allof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect],
},
{
text: 'contains any of',
value: 'anyof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect],
},
{
text: 'does not contain all of',
value: 'nallof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect],
},
{
text: 'does not contain any of',
value: 'nanyof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect],
},
{
text: getGtText(fieldUiType),
value: 'gt',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: getLtText(fieldUiType),
value: 'lt',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: getGteText(fieldUiType),
value: 'gte',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: getLteText(fieldUiType),
value: 'lte',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: 'is within',
value: 'isWithin',
ignoreVal: true,
includedTypes: [UITypes.Date, UITypes.DateTime],
},
{
text: 'is blank',
value: 'blank',
ignoreVal: true,
excludedTypes: [UITypes.Checkbox, UITypes.Links, UITypes.Rollup],
},
{
text: 'is not blank',
value: 'notblank',
ignoreVal: true,
excludedTypes: [UITypes.Checkbox, UITypes.Links, UITypes.Rollup],
},
]
}[] => {
const isDateMonth = dateFormat && isDateMonthFormat(dateFormat)
return [
{
text: 'is checked',
value: 'checked',
ignoreVal: true,
includedTypes: [UITypes.Checkbox],
},
{
text: 'is not checked',
value: 'notchecked',
ignoreVal: true,
includedTypes: [UITypes.Checkbox],
},
{
text: getEqText(fieldUiType),
value: 'eq',
ignoreVal: false,
excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.Attachment],
},
{
text: getNeqText(fieldUiType),
value: 'neq',
ignoreVal: false,
excludedTypes: [UITypes.Checkbox, UITypes.MultiSelect, UITypes.Attachment],
},
{
text: getLikeText(fieldUiType),
value: 'like',
ignoreVal: false,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: getNotLikeText(fieldUiType),
value: 'nlike',
ignoreVal: false,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: 'is empty',
value: 'empty',
ignoreVal: true,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: 'is not empty',
value: 'notempty',
ignoreVal: true,
excludedTypes: [
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
...numericUITypes,
],
},
{
text: 'is null',
value: 'null',
ignoreVal: true,
excludedTypes: [
...numericUITypes,
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
],
},
{
text: 'is not null',
value: 'notnull',
ignoreVal: true,
excludedTypes: [
...numericUITypes,
UITypes.Checkbox,
UITypes.SingleSelect,
UITypes.MultiSelect,
UITypes.Collaborator,
UITypes.Attachment,
UITypes.LinkToAnotherRecord,
UITypes.Lookup,
UITypes.Date,
UITypes.DateTime,
UITypes.Time,
],
},
{
text: 'contains all of',
value: 'allof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect],
},
{
text: 'contains any of',
value: 'anyof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect],
},
{
text: 'does not contain all of',
value: 'nallof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect],
},
{
text: 'does not contain any of',
value: 'nanyof',
ignoreVal: false,
includedTypes: [UITypes.MultiSelect, UITypes.SingleSelect],
},
{
text: getGtText(fieldUiType),
value: 'gt',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: getLtText(fieldUiType),
value: 'lt',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: getGteText(fieldUiType),
value: 'gte',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: getLteText(fieldUiType),
value: 'lte',
ignoreVal: false,
includedTypes: [...numericUITypes, UITypes.Date, UITypes.DateTime, UITypes.Time],
},
{
text: 'is within',
value: 'isWithin',
ignoreVal: true,
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'is blank',
value: 'blank',
ignoreVal: true,
excludedTypes: [UITypes.Checkbox, UITypes.Links, UITypes.Rollup],
},
{
text: 'is not blank',
value: 'notblank',
ignoreVal: true,
excludedTypes: [UITypes.Checkbox, UITypes.Links, UITypes.Rollup],
},
]
}
export const comparisonSubOpList = (
// TODO: type
comparison_op: string,
dateFormat?: string,
): {
text: string
value: string
@ -281,6 +286,8 @@ export const comparisonSubOpList = (
includedTypes?: UITypes[]
excludedTypes?: UITypes[]
}[] => {
const isDateMonth = dateFormat && isDateMonthFormat(dateFormat)
if (comparison_op === 'isWithin') {
return [
{
@ -338,31 +345,31 @@ export const comparisonSubOpList = (
text: 'today',
value: 'today',
ignoreVal: true,
includedTypes: [UITypes.Date, UITypes.DateTime],
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'tomorrow',
value: 'tomorrow',
ignoreVal: true,
includedTypes: [UITypes.Date, UITypes.DateTime],
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'yesterday',
value: 'yesterday',
ignoreVal: true,
includedTypes: [UITypes.Date, UITypes.DateTime],
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'one week ago',
value: 'oneWeekAgo',
ignoreVal: true,
includedTypes: [UITypes.Date, UITypes.DateTime],
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'one week from now',
value: 'oneWeekFromNow',
ignoreVal: true,
includedTypes: [UITypes.Date, UITypes.DateTime],
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'one month ago',
@ -380,16 +387,16 @@ export const comparisonSubOpList = (
text: 'number of days ago',
value: 'daysAgo',
ignoreVal: false,
includedTypes: [UITypes.Date, UITypes.DateTime],
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'number of days from now',
value: 'daysFromNow',
ignoreVal: false,
includedTypes: [UITypes.Date, UITypes.DateTime],
includedTypes: [...(isDateMonth ? [] : [UITypes.Date, UITypes.DateTime])],
},
{
text: 'exact date',
text: isDateMonth ? 'exact month' : 'exact date',
value: 'exactDate',
ignoreVal: false,
includedTypes: [UITypes.Date, UITypes.DateTime],

1
packages/nc-gui/utils/index.ts

@ -1,6 +1,5 @@
export * from './NcAutocompleteTree'
export * from './colorsUtils'
export * from './dateTimeUtils'
export * from './deepCompare'
export * from './formulaUtils'
export * from './durationUtils'

3
packages/nocodb-sdk/package.json

@ -39,7 +39,8 @@
},
"dependencies": {
"axios": "^1.6.2",
"jsep": "^1.3.8"
"jsep": "^1.3.8",
"dayjs": "^1.11.9"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^6.13.1",

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

Loading…
Cancel
Save