Browse Source

Merge branch 'develop' into refactor/timezone-locale

pull/5505/head
Wing-Kam Wong 1 year ago
parent
commit
79cddca845
  1. 2
      packages/nc-gui/components/account/AppStore.vue
  2. 4
      packages/nc-gui/components/account/License.vue
  3. 22
      packages/nc-gui/components/account/ResetPassword.vue
  4. 21
      packages/nc-gui/components/account/Token.vue
  5. 11
      packages/nc-gui/components/account/UserList.vue
  6. 18
      packages/nc-gui/components/account/UsersModal.vue
  7. 4
      packages/nc-gui/components/api-client/Headers.vue
  8. 6
      packages/nc-gui/components/api-client/Params.vue
  9. 21
      packages/nc-gui/components/dashboard/settings/AuditTab.vue
  10. 6
      packages/nc-gui/components/dashboard/settings/Metadata.vue
  11. 16
      packages/nc-gui/components/dashboard/settings/Modal.vue
  12. 6
      packages/nc-gui/components/dashboard/settings/UIAcl.vue
  13. 30
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  14. 25
      packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue
  15. 19
      packages/nc-gui/components/dlg/QuickImport.vue
  16. 13
      packages/nc-gui/components/dlg/TableCreate.vue
  17. 19
      packages/nc-gui/components/dlg/TableDuplicate.vue
  18. 38
      packages/nc-gui/components/dlg/TableRename.vue
  19. 10
      packages/nc-gui/components/dlg/ViewCreate.vue
  20. 6
      packages/nc-gui/components/dlg/ViewDelete.vue
  21. 2
      packages/nc-gui/components/general/ShareBaseButton.vue
  22. 7
      packages/nc-gui/components/smartsheet/toolbar/FilterInput.vue
  23. 22
      packages/nc-gui/components/tabs/auth/ApiTokenManagement.vue
  24. 22
      packages/nc-gui/components/tabs/auth/UserManagement.vue
  25. 101
      packages/nc-gui/components/tabs/auth/user-management/ShareBase.vue
  26. 32
      packages/nc-gui/components/tabs/auth/user-management/UsersModal.vue
  27. 8
      packages/nc-gui/components/webhook/Drawer.vue
  28. 6
      packages/nc-gui/components/webhook/Editor.vue
  29. 4
      packages/nc-gui/components/webhook/List.vue
  30. 24
      packages/nc-gui/composables/useSharedFormViewStore.ts
  31. 6
      packages/nc-gui/lang/ar.json
  32. 6
      packages/nc-gui/lang/bn_IN.json
  33. 6
      packages/nc-gui/lang/cs.json
  34. 6
      packages/nc-gui/lang/da.json
  35. 6
      packages/nc-gui/lang/de.json
  36. 6
      packages/nc-gui/lang/en.json
  37. 6
      packages/nc-gui/lang/es.json
  38. 6
      packages/nc-gui/lang/eu.json
  39. 124
      packages/nc-gui/lang/fa.json
  40. 6
      packages/nc-gui/lang/fi.json
  41. 6
      packages/nc-gui/lang/fr.json
  42. 6
      packages/nc-gui/lang/he.json
  43. 6
      packages/nc-gui/lang/hi.json
  44. 6
      packages/nc-gui/lang/hr.json
  45. 6
      packages/nc-gui/lang/id.json
  46. 6
      packages/nc-gui/lang/it.json
  47. 6
      packages/nc-gui/lang/ja.json
  48. 6
      packages/nc-gui/lang/ko.json
  49. 6
      packages/nc-gui/lang/lv.json
  50. 6
      packages/nc-gui/lang/nl.json
  51. 6
      packages/nc-gui/lang/no.json
  52. 6
      packages/nc-gui/lang/pl.json
  53. 6
      packages/nc-gui/lang/pt.json
  54. 6
      packages/nc-gui/lang/pt_BR.json
  55. 6
      packages/nc-gui/lang/ru.json
  56. 6
      packages/nc-gui/lang/sk.json
  57. 6
      packages/nc-gui/lang/sl.json
  58. 6
      packages/nc-gui/lang/sv.json
  59. 6
      packages/nc-gui/lang/th.json
  60. 6
      packages/nc-gui/lang/tr.json
  61. 6
      packages/nc-gui/lang/uk.json
  62. 6
      packages/nc-gui/lang/vi.json
  63. 6
      packages/nc-gui/lang/zh-Hans.json
  64. 6
      packages/nc-gui/lang/zh-Hant.json
  65. 8
      packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts
  66. 2
      packages/nocodb/src/db/functionMappings/sqlite.ts

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

@ -1,6 +1,6 @@
<template>
<div class="h-full overflow-y-scroll scrollbar-thin-dull pt-2">
<div class="text-xl mt-4 mb-8 text-center font-weight-bold">{{ $t('title.appStore') }}</div>
<div class="text-xl mt-4 mb-8 text-left font-weight-bold">{{ $t('title.appStore') }}</div>
<div>
<LazyDashboardSettingsAppStore />
</div>

4
packages/nc-gui/components/account/License.vue

@ -40,7 +40,9 @@ loadLicense()
<div>
<a-textarea v-model:value="key" placeholder="License key" class="!mt-2 !max-w-[600px]"></a-textarea>
</div>
<div class="text-center"><a-button class="mt-4" @click="setLicense" type="primary">Save license key</a-button></div>
<div class="text-center">
<a-button class="mt-4 !h-[2.2rem] !rounded-md" @click="setLicense" type="primary">Save license key</a-button>
</div>
</div>
</div>
</template>

22
packages/nc-gui/components/account/ResetPassword.vue

@ -65,13 +65,13 @@ const resetError = () => {
</script>
<template>
<div class="mx-auto relative flex flex-col justify-center gap-2 w-full px-8 md:(bg-white) max-w-[900px]">
<div class="text-xl mt-4 mb-8 text-center font-weight-bold">{{ $t('activity.changePwd') }}</div>
<div class="mx-auto relative flex flex-col justify-start gap-2 w-full px-8 md:(bg-white) max-w-[900px]">
<div class="text-xl my-4 text-left font-weight-bold">{{ $t('activity.changePwd') }}</div>
<a-form
ref="formValidator"
data-testid="nc-user-settings-form"
layout="vertical"
class="change-password lg:max-w-3/4 w-full !mx-auto"
class="change-password lg:max-w-3/4 w-full"
no-style
:model="form"
@finish="passwordChange"
@ -118,13 +118,19 @@ const resetError = () => {
/>
</a-form-item>
<div class="text-center">
<button data-testid="nc-user-settings-form__submit" class="scaling-btn bg-opacity-100" type="submit">
<span class="flex items-center gap-2">
<div class="text-right">
<a-button
size="middle"
data-testid="nc-user-settings-form__submit"
class="!rounded-md !h-[2.5rem]"
type="primary"
html-type="submit"
>
<div class="flex justify-center items-center gap-2">
<component :is="iconMap.passwordChange" />
{{ $t('activity.changePwd') }}
</span>
</button>
</div>
</a-button>
</div>
</a-form>
</div>

21
packages/nc-gui/components/account/Token.vue

@ -100,12 +100,18 @@ const descriptionInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
<template>
<div class="h-full overflow-y-scroll scrollbar-thin-dull pt-2">
<div class="text-xl mt-4 mb-8 text-center font-weight-bold">Token Management</div>
<div class="max-w-[900px] mx-auto p-4" data-testid="nc-token-list">
<div class="text-xl my-4 text-left font-weight-bold">Token Management</div>
<div class="py-2 flex gap-4 items-center">
<div class="flex-grow"></div>
<component :is="iconMap.reload" class="cursor-pointer" @click="loadTokens" />
<a-button data-testid="nc-token-create" size="small" type="primary" @click="showNewTokenModal = true">
<a-button
class="!rounded-md"
data-testid="nc-token-create"
size="middle"
type="primary"
@click="showNewTokenModal = true"
>
<div class="flex items-center gap-1">
<component :is="iconMap.plus" />
Add new token
@ -197,9 +203,9 @@ const descriptionInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
<template #overlay>
<a-menu data-testid="nc-token-row-action-icon">
<a-menu-item>
<div class="flex flex-row items-center py-3 h-[1rem] nc-delete-token" @click="deleteToken(record.token)">
<div class="flex flex-row items-center py-3 h-[2rem] nc-delete-token" @click="deleteToken(record.token)">
<component :is="iconMap.delete" class="flex" />
<div class="text-xs pl-2">{{ $t('general.remove') }}</div>
<div class="text-sm pl-2">{{ $t('general.remove') }}</div>
</div>
</a-menu-item>
</a-menu>
@ -228,7 +234,7 @@ const descriptionInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</a-button>
<!-- Generate Token -->
<div class="flex flex-row justify-center w-full -mt-1 mb-3">
<div class="flex flex-row w-full -mt-1 mb-3">
<a-typography-title :level="5">{{ $t('title.generateToken') }}</a-typography-title>
</div>
@ -248,11 +254,12 @@ const descriptionInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
v-model:value="selectedTokenData.description"
data-testid="nc-token-modal-description"
:placeholder="$t('labels.description')"
class="h-9 rounded-md"
/>
<!-- Generate -->
<div class="flex flex-row justify-center">
<a-button type="primary" html-type="submit" data-testid="nc-token-modal-save">
<div class="flex flex-row justify-end">
<a-button size="middle" class="!rounded-md" type="primary" html-type="submit" data-testid="nc-token-modal-save">
{{ $t('general.generate') }}
</a-button>
</div>

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

@ -131,14 +131,14 @@ const copyPasswordResetUrl = async (user: User) => {
<template>
<div data-testid="nc-super-user-list">
<div class="text-xl mt-4 mb-8 text-center font-weight-bold">User Management</div>
<div class="max-w-[900px] mx-auto p-4">
<div class="max-w-[900px] mx-auto">
<div class="text-xl my-4 text-left font-weight-bold">User Management</div>
<div class="py-2 flex gap-4 items-center">
<a-input-search
v-model:value="searchText"
size="small"
size="middle"
class="max-w-[300px]"
placeholder="Filter by email"
placeholder="Search Users"
@blur="loadUsers"
@keydown.enter="loadUsers"
>
@ -147,7 +147,8 @@ const copyPasswordResetUrl = async (user: User) => {
<component :is="iconMap.reload" class="cursor-pointer" @click="loadUsers" />
<a-button
data-testid="nc-super-user-invite"
size="small"
size="middle"
class="!rounded-md"
type="primary"
@click="
() => {

18
packages/nc-gui/components/account/UsersModal.vue

@ -125,13 +125,13 @@ const emailInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
<div class="px-2 mt-1.5">
<template v-if="usersData.invitationToken">
<div class="flex flex-col mt-1 border-b-1 pb-5">
<div class="flex flex-col mt-1 pb-5">
<div class="flex flex-row items-center pl-1.5 pb-1 h-[1.1rem]">
<component :is="iconMap.account" />
<div class="text-xs ml-0.5 mt-0.5">Copy Invite Token</div>
</div>
<a-alert class="mt-1" type="success" show-icon>
<a-alert class="!mt-2" type="success" show-icon>
<template #message>
<div class="flex flex-row justify-between items-center py-1">
<div class="flex pl-2 text-green-700 text-xs">
@ -152,8 +152,8 @@ const emailInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
{{ usersData.invitationToken && usersData.emails }}
</div>
<div class="flex flex-row justify-start mt-4 ml-2">
<a-button size="small" outlined @click="clickInviteMore">
<div class="flex flex-row justify-end mt-4 ml-2">
<a-button size="middle" outlined @click="clickInviteMore">
<div class="flex flex-row justify-center items-center space-x-0.5">
<MaterialSymbolsSendOutline class="flex mx-auto text-gray-600 h-[0.8rem]" />
@ -165,11 +165,6 @@ const emailInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</template>
<div v-else class="flex flex-col pb-4">
<div class="flex flex-row items-center pl-2 pb-1 h-[1rem]">
<component :is="iconMap.account" />
<div class="text-xs ml-0.5 mt-0.5">{{ $t('activity.inviteUser') }}</div>
</div>
<div class="border-1 py-3 px-4 rounded-md mt-1">
<a-form
ref="formRef"
@ -191,6 +186,7 @@ const emailInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
<a-input
:ref="emailInput"
v-model:value="usersData.emails"
size="middle"
validate-trigger="onBlur"
:placeholder="$t('labels.email')"
/>
@ -228,8 +224,8 @@ const emailInput: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</div>
</div>
<div class="flex flex-row justify-center">
<a-button type="primary" html-type="submit">
<div class="flex flex-row justify-end">
<a-button type="primary" class="!rounded-md" html-type="submit">
<div class="flex flex-row justify-center items-center space-x-1.5">
<MaterialSymbolsSendOutline class="flex h-[0.8rem]" />
<div>{{ $t('activity.invite') }}</div>

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

@ -74,11 +74,11 @@ const filterOption = (input: string, option: Option) => {
</th>
<th>
<div class="text-center font-normal mb-2">Header Name</div>
<div class="text-left font-normal ml-2">Header Name</div>
</th>
<th>
<div class="text-center font-normal mb-2">Value</div>
<div class="text-left font-normal ml-2">Value</div>
</th>
<th>

6
packages/nc-gui/components/api-client/Params.vue

@ -15,7 +15,7 @@ const deleteParamRow = (i: number) => vModel.value.splice(i, 1)
</script>
<template>
<div class="flex flex-row justify-center">
<div class="flex flex-row justify-start">
<table>
<thead>
<tr>
@ -24,11 +24,11 @@ const deleteParamRow = (i: number) => vModel.value.splice(i, 1)
</th>
<th>
<div class="text-center font-normal mb-2">Param Name</div>
<div class="text-left font-normal ml-2">Param Name</div>
</th>
<th>
<div class="text-center font-normal mb-2">Value</div>
<div class="text-left font-normal ml-2">Value</div>
</th>
<th>

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

@ -92,8 +92,8 @@ const columns = [
<template>
<div class="flex flex-col gap-4 w-full">
<div v-if="!appInfo.auditEnabled" class="text-red-500">Audit logs are currently disabled by administrators.</div>
<div class="flex flex-row justify-between items-center">
<a-button class="self-start" @click="loadAudits">
<div class="flex flex-row justify-end items-center">
<a-button class="self-start !rounded-md" @click="loadAudits">
<!-- Reload -->
<div class="flex items-center gap-2 text-gray-600 font-light">
<component :is="iconMap.reload" :class="{ 'animate-infinite animate-spin !text-success': isLoading }" />
@ -101,14 +101,6 @@ const columns = [
{{ $t('general.reload') }}
</div>
</a-button>
<a-pagination
v-model:current="currentPage"
v-model:page-size="currentLimit"
:total="totalRows"
show-less-items
@change="loadAudits"
/>
</div>
<a-table
@ -124,6 +116,15 @@ const columns = [
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" :description="$t('labels.noData')" />
</template>
</a-table>
<div class="flex flex-row justify-center items-center">
<a-pagination
v-model:current="currentPage"
v-model:page-size="currentLimit"
:total="totalRows"
show-less-items
@change="loadAudits"
/>
</div>
</div>
</template>

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

@ -90,7 +90,11 @@ const columns = [
<div class="flex flex-col w-3/5">
<div class="flex flex-row justify-end items-center w-full mb-4">
<!-- Reload -->
<a-button v-e="['a:proj-meta:meta-data:reload']" class="self-start nc-btn-metasync-reload" @click="loadMetaDiff">
<a-button
v-e="['a:proj-meta:meta-data:reload']"
class="self-start !rounded-md nc-btn-metasync-reload"
@click="loadMetaDiff"
>
<div class="flex items-center gap-2 text-gray-600 font-light">
<component :is="iconMap.reload" :class="{ 'animate-infinite animate-spin !text-success': isLoading }" />
{{ $t('general.reload') }}

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

@ -178,13 +178,9 @@ watch(
<!-- Side tabs -->
<a-layout-sider>
<a-menu v-model:selected-keys="selectedTabKeys" class="tabs-menu h-full" :open-keys="[]">
<a-menu-item
v-for="(tab, key) of tabsInfo"
:key="key"
class="group active:(!ring-0) hover:(!bg-primary !bg-opacity-25)"
>
<a-menu-item v-for="(tab, key) of tabsInfo" :key="key" class="active:(!ring-0) hover:(!bg-primary !bg-opacity-25)">
<div class="flex items-center space-x-2" @click="tab.onClick">
<component :is="tab.icon" class="group-hover:text-accent" />
<component :is="tab.icon" />
<div class="select-none">
{{ tab.title }}
@ -223,10 +219,11 @@ watch(
<div v-if="vDataState === ''" class="flex flex-row justify-end items-center w-full gap-1">
<a-button
v-if="dataSourcesAwakened"
class="self-start nc-btn-new-datasource"
type="primary"
class="self-start !rounded-md nc-btn-new-datasource"
@click="vDataState = DataSourcesSubTab.New"
>
<div v-if="vDataState === ''" class="flex items-center gap-2 text-primary font-light">
<div v-if="vDataState === ''" class="flex items-center gap-2 font-light">
<component :is="iconMap.plusCircle" class="group-hover:text-accent" />
New
</div>
@ -234,7 +231,8 @@ watch(
<!-- Reload -->
<a-button
v-e="['a:proj-meta:data-sources:reload']"
class="self-start nc-btn-metasync-reload"
type="text"
class="self-start !rounded-md nc-btn-metasync-reload"
@click="dataSourcesReload = true"
>
<div class="flex items-center gap-2 text-gray-600 font-light">

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

@ -125,15 +125,15 @@ const columns = [
</template>
</a-input>
<a-button class="self-start nc-acl-reload" @click="loadTableList">
<a-button type="text" ghost class="self-start !rounded-md nc-acl-reload" @click="loadTableList">
<div class="flex items-center gap-2 text-gray-600 font-light">
<component :is="iconMap.reload" :class="{ 'animate-infinite animate-spin !text-success': isLoading }" />
Reload
</div>
</a-button>
<a-button class="self-start nc-acl-save" @click="saveUIAcl">
<div class="flex items-center gap-2 text-gray-600 font-light">
<a-button type="primary" class="!rounded-md self-start nc-acl-save" @click="saveUIAcl">
<div class="flex items-center gap-2 text-white font-light">
<component :is="iconMap.save" />
Save
</div>

30
packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue

@ -374,8 +374,8 @@ watch(
</script>
<template>
<div class="create-base max-w-800px mx-auto bg-white relative flex flex-col justify-center gap-2 w-full p-8">
<h1 class="prose-2xl font-bold self-center my-4">New Base</h1>
<div class="create-base max-w-800px bg-white relative flex flex-col justify-center gap-2 w-full p-8">
<h1 class="prose-2xl font-bold self-start my-4">New Base</h1>
<a-form
ref="form"
@ -493,17 +493,17 @@ watch(
>
<a-input v-model:value="formState.dataSource.searchPath[0]" />
</a-form-item>
<div class="flex items-right justify-end gap-2">
<!-- Use Connection URL -->
<a-button type="primary" class="nc-extdb-btn-import-url !rounded-md" @click.stop="importURLDlg = true">
{{ $t('activity.useConnectionUrl') }}
</a-button>
</div>
<a-collapse ghost expand-icon-position="right" class="!mt-6">
<a-collapse-panel key="1">
<template #header>
<div class="flex items-center gap-2">
<!-- Use Connection URL -->
<a-button type="default" class="nc-extdb-btn-import-url" @click.stop="importURLDlg = true">
{{ $t('activity.useConnectionUrl') }}
</a-button>
<span>{{ $t('title.advancedParameters') }}</span>
</div>
<span>{{ $t('title.advancedParameters') }}</span>
</template>
<a-form-item label="SSL mode">
<a-select v-model:value="formState.sslUse" dropdown-class-name="nc-dropdown-ssl-mode" @select="onSSLModeChange">
@ -600,7 +600,7 @@ watch(
</a-form-item>
<div class="flex justify-end">
<a-button class="!shadow-md" @click="handleEditJSON()">
<a-button type="primary" class="!rounded-md" @click="handleEditJSON()">
<!-- Edit connection JSON -->
{{ $t('activity.editConnJson') }}
</a-button>
@ -609,13 +609,13 @@ watch(
</a-collapse>
</template>
<a-form-item class="flex justify-center !mt-5">
<div class="flex justify-center gap-2">
<a-button type="primary" ghost class="nc-extdb-btn-test-connection" @click="testConnection">
<a-form-item class="flex justify-end !mt-5">
<div class="flex justify-end gap-2">
<a-button type="text" class="nc-extdb-btn-test-connection !rounded-md" @click="testConnection">
{{ $t('activity.testDbConn') }}
</a-button>
<a-button type="primary" :disabled="!testSuccess" class="nc-extdb-btn-submit !shadow" @click="createBase">
<a-button type="primary" :disabled="!testSuccess" class="nc-extdb-btn-submit !rounded-md" @click="createBase">
{{ $t('general.submit') }}
</a-button>
</div>
@ -636,7 +636,7 @@ watch(
<a-modal
v-model:visible="importURLDlg"
:title="$t('activity.useConnectionUrl')"
width="600px"
width="500px"
:ok-text="$t('general.ok')"
:cancel-text="$t('general.cancel')"
wrap-class-name="nc-modal-connection-url"

25
packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue

@ -346,8 +346,8 @@ onMounted(async () => {
</script>
<template>
<div class="edit-base max-w-800px mx-auto bg-white relative flex flex-col justify-center gap-2 w-full p-8">
<h1 class="prose-2xl font-bold self-center my-4">Edit Base</h1>
<div class="edit-base max-w-800px bg-white relative flex flex-col justify-start gap-2 w-full p-2">
<h1 class="prose-2xl font-bold self-start">Edit Base</h1>
<a-form
ref="form"
@ -465,15 +465,16 @@ onMounted(async () => {
>
<a-input v-model:value="formState.dataSource.searchPath[0]" />
</a-form-item>
<!-- Use Connection URL -->
<div class="flex justify-end gap-2">
<a-button type="primary" class="nc-extdb-btn-import-url !rounded-md" @click.stop="importURLDlg = true">
{{ $t('activity.useConnectionUrl') }}
</a-button>
</div>
<a-collapse ghost expand-icon-position="right" class="!mt-6">
<a-collapse-panel key="1">
<template #header>
<div class="flex items-center gap-2">
<!-- Use Connection URL -->
<a-button type="default" class="nc-extdb-btn-import-url" @click.stop="importURLDlg = true">
{{ $t('activity.useConnectionUrl') }}
</a-button>
<span>{{ $t('title.advancedParameters') }}</span>
</div>
</template>
@ -572,7 +573,7 @@ onMounted(async () => {
</a-form-item>
<div class="flex justify-end">
<a-button class="!shadow-md" @click="handleEditJSON()">
<a-button type="primary" class="!rounded-md" @click="handleEditJSON()">
<!-- Edit connection JSON -->
{{ $t('activity.editConnJson') }}
</a-button>
@ -581,13 +582,13 @@ onMounted(async () => {
</a-collapse>
</template>
<a-form-item class="flex justify-center !mt-5">
<div class="flex justify-center gap-2">
<a-button type="primary" ghost class="nc-extdb-btn-test-connection" @click="testConnection">
<a-form-item class="flex justify-end !mt-5">
<div class="flex justify-end gap-2">
<a-button type="text" class="nc-extdb-btn-test-connection" @click="testConnection">
{{ $t('activity.testDbConn') }}
</a-button>
<a-button type="primary" :disabled="!testSuccess" class="nc-extdb-btn-submit !shadow" @click="editBase">
<a-button type="primary" :disabled="!testSuccess" class="nc-extdb-btn-submit !rounded-md" @click="editBase">
{{ $t('general.submit') }}
</a-button>
</div>

19
packages/nc-gui/components/dlg/QuickImport.vue

@ -433,7 +433,7 @@ const beforeUpload = (file: UploadFile) => {
</template>
<div class="pr-10 pt-5">
<a-form :model="importState" name="quick-import-url-form" layout="horizontal" class="mb-0">
<a-form :model="importState" name="quick-import-url-form" layout="vertical" class="mb-0">
<a-form-item :label="importMeta.urlInputLabel" v-bind="validateInfos.url">
<a-input v-model:value="importState.url" size="large" />
</a-form-item>
@ -482,13 +482,14 @@ const beforeUpload = (file: UploadFile) => {
</div>
</a-spin>
<template #footer>
<a-button v-if="templateEditorModal" key="back" @click="templateEditorModal = false">Back</a-button>
<a-button v-if="templateEditorModal" key="back" class="!rounded-md" @click="templateEditorModal = false">Back</a-button>
<a-button v-else key="cancel" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button v-else key="cancel" class="!rounded-md" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button
v-if="activeKey === 'jsonEditorTab' && !templateEditorModal"
key="format"
class="!rounded-md"
:disabled="disableFormatJsonButton"
@click="formatJson"
>
@ -499,7 +500,7 @@ const beforeUpload = (file: UploadFile) => {
v-if="!templateEditorModal"
key="pre-import"
type="primary"
class="nc-btn-import"
class="nc-btn-import !rounded-md"
:loading="preImportLoading"
:disabled="disablePreImportButton"
@click="handlePreImport"
@ -507,7 +508,15 @@ const beforeUpload = (file: UploadFile) => {
{{ $t('activity.import') }}
</a-button>
<a-button v-else key="import" type="primary" :loading="importLoading" :disabled="disableImportButton" @click="handleImport">
<a-button
v-else
key="import"
type="primary"
class="!rounded-md"
:loading="importLoading"
:disabled="disableImportButton"
@click="handleImport"
>
{{ $t('activity.import') }}
</a-button>
</template>

13
packages/nc-gui/components/dlg/TableCreate.vue

@ -118,24 +118,21 @@ onMounted(() => {
<a-modal
v-model:visible="dialogShow"
:class="{ active: dialogShow }"
width="max(30vw, 600px)"
:title="$t('activity.createTable')"
centered
wrap-class-name="nc-modal-table-create"
@keydown.esc="dialogShow = false"
>
<template #footer>
<a-button key="back" size="large" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button key="back" size="middle" class="!rounded-md" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button key="submit" size="large" type="primary" :loading="creating" @click="_createTable"
<a-button key="submit" size="middle" class="!rounded-md" type="primary" :loading="creating" @click="_createTable"
>{{ $t('general.submit') }}
</a-button>
</template>
<div class="pl-10 pr-10 pt-5">
<div>
<a-form :model="table" name="create-new-table-form" @keydown.enter="_createTable">
<!-- Create A New Table -->
<div class="prose-xl font-bold self-center my-4">{{ $t('activity.createTable') }}</div>
<!-- hint="Enter table name" -->
<!-- Table name -->
<div class="mb-2">{{ $t('labels.tableName') }}</div>
@ -206,7 +203,7 @@ onMounted(() => {
overflow: hidden;
&.active {
max-height: 200px;
max-height: 100px;
}
}
</style>

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

@ -50,29 +50,24 @@ const isEaster = ref(false)
<a-modal
v-model:visible="dialogShow"
:class="{ active: dialogShow }"
width="max(30vw, 600px)"
centered
wrap-class-name="nc-modal-table-duplicate"
@keydown.esc="dialogShow = false"
>
<template #footer>
<a-button key="back" size="large" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button key="back" size="middle" class="!rounded-md" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button key="submit" size="large" type="primary" :loading="isLoading" @click="_duplicate"
<a-button key="submit" size="middle" type="primary" class="!rounded-md" :loading="isLoading" @click="_duplicate"
>{{ $t('general.confirm') }}
</a-button>
</template>
<div class="pl-10 pr-10 pt-5">
<div class="prose-xl font-bold self-center my-4" @dblclick="isEaster = !isEaster">{{ $t('general.duplicate') }}</div>
<div class="mb-2">Are you sure you want to duplicate the `{{ table.title }}` table?</div>
<div class="prose-md self-center text-gray-500 mt-4">{{ $t('title.advancedSettings') }}</div>
<a-divider class="!m-0 !p-0 !my-2" />
<div>
<div class="prose-xl font-bold self-center my-4" @dblclick="isEaster = !isEaster">
{{ $t('general.duplicate') }} {{ table.title }}
</div>
<div class="text-xs p-2">
<div class="text-xs">
<a-checkbox v-model:checked="options.includeData">Include data</a-checkbox>
<a-checkbox v-model:checked="options.includeViews">Include views</a-checkbox>
<a-checkbox v-show="isEaster" v-model:checked="options.includeHooks">Include hooks</a-checkbox>

38
packages/nc-gui/components/dlg/TableRename.vue

@ -177,31 +177,33 @@ const renameTable = async (undo = false) => {
:class="{ active: dialogShow }"
:title="$t('activity.renameTable')"
:mask-closable="false"
centered
wrap-class-name="nc-modal-table-rename"
@keydown.esc="dialogShow = false"
@finish="renameTable"
>
<template #footer>
<a-button key="back" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button key="back" class="!rounded-md" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
<a-button key="submit" type="primary" :loading="loading" @click="renameTable()">{{ $t('general.submit') }}</a-button>
<a-button key="submit" class="!rounded-md" type="primary" :loading="loading" @click="renameTable()">{{
$t('general.submit')
}}</a-button>
</template>
<div class="pl-10 pr-10 pt-5">
<a-form :model="formState" name="create-new-table-form">
<!-- hint="Enter table name" -->
<div class="mb-2">{{ $t('msg.info.enterTableName') }}</div>
<a-form-item v-bind="validateInfos.title">
<a-input
ref="inputEl"
v-model:value="formState.title"
hide-details
:placeholder="$t('msg.info.enterTableName')"
@keydown.enter="renameTable()"
/>
</a-form-item>
</a-form>
</div>
<a-form :model="formState" name="create-new-table-form">
<!-- hint="Enter table name" -->
<div class="mb-2">{{ $t('msg.info.enterTableName') }}</div>
<a-form-item v-bind="validateInfos.title">
<a-input
ref="inputEl"
v-model:value="formState.title"
hide-details
size="large"
:placeholder="$t('msg.info.enterTableName')"
@keydown.enter="renameTable()"
/>
</a-form-item>
</a-form>
</a-modal>
</template>

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

@ -207,7 +207,7 @@ async function onSubmit() {
<template>
<a-modal
v-model:visible="vModel"
class="!top-[35%]"
centered
:class="{ active: vModel }"
:confirm-loading="loading"
wrap-class-name="nc-modal-view-create"
@ -219,7 +219,7 @@ async function onSubmit() {
<a-form ref="formValidator" layout="vertical" :model="form">
<a-form-item :label="$t('labels.viewName')" name="title" :rules="viewNameRules">
<a-input ref="inputEl" v-model:value="form.title" autofocus @keydown.enter="onSubmit" />
<a-input ref="inputEl" v-model:value="form.title" size="large" autofocus @keydown.enter="onSubmit" />
</a-form-item>
<a-form-item
v-if="form.type === ViewTypes.KANBAN"
@ -254,8 +254,10 @@ async function onSubmit() {
</a-form>
<template #footer>
<a-button key="back" @click="vModel = false">{{ $t('general.cancel') }}</a-button>
<a-button key="submit" type="primary" :loading="loading" @click="onSubmit">{{ $t('general.submit') }}</a-button>
<a-button key="back" class="!rounded-md" @click="vModel = false">{{ $t('general.cancel') }}</a-button>
<a-button key="submit" class="!rounded-md" type="primary" :loading="loading" @click="onSubmit">{{
$t('general.submit')
}}</a-button>
</template>
</a-modal>
</template>

6
packages/nc-gui/components/dlg/ViewDelete.vue

@ -50,7 +50,7 @@ async function onDelete() {
<template>
<a-modal
v-model:visible="vModel"
class="!top-[35%]"
centered
:class="{ active: vModel }"
:confirm-loading="isLoading"
wrap-class-name="nc-modal-view-delete"
@ -60,9 +60,9 @@ async function onDelete() {
{{ $t('msg.info.deleteViewConfirmation') }}
<template #footer>
<a-button key="back" @click="vModel = false">{{ $t('general.cancel') }}</a-button>
<a-button key="back" class="!rounded-md" @click="vModel = false">{{ $t('general.cancel') }}</a-button>
<a-button key="submit" danger html-type="submit" :loading="isLoading" @click="onDelete">
<a-button key="submit" class="!rounded-md" danger html-type="submit" :loading="isLoading" @click="onDelete">
{{ $t('general.submit') }}
</a-button>
</template>

2
packages/nc-gui/components/general/ShareBaseButton.vue

@ -43,7 +43,7 @@ useEventListener(document, 'keydown', async (e: KeyboardEvent) => {
<template #title>
<span class="text-xs">{{ $t('activity.inviteTeam') }}</span>
</template>
<a-button type="primary" class="!rounded-md mr-1" size="medium">
<a-button type="primary" class="!rounded-md mr-1" size="middle">
<div class="flex items-center space-x-1 cursor-pointer text-xs font-weight-bold">
<component :is="iconMap.accountPlus" class="mr-1 nc-share-base hover:text-accent text-sm" />
{{ $t('activity.share') }}

7
packages/nc-gui/components/smartsheet/toolbar/FilterInput.vue

@ -2,8 +2,9 @@
import type { ColumnType } from 'nocodb-sdk'
import { storeToRefs } from 'pinia'
import {
ActiveCellInj,
ColumnInj,
EditModeInj,
IsFormInj,
ReadonlyInj,
computed,
isBoolean,
@ -182,6 +183,10 @@ const hasExtraPadding = $computed(() => {
isYear(column.value, abstractType))
)
})
// provide the following to override the default behavior and enable input fields like in form
provide(ActiveCellInj, ref(true))
provide(IsFormInj, ref(true))
</script>
<template>

22
packages/nc-gui/components/tabs/auth/ApiTokenManagement.vue

@ -119,7 +119,7 @@ onMounted(() => {
</a-button>
<!-- Generate Token -->
<div class="flex flex-row justify-center w-full -mt-1 mb-3">
<div class="flex flex-row justify-start w-full -mt-1 mb-3">
<a-typography-title :level="5">{{ $t('title.generateToken') }}</a-typography-title>
</div>
@ -129,16 +129,16 @@ onMounted(() => {
:model="selectedTokenData"
name="basic"
layout="vertical"
class="flex flex-col justify-center space-y-6"
class="flex flex-col justify-center space-y-3"
no-style
autocomplete="off"
@finish="generateToken"
>
<a-input v-model:value="selectedTokenData.description" :placeholder="$t('labels.description')" />
<a-input v-model:value="selectedTokenData.description" size="middle" :placeholder="$t('labels.description')" />
<!-- Generate -->
<div class="flex flex-row justify-center">
<a-button type="primary" html-type="submit">
<div class="flex flex-row justify-end">
<a-button type="primary" html-type="submit" class="!rounded-md">
{{ $t('general.generate') }}
</a-button>
</div>
@ -157,14 +157,14 @@ onMounted(() => {
<div class="flex flex-col h-full">
<div class="flex flex-row justify-center mt-2 text-center w-full text-base">This action will remove this API Token</div>
<div class="flex mt-6 justify-center space-x-2">
<a-button @click="showDeleteTokenModal = false"> {{ $t('general.cancel') }}</a-button>
<a-button type="primary" danger @click="deleteToken()"> {{ $t('general.confirm') }}</a-button>
<div class="flex mt-6 justify-end space-x-2">
<a-button class="!rounded-md" @click="showDeleteTokenModal = false"> {{ $t('general.cancel') }}</a-button>
<a-button class="!rounded-md" type="primary" danger @click="deleteToken()"> {{ $t('general.confirm') }}</a-button>
</div>
</div>
</a-modal>
<div class="flex flex-col px-10 mt-6">
<div class="flex flex-col px-10">
<div class="flex flex-row justify-end">
<div class="flex flex-row space-x-1">
<a-button size="middle" type="text" @click="loadApiTokens()">
@ -175,7 +175,7 @@ onMounted(() => {
</a-button>
<!-- Add New Token -->
<a-button size="middle" type="primary" ghost @click="openNewTokenModal">
<a-button type="primary" size="middle" class="!rounded-md" @click="openNewTokenModal">
<div class="flex flex-row justify-center items-center caption capitalize space-x-1">
<component :is="iconMap.plus" />
<div>{{ $t('activity.newToken') }}</div>
@ -244,7 +244,7 @@ onMounted(() => {
<template #overlay>
<a-menu>
<a-menu-item>
<div class="flex flex-row items-center py-3 h-[1rem]" @click="openDeleteModal(item)">
<div class="flex flex-row items-center py-4 h-[1rem]" @click="openDeleteModal(item)">
<component :is="iconMap.delete" class="flex" />
<div class="text-xs pl-2">{{ $t('general.remove') }}</div>
</div>

22
packages/nc-gui/components/tabs/auth/UserManagement.vue

@ -204,6 +204,7 @@ const isSuperAdmin = (user: { main_roles?: string }) => {
:closable="false"
width="28rem"
centered
class="!rounded-md"
:footer="null"
wrap-class-name="nc-modal-delete-user"
>
@ -211,9 +212,9 @@ const isSuperAdmin = (user: { main_roles?: string }) => {
<div class="flex flex-row justify-center mt-2 text-center w-full text-base">
This action will remove this user from this project
</div>
<div class="flex mt-6 justify-center space-x-2">
<a-button @click="showUserDeleteModal = false"> {{ $t('general.cancel') }}</a-button>
<a-button type="primary" danger @click="deleteUser"> {{ $t('general.confirm') }}</a-button>
<div class="flex mt-6 justify-end space-x-2">
<a-button class="!rounded-md" @click="showUserDeleteModal = false"> {{ $t('general.cancel') }}</a-button>
<a-button class="!rounded-md" type="primary" danger @click="deleteUser"> {{ $t('general.confirm') }}</a-button>
</div>
</div>
</a-modal>
@ -240,8 +241,7 @@ const isSuperAdmin = (user: { main_roles?: string }) => {
v-e="['c:user:invite']"
size="middle"
type="primary"
ghost
class="nc-invite-team"
class="nc-invite-team !rounded-md"
@click="onInvite"
>
<div class="flex flex-row justify-center items-center caption capitalize space-x-1">
@ -254,12 +254,12 @@ const isSuperAdmin = (user: { main_roles?: string }) => {
<div class="px-5">
<div class="flex flex-row border-b-1 pb-2 px-2">
<div class="flex flex-row w-4/6 space-x-1 items-center pl-1">
<div class="flex flex-row w-3/6 space-x-1 items-center pl-1">
<component :is="iconMap.email" class="flex text-gray-500 -mt-0.5" />
<div class="text-gray-600 text-xs space-x-1">{{ $t('labels.email') }}</div>
</div>
<div class="flex flex-row justify-center w-1/6 space-x-1 items-center pl-1">
<div class="flex flex-row justify-start w-2/6 space-x-1 items-center pl-1">
<component :is="iconMap.role" class="flex text-gray-500 -mt-0.5" />
<div class="text-gray-600 text-xs">{{ $t('objects.role') }}</div>
@ -270,21 +270,21 @@ const isSuperAdmin = (user: { main_roles?: string }) => {
</div>
<div v-for="(user, index) of users" :key="index" class="flex flex-row items-center border-b-1 py-2 px-2 nc-user-row">
<div class="flex w-4/6 flex-wrap nc-user-email">
<div class="flex w-3/6 flex-wrap nc-user-email">
{{ user.email }}
</div>
<div class="flex w-1/6 justify-center flex-wrap ml-4">
<div class="flex w-2/6 justify-start gap-2 flex-wrap ml-4">
<div
v-if="isSuperAdmin(user)"
class="rounded-full px-2 py-1 nc-user-role"
class="rounded-full px-3 py-1 nc-user-role"
:style="{ backgroundColor: projectRoleTagColors[OrgUserRoles.SUPER_ADMIN] }"
>
Super Admin
</div>
<div
v-if="user.roles"
class="rounded-full px-2 py-1 nc-user-role"
class="rounded-full px-3 py-1 nc-user-role"
:style="{ backgroundColor: projectRoleTagColors[user.roles] }"
>
{{ $t(`objects.roleType.${user.roles}`) }}

101
packages/nc-gui/components/tabs/auth/user-management/ShareBase.vue

@ -152,13 +152,55 @@ onMounted(() => {
</script>
<template>
<div class="flex flex-col w-full" data-testid="nc-share-base-sub-modal">
<div class="flex flex-row items-center space-x-0.5 pl-2 h-[0.8rem]">
<component :is="iconMap.share" />
<div class="flex flex-col gap-2 w-full" data-testid="nc-share-base-sub-modal">
<!-- Generate publicly shareable readonly base -->
<div class="flex text-xs text-gray-500 justify-start ml-1">{{ $t('msg.info.generatePublicShareableReadonlyBase') }}</div>
<div class="text-xs">{{ $t('activity.shareBase.link') }}</div>
</div>
<div class="flex flex-row justify-between mx-1">
<a-dropdown v-model="showEditBaseDropdown" class="flex" overlay-class-name="nc-dropdown-shared-base-toggle">
<a-button>
<div class="flex flex-row rounded-md items-center space-x-2 nc-disable-shared-base">
<div v-if="base?.uuid">{{ $t('activity.shareBase.enable') }}</div>
<div v-else>{{ $t('activity.shareBase.disable') }}</div>
<IcRoundKeyboardArrowDown class="h-[1rem]" />
</div>
</a-button>
<template #overlay>
<a-menu>
<a-menu-item>
<div v-if="base?.uuid" class="py-3" @click="disableSharedBase">{{ $t('activity.shareBase.disable') }}</div>
<div v-else class="py-3" @click="createShareBase(ShareBaseRole.Viewer)">{{ $t('activity.shareBase.enable') }}</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<a-select
v-if="base?.uuid"
v-model:value="base.role"
class="flex nc-shared-base-role"
dropdown-class-name="nc-dropdown-share-base-role"
>
<template #suffixIcon>
<div class="flex flex-row">
<IcRoundKeyboardArrowDown class="text-black -mt-0.5 h-[1rem]" />
</div>
</template>
<a-select-option
v-for="(role, index) in [ShareBaseRole.Editor, ShareBaseRole.Viewer]"
:key="index"
:value="role"
dropdown-class-name="capitalize"
@click="createShareBase(role)"
>
<div class="w-full px-2 capitalize">
{{ role }}
</div>
</a-select-option>
</a-select>
</div>
<div v-if="base?.uuid" class="flex flex-row mt-2 bg-red-50 py-4 mx-1 px-2 items-center rounded-sm w-full justify-between">
<span class="flex text-xs overflow-x-hidden overflow-ellipsis text-gray-700 pl-2 nc-url">{{ url }}</span>
@ -212,54 +254,5 @@ onMounted(() => {
</a-tooltip>
</div>
</div>
<!-- Generate publicly shareable readonly base -->
<div class="flex text-xs text-gray-500 mt-2 justify-start ml-2">{{ $t('msg.info.generatePublicShareableReadonlyBase') }}</div>
<div class="mt-4 flex flex-row justify-between mx-1">
<a-dropdown v-model="showEditBaseDropdown" class="flex" overlay-class-name="nc-dropdown-shared-base-toggle">
<a-button>
<div class="flex flex-row items-center space-x-2 nc-disable-shared-base">
<div v-if="base?.uuid">{{ $t('activity.shareBase.enable') }}</div>
<div v-else>{{ $t('activity.shareBase.disable') }}</div>
<IcRoundKeyboardArrowDown class="h-[1rem]" />
</div>
</a-button>
<template #overlay>
<a-menu>
<a-menu-item>
<div v-if="base?.uuid" class="py-3" @click="disableSharedBase">{{ $t('activity.shareBase.disable') }}</div>
<div v-else class="py-3" @click="createShareBase(ShareBaseRole.Viewer)">{{ $t('activity.shareBase.enable') }}</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<a-select
v-if="base?.uuid"
v-model:value="base.role"
class="flex nc-shared-base-role"
dropdown-class-name="nc-dropdown-share-base-role"
>
<template #suffixIcon>
<div class="flex flex-row">
<IcRoundKeyboardArrowDown class="text-black -mt-0.5 h-[1rem]" />
</div>
</template>
<a-select-option
v-for="(role, index) in [ShareBaseRole.Editor, ShareBaseRole.Viewer]"
:key="index"
:value="role"
dropdown-class-name="capitalize"
@click="createShareBase(role)"
>
<div class="w-full px-2 capitalize">
{{ role }}
</div>
</a-select-option>
</a-select>
</div>
</div>
</template>

32
packages/nc-gui/components/tabs/auth/user-management/UsersModal.vue

@ -230,19 +230,13 @@ watch(
</template>
<div v-else class="flex flex-col pb-4">
<div class="flex flex-row items-center pl-2 pb-1 h-[1rem]">
<div v-if="selectedUser" class="flex flex-row items-center pl-2 pb-1 h-[1rem]">
<component :is="iconMap.account" />
<div class="text-xs ml-0.5 mt-0.5">{{ selectedUser ? $t('activity.editUser') : $t('activity.inviteTeam') }}</div>
</div>
<div class="border-1 py-3 px-4 rounded-md mt-1">
<a-form
ref="formRef"
:validate-on-rule-change="false"
:model="usersData"
validate-trigger="onBlur"
@finish="saveUser"
>
<a-form ref="formRef" :validate-on-rule-change="false" :model="usersData" validate-trigger="onBlur" @finish="saveUser">
<div class="border-1 py-3 px-4 rounded-md mt-1">
<div class="flex flex-row space-x-4">
<div class="flex flex-col w-3/4">
<a-form-item
@ -256,6 +250,7 @@ watch(
<a-input
ref="emailField"
v-model:value="usersData.emails"
size="middle"
validate-trigger="onBlur"
:placeholder="$t('labels.email')"
:disabled="!!selectedUser"
@ -267,11 +262,16 @@ watch(
<a-form-item name="role" :rules="[{ required: true, message: 'Role required' }]">
<div class="ml-1 mb-1 text-xs text-gray-500">{{ $t('labels.selectUserRole') }}</div>
<a-select v-model:value="usersData.role" class="nc-user-roles" dropdown-class-name="nc-dropdown-user-role">
<a-select
v-model:value="usersData.role"
size="middle"
class="nc-user-roles !rounded-md"
dropdown-class-name="nc-dropdown-user-role"
>
<a-select-option v-for="(role, index) in projectRoles" :key="index" :value="role" class="nc-role-option">
<div class="flex flex-row h-full justify-start items-center">
<div
class="px-2 py-1 flex rounded-full text-xs"
class="px-3 py-1 flex rounded-full text-xs"
:style="{ backgroundColor: projectRoleTagColors[role] }"
>
{{ role }}
@ -283,8 +283,8 @@ watch(
</div>
</div>
<div class="flex flex-row justify-center">
<a-button type="primary" html-type="submit">
<div class="flex flex-row justify-end">
<a-button type="primary" html-type="submit" class="!rounded-md">
<div v-if="selectedUser">{{ $t('general.save') }}</div>
<div v-else class="flex flex-row justify-center items-center space-x-1.5">
@ -293,11 +293,11 @@ watch(
</div>
</a-button>
</div>
</a-form>
</div>
</div>
</a-form>
</div>
<div class="flex mt-4">
<div class="flex">
<LazyTabsAuthUserManagementShareBase />
</div>
</div>

8
packages/nc-gui/components/webhook/Drawer.vue

@ -44,7 +44,13 @@ async function addHook() {
</a-layout-content>
<a-layout-footer class="!bg-white border-t flex">
<a-button v-e="['e:hiring']" class="mx-auto mb-4" href="https://angel.co/company/nocodb" target="_blank" size="large">
<a-button
v-e="['e:hiring']"
class="mx-auto mb-4 !rounded-md"
href="https://angel.co/company/nocodb"
target="_blank"
size="large"
>
🚀 {{ $t('labels.weAreHiring') }}! 🚀
</a-button>
</a-layout-footer>

6
packages/nc-gui/components/webhook/Editor.vue

@ -460,15 +460,15 @@ onMounted(async () => {
</div>
</div>
<div>
<a-button class="mr-3 nc-btn-webhook-test" size="large" @click="testWebhook">
<div class="flex flex-row gap-2">
<a-button class="nc-btn-webhook-test !rounded-md" size="middle" @click="testWebhook">
<div class="flex items-center">
<MdiGestureDoubleTap class="mr-2" />
{{ $t('activity.testWebhook') }}
</div>
</a-button>
<a-button class="nc-btn-webhook-save" type="primary" size="large" @click.prevent="saveHooks">
<a-button class="nc-btn-webhook-save !rounded-md" type="primary" size="middle" @click.prevent="saveHooks">
<div class="flex items-center">
<component :is="iconMap.save" class="mr-2" />
<!-- Save -->

4
packages/nc-gui/components/webhook/List.vue

@ -108,9 +108,9 @@ onMounted(() => {
<a-button
v-e="['c:webhook:add']"
class="float-right nc-btn-create-webhook"
class="float-right !rounded-md nc-btn-create-webhook"
type="primary"
size="large"
size="middle"
@click="emit('add')"
>
{{ $t('activity.addWebhook') }}

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

@ -1,7 +1,7 @@
import useVuelidate from '@vuelidate/core'
import { helpers, minLength, required } from '@vuelidate/validators'
import type { Ref } from 'vue'
import type { BoolType, ColumnType, FormType, LinkToAnotherRecordType, StringOrNullType, TableType, ViewType } from 'nocodb-sdk'
import type { BoolType, ColumnType, FormType, LinkToAnotherRecordType, StringOrNullType, TableType, ViewType, FormColumnType } from 'nocodb-sdk'
import { ErrorMessages, RelationTypes, UITypes, isVirtualCol } from 'nocodb-sdk'
import { isString } from '@vueuse/core'
import {
@ -83,7 +83,27 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share
sharedView.value = viewMeta
sharedFormView.value = viewMeta.view
meta.value = viewMeta.model
columns.value = viewMeta.model?.columns
const fieldById = (viewMeta.columns || []).reduce(
(o: Record<string, any>, f: Record<string, any>) => ({
...o,
[f.fk_column_id]: f,
}),
{} as Record<string, FormColumnType>,
)
let order = 1
columns.value = meta?.value?.columns
?.map((c: Record<string, any>) => ({
...c,
fk_column_id: c.id,
fk_view_id: viewMeta.id,
...(fieldById[c.id] ? fieldById[c.id] : {}),
order: (fieldById[c.id] && fieldById[c.id].order) || order++,
id: fieldById[c.id] && fieldById[c.id].id,
}))
.sort((a: Record<string, any>, b: Record<string, any>) => a.order - b.order) as Record<string, any>[]
const _sharedViewMeta = (viewMeta as any).meta
sharedViewMeta.value = isString(_sharedViewMeta) ? JSON.parse(_sharedViewMeta) : _sharedViewMeta

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

@ -385,10 +385,10 @@
"nextRecord": "السجل التالي",
"previousRecord": "السجل السابق",
"copyApiURL": "نسخ رابط API",
"createTable": "إنشاء جدول",
"createTable": "Create New Table",
"refreshTable": "تحديث الجدول",
"renameTable": "إعادة تسمية الجدول",
"deleteTable": "حذف الجدول",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "إضافة حقل جديد إلى هذا الجدول",
"setDisplay": "Set as Display value",
"addRow": "إضافة صف جديد",

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

@ -385,10 +385,10 @@
"nextRecord": "পরবরকরড",
"previousRecord": "পববরকরড",
"copyApiURL": "অনিি এপিআই ইউআরএল",
"createTable": "িল তি",
"createTable": "Create New Table",
"refreshTable": "টিল রিশ",
"renameTable": "িল নম পরিবরতন",
"deleteTable": "बल मि",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "এই টি নতন কর যত করন",
"setDisplay": "Set as Display value",
"addRow": "নতন সিত করন",

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

@ -385,10 +385,10 @@
"nextRecord": "Další záznam",
"previousRecord": "Předchozí rekord",
"copyApiURL": "Kopírování adresy URL rozhraní API",
"createTable": "Vytvoření tabulky",
"createTable": "Create New Table",
"refreshTable": "Tabulky Obnovení",
"renameTable": "Přejmenování tabulky",
"deleteTable": "Tabulka Odstranit",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Přidání nového pole do této tabulky",
"setDisplay": "Set as Display value",
"addRow": "Přidat nový řádek",

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

@ -385,10 +385,10 @@
"nextRecord": "Næste post",
"previousRecord": "Forrige post",
"copyApiURL": "COPY API URL.",
"createTable": "Opret tabel",
"createTable": "Create New Table",
"refreshTable": "Genopfrisk Tabeller",
"renameTable": "Omdøb Tabel",
"deleteTable": "Slet Tabel",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Tilføj nyt felt til denne tabel",
"setDisplay": "Sæt som visningsværdi",
"addRow": "Tilføj ny post",

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

@ -385,10 +385,10 @@
"nextRecord": "Nächster Eintrag",
"previousRecord": "Vorheriger Eintrag",
"copyApiURL": "API-URL kopieren",
"createTable": "Tabelle erstellen",
"createTable": "Create New Table",
"refreshTable": "Tabellen aktualisieren",
"renameTable": "Tabelle umbenennen",
"deleteTable": "Tabelle löschen",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Neues Feld zu dieser Tabelle hinzufügen",
"setDisplay": "Set as Display value",
"addRow": "Neue Zeile hinzufügen",

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

@ -385,10 +385,10 @@
"nextRecord": "Next record",
"previousRecord": "Previous record",
"copyApiURL": "Copy API URL",
"createTable": "Table Create",
"createTable": "Create New Table",
"refreshTable": "Tables Refresh",
"renameTable": "Table Rename",
"deleteTable": "Table Delete",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Add new field to this table",
"setDisplay": "Set as Display value",
"addRow": "Add new row",

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

@ -385,10 +385,10 @@
"nextRecord": "Siguiente registro",
"previousRecord": "Registro anterior",
"copyApiURL": "Copiar URL del API",
"createTable": "Crear tabla",
"createTable": "Create New Table",
"refreshTable": "Refrescar tablas",
"renameTable": "Cambiar el nombre de la tabla",
"deleteTable": "Borrar tabla",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Añadir nuevo campo a esta tabla",
"setDisplay": "Set as Display value",
"addRow": "Añadir nueva fila",

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

@ -385,10 +385,10 @@
"nextRecord": "Next record",
"previousRecord": "Previous record",
"copyApiURL": "Copy API URL",
"createTable": "Table Create",
"createTable": "Create New Table",
"refreshTable": "Tables Refresh",
"renameTable": "Table Rename",
"deleteTable": "Table Delete",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Add new field to this table",
"setDisplay": "Set as Display value",
"addRow": "Add new row",

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

@ -385,10 +385,10 @@
"nextRecord": "رکورد بعدی",
"previousRecord": "رکورد قبلی",
"copyApiURL": "کپی کردن API URL",
"createTable": "ایجاد جدول",
"createTable": "Create New Table",
"refreshTable": "نوسازی جداول",
"renameTable": "تغییر نام جدول",
"deleteTable": "حذف جدول",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "اضافه کردن فیلد جدید به این جدول",
"setDisplay": "تنظیم به عنوان مقدار نمایش",
"addRow": "اضافه کردن ردیف جدید",
@ -452,30 +452,30 @@
"linkRecord": "لینک کردن رکورد",
"addNewRecord": "افزودن رکورد جدید",
"useConnectionUrl": "استفاده از لینک اتصال",
"toggleCommentsDraw": "Toggle comments draw",
"expandRecord": "Expand Record",
"deleteRecord": "Delete Record",
"toggleCommentsDraw": "تعویض حالت نظرات",
"expandRecord": "بسط دادن رکورد",
"deleteRecord": "حذف رکورد",
"erd": {
"showColumns": "Show Columns",
"showPkAndFk": "Show Primary and Foreign Keys",
"showSqlViews": "Show SQL Views",
"showMMTables": "Show Many to Many tables",
"showJunctionTableNames": "Show Junction Table Names"
"showColumns": "نمایش ستون",
"showPkAndFk": "نمایش کلید های اصلی و خارجی",
"showSqlViews": "نمایش نماهای SQL",
"showMMTables": "نمایش جدولهای بسیار به بسیار",
"showJunctionTableNames": "نمایش نام جدول های اتصال"
},
"kanban": {
"collapseStack": "Collapse Stack",
"deleteStack": "Delete Stack",
"stackedBy": "Stacked By",
"chooseGroupingField": "Choose a Grouping Field",
"addOrEditStack": "Add / Edit Stack"
"collapseStack": "جمع کردن دسته",
"deleteStack": "حذف دسته",
"stackedBy": "دستهبندی با",
"chooseGroupingField": "انتخاب فیلد گروهبندی",
"addOrEditStack": "اضافه/ویرایش دسته"
},
"map": {
"mappedBy": "Mapped By",
"chooseMappingField": "Choose a Mapping Field",
"openInGoogleMaps": "Google Maps",
"mappedBy": "نگاشته شده با",
"chooseMappingField": "انتخاب فیلد نگاشتن",
"openInGoogleMaps": "گوگل مپس",
"openInOpenStreetMap": "OSM"
},
"toggleMobileMode": "Toggle Mobile Mode"
"toggleMobileMode": "تغییر وضعیت حالت موبایل"
},
"tooltip": {
"saveChanges": "ذخیره تغییرات",
@ -522,35 +522,35 @@
"noItemsFound": "مواردی یافت نشد",
"defaultValue": "مقدار پیشفرض",
"filterByEmail": "فیلترکردن بر مبنای پست الکترونیکی",
"filterQuery": "Filter query",
"selectField": "Select field"
"filterQuery": "فیلتر کردن پرسش",
"selectField": "انتخاب فیلد"
},
"msg": {
"warning": {
"barcode": {
"renderError": "Barcode error - please check compatibility between input and barcode type"
"renderError": "خطای بارکد - لطفا سازگاری بین ورودی و نوع بارکد را بررسی کنید"
},
"nonEditableFields": {
"computedFieldUnableToClear": "Warning: Computed field - unable to clear text",
"qrFieldsCannotBeDirectlyChanged": "Warning: QR fields cannot be directly changed."
"computedFieldUnableToClear": "اخطار: فیلد محاسبه شده - نمیتوان متن را خالی کرد",
"qrFieldsCannotBeDirectlyChanged": "اخطار: فیلدهای QR نمیتوانند به طور مستقیم ویرایش شوند."
}
},
"info": {
"pasteNotSupported": "Paste operation is not supported on the active cell",
"pasteNotSupported": "عملیات جایگذاری در سلول فعال پشتیبانی نمیشود",
"roles": {
"orgCreator": "Creator can create new projects and access any invited project.",
"orgViewer": "Viewer is not allowed to create new projects but they can access any invited project."
"orgCreator": "تولید کننده می تواند پروژه های جدید ایجاد کند و به هر پروژه ی دعوت شده دسترسی داشته باشد.",
"orgViewer": "بیننده اجازه ندارد پروژه های جدید ایجاد کند اما میتواند به هر پروژه دعوت شده دسترسی داشته باشد."
},
"codeScanner": {
"loadingScanner": "Loading the scanner...",
"selectColumn": "Select a column (QR code or Barcode) that you want to use for finding a row by scanning.",
"moreThanOneRowFoundForCode": "More than one row found for this code. Currently only unique codes are supported.",
"noRowFoundForCode": "No row found for this code for the selected column"
"loadingScanner": "در حال بارگزاری اسکنر...",
"selectColumn": "یک ستون (QR Code یا Barcode) که میخواهید با اسکن کردن پیدا کنید را انتخاب کنید.",
"moreThanOneRowFoundForCode": "بیش از یک ردیف برای این کد پیدا شد. در حال حاضر تنها کد های یکتا پشتیبانی می شوند.",
"noRowFoundForCode": "برای این کد در ستون انتخاب شده ردیفی پیدا نشد"
},
"map": {
"overLimit": "You're over the limit.",
"closeLimit": "You're getting close to the limit.",
"limitNumber": "The limit of markers shown in a Map View is 1000 records."
"overLimit": "از محدودیت فراتر رفته اید.",
"closeLimit": "به محدودیت نزدیک می شوید.",
"limitNumber": "محدودیت نشانگر های نمایش داده شده در نمای نقشه 1000 رکورد می باشد."
},
"footerInfo": "تعداد ردیفها در هر صفحه",
"upload": "فایل را برای بارگذاری انتخاب کنید",
@ -634,7 +634,7 @@
"gallery": "افزودن نمایش گالری",
"form": "افزودن نمایش فرم",
"kanban": "افزودن نمایش کانبان",
"map": "Add Map View",
"map": "اضافه کردن نمای نقشه",
"calendar": "افزودن نمایش تقویم"
},
"tablesMetadataInSync": "متاداده جداول در حالت همگامسازی است",
@ -643,35 +643,35 @@
"addDefaultColumns": "افزودن ستونهای پیشفرض",
"tableNameInDb": "نام جدول به عنوان ذخیره شده در پایگاه داده",
"airtable": {
"credentials": "Where to find this?"
"credentials": "این را کجا می توان یافت?"
},
"import": {
"clickOrDrag": "Click or drag file to this area to upload"
"clickOrDrag": "برای آپلود کلیک کنید یا فایل را در این ناحیه بکشید"
},
"metaDataRecreated": "Table metadata recreated successfully",
"invalidCredentials": "Invalid credentials",
"downloadingMoreFiles": "Downloading more files",
"copiedToClipboard": "Copied to clipboard",
"requriedFieldsCantBeMoved": "Required field can't be moved",
"updateNotAllowedWithoutPK": "Update not allowed for table which doesn't have primary key",
"autoIncFieldNotEditable": "Auto increment field is not editable",
"editingPKnotSupported": "Editing primary key not supported",
"deletedCache": "Deleted cache successfully",
"cacheEmpty": "Cache is empty",
"exportedCache": "Exported Cache Successfully",
"valueAlreadyInList": "This value is already in the list",
"noColumnsToUpdate": "No columns to update",
"tableDeleted": "Deleted table successfully",
"generatePublicShareableReadonlyBase": "Generate publicly shareable readonly base",
"deleteViewConfirmation": "Are you sure you want to delete this view?",
"deleteTableConfirmation": "Do you want to delete the table",
"showM2mTables": "Show M2M Tables",
"showM2mTablesDesc": "Many-to-many relation is supported via a junction table & is hidden by default. Enable this option to list all such tables along with existing tables.",
"showNullInCells": "Show NULL in Cells",
"showNullInCellsDesc": "Display 'NULL' tag in cells holding NULL value. This helps differentiate against cells holding EMPTY string.",
"showNullAndEmptyInFilter": "Show NULL and EMPTY in Filter",
"showNullAndEmptyInFilterDesc": "Enable 'additional' filters to differentiate fields containing NULL & Empty Strings. Default support for Blank treats both NULL & Empty strings alike.",
"deleteKanbanStackConfirmation": "Deleting this stack will also remove the select option `{stackToBeDeleted}` from the `{groupingField}`. The records will move to the uncategorized stack.",
"metaDataRecreated": "فراداده جدول با موفقیت بازآفرینی شد",
"invalidCredentials": "اطلاعات اشتباه",
"downloadingMoreFiles": "در حال دانلود فایل های بیشتر",
"copiedToClipboard": "به کلیپبورد کپی شد",
"requriedFieldsCantBeMoved": "فیلد الزامی را نمیتوان انتقال داد",
"updateNotAllowedWithoutPK": "برای جدولی که کلید اصلی ندارد آپدیت مجاز نیست",
"autoIncFieldNotEditable": "فیلد افزایش خودکار قابل ویرایش نیست",
"editingPKnotSupported": "ویرایش کلید اصلی پشتیبانی نشده است",
"deletedCache": "حافظه کش با موفقیت حذف شد",
"cacheEmpty": "حافظه کش خالی هست",
"exportedCache": "حافظه کش با موفقیت اکسپورت شد",
"valueAlreadyInList": "این مقدار قبلا در لیست وجود دارد",
"noColumnsToUpdate": "ستونی برای ویرایش نیست",
"tableDeleted": "جدول با موفقیت حذف شد",
"generatePublicShareableReadonlyBase": "تولید پایگاه داده فقط خواندنی با قابلیت به اشتراک کذاری عمومی",
"deleteViewConfirmation": "آیا اطمینان دارید که میخواهید این نما را حذف کنید?",
"deleteTableConfirmation": "آیا میخواهید جدول را حذف کنید",
"showM2mTables": "نمایش جدول های بسیار به بسیار",
"showM2mTablesDesc": "رابطه های بسیار به بسیار از طریق یک جدول رابط پشتیبانی می شود و به صورت پیشفرض مخفی شده است. این گزینه را فعال کنید تا همه این چنین جدول ها در کنار جدول های موجود نمایش داده شوند.",
"showNullInCells": "مقادیر NULL در سلول ها نمایش داده شود",
"showNullInCellsDesc": "نمایش تگ های 'NULL' در سلول هایی که مقدار NULL دارند. این گزینه برای تمایز با سلول هایی که استرینگ خالی دارند به شما کمک میکند.",
"showNullAndEmptyInFilter": "نمایش مقادیر NULL و EMPTY در فیلتر",
"showNullAndEmptyInFilterDesc": "فعال کردن فیلتر های 'بیشتر' برای تمایز میان فیلد هایی که دارای استرینگ های NULL و EMPTY هستند. پشتیبانی پیشفرض برای سلول های خالی، تفاوتی میان استرینگ های EMPTY و NULL قائل نمیشود.",
"deleteKanbanStackConfirmation": "حذف این دسته همینطور باعث حذف گزینه `{stackToBeDeleted}` از `{groupingField}` خواهد شد. رکورد های این دسته به دسته گروهبندی نشده منتقل خواهند شد.",
"computedFieldEditWarning": "Computed field: contents are read-only. Use column edit menu to reconfigure",
"computedFieldDeleteWarning": "Computed field: contents are read-only. Unable to clear content.",
"noMoreRecords": "No more records"

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

@ -385,10 +385,10 @@
"nextRecord": "Seuraava ennätys",
"previousRecord": "Edellinen ennätys",
"copyApiURL": "Kopioi API URL",
"createTable": "Taulukko Luo",
"createTable": "Create New Table",
"refreshTable": "Taulukot päivitys",
"renameTable": "Taulukko uudelleen",
"deleteTable": "Taulukko poistaa",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Lisää uusi kenttä tähän taulukkoon",
"setDisplay": "Set as Display value",
"addRow": "Lisää uusi rivi",

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

@ -385,10 +385,10 @@
"nextRecord": "Ligne suivante",
"previousRecord": "Ligne précédente",
"copyApiURL": "Copier l'URL de l'API",
"createTable": "Créer un tableau",
"createTable": "Create New Table",
"refreshTable": "Actualiser le tableau",
"renameTable": "Renommer le tableau",
"deleteTable": "Supprimer le tableau",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Ajouter un nouveau champ à ce tableau",
"setDisplay": "Set as Display value",
"addRow": "Ajouter une nouvelle ligne",

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

@ -385,10 +385,10 @@
"nextRecord": "רשומה הבאה",
"previousRecord": "רשימה קודמת",
"copyApiURL": "העתק URL API.",
"createTable": "טבלה צור",
"createTable": "Create New Table",
"refreshTable": "טבלאות רענון",
"renameTable": "שולחן שינוי שם",
"deleteTable": "טבלה מחיקה",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "הוסף שדה חדש לטבלה זו",
"setDisplay": "Set as Display value",
"addRow": "הוסף שורה חדשה",

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

@ -385,10 +385,10 @@
"nextRecord": "अगलिड",
"previousRecord": "पिछलिड",
"copyApiURL": "API URL क कर",
"createTable": "ि बन",
"createTable": "Create New Table",
"refreshTable": "टबलस रिश",
"renameTable": "ि",
"deleteTable": "बल मि",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "इस ति नयड ज",
"setDisplay": "Set as Display value",
"addRow": "नई पि",

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

@ -385,10 +385,10 @@
"nextRecord": "Sljedeći rekord",
"previousRecord": "Prethodni rekord",
"copyApiURL": "Kopirajte API URL",
"createTable": "Tablica stvoriti",
"createTable": "Create New Table",
"refreshTable": "Tablice osvježavaju",
"renameTable": "Preimenovati stolom",
"deleteTable": "Obriši tablicu",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Dodajte novo polje na ovu tablicu",
"setDisplay": "Set as Display value",
"addRow": "Dodaj novi red",

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

@ -385,10 +385,10 @@
"nextRecord": "Rekor selanjutnya",
"previousRecord": "Rekor sebelumnya",
"copyApiURL": "Salin API URL.",
"createTable": "Tabel Create.",
"createTable": "Create New Table",
"refreshTable": "Tabel Refresh.",
"renameTable": "Ganti nama meja",
"deleteTable": "Table Delete.",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Tambahkan bidang baru ke tabel ini",
"setDisplay": "Set as Display value",
"addRow": "Tambahkan baris baru",

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

@ -385,10 +385,10 @@
"nextRecord": "Prossimo record.",
"previousRecord": "Record precedente",
"copyApiURL": "Copia l'URL delle API",
"createTable": "Crea tabella.",
"createTable": "Create New Table",
"refreshTable": "Aggiorna tabella",
"renameTable": "Rinomina tabella",
"deleteTable": "Elimina tabella",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Aggiungi un nuovo campo a questa tabella",
"setDisplay": "Set as Display value",
"addRow": "Aggiungi nuova riga",

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

@ -385,10 +385,10 @@
"nextRecord": "次のレコード",
"previousRecord": "前のレコード",
"copyApiURL": "API URL をコピー",
"createTable": "テーブルを作成",
"createTable": "Create New Table",
"refreshTable": "テーブルを更新",
"renameTable": "テーブル名の変更",
"deleteTable": "テーブルを削除",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "新しいフィールドを追加",
"setDisplay": "Set as Display value",
"addRow": "行を追加",

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

@ -385,10 +385,10 @@
"nextRecord": "다음 기록",
"previousRecord": "이전 기록",
"copyApiURL": "API URL 복사",
"createTable": "테이블 작성",
"createTable": "Create New Table",
"refreshTable": "테이블 새로 고침",
"renameTable": "테이블 이름 바꾸기",
"deleteTable": "테이블 삭제",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "테이블에 새 필드 추가",
"setDisplay": "Set as Display value",
"addRow": "행 추가",

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

@ -385,10 +385,10 @@
"nextRecord": "Nākošais ieraksts",
"previousRecord": "Iepriekšējais ieraksts",
"copyApiURL": "Kopēt API saiti",
"createTable": "Tabulas izveidošana",
"createTable": "Create New Table",
"refreshTable": "Tabulas atsvaidzināšana",
"renameTable": "Tabulas pārdēvēšana",
"deleteTable": "Tabulas dzēšana",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Jauna lauka pievienošana",
"setDisplay": "Set as Display value",
"addRow": "Pievienot ierakstu",

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

@ -385,10 +385,10 @@
"nextRecord": "Volgend record",
"previousRecord": "Vorig record",
"copyApiURL": "Kopieer API URL",
"createTable": "Tabel creëren",
"createTable": "Create New Table",
"refreshTable": "Tabellen verversen",
"renameTable": "Tabel hernoemen",
"deleteTable": "Tabel verwijderen",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Voeg nieuw veld toe aan deze tabel",
"setDisplay": "Set as Display value",
"addRow": "Nieuwe rij toevoegen",

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

@ -385,10 +385,10 @@
"nextRecord": "Neste rekord",
"previousRecord": "Tidligere post",
"copyApiURL": "Kopier API URL",
"createTable": "Tabellen CREATE.",
"createTable": "Create New Table",
"refreshTable": "Tabeller oppdatering",
"renameTable": "Tabell omdøpe",
"deleteTable": "Bordet slett",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Legg til nytt felt i denne tabellen",
"setDisplay": "Set as Display value",
"addRow": "Legg til ny rad",

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

@ -385,10 +385,10 @@
"nextRecord": "Następny rekord",
"previousRecord": "Poprzednie nagranie",
"copyApiURL": "Kopiuj adres URL API.",
"createTable": "Stół tworzenie",
"createTable": "Create New Table",
"refreshTable": "Tabele odświeżania",
"renameTable": "Zmień nazwę tabeli.",
"deleteTable": "Usuń tabelę",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Dodaj nowe pole do tej tabeli",
"setDisplay": "Ustaw jako wartość wyświetlana",
"addRow": "Dodaj nowy rząd",

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

@ -385,10 +385,10 @@
"nextRecord": "Próximo registro",
"previousRecord": "Registro anterior",
"copyApiURL": "Copiar URL da API",
"createTable": "Tabela Create.",
"createTable": "Create New Table",
"refreshTable": "Tabelas atualizam",
"renameTable": "Tabela Renomear",
"deleteTable": "Tabela Delete.",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Adicionar novo campo a esta tabela",
"setDisplay": "Set as Display value",
"addRow": "Adicionar nova linha",

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

@ -385,10 +385,10 @@
"nextRecord": "Próximo registro",
"previousRecord": "Registro anterior",
"copyApiURL": "Copiar URL da API",
"createTable": "Tabela Create.",
"createTable": "Create New Table",
"refreshTable": "Tabelas atualizam",
"renameTable": "Tabela Renomear",
"deleteTable": "Tabela Delete.",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Adicionar novo campo a esta tabela",
"setDisplay": "Set as Display value",
"addRow": "Adicionar nova linha",

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

@ -385,10 +385,10 @@
"nextRecord": "Следующая запись",
"previousRecord": "Предыдущая запись",
"copyApiURL": "Скопируйте URL API",
"createTable": "Создать таблицу",
"createTable": "Create New Table",
"refreshTable": "Обновление таблицы",
"renameTable": "Переименовать таблицу",
"deleteTable": "Удалить таблицу",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Добавить новое поле в эту таблицу",
"setDisplay": "Установить как значение отображения",
"addRow": "Добавить новую строку",

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

@ -385,10 +385,10 @@
"nextRecord": "Ďalší záznam",
"previousRecord": "Predchádzajúci rekord",
"copyApiURL": "Kopírovanie adresy URL API",
"createTable": "Vytvorenie tabuľky",
"createTable": "Create New Table",
"refreshTable": "Tabuľky Obnovenie",
"renameTable": "Premenovanie tabuľky",
"deleteTable": "Tabuľka Vymazať",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Pridanie nového poľa do tejto tabuľky",
"setDisplay": "Set as Display value",
"addRow": "Pridanie nového riadku",

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

@ -385,10 +385,10 @@
"nextRecord": "Naslednji zapis",
"previousRecord": "Prejšnji zapisnik",
"copyApiURL": "Kopiraj API URL",
"createTable": "Tabela Ustvari.",
"createTable": "Create New Table",
"refreshTable": "Osveži",
"renameTable": "Preimenuj tabele",
"deleteTable": "Tabela Delete.",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "V to tabelo dodajte novo polje",
"setDisplay": "Set as Display value",
"addRow": "Dodaj novo vrstico",

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

@ -385,10 +385,10 @@
"nextRecord": "Nästa post",
"previousRecord": "Tidigare post",
"copyApiURL": "Kopiera API-URL",
"createTable": "Bord skapar",
"createTable": "Create New Table",
"refreshTable": "Tabeller uppdateras",
"renameTable": "Bordsbyte",
"deleteTable": "Bord radera",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Lägg till nytt fält till den här tabellen",
"setDisplay": "Set as Display value",
"addRow": "Lägg till ny rad",

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

@ -385,10 +385,10 @@
"nextRecord": "บนทกตอไป",
"previousRecord": "บนทกกอนหนา",
"copyApiURL": "คดลอก URL API",
"createTable": "ตารางสราง",
"createTable": "Create New Table",
"refreshTable": "รเฟรชตาราง",
"renameTable": "ตารางเปลยนช",
"deleteTable": "ลบตาราง",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "เพมฟลดใหมลงในตารางน",
"setDisplay": "Set as Display value",
"addRow": "เพมแถวใหม",

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

@ -385,10 +385,10 @@
"nextRecord": "Sonraki kayıt",
"previousRecord": "Önceki kayıt",
"copyApiURL": "API linkini kopyala",
"createTable": "Tablo Oluştur",
"createTable": "Create New Table",
"refreshTable": "Tabloları Yenile",
"renameTable": "Tabloyu Yeniden Adlandır",
"deleteTable": "Tabloyu Sil",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Tabloya yeni alan ekle",
"setDisplay": "Set as Display value",
"addRow": "Yeni satır ekle",

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

@ -385,10 +385,10 @@
"nextRecord": "Наступний запис",
"previousRecord": "Попередній запис",
"copyApiURL": "Копіювати URL-адресу API",
"createTable": "Створити таблицю",
"createTable": "Create New Table",
"refreshTable": "Оновити таблицю",
"renameTable": "Перейменувати таблицю",
"deleteTable": "Видалити таблицю",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Додати нове поле до цієї таблиці",
"setDisplay": "Встановити як значення для показу",
"addRow": "Додати новий рядок",

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

@ -385,10 +385,10 @@
"nextRecord": "Hồ sơ tiếp theo",
"previousRecord": "Hồ sơ trước đó",
"copyApiURL": "Sao chép URL API.",
"createTable": "Bảng tạo",
"createTable": "Create New Table",
"refreshTable": "Bàn làm mới",
"renameTable": "Đổi tên bảng.",
"deleteTable": "Bảng xóa",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "Thêm trường mới vào bảng này",
"setDisplay": "Set as Display value",
"addRow": "Thêm hàng mới",

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

@ -385,10 +385,10 @@
"nextRecord": "下一条记录",
"previousRecord": "上一条纪录",
"copyApiURL": "复制 API 链接",
"createTable": "创建表格",
"createTable": "Create New Table",
"refreshTable": "刷新表格",
"renameTable": "重命名表格",
"deleteTable": "删除表格",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "添加新字段",
"setDisplay": "设置为显示值",
"addRow": "添加新行",

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

@ -385,10 +385,10 @@
"nextRecord": "下一步記錄",
"previousRecord": "之前的紀錄",
"copyApiURL": "複製 API 網址",
"createTable": "表創造",
"createTable": "Create New Table",
"refreshTable": "表刷新",
"renameTable": "表重命名",
"deleteTable": "表刪除",
"renameTable": "Rename Table",
"deleteTable": "Delete Table",
"addField": "將新字段添加到此表",
"setDisplay": "Set as Display value",
"addRow": "新增行",

8
packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts

@ -835,11 +835,9 @@ async function _formulaQueryBuilder(
return { builder: query };
} else if (pt.type === 'UnaryExpression') {
const query = knex.raw(
`${pt.operator}${fn(
pt.argument,
null,
pt.operator,
).toQuery()}${colAlias}`,
`${pt.operator}${(
await fn(pt.argument, null, pt.operator)
).builder.toQuery()}${colAlias}`,
);
if (prevBinaryOp && pt.operator !== prevBinaryOp) {
query.wrap('(', ')');

2
packages/nocodb/src/db/functionMappings/sqlite.ts

@ -188,7 +188,7 @@ const sqlite3 = {
default:
sql = '';
}
return { builder: knex.raw(`${sql} ${colAlias}`) };
return { builder: knex.raw(`ROUND(${sql}) ${colAlias}`) };
},
WEEKDAY: async ({ fn, knex, pt, colAlias }: MapFnArgs) => {
// strftime('%w', date) - day of week 0 - 6 with Sunday == 0

Loading…
Cancel
Save