Browse Source

Merge branch 'develop' into feat/kanban-view

pull/3818/head
Wing-Kam Wong 2 years ago
parent
commit
fb7867bb95
  1. 2
      packages/nc-gui/components/cell/DatePicker.vue
  2. 2
      packages/nc-gui/components/cell/DateTimePicker.vue
  3. 2
      packages/nc-gui/components/cell/TimePicker.vue
  4. 21
      packages/nc-gui/components/cell/Url.vue
  5. 2
      packages/nc-gui/components/cell/YearPicker.vue
  6. 8
      packages/nc-gui/components/cell/attachment/Modal.vue
  7. 4
      packages/nc-gui/components/dashboard/TreeView.vue
  8. 18
      packages/nc-gui/components/dashboard/settings/AppStore.vue
  9. 1
      packages/nc-gui/components/dashboard/settings/Modal.vue
  10. 8
      packages/nc-gui/components/dlg/AirtableImport.vue
  11. 8
      packages/nc-gui/components/dlg/QuickImport.vue
  12. 8
      packages/nc-gui/components/dlg/TableCreate.vue
  13. 1
      packages/nc-gui/components/dlg/TableRename.vue
  14. 2
      packages/nc-gui/components/dlg/ViewCreate.vue
  15. 2
      packages/nc-gui/components/dlg/ViewDelete.vue
  16. 2
      packages/nc-gui/components/general/HelpAndSupport.vue
  17. 4
      packages/nc-gui/components/general/MiniSidebar.vue
  18. 2
      packages/nc-gui/components/general/ReleaseInfo.vue
  19. 27
      packages/nc-gui/components/general/language/Menu.vue
  20. 10
      packages/nc-gui/components/general/language/index.vue
  21. 1
      packages/nc-gui/components/shared-view/AskPassword.vue
  22. 6
      packages/nc-gui/components/smartsheet-column/SelectOptions.vue
  23. 8
      packages/nc-gui/components/smartsheet-header/Cell.vue
  24. 2
      packages/nc-gui/components/smartsheet-header/Menu.vue
  25. 8
      packages/nc-gui/components/smartsheet-header/VirtualCell.vue
  26. 3
      packages/nc-gui/components/smartsheet-toolbar/ColumnFilter.vue
  27. 2
      packages/nc-gui/components/smartsheet-toolbar/ColumnFilterMenu.vue
  28. 2
      packages/nc-gui/components/smartsheet-toolbar/Export.vue
  29. 2
      packages/nc-gui/components/smartsheet-toolbar/FieldsMenu.vue
  30. 8
      packages/nc-gui/components/smartsheet-toolbar/MoreActions.vue
  31. 1
      packages/nc-gui/components/smartsheet-toolbar/ShareView.vue
  32. 2
      packages/nc-gui/components/smartsheet-toolbar/SortListMenu.vue
  33. 10
      packages/nc-gui/components/smartsheet-toolbar/ViewActions.vue
  34. 2
      packages/nc-gui/components/smartsheet/ApiSnippet.vue
  35. 2
      packages/nc-gui/components/smartsheet/Form.vue
  36. 26
      packages/nc-gui/components/smartsheet/Grid.vue
  37. 1
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  38. 2
      packages/nc-gui/components/smartsheet/sidebar/toolbar/DebugMeta.vue
  39. 20
      packages/nc-gui/components/tabs/auth/ApiTokenManagement.vue
  40. 11
      packages/nc-gui/components/tabs/auth/UserManagement.vue
  41. 2
      packages/nc-gui/components/tabs/auth/user-management/ShareBase.vue
  42. 10
      packages/nc-gui/components/tabs/auth/user-management/UsersModal.vue
  43. 3
      packages/nc-gui/components/virtual-cell/Lookup.vue
  44. 9
      packages/nc-gui/components/virtual-cell/components/ListChildItems.vue
  45. 8
      packages/nc-gui/components/virtual-cell/components/ListItems.vue
  46. 1
      packages/nc-gui/components/webhook/Drawer.vue
  47. 1
      packages/nc-gui/composables/index.ts
  48. 48
      packages/nc-gui/composables/useCellUrlConfig.ts
  49. 8
      packages/nc-gui/composables/useGlobal/state.ts
  50. 4
      packages/nc-gui/composables/useGlobal/types.ts
  51. 1
      packages/nc-gui/composables/useTable.ts
  52. 1
      packages/nc-gui/context/index.ts
  53. 10
      packages/nc-gui/layouts/base.vue
  54. 4
      packages/nc-gui/lib/enums.ts
  55. 6
      packages/nc-gui/lib/types.ts
  56. 8
      packages/nc-gui/nuxt-shim.d.ts
  57. 10
      packages/nc-gui/nuxt.config.ts
  58. 194
      packages/nc-gui/package-lock.json
  59. 2
      packages/nc-gui/package.json
  60. 7
      packages/nc-gui/pages/[projectType]/[projectId]/index.vue
  61. 1
      packages/nc-gui/pages/[projectType]/form/[viewId]/index.vue
  62. 3
      packages/nc-gui/pages/[projectType]/view/[viewId].vue
  63. 9
      packages/nc-gui/pages/index/index/create-external.vue
  64. 3
      packages/nc-gui/pages/index/index/index.vue
  65. 2
      packages/nc-gui/pages/projects/index/index.vue
  66. 2
      packages/nc-gui/pages/signin.vue
  67. 2
      packages/nc-gui/pages/signup/[[token]].vue
  68. 69
      packages/nc-gui/plugins/a.i18n.ts
  69. 10
      packages/nc-gui/plugins/state.ts
  70. 28
      packages/noco-docs/content/en/developer-resources/accessing-apis.md
  71. 40
      packages/noco-docs/content/en/developer-resources/webhooks.md
  72. 121
      packages/noco-docs/content/en/engineering/development-setup.md
  73. 85
      packages/noco-docs/content/en/engineering/translation.md
  74. 2
      packages/noco-docs/content/en/index.md
  75. 6
      packages/noco-docs/content/en/setup-and-usages/audit.md
  76. 7
      packages/noco-docs/content/en/setup-and-usages/code-snippets.md
  77. 39
      packages/noco-docs/content/en/setup-and-usages/column-operations.md
  78. 36
      packages/noco-docs/content/en/setup-and-usages/dashboard.md
  79. 8
      packages/noco-docs/content/en/setup-and-usages/formulas.md
  80. 32
      packages/noco-docs/content/en/setup-and-usages/import-airtable-to-sql-database-within-a-minute-for-free.md
  81. 8
      packages/noco-docs/content/en/setup-and-usages/languages.md
  82. 19
      packages/noco-docs/content/en/setup-and-usages/link-to-another-record.md
  83. 64
      packages/noco-docs/content/en/setup-and-usages/lookup.md
  84. 18
      packages/noco-docs/content/en/setup-and-usages/meta-management.md
  85. 6
      packages/noco-docs/content/en/setup-and-usages/primary-key.md
  86. 24
      packages/noco-docs/content/en/setup-and-usages/primary-value.md
  87. 50
      packages/noco-docs/content/en/setup-and-usages/rollup.md
  88. 18
      packages/noco-docs/content/en/setup-and-usages/sync-schema.md
  89. 123
      packages/noco-docs/content/en/setup-and-usages/table-operations.md
  90. 36
      packages/noco-docs/content/en/setup-and-usages/team-and-auth.md
  91. 72
      packages/noco-docs/content/en/setup-and-usages/views.md
  92. 2
      packages/nocodb/Dockerfile
  93. 21
      scripts/cypress/integration/common/00_pre_configurations.js
  94. 6
      scripts/cypress/integration/common/1b_table_column_operations.js
  95. 2
      scripts/cypress/integration/common/1d_pg_table_view_drag_drop_reorder.js
  96. 2
      scripts/cypress/integration/common/1d_table_view_drag_drop_reorder.js
  97. 12
      scripts/cypress/integration/common/2a_table_with_belongs_to_colulmn.js
  98. 16
      scripts/cypress/integration/common/2b_table_with_m2m_column.js
  99. 8
      scripts/cypress/integration/common/3a_filter_sort_fields_operations.js
  100. 15
      scripts/cypress/integration/common/3b_formula_column.js
  101. Some files were not shown because too many files have changed in this diff Show More

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

@ -67,7 +67,7 @@ const placeholder = computed(() => (isDateInvalid ? 'Invalid date' : ''))
:placeholder="placeholder"
:allow-clear="!readOnly"
:input-read-only="true"
:dropdown-class-name="randomClass"
:dropdown-class-name="`${randomClass} nc-picker-date`"
:open="readOnly ? false : open"
@click="open = !open"
>

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

@ -67,7 +67,7 @@ watch(
:placeholder="isDateInvalid ? 'Invalid date' : ''"
:allow-clear="!readOnly"
:input-read-only="true"
:dropdown-class-name="randomClass"
:dropdown-class-name="`${randomClass} nc-picker-datetime`"
:open="readOnly ? false : open"
:disabled="readOnly"
@click="open = !open"

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

@ -79,7 +79,7 @@ watch(
:allow-clear="!readOnly"
:input-read-only="true"
:open="readOnly ? false : open"
:popup-class-name="randomClass"
:popup-class-name="`${randomClass} nc-picker-time`"
@click="open = !open"
@ok="open = !open"
>

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

@ -2,7 +2,7 @@
import type { VNodeRef } from '@vue/runtime-core'
import { message } from 'ant-design-vue'
import { useI18n } from 'vue-i18n'
import { ColumnInj, EditModeInj, computed, inject, isValidURL } from '#imports'
import { CellUrlDisableOverlayInj, ColumnInj, EditModeInj, computed, inject, isValidURL, ref } from '#imports'
import MiCircleWarning from '~icons/mi/circle-warning'
const { modelValue: value } = defineProps<Props>()
@ -16,6 +16,7 @@ const column = inject(ColumnInj)!
const editEnabled = inject(EditModeInj)!
const disableOverlay = inject(CellUrlDisableOverlayInj)
// Used in the logic of when to display error since we are not storing the url if its not valid
const localState = ref(value)
@ -39,6 +40,7 @@ const url = computed(() => {
return `https://${value}`
})
const urlOptions = useCellUrlConfig(url)
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
@ -59,7 +61,22 @@ watch(
<div class="flex flex-row items-center justify-between">
<input v-if="editEnabled" :ref="focus" v-model="vModel" class="outline-none text-sm w-full" @blur="editEnabled = false" />
<nuxt-link v-else-if="isValid" class="text-sm underline hover:opacity-75" :to="url" target="_blank">{{ value }} </nuxt-link>
<nuxt-link
v-else-if="isValid && !urlOptions?.overlay"
class="z-3 text-sm underline hover:opacity-75"
:to="url"
:target="urlOptions?.behavior === 'replace' ? undefined : '_blank'"
>
{{ value }}
</nuxt-link>
<nuxt-link
v-else-if="isValid && !disableOverlay && urlOptions?.overlay"
class="z-3 w-full h-full text-center !no-underline hover:opacity-75"
:to="url"
:target="urlOptions?.behavior === 'replace' ? undefined : '_blank'"
>
{{ urlOptions.overlay }}
</nuxt-link>
<span v-else class="w-9/10 overflow-ellipsis overflow-hidden">{{ value }}</span>

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

@ -66,7 +66,7 @@ const placeholder = computed(() => (isYearInvalid ? 'Invalid year' : ''))
:allow-clear="!readOnly"
:input-read-only="true"
:open="readOnly ? false : open"
:dropdown-class-name="randomClass"
:dropdown-class-name="`${randomClass} nc-picker-year`"
@click="open = !open"
@change="open = !open"
>

8
packages/nc-gui/components/cell/attachment/Modal.vue

@ -58,7 +58,13 @@ function onClick(item: Record<string, any>) {
</script>
<template>
<a-modal v-model:visible="modalVisible" class="nc-attachment-modal" width="80%" :footer="null">
<a-modal
v-model:visible="modalVisible"
class="nc-attachment-modal"
width="80%"
:footer="null"
wrap-class-name="nc-modal-attachment-expand-cell"
>
<template #title>
<div class="flex gap-4">
<div

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

@ -218,7 +218,7 @@ function openTableCreateDialog() {
<template>
<div class="nc-treeview-container flex flex-col">
<a-dropdown :trigger="['contextmenu']">
<a-dropdown :trigger="['contextmenu']" overlay-class-name="nc-dropdown-tree-view-context-menu">
<div class="pt-2 pl-2 pb-2 flex-1 overflow-y-auto flex flex-col scrollbar-thin-dull" :class="{ 'mb-[20px]': isSharedBase }">
<div class="py-1 px-3 flex w-full items-center gap-1 cursor-pointer" @contextmenu="setMenuContext('main')">
<span class="flex-1 text-bold uppercase nc-project-tree text-gray-500 font-weight-bold">
@ -238,7 +238,7 @@ function openTableCreateDialog() {
<span class="text-gray-500 group-hover:(text-primary/100) flex-1 nc-add-new-table">{{ $t('tooltip.addTable') }}</span>
<a-dropdown v-if="!isSharedBase" :trigger="['click']" @click.stop>
<a-dropdown v-if="!isSharedBase" :trigger="['click']" overlay-class-name="nc-dropdown-import-menu" @click.stop>
<MdiDotsVertical class="transition-opacity opacity-0 group-hover:opacity-100 nc-import-menu" />
<template #overlay>

18
packages/nc-gui/components/dashboard/settings/AppStore.vue

@ -72,7 +72,14 @@ onMounted(async () => {
</script>
<template>
<a-modal v-model:visible="showPluginInstallModal" :closable="false" centered min-height="300" :footer="null">
<a-modal
v-model:visible="showPluginInstallModal"
:closable="false"
centered
min-height="300"
:footer="null"
wrap-class-name="nc-modal-plugin-install"
>
<AppInstall
v-if="pluginApp && showPluginInstallModal"
:id="pluginApp.id"
@ -81,7 +88,14 @@ onMounted(async () => {
/>
</a-modal>
<a-modal v-model:visible="showPluginUninstallModal" :closable="false" width="24rem" centered :footer="null">
<a-modal
v-model:visible="showPluginUninstallModal"
:closable="false"
width="24rem"
centered
:footer="null"
wrap-class-name="nc-modal-plugin-uninstall"
>
<div class="flex flex-col h-full">
<div class="flex flex-row justify-center mt-2 text-center w-full text-base">
{{ `Click on confirm to reset ${pluginApp && pluginApp.title}` }}

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

@ -159,6 +159,7 @@ watch(
:footer="null"
width="max(90vw, 600px)"
:closable="false"
wrap-class-name="nc-modal-settings"
@cancel="emits('update:modelValue', false)"
>
<!-- Settings -->

8
packages/nc-gui/components/dlg/AirtableImport.vue

@ -231,7 +231,13 @@ onBeforeUnmount(() => {
</script>
<template>
<a-modal v-model:visible="dialogShow" width="max(30vw, 600px)" class="p-2" @keydown.esc="dialogShow = false">
<a-modal
v-model:visible="dialogShow"
width="max(30vw, 600px)"
class="p-2"
wrap-class-name="nc-modal-airtable-import"
@keydown.esc="dialogShow = false"
>
<div class="px-5">
<!-- Quick Import -->
<div class="mt-5 prose-xl font-weight-bold">{{ $t('title.quickImport') }} - AIRTABLE</div>

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

@ -284,7 +284,12 @@ const customReqCbk = (customReqArgs: { file: any; onSuccess: () => void }) => {
</script>
<template>
<a-modal v-model:visible="dialogShow" :width="modalWidth" @keydown.esc="dialogShow = false">
<a-modal
v-model:visible="dialogShow"
:width="modalWidth"
wrap-class-name="nc-modal-quick-import"
@keydown.esc="dialogShow = false"
>
<div class="px-5">
<div class="prose-xl font-weight-bold my-5">{{ importMeta.header }}</div>
@ -298,6 +303,7 @@ const customReqCbk = (customReqArgs: { file: any; onSuccess: () => void }) => {
:import-only="importOnly"
:quick-import-type="importType"
:max-rows-to-parse="importState.parserConfig.maxRowsToParse"
class="nc-quick-import-template-editor"
@import="handleImport"
/>

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

@ -80,7 +80,13 @@ onMounted(() => {
</script>
<template>
<a-modal v-model:visible="dialogShow" width="max(30vw, 600px)" centered @keydown.esc="dialogShow = false">
<a-modal
v-model:visible="dialogShow"
width="max(30vw, 600px)"
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>

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

@ -125,6 +125,7 @@ const renameTable = async () => {
v-model:visible="dialogShow"
:title="$t('activity.renameTable')"
:mask-closable="false"
wrap-class-name="nc-modal-table-rename"
@keydown.esc="dialogShow = false"
@finish="renameTable"
>

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

@ -142,7 +142,7 @@ async function onSubmit() {
</script>
<template>
<a-modal v-model:visible="vModel" class="!top-[35%]" :confirm-loading="loading">
<a-modal v-model:visible="vModel" class="!top-[35%]" :confirm-loading="loading" wrap-class-name="nc-modal-view-create">
<template #title>
{{ $t('general.create') }} <span class="text-capitalize">{{ typeAlias }}</span> {{ $t('objects.view') }}
</template>

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

@ -48,7 +48,7 @@ async function onDelete() {
</script>
<template>
<a-modal v-model:visible="vModel" class="!top-[35%]" :confirm-loading="isLoading">
<a-modal v-model:visible="vModel" class="!top-[35%]" :confirm-loading="isLoading" wrap-class-name="nc-modal-view-delete">
<template #title> {{ $t('general.delete') }} {{ $t('objects.view') }} </template>
{{ $t('msg.info.deleteViewConfirmation') }}

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

@ -27,7 +27,7 @@ const openSwaggerLink = () => {
<a-drawer
v-bind="$attrs"
v-model:visible="showDrawer"
class="h-full relative"
class="h-full relative nc-drawer-help-and-support"
placement="right"
size="small"
:closable="false"

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

@ -28,7 +28,7 @@ const logout = () => {
collapsible
theme="light"
>
<a-dropdown placement="bottom" :trigger="['click']">
<a-dropdown placement="bottom" :trigger="['click']" overlay-class-name="nc-dropdown">
<div class="transition-all duration-200 p-2 cursor-pointer transform hover:scale-105 nc-noco-brand-icon">
<img width="35" alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" />
</div>
@ -60,7 +60,7 @@ const logout = () => {
</a-dropdown>
<div id="sidebar" ref="sidebar" class="text-white flex-auto flex flex-col items-center w-full">
<a-dropdown :trigger="['contextmenu']" placement="right">
<a-dropdown :trigger="['contextmenu']" placement="right" overlay-class-name="nc-dropdown">
<div :class="[route.name === 'index' ? 'active' : '']" class="nc-mini-sidebar-item" @click="navigateTo('/')">
<MdiFolder class="cursor-pointer transform hover:scale-105 text-2xl" />
</div>

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

@ -40,7 +40,7 @@ onMounted(async () => await fetchReleaseInfo())
<template>
<div v-if="releaseAlert" class="flex items-center">
<a-dropdown :trigger="['click']" placement="bottom">
<a-dropdown :trigger="['click']" placement="bottom" overlay-class-name="nc-dropdown-upgrade-menu">
<a-button class="!bg-primary !border-none">
<div class="flex gap-1 items-center text-white">
<span class="text-sm font-weight-medium">{{ $t('activity.upgrade.available') }}</span>

27
packages/nc-gui/components/general/language/Menu.vue

@ -1,14 +1,15 @@
<script lang="ts" setup>
import { Language } from '~/lib'
import { onMounted, useGlobal, useI18n, useNuxtApp } from '#imports'
import { setI18nLanguage } from '~/plugins/a.i18n'
const { $e } = useNuxtApp()
const { lang: currentLang } = useGlobal()
const { availableLocales = ['en'], locale } = useI18n()
const { locale } = useI18n()
const languages = $computed(() => availableLocales.sort())
const languages = $computed(() => Object.entries(Language).sort())
const isRtlLang = $computed(() => ['fa'].includes(currentLang.value))
@ -21,9 +22,11 @@ function applyDirection() {
document.body.style.direction = targetDirection
}
function changeLanguage(lang: string) {
currentLang.value = lang
locale.value = lang
async function changeLanguage(lang: string) {
const nextLang = lang as keyof typeof Language
await setI18nLanguage(nextLang)
currentLang.value = nextLang
applyDirection()
@ -37,15 +40,15 @@ onMounted(() => {
<template>
<a-menu-item
v-for="lang of languages"
:key="lang"
:class="lang === locale ? '!bg-primary bg-opacity-10 text-primary' : ''"
v-for="[key, lang] of languages"
:key="key"
:class="key === locale ? '!bg-primary bg-opacity-10 text-primary' : ''"
class="group"
:value="lang"
@click="changeLanguage(lang)"
:value="key"
@click="changeLanguage(key)"
>
<div :class="lang === locale ? '!font-semibold !text-primary' : ''" class="nc-project-menu-item capitalize">
{{ Language[lang] || lang }}
<div :class="key === locale ? '!font-semibold !text-primary' : ''" class="nc-project-menu-item capitalize">
{{ Language[key] || lang }}
</div>
</a-menu-item>

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

@ -1,6 +1,12 @@
<template>
<a-dropdown class="select-none color-transition" :trigger="['click']">
<MaterialSymbolsTranslate v-bind="$attrs" class="md:text-xl cursor-pointer nc-menu-translate" />
<a-dropdown
class="select-none color-transition cursor-pointer"
:trigger="['click']"
overlay-class-name="nc-dropdown-menu-translate"
>
<div v-bind="$attrs" class="flex items-center justify-center">
<MaterialSymbolsTranslate class="md:text-xl nc-menu-translate" />
</div>
<template #overlay>
<a-menu class="scrollbar-thin-dull min-w-50 max-h-90vh overflow-auto !py-0 rounded">

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

@ -33,6 +33,7 @@ const onFinish = async () => {
centered
:footer="null"
:mask-closable="false"
wrap-class-name="nc-modal-shared-view-password-dlg"
@close="vModel = false"
>
<div class="w-full flex flex-col">

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

@ -97,7 +97,11 @@ watch(inputs, () => {
<template #item="{ element, index }">
<div class="flex py-1 items-center">
<MdiDragIcon small class="nc-child-draggable-icon handle" />
<a-dropdown v-model:visible="colorMenus[index]" :trigger="['click']">
<a-dropdown
v-model:visible="colorMenus[index]"
:trigger="['click']"
overlay-class-name="nc-dropdown-select-color-options"
>
<template #overlay>
<GeneralColorPicker v-model="element.color" :pick-button="true" @update:model-value="colorMenus[index] = false" />
</template>

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

@ -28,7 +28,13 @@ const editColumnDropdown = ref(false)
<SmartsheetHeaderMenu v-if="!isForm && isUIAllowed('edit-column')" @edit="editColumnDropdown = true" />
</template>
<a-dropdown v-model:visible="editColumnDropdown" class="h-full" :trigger="['click']" placement="bottomRight">
<a-dropdown
v-model:visible="editColumnDropdown"
class="h-full"
:trigger="['click']"
placement="bottomRight"
overlay-class-name="nc-dropdown-edit-column"
>
<div />
<template #overlay>
<SmartsheetColumnEditOrAddProvider

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

@ -61,7 +61,7 @@ const setAsPrimaryValue = async () => {
</script>
<template>
<a-dropdown v-if="!isLocked" placement="bottomRight" :trigger="['click']">
<a-dropdown v-if="!isLocked" placement="bottomRight" :trigger="['click']" overlay-class-name="nc-dropdown-column-operations">
<MdiMenuDown class="h-full text-grey nc-ui-dt-dropdown cursor-pointer outline-0" />
<template #overlay>

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

@ -115,7 +115,13 @@ const tooltipMsg = computed(() => {
<SmartsheetHeaderMenu v-if="!isForm && isUIAllowed('edit-column')" :virtual="true" @edit="editColumnDropdown = true" />
</template>
<a-dropdown v-model:visible="editColumnDropdown" class="h-full" :trigger="['click']" placement="bottomRight">
<a-dropdown
v-model:visible="editColumnDropdown"
class="h-full"
:trigger="['click']"
placement="bottomRight"
overlay-class-name="nc-dropdown-edit-column"
>
<div />
<template #overlay>
<SmartsheetColumnEditOrAddProvider

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

@ -156,6 +156,7 @@ defineExpose({
:dropdown-match-select-width="false"
class="shrink grow-0"
placeholder="Group op"
dropdown-class-name="nc-dropdown-filter-logical-op-group"
@click.stop
@change="saveOrUpdate(filter, i)"
>
@ -203,6 +204,7 @@ defineExpose({
class="h-full"
hide-details
:disabled="filter.readOnly"
dropdown-class-name="nc-dropdown-filter-logical-op"
@click.stop
@change="filterUpdateCondition(filter, i)"
>
@ -230,6 +232,7 @@ defineExpose({
variant="solo"
:disabled="filter.readOnly"
hide-details
dropdown-class-name="nc-dropdown-filter-comp-op"
@change="filterUpdateCondition(filter, i)"
>
<a-select-option v-for="compOp in comparisonOpList" :key="compOp.value" :value="compOp.value" class="">

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

@ -51,7 +51,7 @@ const filterAutoSaveLoc = computed({
</script>
<template>
<a-dropdown :trigger="['click']">
<a-dropdown :trigger="['click']" overlay-class-name="nc-dropdown-filter-menu">
<div :class="{ 'nc-badge nc-active-btn': filtersLength }">
<a-button v-t="['c:filter']" class="nc-filter-menu-btn nc-toolbar-btn txt-sm" :disabled="isLocked">
<div class="flex items-center gap-1">

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

@ -1,5 +1,5 @@
<template>
<a-dropdown :trigger="['click']">
<a-dropdown :trigger="['click']" overlay-class-name="nc-dropdown-actions-menu">
<a-button v-t="['c:actions']" class="nc-actions-menu-btn nc-toolbar-btn">
<div class="flex gap-2 items-center">
<MdiDownload class="group-hover:text-accent text-gray-500" />

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

@ -116,7 +116,7 @@ const getIcon = (c: ColumnType) =>
</script>
<template>
<a-dropdown :trigger="['click']">
<a-dropdown :trigger="['click']" overlay-class-name="nc-dropdown-fields-menu">
<div :class="{ 'nc-badge nc-active-btn': isAnyFieldHidden }">
<a-button v-t="['c:fields']" class="nc-fields-menu-btn nc-toolbar-btn" :disabled="isLocked">
<div class="flex items-center gap-1">

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

@ -166,7 +166,13 @@ const exportFile = async (exportType: ExportTypes) => {
<WebhookDrawer v-if="showWebhookDrawer" v-model="showWebhookDrawer" />
<a-modal v-model:visible="sharedViewListDlg" :title="$t('activity.listSharedView')" width="max(900px,60vw)" :footer="null">
<a-modal
v-model:visible="sharedViewListDlg"
:title="$t('activity.listSharedView')"
width="max(900px,60vw)"
:footer="null"
wrap-class-name="nc-modal-shared-view-list"
>
<SmartsheetToolbarSharedViewList v-if="sharedViewListDlg" />
</a-modal>
</div>

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

@ -132,6 +132,7 @@ watch(passwordProtected, (value) => {
:title="$t('msg.info.privateLink')"
:footer="null"
width="min(100vw,640px)"
wrap-class-name="nc-modal-share-view"
>
<div class="share-link-box nc-share-link-box bg-primary-50">
<div class="flex-1 h-min text-xs">{{ sharedViewUrl }}</div>

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

@ -41,7 +41,7 @@ watch(
</script>
<template>
<a-dropdown offset-y class="" :trigger="['click']" overlay-class-name="sort-menu-overlay">
<a-dropdown offset-y class="" :trigger="['click']" overlay-class-name="nc-dropdown-sort-menu">
<div :class="{ 'nc-badge nc-active-btn': sorts?.length }">
<a-button v-t="['c:sort']" class="nc-sort-menu-btn nc-toolbar-btn" :disabled="isLocked"
><div class="flex items-center gap-1">

10
packages/nc-gui/components/smartsheet-toolbar/ViewActions.vue

@ -81,7 +81,7 @@ const { isSqlView } = useSmartsheetStoreOrThrow()
<template>
<div>
<a-dropdown :trigger="['click']">
<a-dropdown :trigger="['click']" overlay-class-name="nc-dropdown-actions-menu">
<a-button v-t="['c:actions']" class="nc-actions-menu-btn nc-toolbar-btn">
<div class="flex gap-2 items-center">
<component
@ -221,7 +221,13 @@ const { isSqlView } = useSmartsheetStoreOrThrow()
<WebhookDrawer v-if="showWebhookDrawer" v-model="showWebhookDrawer" />
<a-modal v-model:visible="sharedViewListDlg" :title="$t('activity.listSharedView')" width="max(900px,60vw)" :footer="null">
<a-modal
v-model:visible="sharedViewListDlg"
:title="$t('activity.listSharedView')"
width="max(900px,60vw)"
:footer="null"
wrap-class-name="nc-modal-shared-view-list"
>
<SmartsheetToolbarSharedViewList v-if="sharedViewListDlg" />
</a-modal>
<SmartsheetApiSnippet v-model="showApiSnippetDrawer" />

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

@ -136,7 +136,7 @@ watch($$(activeLang), (newLang) => {
<template>
<a-drawer
v-model:visible="vModel"
class="h-full relative"
class="h-full relative nc-drawer-api-snippet"
style="color: red"
placement="right"
size="large"

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

@ -470,7 +470,7 @@ onMounted(async () => {
<!-- Drag and drop fields here to hide -->
{{ $t('msg.info.dragDropHide') }}
</div>
<a-dropdown v-model:visible="showColumnDropdown" :trigger="['click']">
<a-dropdown v-model:visible="showColumnDropdown" :trigger="['click']" overlay-class-name="nc-dropdown-form-add-column">
<a-button type="link" class="w-full caption mt-2" size="large" @click.stop="showColumnDropdown = true">
<div class="flex items-center prose-sm justify-center text-gray-400">
<mdi-plus />

26
packages/nc-gui/components/smartsheet/Grid.vue

@ -5,6 +5,7 @@ import { message } from 'ant-design-vue'
import { useI18n } from 'vue-i18n'
import {
ActiveViewInj,
CellUrlDisableOverlayInj,
ChangePageInj,
FieldsInj,
IsFormInj,
@ -109,6 +110,9 @@ provide(ChangePageInj, changePage)
provide(ReadonlyInj, !hasEditPermission)
const disableUrlOverlay = ref(false)
provide(CellUrlDisableOverlayInj, disableUrlOverlay)
reloadViewDataHook?.on(async () => {
await loadData()
})
@ -201,6 +205,10 @@ const makeEditable = (row: Row, col: ColumnType) => {
/** handle keypress events */
const onKeyDown = async (e: KeyboardEvent) => {
if (e.key === 'Alt') {
disableUrlOverlay.value = true
return
}
if (selected.row === null || selected.col === null) return
/** on tab key press navigate through cells */
switch (e.key) {
@ -284,8 +292,14 @@ const onKeyDown = async (e: KeyboardEvent) => {
break
}
}
const onKeyUp = async (e: KeyboardEvent) => {
if (e.key === 'Alt') {
disableUrlOverlay.value = false
}
}
useEventListener(document, 'keydown', onKeyDown)
useEventListener(document, 'keyup', onKeyUp)
/** On clicking outside of table reset active cell */
const smartTable = ref(null)
@ -363,7 +377,11 @@ onBeforeUnmount(async () => {
<a-spin size="large" />
</div>
<div v-else class="nc-grid-wrapper min-h-0 flex-1 scrollbar-thin-dull">
<a-dropdown v-model:visible="contextMenu" :trigger="isSqlView ? [] : ['contextmenu']">
<a-dropdown
v-model:visible="contextMenu"
:trigger="isSqlView ? [] : ['contextmenu']"
overlay-class-name="nc-dropdown-grid-context-menu"
>
<table
ref="smartTable"
class="xc-row-table nc-grid backgroundColorDefault !h-auto bg-white"
@ -411,7 +429,11 @@ onBeforeUnmount(async () => {
class="cursor-pointer"
@click.stop="addColumnDropdown = true"
>
<a-dropdown v-model:visible="addColumnDropdown" :trigger="['click']">
<a-dropdown
v-model:visible="addColumnDropdown"
:trigger="['click']"
overlay-class-name="nc-dropdown-grid-add-column"
>
<div class="h-full w-[60px] flex items-center justify-center">
<MdiPlus class="text-sm nc-column-add" />
</div>

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

@ -108,6 +108,7 @@ export default {
width="min(90vw,1000px)"
:body-style="{ 'padding': 0, 'display': 'flex', 'flex-direction': 'column' }"
:closable="false"
class="nc-drawer-expanded-form"
>
<Header @cancel="onClose" />
<div class="!bg-gray-100 rounded flex-1">

2
packages/nc-gui/components/smartsheet/sidebar/toolbar/DebugMeta.vue

@ -18,7 +18,7 @@ const localTables = tables.value.filter((t) => metas[t.id as string])
<mdi-bug-outline class="cursor-pointer" @click="editorOpen = true" />
</a-tooltip>
<a-modal v-model:visible="editorOpen" :footer="null" width="80%">
<a-modal v-model:visible="editorOpen" :footer="null" width="80%" wrap-class-name="nc-modal-debug-meta">
<a-tabs v-model:activeKey="tabKey" type="card" closeable="false" class="shadow-sm">
<a-tab-pane v-for="table in localTables" :key="table.id" :tab="table.title">
<MonacoEditor v-model="metas[table.id]" class="h-max-[70vh]" :read-only="true" />

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

@ -98,7 +98,14 @@ onMounted(() => {
</script>
<template>
<a-modal v-model:visible="showNewTokenModal" :closable="false" width="28rem" centered :footer="null">
<a-modal
v-model:visible="showNewTokenModal"
:closable="false"
width="28rem"
centered
:footer="null"
wrap-class-name="nc-modal-generate-token"
>
<div class="relative flex flex-col h-full">
<a-button type="text" class="!absolute top-0 right-0 rounded-md -mt-2 -mr-3" @click="showNewTokenModal = false">
<template #icon>
@ -131,7 +138,14 @@ onMounted(() => {
</a-form>
</div>
</a-modal>
<a-modal v-model:visible="showDeleteTokenModal" :closable="false" width="28rem" centered :footer="null">
<a-modal
v-model:visible="showDeleteTokenModal"
:closable="false"
width="28rem"
centered
:footer="null"
wrap-class-name="nc-modal-delete-token"
>
<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">
@ -195,7 +209,7 @@ onMounted(() => {
</a-button>
</a-tooltip>
<a-dropdown :trigger="['click']" class="flex" placement="bottomRight">
<a-dropdown :trigger="['click']" class="flex" placement="bottomRight" overlay-class-name="nc-dropdown-api-token-mgmt">
<div class="flex flex-row items-center">
<a-button type="text" class="!px-0">
<div class="flex flex-row items-center h-[1.2rem]">

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

@ -173,7 +173,14 @@ watchDebounced(searchText, () => loadUsers(), { debounce: 300, maxWait: 600 })
@closed="showUserModal = false"
@reload="loadUsers()"
/>
<a-modal v-model:visible="showUserDeleteModal" :closable="false" width="28rem" centered :footer="null">
<a-modal
v-model:visible="showUserDeleteModal"
:closable="false"
width="28rem"
centered
:footer="null"
wrap-class-name="nc-modal-delete-user"
>
<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 user from this project
@ -282,7 +289,7 @@ watchDebounced(searchText, () => loadUsers(), { debounce: 300, maxWait: 600 })
</a-button>
</a-tooltip>
<a-dropdown :trigger="['click']" class="flex" placement="bottomRight">
<a-dropdown :trigger="['click']" class="flex" placement="bottomRight" overlay-class-name="nc-dropdown-user-mgmt">
<div class="flex flex-row items-center">
<a-button type="text" class="!px-0">
<div class="flex flex-row items-center h-[1.2rem]">

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

@ -195,7 +195,7 @@ onMounted(() => {
<!-- 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">
<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>

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

@ -130,7 +130,15 @@ const clickInviteMore = () => {
</script>
<template>
<a-modal :footer="null" centered :visible="show" :closable="false" width="max(50vw, 44rem)" @cancel="emit('closed')">
<a-modal
:footer="null"
centered
:visible="show"
:closable="false"
width="max(50vw, 44rem)"
wrap-class-name="nc-modal-invite-user-and-share-base"
@cancel="emit('closed')"
>
<div class="flex flex-col">
<div class="flex flex-row justify-between items-center pb-1.5 mb-2 border-b-1 w-full">
<a-typography-title class="select-none" :level="4"> {{ $t('activity.share') }}: {{ project.title }} </a-typography-title>

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

@ -2,7 +2,7 @@
import type { ColumnType, LinkToAnotherRecordType, LookupType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isVirtualCol } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { CellValueInj, ColumnInj, MetaInj, ReadonlyInj, computed, inject, provide, useColumn, useMetas } from '#imports'
import { CellUrlDisableOverlayInj, CellValueInj, ColumnInj, MetaInj, ReadonlyInj, computed, inject, provide, useColumn, useMetas } from '#imports'
const { metas, getMeta } = useMetas()
@ -32,6 +32,7 @@ const lookupColumn = computed<any>(
)
provide(MetaInj, lookupTableMeta)
provide(CellUrlDisableOverlayInj, ref(true))
const lookupColumnMetaProps = useColumn(lookupColumn)
</script>

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

@ -87,7 +87,14 @@ watch(
</script>
<template>
<component :is="container" v-model:visible="vModel" :footer="null" title="Child list" :body-style="{ padding: 0 }">
<component
:is="container"
v-model:visible="vModel"
:footer="null"
title="Child list"
:body-style="{ padding: 0 }"
wrap-class-name="nc-modal-child-list"
>
<div class="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col py-6">
<div class="flex mb-4 items-center gap-2 px-12">
<div class="flex-1" />

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

@ -104,7 +104,13 @@ watch(expandedFormDlg, (nexVal) => {
</script>
<template>
<a-modal v-model:visible="vModel" :footer="null" :title="$t('activity.linkRecord')" :body-style="{ padding: 0 }">
<a-modal
v-model:visible="vModel"
:footer="null"
:title="$t('activity.linkRecord')"
:body-style="{ padding: 0 }"
wrap-class-name="nc-modal-link-record"
>
<div class="max-h-[max(calc(100vh_-_300px)_,500px)] flex flex-col py-6">
<div class="flex mb-4 items-center gap-2 px-12">
<a-input

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

@ -29,6 +29,7 @@ async function editHook(hook: Record<string, any>) {
placement="right"
width="700px"
:body-style="{ background: 'rgba(67, 81, 232, 0.05)', padding: '0px 0px', overflow: 'hidden' }"
class="nc-drawer-webhook"
@keydown.esc="vModel = false"
>
<a-layout class="">

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

@ -25,3 +25,4 @@ export * from './useSmartsheetStore'
export * from './useLTARStore'
export * from './useExpandedFormStore'
export * from './useSharedFormViewStore'
export * from './useCellUrlConfig'

48
packages/nc-gui/composables/useCellUrlConfig.ts

@ -0,0 +1,48 @@
import type { ComputedRef } from 'vue'
import { useRoute } from '#imports'
export interface CellUrlOptions {
behavior?: string
overlay?: string
}
const parseUrlRules = (serialized: string | undefined): Array<[RegExp, CellUrlOptions]> | undefined => {
if (!serialized) return undefined
try {
const rules: Array<[RegExp, {}]> = Object.entries(JSON.parse(serialized)).map(([key, value]) => [
new RegExp(key),
value as {},
])
return rules
} catch (err) {
console.error(err)
return undefined
}
}
const [useProvideCellUrlConfig, useCellUrlGeneralConfig] = useInjectionState(() => {
const route = useRoute()
return {
behavior: route.query.url_behavior as string | undefined,
overlay: route.query.url_overlay as string | undefined,
rules: parseUrlRules(route.query.url_rules as string),
}
}, 'cell-url-config')
export { useProvideCellUrlConfig }
export function useCellUrlConfig(url: ComputedRef<string>) {
const config = useCellUrlGeneralConfig()
if (!config) return undefined
return computed(() => {
const { behavior, overlay, rules } = config
const options = { behavior, overlay }
if (rules && (!behavior || !overlay)) {
for (const [regex, value] of rules) {
if (url.value.match(regex)) return Object.assign(options, value)
}
}
return options
})
}

8
packages/nc-gui/composables/useGlobal/state.ts

@ -4,7 +4,7 @@ import type { JwtPayload } from 'jwt-decode'
import type { AppInfo, State, StoredState } from './types'
import { BASE_URL } from '~/lib'
import { computed, ref, toRefs, useCounter, useNuxtApp, useTimestamp } from '#imports'
import type { User } from '~/lib'
import type { Language, User } from '~/lib'
export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
/** get the preferred languages of a user, according to browser settings */
@ -25,12 +25,12 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
* If the user has not set a preferred language, we fall back to 'en'.
* If the user has set a preferred language, we try to find a matching locale in the available locales.
*/
const preferredLanguage = preferredLanguages.reduce((locale, language) => {
const preferredLanguage = preferredLanguages.reduce<keyof typeof Language>((locale, language) => {
/** split language to language and code, e.g. en-GB -> [en, GB] */
const [lang, code] = language.split(/[_-]/)
/** find all locales that match the language */
let availableLocales = i18n.availableLocales.filter((locale) => locale.startsWith(lang))
let availableLocales = i18n.global.availableLocales.filter((locale) => locale.startsWith(lang))
/** If we can match more than one locale, we check if the code of the language matches as well */
if (availableLocales.length > 1) {
@ -41,7 +41,7 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
const availableLocale = availableLocales[0]
/** if we found a matching locale, return it */
if (availableLocale) locale = availableLocale
if (availableLocale) locale = availableLocale as keyof typeof Language
return locale
}, 'en' /** fallback locale */)

4
packages/nc-gui/composables/useGlobal/types.ts

@ -1,7 +1,7 @@
import type { ComputedRef, Ref, ToRefs } from 'vue'
import type { WritableComputedRef } from '@vue/reactivity'
import type { JwtPayload } from 'jwt-decode'
import type { User } from '~/lib'
import type { Language, User } from '~/lib'
import type { useCounter } from '#imports'
export interface FeedbackForm {
@ -30,7 +30,7 @@ export interface AppInfo {
export interface StoredState {
token: string | null
user: User | null
lang: string
lang: keyof typeof Language
darkMode: boolean
feedbackForm: FeedbackForm
filterAutoSave: boolean

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

@ -63,6 +63,7 @@ export function useTable(onTableCreate?: (tableMeta: TableType) => void) {
// 'Click Submit to Delete The table'
Modal.confirm({
title: `${t('msg.info.deleteTableConfirmation')} : ${table.title}?`,
wrapClassName: 'nc-modal-table-delete',
okText: t('general.yes'),
okType: 'danger',
cancelText: t('general.no'),

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

@ -29,3 +29,4 @@ export const FieldsInj: InjectionKey<Ref<any[]>> = Symbol('fields-injection')
export const ViewListInj: InjectionKey<Ref<ViewType[]>> = Symbol('view-list-injection')
export const EditModeInj: InjectionKey<Ref<boolean>> = Symbol('edit-mode-injection')
export const SharedViewPasswordInj: InjectionKey<Ref<string | null>> = Symbol('shared-view-password-injection')
export const CellUrlDisableOverlayInj: InjectionKey<Ref<boolean>> = Symbol('cell-url-disable-url')

10
packages/nc-gui/layouts/base.vue

@ -69,7 +69,7 @@ hooks.hook('page:finish', () => {
</a-tooltip>
<template v-if="signedIn && !isSharedBase">
<a-dropdown :trigger="['click']">
<a-dropdown :trigger="['click']" overlay-class-name="nc-dropdown-user-accounts-menu">
<MdiDotsVertical class="md:text-xl cursor-pointer hover:text-accent nc-menu-accounts text-white" @click.prevent />
<template #overlay>
@ -102,11 +102,7 @@ hooks.hook('page:finish', () => {
<a-tooltip placement="bottom">
<template #title> Switch language</template>
<Transition name="layout">
<div v-if="!signedIn" class="nc-lang-btn">
<GeneralLanguage />
</div>
</Transition>
<GeneralLanguage class="nc-lang-btn" />
</a-tooltip>
<div class="w-full h-full overflow-hidden">
@ -116,7 +112,7 @@ hooks.hook('page:finish', () => {
</a-layout>
</template>
<style lang="scss" scoped>
<style lang="scss">
.nc-lang-btn {
@apply color-transition flex items-center justify-center fixed bottom-10 right-10 z-99 w-12 h-12 rounded-full shadow-md shadow-gray-500 p-2 !bg-primary text-white active:(ring ring-accent) hover:(ring ring-accent);

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

@ -50,8 +50,8 @@ export enum Language {
tr = 'Türk',
uk = 'Українська',
vi = 'Tiếng Việt',
zh_Hans = '简体中文',
zh_Hant = '繁體中文',
'zh-Hans' = '简体中文',
'zh-Hant' = '繁體中文',
}
export enum NavigateDir {

6
packages/nc-gui/lib/types.ts

@ -1,5 +1,7 @@
import type { FilterType } from 'nocodb-sdk'
import type { Role } from './enums'
import type { I18n } from 'vue-i18n'
import type { Language, Role } from './enums'
export interface User {
id: string
email: string
@ -32,3 +34,5 @@ export interface Field {
export type Roles = Record<Role, boolean>
export type Filter = FilterType & { status?: 'update' | 'delete' | 'create'; parentId?: string; readOnly?: boolean }
export type NocoI18n = I18n<{}, unknown, unknown, string, false>

8
packages/nc-gui/nuxt-shim.d.ts vendored

@ -1,10 +1,6 @@
import type { Api as BaseAPI } from 'nocodb-sdk'
import type { I18n } from 'vue-i18n'
import type { UseGlobalReturn } from './composables/useGlobal/types'
import type en from './lang/en.json'
type MessageSchema = typeof en
import type { NocoI18n } from './lib'
declare module '#app/nuxt' {
interface NuxtApp {
@ -21,7 +17,7 @@ declare module '#app/nuxt' {
declare module '@vue/runtime-core' {
interface App {
i18n: I18n<MessageSchema, unknown, unknown, false>['global']
i18n: NocoI18n
}
}

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

@ -1,4 +1,4 @@
import path from 'path'
import { dirname, resolve } from 'node:path'
import { defineNuxtConfig } from 'nuxt'
import vueI18n from '@intlify/vite-plugin-vue-i18n'
import Icons from 'unplugin-icons/vite'
@ -13,9 +13,7 @@ export default defineNuxtConfig({
modules: ['@vueuse/nuxt', 'nuxt-windicss', '@nuxt/image-edge'],
ssr: false,
app: {
cdnURL: process.env.NODE_ENV === 'production' ? '.' : undefined,
},
css: [
'virtual:windi.css',
'virtual:windi-devtools',
@ -54,7 +52,7 @@ export default defineNuxtConfig({
},
plugins: [
vueI18n({
include: path.resolve(__dirname, './lang'),
include: [resolve(dirname('./lang/**'))],
runtimeOnly: false,
}),
Icons({
@ -103,6 +101,7 @@ export default defineNuxtConfig({
},
},
},
experimental: {
reactivityTransform: true,
},
@ -110,6 +109,7 @@ export default defineNuxtConfig({
image: {
dir: 'assets/',
},
autoImports: {
dirs: ['./context', './utils', './lib'],
imports: [{ name: 'useI18n', from: 'vue-i18n' }],

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

@ -29,7 +29,7 @@
"unique-names-generator": "^4.7.1",
"vue-dompurify-html": "^3.0.0",
"vue-github-button": "^3.0.3",
"vue-i18n": "^9.1.10",
"vue-i18n": "^9.2.2",
"vuedraggable": "^4.1.0",
"xlsx": "^0.17.3"
},
@ -79,7 +79,7 @@
}
},
"../nocodb-sdk": {
"version": "0.96.3",
"version": "0.96.4",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@ -1291,43 +1291,40 @@
}
},
"node_modules/@intlify/core-base": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz",
"integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
"integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
"dependencies": {
"@intlify/devtools-if": "9.1.10",
"@intlify/message-compiler": "9.1.10",
"@intlify/message-resolver": "9.1.10",
"@intlify/runtime": "9.1.10",
"@intlify/shared": "9.1.10",
"@intlify/vue-devtools": "9.1.10"
"@intlify/devtools-if": "9.2.2",
"@intlify/message-compiler": "9.2.2",
"@intlify/shared": "9.2.2",
"@intlify/vue-devtools": "9.2.2"
},
"engines": {
"node": ">= 10"
"node": ">= 14"
}
},
"node_modules/@intlify/devtools-if": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz",
"integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
"integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
"dependencies": {
"@intlify/shared": "9.1.10"
"@intlify/shared": "9.2.2"
},
"engines": {
"node": ">= 10"
"node": ">= 14"
}
},
"node_modules/@intlify/message-compiler": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz",
"integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
"integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
"dependencies": {
"@intlify/message-resolver": "9.1.10",
"@intlify/shared": "9.1.10",
"@intlify/shared": "9.2.2",
"source-map": "0.6.1"
},
"engines": {
"node": ">= 10"
"node": ">= 14"
}
},
"node_modules/@intlify/message-compiler/node_modules/source-map": {
@ -1338,33 +1335,12 @@
"node": ">=0.10.0"
}
},
"node_modules/@intlify/message-resolver": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz",
"integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w==",
"engines": {
"node": ">= 10"
}
},
"node_modules/@intlify/runtime": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz",
"integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==",
"dependencies": {
"@intlify/message-compiler": "9.1.10",
"@intlify/message-resolver": "9.1.10",
"@intlify/shared": "9.1.10"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/@intlify/shared": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz",
"integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
"engines": {
"node": ">= 10"
"node": ">= 14"
}
},
"node_modules/@intlify/vite-plugin-vue-i18n": {
@ -1410,16 +1386,15 @@
}
},
"node_modules/@intlify/vue-devtools": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz",
"integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
"integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
"dependencies": {
"@intlify/message-resolver": "9.1.10",
"@intlify/runtime": "9.1.10",
"@intlify/shared": "9.1.10"
"@intlify/core-base": "9.2.2",
"@intlify/shared": "9.2.2"
},
"engines": {
"node": ">= 10"
"node": ">= 14"
}
},
"node_modules/@ioredis/commands": {
@ -2877,9 +2852,9 @@
}
},
"node_modules/@vue/devtools-api": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz",
"integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ=="
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.2.1.tgz",
"integrity": "sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ=="
},
"node_modules/@vue/reactivity": {
"version": "3.2.37",
@ -14654,17 +14629,17 @@
}
},
"node_modules/vue-i18n": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz",
"integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
"integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
"dependencies": {
"@intlify/core-base": "9.1.10",
"@intlify/shared": "9.1.10",
"@intlify/vue-devtools": "9.1.10",
"@vue/devtools-api": "^6.0.0-beta.7"
"@intlify/core-base": "9.2.2",
"@intlify/shared": "9.2.2",
"@intlify/vue-devtools": "9.2.2",
"@vue/devtools-api": "^6.2.1"
},
"engines": {
"node": ">= 10"
"node": ">= 14"
},
"peerDependencies": {
"vue": "^3.0.0"
@ -16184,33 +16159,30 @@
}
},
"@intlify/core-base": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.1.10.tgz",
"integrity": "sha512-So9CNUavB/IsZ+zBmk2Cv6McQp6vc2wbGi1S0XQmJ8Vz+UFcNn9MFXAe9gY67PreIHrbLsLxDD0cwo1qsxM1Nw==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
"integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
"requires": {
"@intlify/devtools-if": "9.1.10",
"@intlify/message-compiler": "9.1.10",
"@intlify/message-resolver": "9.1.10",
"@intlify/runtime": "9.1.10",
"@intlify/shared": "9.1.10",
"@intlify/vue-devtools": "9.1.10"
"@intlify/devtools-if": "9.2.2",
"@intlify/message-compiler": "9.2.2",
"@intlify/shared": "9.2.2",
"@intlify/vue-devtools": "9.2.2"
}
},
"@intlify/devtools-if": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.1.10.tgz",
"integrity": "sha512-SHaKoYu6sog3+Q8js1y3oXLywuogbH1sKuc7NSYkN3GElvXSBaMoCzW+we0ZSFqj/6c7vTNLg9nQ6rxhKqYwnQ==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
"integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
"requires": {
"@intlify/shared": "9.1.10"
"@intlify/shared": "9.2.2"
}
},
"@intlify/message-compiler": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.1.10.tgz",
"integrity": "sha512-+JiJpXff/XTb0EadYwdxOyRTB0hXNd4n1HaJ/a4yuV960uRmPXaklJsedW0LNdcptd/hYUZtCkI7Lc9J5C1gxg==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
"integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
"requires": {
"@intlify/message-resolver": "9.1.10",
"@intlify/shared": "9.1.10",
"@intlify/shared": "9.2.2",
"source-map": "0.6.1"
},
"dependencies": {
@ -16221,25 +16193,10 @@
}
}
},
"@intlify/message-resolver": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/message-resolver/-/message-resolver-9.1.10.tgz",
"integrity": "sha512-5YixMG/M05m0cn9+gOzd4EZQTFRUu8RGhzxJbR1DWN21x/Z3bJ8QpDYj6hC4FwBj5uKsRfKpJQ3Xqg98KWoA+w=="
},
"@intlify/runtime": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/runtime/-/runtime-9.1.10.tgz",
"integrity": "sha512-7QsuByNzpe3Gfmhwq6hzgXcMPpxz8Zxb/XFI6s9lQdPLPe5Lgw4U1ovRPZTOs6Y2hwitR3j/HD8BJNGWpJnOFA==",
"requires": {
"@intlify/message-compiler": "9.1.10",
"@intlify/message-resolver": "9.1.10",
"@intlify/shared": "9.1.10"
}
},
"@intlify/shared": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.1.10.tgz",
"integrity": "sha512-Om54xJeo1Vw+K1+wHYyXngE8cAbrxZHpWjYzMR9wCkqbhGtRV5VLhVc214Ze2YatPrWlS2WSMOWXR8JktX/IgA=="
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q=="
},
"@intlify/vite-plugin-vue-i18n": {
"version": "6.0.1",
@ -16264,13 +16221,12 @@
}
},
"@intlify/vue-devtools": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.1.10.tgz",
"integrity": "sha512-5l3qYARVbkWAkagLu1XbDUWRJSL8br1Dj60wgMaKB0+HswVsrR6LloYZTg7ozyvM621V6+zsmwzbQxbVQyrytQ==",
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
"integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
"requires": {
"@intlify/message-resolver": "9.1.10",
"@intlify/runtime": "9.1.10",
"@intlify/shared": "9.1.10"
"@intlify/core-base": "9.2.2",
"@intlify/shared": "9.2.2"
}
},
"@ioredis/commands": {
@ -17429,9 +17385,9 @@
}
},
"@vue/devtools-api": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.1.4.tgz",
"integrity": "sha512-IiA0SvDrJEgXvVxjNkHPFfDx6SXw0b/TUkqMcDZWNg9fnCAHbTpoo59YfJ9QLFkwa3raau5vSlRVzMSLDnfdtQ=="
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.2.1.tgz",
"integrity": "sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ=="
},
"@vue/reactivity": {
"version": "3.2.37",
@ -26119,14 +26075,14 @@
}
},
"vue-i18n": {
"version": "9.1.10",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.1.10.tgz",
"integrity": "sha512-jpr7gV5KPk4n+sSPdpZT8Qx3XzTcNDWffRlHV/cT2NUyEf+sEgTTmLvnBAibjOFJ0zsUyZlVTAWH5DDnYep+1g==",
"requires": {
"@intlify/core-base": "9.1.10",
"@intlify/shared": "9.1.10",
"@intlify/vue-devtools": "9.1.10",
"@vue/devtools-api": "^6.0.0-beta.7"
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
"integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
"requires": {
"@intlify/core-base": "9.2.2",
"@intlify/shared": "9.2.2",
"@intlify/vue-devtools": "9.2.2",
"@vue/devtools-api": "^6.2.1"
}
},
"vue-router": {

2
packages/nc-gui/package.json

@ -37,7 +37,7 @@
"unique-names-generator": "^4.7.1",
"vue-dompurify-html": "^3.0.0",
"vue-github-button": "^3.0.3",
"vue-i18n": "^9.1.10",
"vue-i18n": "^9.2.2",
"vuedraggable": "^4.1.0",
"xlsx": "^0.17.3"
},

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

@ -193,7 +193,12 @@ if (type && name) {
<img alt="NocoDB" src="~/assets/img/icons/512x512-trans.png" />
</a>
<a-dropdown class="h-full min-w-0 flex-1" :trigger="['click']" placement="bottom">
<a-dropdown
class="h-full min-w-0 flex-1"
:trigger="['click']"
placement="bottom"
overlay-class-name="nc-dropdown-project-menu"
>
<div
:style="{ width: isOpen ? 'calc(100% - 40px) pr-2' : '100%' }"
:class="[isOpen ? '' : 'justify-center']"

1
packages/nc-gui/pages/[projectType]/form/[viewId]/index.vue

@ -136,6 +136,7 @@ function isRequired(_columnObj: Record<string, any>, required = false) {
centered
:footer="null"
:mask-closable="false"
wrap-class-name="nc-modal-shared-form-password-dlg"
@close="passwordDlg = false"
>
<div class="w-full flex flex-col">

3
packages/nc-gui/pages/[projectType]/view/[viewId].vue

@ -8,6 +8,7 @@ import {
extractSdkResponseErrorMsg,
provide,
ref,
useProvideCellUrlConfig,
useRoute,
useSharedView,
} from '#imports'
@ -24,6 +25,8 @@ const reloadEventHook = createEventHook<void>()
provide(ReloadViewDataHookInj, reloadEventHook)
provide(ReadonlyInj, true)
useProvideCellUrlConfig()
const { loadSharedView } = useSharedView()
const showPassword = ref(false)

9
packages/nc-gui/pages/index/index/create-external.vue

@ -539,7 +539,13 @@ onMounted(() => {
</a-form-item>
</a-form>
<a-modal v-model:visible="configEditDlg" :title="$t('activity.editConnJson')" width="600px" @ok="handleOk">
<a-modal
v-model:visible="configEditDlg"
:title="$t('activity.editConnJson')"
width="600px"
wrap-class-name="nc-modal-edit-connection-json"
@ok="handleOk"
>
<MonacoEditor v-if="configEditDlg" v-model="customFormState" class="h-[400px] w-full" />
</a-modal>
@ -550,6 +556,7 @@ onMounted(() => {
width="600px"
:ok-text="$t('general.ok')"
:cancel-text="$t('general.cancel')"
wrap-class-name="nc-modal-connection-url"
@ok="handleImportURL"
>
<a-input v-model:value="importURL" />

3
packages/nc-gui/pages/index/index/index.vue

@ -48,6 +48,7 @@ const deleteProject = (project: ProjectType) => {
Modal.confirm({
title: `Do you want to delete '${project.title}' project?`,
wrapClassName: 'nc-modal-project-delete',
okText: 'Yes',
okType: 'danger',
cancelText: 'No',
@ -136,7 +137,7 @@ const getProjectPrimary = (project: ProjectType) => {
<div class="flex-1" />
<a-dropdown v-if="isUIAllowed('projectCreate', true)" :trigger="['click']">
<a-dropdown v-if="isUIAllowed('projectCreate', true)" :trigger="['click']" overlay-class-name="nc-dropdown-create-project">
<button class="nc-new-project-menu">
<span class="flex items-center w-full">
{{ $t('title.newProj') }}

2
packages/nc-gui/pages/projects/index/index.vue

@ -71,7 +71,7 @@ const formatTitle = (title: string) =>
<div v-for="(project, i) of projects" :key="project.id" class="group flex flex-col items-center gap-2">
<div class="thumbnail" :style="{ '--thumbnail-color': getColorByIndex(i) }" @click="openProject(project)">
{{ formatTitle(project.title) }}
<a-dropdown @click.stop>
<a-dropdown overlay-class-name="nc-dropdown-project-operations" @click.stop>
<MdiMenuDown class="menu-icon" />
<template #overlay>
<a-menu>

2
packages/nc-gui/pages/signin.vue

@ -152,7 +152,7 @@ function resetError() {
.password {
input {
@apply !border-none;
@apply !border-none !m-0;
}
}

2
packages/nc-gui/pages/signup/[[token]].vue

@ -197,7 +197,7 @@ function resetError() {
.password {
input {
@apply !border-none;
@apply !border-none !m-0;
}
}

69
packages/nc-gui/plugins/a.i18n.ts

@ -1,9 +1,11 @@
import { defineNuxtPlugin } from 'nuxt/app'
import { createI18n } from 'vue-i18n'
import { nextTick } from 'vue'
import type { Language, NocoI18n } from '~/lib'
let i18n: ReturnType<typeof createI18n>
let globalI18n: NocoI18n
export const createI18nPlugin = async () =>
export const createI18nPlugin = async (): Promise<NocoI18n> =>
createI18n({
locale: 'en', // Set the initial locale
@ -12,49 +14,32 @@ export const createI18nPlugin = async () =>
legacy: false, // disable legacy API (we use the composition API and inject utilities)
globalInjection: true, // enable global injection, so all utilities are injected into all components
// Associate each locale to a content file
messages: {
ar: await import('~/lang/ar.json'),
bn_IN: await import('~/lang/bn_IN.json'),
da: await import('~/lang/da.json'),
de: await import('~/lang/de.json'),
en: await import('~/lang/en.json'),
es: await import('~/lang/es.json'),
fa: await import('~/lang/fa.json'),
fi: await import('~/lang/fi.json'),
fr: await import('~/lang/fr.json'),
he: await import('~/lang/he.json'),
hi: await import('~/lang/hi.json'),
hr: await import('~/lang/hr.json'),
id: await import('~/lang/id.json'),
it: await import('~/lang/it.json'),
ja: await import('~/lang/ja.json'),
ko: await import('~/lang/ko.json'),
lv: await import('~/lang/lv.json'),
nl: await import('~/lang/nl.json'),
no: await import('~/lang/no.json'),
pl: await import('~/lang/pl.json'),
pt: await import('~/lang/pt.json'),
pt_BR: await import('~/lang/pt_BR.json'),
ru: await import('~/lang/ru.json'),
sv: await import('~/lang/sv.json'),
sl: await import('~/lang/sl.json'),
th: await import('~/lang/th.json'),
tr: await import('~/lang/tr.json'),
uk: await import('~/lang/uk.json'),
vi: await import('~/lang/vi.json'),
zh_Hans: await import('~/lang/zh-Hans.json'),
zh_Hant: await import('~/lang/zh-Hant.json'),
},
})
export const getI18n = () => globalI18n
export async function setI18nLanguage(locale: keyof typeof Language, i18n = globalI18n) {
if (!i18n.global.availableLocales.includes(locale)) {
await loadLocaleMessages(locale)
}
i18n.global.locale.value = locale
}
export async function loadLocaleMessages(locale: keyof typeof Language, i18n: NocoI18n = globalI18n) {
// load locale messages with dynamic import
const messages = await import(`../lang/${locale}.json`)
// set locale and locale message
i18n.global.setLocaleMessage(locale, messages.default)
return nextTick()
}
export default defineNuxtPlugin(async (nuxtApp) => {
i18n = (await createI18nPlugin()) as any
globalI18n = await createI18nPlugin()
nuxtApp.vueApp.i18n = i18n.global as any
nuxtApp.vueApp.i18n = globalI18n
nuxtApp.vueApp.use(i18n)
nuxtApp.vueApp.use(globalI18n)
})
export const getI18n = () => i18n

10
packages/nc-gui/plugins/state.ts

@ -1,4 +1,5 @@
import { defineNuxtPlugin, useApi, useGlobal } from '#imports'
import { loadLocaleMessages, setI18nLanguage } from '~/plugins/a.i18n'
/**
* Initialize global state and watches for changes
@ -12,13 +13,18 @@ import { defineNuxtPlugin, useApi, useGlobal } from '#imports'
* console.log($state.lang.value) // 'en'
* ```
*/
export default defineNuxtPlugin(async (nuxtApp) => {
export default defineNuxtPlugin(async () => {
const state = useGlobal()
const { api } = useApi()
const currentLang = state.lang.value
/** force load initial locale messages */
await loadLocaleMessages(currentLang)
/** set i18n locale to stored language */
nuxtApp.vueApp.i18n.locale.value = state.lang.value
await setI18nLanguage(currentLang)
try {
state.appInfo.value = await api.utils.appInfo()

28
packages/noco-docs/content/en/developer-resources/accessing-apis.md

@ -14,27 +14,34 @@ Auth Token is a JWT Token generated based on the logged-in user. By default, the
- Go to NocoDB Project, click the rightmost button and click ``Copy Auth Token``.
<img width="219" alt="image" src="https://user-images.githubusercontent.com/35857179/164874424-7622112f-9729-4514-81d2-5c6631b19ed0.png">
![Screenshot 2022-09-14 at 10 18 58 AM](https://user-images.githubusercontent.com/86527202/190062565-34ec5f49-b2a9-4ccb-a02f-8ea60980ffd9.png)
<!-- <img width="219" alt="image" src="https://user-images.githubusercontent.com/35857179/164874424-7622112f-9729-4514-81d2-5c6631b19ed0.png"> -->
## API Token
NocoDB allows creating API tokens which allow it to be integrated seamlessly with 3rd party apps. API Token is a Nano ID with a length of 40. If you are passing API Token, make sure that the header is called `xc-token`.
- Go to `Team & Settings` from the left navigation drawer
![image](https://user-images.githubusercontent.com/35857179/161902474-fd06678c-a171-4237-b171-dc028b3753de.png)
- Open `Project Menu`, click on `Team & Settings`
- Click `API Tokens Management`
![image](https://user-images.githubusercontent.com/35857179/161958345-83cb60bf-80f1-4d11-9e9c-52d0b05c7677.png)
<img width="390" alt="image" src="https://user-images.githubusercontent.com/35857179/189115289-07657c15-deab-435f-b0f9-2948007f8c65.png">
<!-- ![image](https://user-images.githubusercontent.com/35857179/161902474-fd06678c-a171-4237-b171-dc028b3753de.png) -->
- Click `API Tokens Management` tab under `Team & Auth` section
<!-- ![image](https://user-images.githubusercontent.com/35857179/161958345-83cb60bf-80f1-4d11-9e9c-52d0b05c7677.png) -->
- Click Add New Token
![image](https://user-images.githubusercontent.com/35857179/161958563-dc5d380a-26c5-4b78-9d4b-e40188bef05a.png)
![Screenshot 2022-09-14 at 10 20 00 AM](https://user-images.githubusercontent.com/86527202/190062728-9c09934f-b5e4-4fec-b4d2-0cd3648bbb39.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/161958563-dc5d380a-26c5-4b78-9d4b-e40188bef05a.png) -->
- Type an recognizable name for your token and click `Generate`
![image](https://user-images.githubusercontent.com/35857179/161958676-e4faa321-13ca-4b11-8d22-1332c522dde7.png)
- Copy API token to your clipboard
![image](https://user-images.githubusercontent.com/35857179/161958822-b0689a6a-a864-429f-8bb2-71eb92808339.png)
![Screenshot 2022-09-14 at 10 20 10 AM](https://user-images.githubusercontent.com/86527202/190062801-db3fab83-7974-4dfe-9c83-bf0d8a7dba1e.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/161958676-e4faa321-13ca-4b11-8d22-1332c522dde7.png) -->
- Copy API token to your clipboard; use action menu to the right of token list
<!-- ![image](https://user-images.githubusercontent.com/35857179/161958822-b0689a6a-a864-429f-8bb2-71eb92808339.png) -->
## Swagger UI
@ -42,7 +49,8 @@ You can interact with the API's resources via Swagger UI.
- Go to NocoDB Project, click the rightmost button and click ``Swagger APIs Doc``.
<img width="215" alt="image" src="https://user-images.githubusercontent.com/35857179/164874429-d8e8f129-9cca-4d47-92c4-0b34b6e0b922.png">
![Screenshot 2022-09-14 at 10 22 00 AM](https://user-images.githubusercontent.com/86527202/190062896-c1c2d529-694f-46ad-b6b1-0ee8d71a6e14.png)
<!-- <img width="215" alt="image" src="https://user-images.githubusercontent.com/35857179/164874429-d8e8f129-9cca-4d47-92c4-0b34b6e0b922.png"> -->
- Click ``Authorize``, paste the token you copied in above steps and click `Authorize` to save.

40
packages/noco-docs/content/en/developer-resources/webhooks.md

@ -10,17 +10,31 @@ menuTitle: "Webhooks"
Some types of notifications can be triggered by a webhook after a particular event.
- Open a Project, Select a table and Click 'More' > 'Webhooks'.
### Open `View menu`, click on `Webhooks`
![Screenshot 2022-02-22 at 11 16 18 AM](https://user-images.githubusercontent.com/86527202/155085373-f9b438ed-98c3-4fb1-9209-1bb52736a35d.png)
![Screenshot 2022-09-14 at 10 32 13 AM](https://user-images.githubusercontent.com/86527202/190064555-77d2444e-250e-4c26-bf65-4bccde166c25.png)
- Click 'Create webhook'
<!-- ![Screenshot 2022-02-22 at 11 16 18 AM](https://user-images.githubusercontent.com/86527202/155085373-f9b438ed-98c3-4fb1-9209-1bb52736a35d.png) -->
### Click `Add new webhook`
![Screenshot 2022-09-14 at 10 33 15 AM](https://user-images.githubusercontent.com/86527202/190064639-c51038bc-cfd0-4f5a-aece-3bade55ae994.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/166660074-0a896ec9-9cd8-403e-a713-61c2cefbae28.png) -->
![image](https://user-images.githubusercontent.com/35857179/166660074-0a896ec9-9cd8-403e-a713-61c2cefbae28.png)
### Configure Webhook
- General configurations
- Webhook Name
- Webhook Trigger
- Webhook Type
- Webhook Type specific configuration : additional configuration details depending on webhook type selected
- Webhook Conditional Trigger
- Only records meeting the criteria will trigger webhook
- Configure the webhook
![Screenshot 2022-09-14 at 10 35 39 AM](https://user-images.githubusercontent.com/86527202/190064668-37245025-81f6-491c-b639-83c8fd131bc3.png)
![image](https://user-images.githubusercontent.com/35857179/166660248-a3c81a34-4334-48c2-846a-65759d761559.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/166660248-a3c81a34-4334-48c2-846a-65759d761559.png) -->
## Triggers
@ -97,12 +111,14 @@ Detailed procedure for discord webhook described [here](https://support.discord.
- Open 'App Store' (under Settings), hover over Discord tile. Click 'Install'.
![Screenshot 2022-02-22 at 11 30 36 AM](https://user-images.githubusercontent.com/86527202/155085257-5bdde1d9-d7b5-471d-bf44-3c3920e7b853.png)
![Screenshot 2022-09-14 at 10 47 59 AM](https://user-images.githubusercontent.com/86527202/190066333-04bab4eb-f114-48e5-b3f9-6327cadb1ca7.png)
<!-- ![Screenshot 2022-02-22 at 11 30 36 AM](https://user-images.githubusercontent.com/86527202/155085257-5bdde1d9-d7b5-471d-bf44-3c3920e7b853.png) -->
- Provide a name of your choice (not to be confused with Discord Channel name).
- Paste Discord Webhook URL copied from Step (1.) above.
![Screenshot 2022-02-22 at 11 31 21 AM](https://user-images.githubusercontent.com/86527202/155085287-f5e45aab-fd33-4138-a7a9-6eddc6dc140b.png)
![Screenshot 2022-09-14 at 10 52 14 AM](https://user-images.githubusercontent.com/86527202/190066365-90e3136b-db24-4514-aa89-c1fb371b33ee.png)
<!-- ![Screenshot 2022-02-22 at 11 31 21 AM](https://user-images.githubusercontent.com/86527202/155085287-f5e45aab-fd33-4138-a7a9-6eddc6dc140b.png) -->
### 3. Configure
@ -155,13 +171,17 @@ Detailed procedure for discord webhook described [here](https://support.discord.
- Open 'App Store' (under Settings), hover over 'Microsoft Teams' tile. Click 'Install'.
![Screenshot 2022-02-22 at 7 32 52 PM](https://user-images.githubusercontent.com/86527202/155148122-60844b42-7d2a-4c0f-9778-a5bc4f9c0107.png)
![Screenshot 2022-09-14 at 10 53 22 AM](https://user-images.githubusercontent.com/86527202/190066409-03311add-3b36-4521-acf7-dba5ffdef3fb.png)
<!-- ![Screenshot 2022-02-22 at 7 32 52 PM](https://user-images.githubusercontent.com/86527202/155148122-60844b42-7d2a-4c0f-9778-a5bc4f9c0107.png) -->
- Provide a name of your choice (not to be confused with Teams Channel name).
- Paste MS Teams Webhook URL copied from Step (1.) above.
<img width="414" alt="154971222-7fe2c25a-d8c6-46b0-ba1e-a05ff1cf6537" src="https://user-images.githubusercontent.com/86527202/155095720-ff1c052c-a4a7-4c10-8f30-d779dac336f3.png">
![Screenshot 2022-09-14 at 10 53 31 AM](https://user-images.githubusercontent.com/86527202/190066430-838eaa69-ac2c-49ce-a0eb-d84c97964f8b.png)
<!-- <img width="414" alt="154971222-7fe2c25a-d8c6-46b0-ba1e-a05ff1cf6537" src="https://user-images.githubusercontent.com/86527202/155095720-ff1c052c-a4a7-4c10-8f30-d779dac336f3.png"> -->
### 3. Configure

121
packages/noco-docs/content/en/engineering/development-setup.md

@ -1,6 +1,6 @@
---
title: "Development setup"
description: "How to setup your development environment"
description: "How to set-up your development environment"
position: 3200
category: "Engineering"
menuTitle: "Development setup"
@ -39,19 +39,130 @@ npm run dev
Any changes made to frontend and backend will be automatically reflected in the browser.
### Cypress
Cypress tests are divided into 4 suites
- SQLite tests
- Postgres tests
- MySQL tests
- Quick import tests
First 3 suites, each have 4 test category
- Table operations (create, delete, rename, add column, delete column, rename column)
- Views (Grid, Gallery, Form)
- Roles (user profiles, access control & preview)
- Miscellaneous (Import, i18n, etc)
#### MySQL tests (ExtDB project)
```shell
# install dependencies(cypress)
npm install
# run mysql database with required database using docker compose
# start MySQL database using docker compose
docker-compose -f ./scripts/docker-compose-cypress.yml up
# Run backend api using following command
npm run start:api
npm run start:api:cache
# Run frontend web UI using following command
npm run start:web
# wait until both 3000 and 8080 ports are available
# or run following command to run it with GUI
npm run cypress:open
# run one of 4 test scripts
- Table operations : restTableOps.js
- Views : restViews.js
- Roles & access control : restRoles.js
- Miscellaneous : restMisc.js
```
#### SQLite tests (XCDB project)
```shell
# install dependencies(cypress)
npm install
# start MySQL database using docker compose
docker-compose -f ./scripts/docker-compose-cypress.yml up
# Run backend api using following command
npm run start:xcdb-api:cache
# Run frontend web UI using following command
npm run start:web
# wait until both 3000 and 8080 ports are available
# or run following command to run it with GUI
npm run cypress:open
# run one of 4 test scripts
- Table operations : xcdb-restTableOps.js
- Views : xcdb-restViews.js
- Roles & access control : xcdb-restRoles.js
- Miscellaneous : xcdb-restMisc.js
```
#### PG tests (ExtDB project)
```shell
# install dependencies(cypress)
npm install
# start PG database using docker compose
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
# Run backend api using following command
npm run start:api:cache
# Run frontend web UI using following command
npm run start:web
# wait until both 3000 and 8080 ports are available
# and run cypress test using following command
npm run cypress:run
# or run following command to run it with GUI
npm run cypress:open
# run one of 4 test scripts
- Table operations : pg-restTableOps.js
- Views : pg-restViews.js
- Roles & access control : pg-restRoles.js
- Miscellaneous : pg-restMisc.js
```
#### Quick import tests (SQLite project)
```shell
# install dependencies(cypress)
npm install
# start MySQL database using docker compose
docker-compose -f ./scripts/docker-compose-cypress.yml up
# copy existing xcdb (v0.91.7) database to ./packages/nocodb/
cp ./scripts/cypress/fixtures/quickTest/noco_0_91_7.db ./packages/nocodb/noco.db
# Run backend api using following command
npm run start:api:cache
# Run frontend web UI using following command
npm run start:web
# wait until both 3000 and 8080 ports are available
# or run following command to run it with GUI
npm run cypress:open
# run test script
- quickTest.js
```
#### Quick import tests (PG)
```shell
# install dependencies(cypress)
npm install
# start PG database using docker compose
docker-compose -f ./scripts/cypress/docker-compose-pg.yml up -d
# copy existing xcdb (v0.91.7) database to ./packages/nocodb/
cp ./scripts/cypress/fixtures/quickTest/noco_0_91_7.db ./packages/nocodb/noco.db
# Run backend api using following command
npm run start:api:cache
# Run frontend web UI using following command
npm run start:web
# wait until both 3000 and 8080 ports are available
# or run following command to run it with GUI
npm run cypress:open
# run test script
- quickTest.js
```

85
packages/noco-docs/content/en/engineering/translation.md

@ -6,48 +6,81 @@ category: "Engineering"
menuTitle: "i18n translation"
---
NocoDB supports many foreign languages & we welcome community contributions via an easy to use [google-spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172).
NocoDB supports many foreign languages & community contributions are now simplified via [Crowdin](https://crowdin.com/)
Your help in fixing i18n goes a long way supporting NocoDB. Please follow below simple procedure to request corrections to existing translation errors.
## How to contribute ? (for community members)
# Public Contributions
### 1. How to change a string value ?
- Make a copy of [Google spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
<img width="995" alt="Screenshot 2022-02-10 at 1 47 06 PM" src="https://user-images.githubusercontent.com/86527202/153368423-d1d898ef-bdcb-48c4-a772-b75e2c66566d.png">
- Find your language code [here](https://developers.google.com/admin-sdk/directory/v1/languages)
- Go to the column containing your language code. Make necessary changes. Origin text in ENGLISH can be found in `Column B` of master spreadsheet.
- Create a new [issue in Github](https://github.com/nocodb/nocodb/issues/new?assignees=dstala&labels=i18n+translation&template=i18n-translation-request.md&title=%5Bi18n%5D+Language+support+extension-+%3Clanguage+code%3E) request with a link to your spreadsheet from Step-1 (for us to verify & update master spreadsheet).
- NocoDB Maintainers will take changes and merge it.
- It's that simple!
### 1. How to add translation corrections (to existing languages)?
- Setup [Crowdin](https://crowdin.com) account
- Join [NocoDB](https://crowdin.com/project/nocodb) project
![Screenshot 2022-09-08 at 10 26 23 PM](https://user-images.githubusercontent.com/86527202/189181511-51b8671e-bee8-45d5-8216-a4a031bc6309.png)
- Click the language that you wish to contribute
![Screenshot 2022-09-08 at 10 29 56 PM](https://user-images.githubusercontent.com/86527202/189182132-0eed7d5a-eaa1-43e1-929d-688f375763c1.png)
- Click the `Translate` button; this opens up `Crowdin Online Editor`
![Screenshot 2022-09-08 at 10 32 17 PM](https://user-images.githubusercontent.com/86527202/189182450-999124e8-566c-40af-9d3c-731a11c1b6aa.png)
- Select string in `English` on the left-hand menu bar [1]
- Propose changes [2]
- Save [3]
Note: Crowdin provides translation recommendation's as in [4]. Click directly if it's apt
![Screenshot 2022-09-08 at 10 37 38 PM](https://user-images.githubusercontent.com/86527202/189184278-69d688ed-4e5a-4d5a-b629-9f6d10d79346.png)
A GitHub Pull Request will be automatically triggered (periodicity- 6 hours). We will follup on remaining integration work items.
---
#### Reference
Refer following articles to get additional details about Crowdin Portal usage
- [Translator Introduction](https://support.crowdin.com/crowdin-intro/)
- [Volunteer Translation Introduction](https://support.crowdin.com/for-volunteer-translators/)
- [Online Editor](https://support.crowdin.com/online-editor/)
---
### 2. How to add a new language ?
Your native language not in list, we will be glad to support with your help! Please follow below steps
Your native language not in list, we will be glad to support with your help! Request for it [here](https://github.com/nocodb/nocodb/issues/new?assignees=dstala&labels=i18n+translation&template=i18n-translation-request.md&title=%5Bi18n%5D+Language+support+extension-+%3Clanguage+code%3E). We will be glad to take your help to set up translations
- Make a copy of [Google spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
<img width="995" alt="Screenshot 2022-02-10 at 1 47 06 PM" src="https://user-images.githubusercontent.com/86527202/153368423-d1d898ef-bdcb-48c4-a772-b75e2c66566d.png">
- Find your language code [here](https://developers.google.com/admin-sdk/directory/v1/languages)
- Replace cell $AB$1 (rightmost, containing text `en`) with language code obtained above.
- Google will generate first version translation in column AB. Review. Make changes as you find appropriate for various items listed. Origin text in ENGLISH can be found in `Column B` of master spreadsheet.
- Create new [issue](https://github.com/nocodb/nocodb/issues/new?assignees=dstala&labels=i18n+translation&template=i18n-translation-request.md&title=%5Bi18n%5D+Language+support+extension-+%3Clanguage+code%3E) request with a link to your spreadsheet from Step-1 (for us to verify & update master spreadsheet).
---
## How to accept i18n contributions ? (for NocoDB maintainers)
# Engineering Contributions (for NocoDB developers & maintainers)
> _This is exclusive to NocoDB maintainers only_
> _This is exclusive to NocoDB developers & maintainers only_
### 1. Adding / Updating a string
- Open master [Spreadsheet](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit#gid=2076107172)
- For the string/ text under consideration, look-up in existing sheet if it exists already
- [New string already exists] Consider re-using it; align string key if required
- [New string need to be inserted] Insert a new record into appropriate categories as defined below
- Download spreadsheet as .csv (File > Download > Comma-seperated values (.csv, current sheet)
- Use noco-i18n-from-cli to generate new language JSON file
- Copy respective i18n/\*.json files to `nocodb/packages/nc-gui/lang`
### Add / update key-value
- [en] make changes directly to `en.json` & commit to `develop`
- [any other language] add changes using `crowdin` portal; procedure described below
### Add a new language
#### GitHub changes
- Update enumeration in `enums.ts` [packages/nc-gui/lib/enums.ts]
- Map JSON path in `a.i18n.ts` [packages/nc-gui/plugins/a.i18n.ts]
- Update array in `6d_language_validation.js` [scripts/cypress/integration/common/6d_language_validation.js]
#### Crowdin changes [admin only]
- Open `NocoDB` project
- Click on `Language` on the home tab
- Select target language, `Update`
![Screenshot 2022-09-08 at 10 52 59 PM](https://user-images.githubusercontent.com/86527202/189186570-5c1c7cad-6d3f-4937-ab4d-fa7ebe022cb1.png)
![Screenshot 2022-09-08 at 10 54 04 PM](https://user-images.githubusercontent.com/86527202/189186632-0b9f5f55-0550-4d8f-a8ae-7e9b9076774e.png)
---
### 2. String Categories
- **General**: simple & common tokens (save, cancel, submit, open, close, home, and such)

2
packages/noco-docs/content/en/index.md

@ -58,6 +58,6 @@ Most internet businesses equip themselves with either spreadsheet or a database
## Our Mission
Our mission is to provide the most powerful no-code interface for databases which is open source to every single internet business in the world. This would not only democratise access to a powerful computing tool but also bring forth a billion+ people who will have radical tinkering-and-building abilities on internet.
# How can I contribute to NocoDB's development ?
## How can I contribute to NocoDB's development ?
Please refer to [here](https://github.com/nocodb/nocodb/blob/develop/.github/CONTRIBUTING.md) for the contribution guidelines.

6
packages/noco-docs/content/en/setup-and-usages/audit.md

@ -6,10 +6,10 @@ category: 'Product'
menuTitle: 'Audit'
---
We are keeping all the user operation logs under Audit. Audits logs can be accessed by clicking `Team & Settings` from the left navigation drawer.
We are keeping all the user operation logs under Audit. To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings`.
<img width="367" alt="image" src="https://user-images.githubusercontent.com/35857179/170426881-ba645392-24a2-4446-b501-0595a0887724.png">
<img width="390" alt="image" src="https://user-images.githubusercontent.com/35857179/189115289-07657c15-deab-435f-b0f9-2948007f8c65.png">
Then, under SETTINGS, click `Audit`.
<img width="1335" alt="image" src="https://user-images.githubusercontent.com/35857179/170428570-627a3763-26ae-4b8f-b5a8-0b8b42638464.png">
<img width="1498" alt="image" src="https://user-images.githubusercontent.com/35857179/189115759-ac1664be-906a-4f36-973b-ed67f39d55a3.png">

7
packages/noco-docs/content/en/setup-and-usages/code-snippets.md

@ -8,14 +8,13 @@ menuTitle: 'Code Snippets'
## Overview
Open a Project, Select a Table and Click `Get API Snippet` on the bottom right area.
In the table toolbar, click Table name button and click `Get API Snippet`.
<img width="1335" alt="image" src="https://user-images.githubusercontent.com/35857179/166663362-43ffe3cc-1053-4bf6-a65e-e4b8bae69fcb.png">
<img width="468" alt="image" src="https://user-images.githubusercontent.com/35857179/189104172-4f7f6b6d-cae1-431e-8a7a-26127cf8a791.png">
A modal box will be shown with sample code snippet for List API.
![image](https://user-images.githubusercontent.com/35857179/166663478-3f802012-7bdc-4265-9ffe-6e51c4bcf4cd.png)
<img width="1498" alt="image" src="https://user-images.githubusercontent.com/35857179/189104418-cfa38ec0-ee91-4e72-83e1-6e28ab0311d1.png">
## Supported Snippet

39
packages/noco-docs/content/en/setup-and-usages/column-operations.md

@ -8,17 +8,23 @@ menuTitle: "Column Operations"
## Fields
<img src="https://user-images.githubusercontent.com/86527202/144435795-7156799c-04de-474d-9125-1b15e07acc3d.png" width="60%"/>
Click `Fields` to control the visibility of a field.
<img width="1262" alt="image" src="https://user-images.githubusercontent.com/35857179/189098625-8b4930e7-9bb4-4e8f-aa44-d2a28a31abdb.png">
By default, all system fields will be hid. However, you can tick `Show system fields` to make them visible.
<img width="1268" alt="image" src="https://user-images.githubusercontent.com/35857179/189098684-4fe2ebfc-df00-40fc-8f3c-1d4d14a8fb23.png">
### Re-order Columns
Column positions can be re-ordered. Open `Fields` menu, and re-order fields as needed by dragging and dropping the `drag icon`.
<img src="https://user-images.githubusercontent.com/86527202/144435838-8cff72eb-eaa2-4268-9749-213283eb8336.png" width="40%"/>
<img width="358" alt="image" src="https://user-images.githubusercontent.com/35857179/189100445-d1a3816e-ddc0-4830-ba0a-a7b65597d264.png">
#### Demo
<!-- #### Demo -->
<img src="https://github.com/dstala/nocodb-files/blob/2c4ca2ff31460ee5636262e88ba303e2d436ba54/ColumnReorder.gif?raw=true" width="100%"/>
<!-- <img src="https://github.com/dstala/nocodb-files/blob/2c4ca2ff31460ee5636262e88ba303e2d436ba54/ColumnReorder.gif?raw=true" width="100%"/> -->
<!-- img src="https://media0.giphy.com/media/z5mYR1XoO85Umd5abh/giphy.gif?cid=790b7611f53d7e966bf9de3ae6b1cd5a7d6380b0ab8a4337&rid=giphy.gif&ct=g" width="60%"/ -->
### Hide / Unhide Columns
@ -29,11 +35,11 @@ To hide / unhide columns, open `Fields` menu, tick checkbox to keep the column v
Tip: You can create different grid views with different fields shown in each view.
</alert>
<img src="https://user-images.githubusercontent.com/86527202/144435852-47f87057-f42f-4691-abbd-9592cde50541.png" width="40%"/>
<img width="355" alt="image" src="https://user-images.githubusercontent.com/35857179/189100701-125b529b-5578-43ad-a707-e8c1738e788c.png">
#### Demo
<!-- #### Demo -->
<img src="https://github.com/dstala/nocodb-files/blob/2c4ca2ff31460ee5636262e88ba303e2d436ba54/ColumnHide.gif?raw=true" width="100%"/>
<!-- <img src="https://github.com/dstala/nocodb-files/blob/2c4ca2ff31460ee5636262e88ba303e2d436ba54/ColumnHide.gif?raw=true" width="100%"/> -->
<!-- img src="https://media2.giphy.com/media/8NXvWfHDoul72dwLhk/giphy.gif?cid=790b76116fa008b45c79bb91bfe611e324fa38cde21a255a&rid=giphy.gif&ct=g" width="60%"/ -->
## Sort
@ -41,22 +47,29 @@ Tip: You can create different grid views with different fields shown in each vie
Sorting allows you to order contents alphabetically (A → Z) / (Z → A) (OR) in ascending / descending order. NocoDB allows nested sorting. You can choose column fields & order in which to apply nested sorting. Lookup, Formula, Nested Data are also supported in Sorting.
<img src="https://user-images.githubusercontent.com/86527202/144435903-84ed8e81-64ec-45e5-a045-9a993238c78c.png" width="75%"/>
<img width="462" alt="image" src="https://user-images.githubusercontent.com/35857179/189100830-29b164a2-dd63-41f9-987a-09de53e0a0ec.png">
<img width="473" alt="image" src="https://user-images.githubusercontent.com/35857179/189100869-e458814c-ef9b-4d88-8d7c-4e7de0f3b416.png">
<img src="https://user-images.githubusercontent.com/86527202/144435925-67b995a0-da10-45c9-bf54-9edcc63c5644.png" width="75%"/>
<img width="607" alt="image" src="https://user-images.githubusercontent.com/35857179/189100945-f2575174-f0d2-48e5-8b89-2d14baa873e5.png">
#### Demo
<img src="https://github.com/dstala/nocodb-files/blob/2c4ca2ff31460ee5636262e88ba303e2d436ba54/ColumnSort-2.gif?raw=true" width="100%"/>
<!-- #### Demo -->
<!-- <img src="https://github.com/dstala/nocodb-files/blob/2c4ca2ff31460ee5636262e88ba303e2d436ba54/ColumnSort-2.gif?raw=true" width="100%"/> -->
<!-- img src="https://media4.giphy.com/media/ThQ8d42U2zdFyZGeZe/giphy.gif?cid=790b761183da2eb690295c5c25f83ace7acf5212c82569a1&rid=giphy.gif&ct=g" width="60%"/ -->
## Filter
Filters allow you to restrict / organize your data on the view as per your needs. NocoDB allows nested filters. You can choose multiple columns and conditions to apply filter. Between filters, you can opt for either `and` or `or` mode operation. Lookup, Formula, Nested Data are also supported in Filtering.
<img src="https://user-images.githubusercontent.com/86527202/144435944-8498be32-76cb-48d1-883a-8f674f2eb68e.png" width="60%"/>
<img width="1011" alt="image" src="https://user-images.githubusercontent.com/35857179/189102268-706ba965-e332-4c93-b2d2-ea04f0fabf11.png">
<img width="1021" alt="image" src="https://user-images.githubusercontent.com/35857179/189102641-bd4f64b1-21fc-42a0-bbe6-2a019e213eda.png">
You can also group several filters together using Filter Group.
<img src="https://user-images.githubusercontent.com/86527202/144435955-361238d5-ecda-448e-a6de-a47086aeec6e.png" width="75%"/>
<img width="1025" alt="image" src="https://user-images.githubusercontent.com/35857179/189102932-aa0e31ef-554f-4e8b-ae0e-2024b7f4d35b.png">
### Supported filters

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

@ -8,60 +8,54 @@ menuTitle: 'Dashboard'
## Setup Your First Super Admin
Once you have started NocoDB, you can visit the dashboard via `example.com/dashboard`.
Click `Let's Begin` button to sign up.
![image](https://user-images.githubusercontent.com/35857179/163138119-be4314f9-22eb-4df6-b0af-b6990c563795.png)
Once you have started NocoDB, you can visit the dashboard via `example.com`. You will be redirected to `example.com/#/signup`.
Enter your work email and your password.
<img width="1485" alt="image" src="https://user-images.githubusercontent.com/35857179/189030350-89a4d361-1f0c-495f-bb03-4958dc5eb556.png">
<alert id="password-conditions">
Your password has at least 8 letters with one uppercase, one number and one special letter
</alert>
![image](https://user-images.githubusercontent.com/35857179/163138460-59ddd93f-a8ef-4c02-8b7b-037a53cefd77.png)
## Initialize Your First Project
Once you have logged into NocoDB, you should see `My Projects`.
![image](https://user-images.githubusercontent.com/35857179/163135335-652470ee-f69e-4b12-8884-63e8056bfce3.png)
<img width="1482" alt="image" src="https://user-images.githubusercontent.com/35857179/189045961-0801accb-e07f-42cd-b679-cab5c3cab8a6.png">
To create a project, you can click `New Project`.
To create a project, you can click `New Project`. You can choose create an empty project or a project connecting to an external database.
![image](https://user-images.githubusercontent.com/35857179/167252813-84876756-f6a1-488a-a185-cbb09f163c5b.png)
<img width="1497" alt="image" src="https://user-images.githubusercontent.com/35857179/189046071-113c424f-c908-4bb6-99f1-a4447337f1fc.png">
### Creating Empty Project
Click `Create`, you need to specify the project name and API type.
Click `Create Project`, you need to specify the project name. The data will be stored in `NC_DB`. If it is not specified, a local SQLite will be created and used.
<alert>
A local SQLite will be used.
NC_DB is an environment variable used to store the meta data in the given database.
</alert>
![image](https://user-images.githubusercontent.com/35857179/163135608-5e135a73-afcd-40bb-9d26-f2970dab7143.png)
<img width="1499" alt="image" src="https://user-images.githubusercontent.com/35857179/189047000-e2f9cf80-fe85-4a79-9e34-76b8a28d66ec.png">
### Connecting to External Database
Click `Create By Connecting To An External Database`, you need to specify the project name, API type, and other database parameters.
<alert type="success">
Tip 1: If you are running NocoDB on Docker and your local DB is running on your host machine, your Host Address would be host.docker.internal instead of localhost.
Tip: If you are running NocoDB on Docker and your local DB is running on your host machine, your Host Address would be host.docker.internal instead of localhost.
</alert>
![image](https://user-images.githubusercontent.com/35857179/163135736-d209061e-893d-4441-aaaa-ff22a1c82ceb.png)
<img width="1500" alt="image" src="https://user-images.githubusercontent.com/35857179/189047070-7600d2f9-bec5-47ed-948e-c6da46202e9c.png">
Currently it supports MySQL, Postgres, MSSQL and SQLite.
![image](https://user-images.githubusercontent.com/35857179/126597320-fd6b19a9-ed3e-4f4a-80b7-880a79a54a11.png)
You can also configure associated SSL & advanced parameters.
![image](https://user-images.githubusercontent.com/35857179/163135911-04e01016-0ffd-4f38-83a8-c667bd268759.png)
<img width="689" alt="image" src="https://user-images.githubusercontent.com/35857179/189047293-05176c44-e162-495a-a7cd-e02377c1f42c.png">
<alert type="success">
Tip 2: You can click Edit Connection JSON and modify SSL settings in "ssl".
Tip: You can click Edit Connection JSON and modify SSL settings in "ssl".
</alert>
```json
@ -83,7 +77,7 @@ Tip 2: You can click Edit Connection JSON and modify SSL settings in "ssl".
```
<alert type="success">
Tip 3: You can click Edit Connection JSON and specify the schema you want to use in "searchPath".
Tip: You can click Edit Connection JSON and specify the schema you want to use in "searchPath".
</alert>
```json
@ -98,4 +92,4 @@ Tip 3: You can click Edit Connection JSON and specify the schema you want to use
Click `Test Database Connection` to see if the connection can be established or not. NocoDB creates a new **empty database** with specified parameters if the database doesn't exist.
![image](https://user-images.githubusercontent.com/35857179/163136039-ad521d74-6996-4173-84ba-cfc55392c3b7.png)
<img width="632" alt="image" src="https://user-images.githubusercontent.com/35857179/189048167-0725c306-12d3-4c5c-91a9-55b0aa63732d.png">

8
packages/noco-docs/content/en/setup-and-usages/formulas.md

@ -8,7 +8,7 @@ menuTitle: "Formulas"
## Adding formula column
![Formula](https://user-images.githubusercontent.com/86527202/144246227-42c44df6-7e3e-4b2c-9bb9-a3c213bcad20.png)
<img width="990" alt="image" src="https://user-images.githubusercontent.com/35857179/189108950-fba76e31-8ae4-4108-916b-e413c841f451.png">
### 1. Click on '+' (Add column)
@ -25,6 +25,12 @@ menuTitle: "Formulas"
### 5. Click on 'Save'
## Editing formula column
Unlike other column types, formula cells cannot be modified by double-clicking since the value is generated based on the formula. Instead, the vaule can be changed by updating the formula in the column setting.
<img width="253" alt="image" src="https://user-images.githubusercontent.com/35857179/189109486-4d41f2b7-0a19-46ef-8bb4-a8d1aabd3592.png">
## Available Formula Features
### Numeric Functions

32
packages/noco-docs/content/en/setup-and-usages/import-airtable-to-sql-database-within-a-minute-for-free.md

@ -47,10 +47,30 @@ Prerequisites: <br/> - A NocoDB Project <br/> - Airtable Credentials
</alert>
Below are 3 simple steps
1. Go to your Project and Click `Add / Import` and click `Airtable`.
![image](https://user-images.githubusercontent.com/35857179/168772072-937b037b-32b3-4e5b-b982-5ee4b9a4959c.png)
![image](https://user-images.githubusercontent.com/35857179/168773192-f3ef9d36-3329-4324-ae25-989b611f66bf.png)
1. Go to your Project, Open `Add / Import` menu and click `Airtable`.
![Screenshot 2022-09-14 at 9 27 51 AM](https://user-images.githubusercontent.com/86527202/190057053-983126b3-287a-4bc4-a1d8-fa89da8f40f8.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/168772072-937b037b-32b3-4e5b-b982-5ee4b9a4959c.png) -->
<!-- ![image](https://user-images.githubusercontent.com/35857179/168773192-f3ef9d36-3329-4324-ae25-989b611f66bf.png) -->
2. Input API key & Shared Base ID / URL (retrieved from `Get Airtable Credentials` above).
![image](https://user-images.githubusercontent.com/35857179/168779663-5bb1dac8-01bd-43fb-8638-318a66a0f4bf.png)
3. Click `Import` and you will see the status.
![image](https://user-images.githubusercontent.com/35857179/168779906-6163b23e-4bcc-4991-8a77-b2fa94e5dcf3.png)
- <1> API Key
- <2> Share Base ID
- <3> Configuration option
- Import Data: disable this option to import only table & view schema's
- Import Secondary Views: disable this option to import only primary grid view per table
- Import Rollup Columns: disable this option to skip Rollup column import
- Import Lookup Columns: disable this option to skip Lookup column import
- Import Attachments Columns: disable this option to skip Attachment column import
- <Not supported yet> Import Formula Columns: disable this option to skip Formula (computation) column import
![Screenshot 2022-09-14 at 9 30 14 AM](https://user-images.githubusercontent.com/86527202/190057133-92807b16-4f2b-4c58-8bae-a2cfe677ee62.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/168779663-5bb1dac8-01bd-43fb-8638-318a66a0f4bf.png) -->
3. Click `Import` and you will see the status
4. Wait until `Go To Dashboard` button is activated on the modal. Import details are captured in log window.
![Screenshot 2022-09-14 at 9 33 42 AM](https://user-images.githubusercontent.com/86527202/190057152-be9ec6cb-e414-465c-8967-d1ad40478ce1.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/168779906-6163b23e-4bcc-4991-8a77-b2fa94e5dcf3.png) -->

8
packages/noco-docs/content/en/setup-and-usages/languages.md

@ -8,12 +8,12 @@ menuTitle: 'Languages'
NocoDB supports multiple lanuages on dashboard. By default, English will be used. However, if you prefer to display in other languages, you can do the following steps to change the language.
Click the icon on top right tool bar
Open `Project Menu` (click on project name on left top to access Project menu)
![image](https://user-images.githubusercontent.com/35857179/161960398-a41f9f23-5786-4a1c-a57e-8c166a2785a5.png)
![Screenshot 2022-09-13 at 11 14 02 AM](https://user-images.githubusercontent.com/86527202/189819445-c1a64ebe-2f6d-41f2-97de-473c48945986.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/161960398-a41f9f23-5786-4a1c-a57e-8c166a2785a5.png) -->
and select the one you prefer. Currently we support the following languages.
and select the one you prefer.
![image](https://user-images.githubusercontent.com/35857179/161960528-fb852ad5-8a12-4fbc-9ad1-7c285980603f.png)
If you want to help translate, please check out <a href ="../engineering/translation" target="_blank">i18n</a>. If you want to request a new language, please create an issue on <a href="https://github.com/nocodb/nocodb/issues" target="_blank">Github</a>.

19
packages/noco-docs/content/en/setup-and-usages/link-to-another-record.md

@ -29,7 +29,7 @@ Workflow details are captured below
## Adding a relationship
![1](https://user-images.githubusercontent.com/86527202/144224170-43f4194f-83d4-4291-8c91-1f66ea1caeda.png)
<img width="1016" alt="image" src="https://user-images.githubusercontent.com/35857179/189105583-20014dd9-e5a6-4f27-b03c-97fad9096b5f.png">
### 1. Create column
@ -45,8 +45,8 @@ Select Column type as "LinkToAnotherRecord" from the drop-down menu
### 4. Choose relationship type
'Has Many': corresponds to the 'One-to-many' relationships
'Many To Many': corresponds to the 'Many-to-many' relationships
- 'Has Many' corresponds to the 'One-to-many' relationships
- 'Many To Many' corresponds to the 'Many-to-many' relationships
### 5. Select child table from drop down menu
@ -59,19 +59,22 @@ A new column will get created in both the parent table & child table
### 1. Open link record tab
Click on the '+' icon in corresponding row - cell
![2truncate](https://user-images.githubusercontent.com/86527202/144224728-1cba50e3-323e-4578-be48-d2a205fb472c.png)
<img width="750" alt="image" src="https://user-images.githubusercontent.com/35857179/189106326-90e46156-798d-4a01-a4eb-4e991ce94c03.png">
### 2. Select from the option displayed
Use 'Filter box' to narrow down on search items
You can opt to insert a new record as well, using "+ New Record" button
![3](https://user-images.githubusercontent.com/86527202/144224530-a258775f-1eea-4c79-88ed-a377d1e35a26.png)
<img width="1014" alt="image" src="https://user-images.githubusercontent.com/35857179/189106494-4b49a200-a44f-41ae-8b54-93b18d867a04.png">
### 3. Column mapping showing "Has Many" relationship
Country 'has many' City
Sheet1 'has many' Sheet2
<img width="756" alt="image" src="https://user-images.githubusercontent.com/35857179/189106702-3b8d7a50-08f4-4a04-b2cb-16db0cf667b3.png">
### 4. Column mapping for "Belongs to" relationship [Automatically updated]
City 'belongs to' Country
![4](https://user-images.githubusercontent.com/86527202/144224542-d28be060-a077-468a-bdc4-b2e8a783d75f.png)
Sheet2 'belongs to' Sheet1
<img width="574" alt="image" src="https://user-images.githubusercontent.com/35857179/189106731-59e5bc3c-bcc5-4796-b5b2-d9b5418bfe2b.png">

64
packages/noco-docs/content/en/setup-and-usages/lookup.md

@ -8,61 +8,35 @@ menuTitle: "Lookup"
## Lookup
### Sample simple Organization structure
- 5 departments (company departments), each department has a team name & associated team code. Vertical **has many** Employees - relationship has been defined
<img src="https://user-images.githubusercontent.com/35857179/161894091-6b6092c2-7184-4fe6-aa17-64ce5a7e97d5.png" width="70%"/>
### Example organization structure
Consider an organization with
- 5 departments (company departments), each department has a team name & associated team code. Each `Team` **has many** `Employees` - relationship has been defined using `LinkToAnotherRecord` column
- 5 employees working at different departments
<img src="https://user-images.githubusercontent.com/35857179/161894109-9b1a45da-c721-4d42-b676-a7c801cc160d.png" width="50%"/>
Now, we can explore how to extract team-code information in Employee table using **LOOKUP** columns
### Adding a lookup column
### 1. Add new column
Click on '+' icon to the left of column headers in Employee table
<img src="https://user-images.githubusercontent.com/35857179/161895281-a43058c9-00be-4e8e-bf12-925284b7bcf8.png" width="70%"/>
### 2. Feed column name
<img src="https://user-images.githubusercontent.com/35857179/161895397-bde8bd31-6e0a-4251-8ffc-a0d0a2605899.png" width="50%"/>
### 3. Select column type as 'Lookup'
<img src="https://user-images.githubusercontent.com/35857179/161895489-046a3ee4-4a42-4a48-95f9-e6cfc92c598a.png" width="50%"/>
### 4. Choose child table
Table Verticals in our example
<img src="https://user-images.githubusercontent.com/35857179/161895601-0e8924ed-9ff0-4215-ab61-151848d01d0d.png" width="50%"/>
### 5. Select child column
<img src="https://user-images.githubusercontent.com/35857179/161895637-e9f9f444-d733-41a4-bd18-8efed6fd16ad.png" width="50%"/>
### 6. Click on 'Save'
<img src="https://user-images.githubusercontent.com/35857179/161895740-e6df9739-178d-4e8c-ba0e-b7537b30b30d.png" width="50%"/>
![Screenshot 2022-09-09 at 12 57 32 PM](https://user-images.githubusercontent.com/86527202/189295738-a4197818-f7d7-4769-acad-13b6d05afe7e.png)
<!-- ![Screenshot 2022-09-09 at 12 18 40 PM](https://user-images.githubusercontent.com/86527202/189291758-21c81ec6-7967-45f1-b49c-b3b6f2701edc.png) -->
<!-- ![Screenshot 2022-09-09 at 12 19 16 PM](https://user-images.githubusercontent.com/86527202/189291766-f619078e-0881-4531-a3f8-ede22269f6fc.png) -->
### 7. Required information is populated in the newly created column
<img src="https://user-images.githubusercontent.com/35857179/161895950-e7b86c0e-74ab-4bf3-b43c-878fe1320fba.png" width="50%"/>
Now, let's explore procedure to retrieve team-code information in Employee table using **LOOKUP** columns
## Nested Lookup
### Configuring a lookup column
#### 1. Add new column : Click on '+' icon to the left of column headers in Employee table
#### 2. Feed column name
#### 3. Select column type as 'Lookup'
#### 4. Choose child table
#### 5. Select child column
#### 6. Click on 'Save'
On top of the previous structure, let's introduce one more table - `Project` which contains `ProjectName` and each employee can be assigned with multiple projects. If we want to include the lookup column `TeamCode` from Employee in Project, we can create a nested lookup.
![Screenshot 2022-09-09 at 12 21 13 PM](https://user-images.githubusercontent.com/86527202/189291720-642a6a96-0b3d-4eaa-886a-20d33a967644.png)
<img src="https://user-images.githubusercontent.com/35857179/161897419-aa00f5eb-3553-46ce-80a1-6c8565366c27.png" width="50%"/>
We can apply the same steps to create the lookup column `TeamCode` in table `Project`. This time we choose the lookup column created previously in table `Employee` as a child table.
Required information is now populated in the newly created column
<img src="https://user-images.githubusercontent.com/35857179/161893922-e1c8b7e5-655b-4096-827c-75105231d9e0.png" width="50%"/>
![Screenshot 2022-09-09 at 12 26 06 PM](https://user-images.githubusercontent.com/86527202/189291679-09503e32-9146-41fa-b28c-d900f2dc35a4.png)
Click save. Then `TeamCode` is populated in table `Project`.
<img src="https://user-images.githubusercontent.com/35857179/161898396-c5c96485-3ec2-4452-88a0-6ed7665d6f34.png" width="50%"/>
## Additional notes
- Nested 'Lookup' supported: a Lookup field can have its child column datatype as Lookup (or Rollup).

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

@ -6,13 +6,15 @@ category: 'Product'
menuTitle: 'Metadata'
---
Project Metadata can be found by clicking `Team & Settings` from the left navigation drawer
Project Metadata includes Database Metadata, UI Access Control and Miscellaneous.
<img width="367" alt="image" src="https://user-images.githubusercontent.com/35857179/170426881-ba645392-24a2-4446-b501-0595a0887724.png">
To access it, click the down arrow button next to Project Name on the top left side, then select `Team & Settings`.
<img width="390" alt="image" src="https://user-images.githubusercontent.com/35857179/189115289-07657c15-deab-435f-b0f9-2948007f8c65.png">
and clicking `Project Metadata`.
![image](https://user-images.githubusercontent.com/35857179/170427133-09faf93f-a41c-428b-b51c-fefe3fb45d9d.png)
<img width="244" alt="image" src="https://user-images.githubusercontent.com/35857179/189116366-c58de4c1-c62d-4ac9-8362-aa08ff92005f.png">
<!-- ## Project Metadata
@ -53,10 +55,16 @@ From the destination project, go to `Project Metadata`. Under ``Export / Import
Go to `Project Metadata`, under ``Metadata``, you can see your metadata sync status. If it is out of sync, you can sync the schema. See <a href="./sync-schema">Sync Schema</a> for more.
<img width="1339" alt="image" src="https://user-images.githubusercontent.com/35857179/170427543-07dfdc30-b8f9-4e4f-bd5b-96f93a16b2fe.png">
<img width="1480" alt="image" src="https://user-images.githubusercontent.com/35857179/189116339-22b202ef-7674-4682-bab7-2b8625e13ea2.png">
## UI Access Control
Go to `Project Metadata`, under ``UI Access Control``, you can control the access to each table by roles.
<img width="1335" alt="image" src="https://user-images.githubusercontent.com/35857179/170427529-8bb403bc-0c1f-43ff-868a-c17c8ce9b778.png">
<img width="1480" alt="image" src="https://user-images.githubusercontent.com/35857179/189116502-78a0dc75-70cb-4bbe-a676-93af53ecca22.png">
## Miscellaneous
Currently only `Show M2M Tables` can be configurated under Miscellaneous.
<img width="1495" alt="image" src="https://user-images.githubusercontent.com/35857179/189116547-3c5ce944-82c0-4068-b91c-60f45b862d32.png">

6
packages/noco-docs/content/en/setup-and-usages/primary-key.md

@ -35,10 +35,10 @@ It is possible to have a table without any primary key.
In such scenario's, new records can be created in NocoDB for this table, but records can't be updated or deleted [as there is now way for NocoDB to uniquely identify these records]
#### Example : Primary Key & optional system fields during new table creation
![Screenshot 2022-06-16 at 12 15 43 PM](https://user-images.githubusercontent.com/86527202/174010350-8610b9c1-a761-4bff-a53d-dc728df47e1b.png)
<img width="596" alt="image" src="https://user-images.githubusercontent.com/35857179/189113679-481bceab-8957-4c5d-a38c-9940f03cfd7e.png">
#### Example : Show System Fields
![Screenshot 2022-06-16 at 12 16 07 PM](https://user-images.githubusercontent.com/86527202/174010379-9e300d42-ad89-4653-afa2-f70fca407ca8.png)
<img width="309" alt="image" src="https://user-images.githubusercontent.com/35857179/189113907-871f7ab0-9bb2-4f04-a726-2d9feb56892e.png">
## Can I change the Primary Key to another column within tables ?
- You can't update Primary Key from NocoDB UI. You can reconfigure it at database level directly & trigger `metasync` explicitly
- You can't update Primary Key from NocoDB UI. You can reconfigure it at database level directly & trigger `meta sync` explicitly.

24
packages/noco-docs/content/en/setup-and-usages/primary-value.md

@ -1,9 +1,9 @@
---
title: "Primary value"
title: "Primary Value"
description: "Understanding Primary Value in NocoDB!"
position: 580
category: "Product"
menuTitle: "Primary value"
menuTitle: "Primary Value"
---
## What is a Primary Value ?
@ -14,19 +14,27 @@ menuTitle: "Primary value"
- Within a spreadsheet, primary value are always highlighted so that it is easier to recognise what row we are in.
- And when LinkToAnotherRecord is created between two tables - it is the primary value that appears in LinkToAnotheRecord column.
#### Example : Primary Value highlighted in actor table
<img width="547" alt="actor" src="https://user-images.githubusercontent.com/5435402/152645708-92b83985-4a0a-42b2-9d01-d26be70fd3aa.png">
#### Example : Primary Value highlighted in Actor table
<img width="646" alt="image" src="https://user-images.githubusercontent.com/35857179/189114321-58ebaa16-20e2-4615-abda-39417a5df5bf.png">
#### Example : Primary Value highlighted in film table
<img width="1406" alt="film-table" src="https://user-images.githubusercontent.com/5435402/152645713-b4df99b2-4eb7-4fea-85f9-0baf47470ef3.png">
#### Example : Primary Value highlighted in Film table
<img width="643" alt="image" src="https://user-images.githubusercontent.com/35857179/189114462-a7fef0e2-f9ac-4943-98d5-fee9f60a4ab5.png">
#### Example : Primary Value associated when LinkToAnotherRecord is created
<img width="753" alt="actor-film" src="https://user-images.githubusercontent.com/5435402/152645714-4061c94a-4cfb-44e5-b112-63cf4ed869fe.png">
<img width="311" alt="image" src="https://user-images.githubusercontent.com/35857179/189114548-193acc4d-f714-4204-a560-97668db7884c.png">
## How to set Primary Value ?
Click down arrow in the target column. Click `Set as Primary Value`.
<img width="251" alt="image" src="https://user-images.githubusercontent.com/35857179/189114857-b452aa6b-5cdb-4a74-9980-cb839d7d15fd.png">
## How is Primary Value identfied for existing database tables ?
- It is usually the first column after the primary key which is not a number.
- If there is no column which is not a number then the column adjacent to primary key is chosen.
## Can I change the Primary Value to another column within tables ?
- Yes, you can. Hover over column which you want as primary column and click ```Set as Primary Value```
- Yes, you can use the same way mentioned above to set Primary Value.

50
packages/noco-docs/content/en/setup-and-usages/rollup.md

@ -8,13 +8,14 @@ menuTitle: "Rollup"
## Rollup
Sample simple Organization structure:
Sample Organization structure:
- 5 Departments (company departments), each department has a team name & associated team code
- 5 Departments, each department has a team name & associated team code
- 5 employees working at different Departments
- Vertical **has many** Employees : relationship has been defined
- Teams **has many** Employees : relationship has been defined
![Screenshot 2022-09-09 at 12 57 32 PM](https://user-images.githubusercontent.com/86527202/189296162-536185f1-31ed-40df-b668-deed7ad630aa.png)
![LookUp](https://user-images.githubusercontent.com/86527202/144038845-402d5401-a214-4166-bc07-fcf8dcc8a961.png)
### RollUp AGGREGATION functions supported
@ -27,46 +28,53 @@ Sample simple Organization structure:
- Sum Distinct
- Average Distinct
Now, we can explore how to extract employee count information per vertical using **"ROLLUP"** columns
Now, we can explore how to extract employee count information per team using **"ROLLUP"** columns
## Adding a rollup column
### 1. Add new column
#### 1. Add new column
Click on '+' icon to the left of column headers in Departments table
![1](https://user-images.githubusercontent.com/86527202/144236273-484edc5b-7f5f-4041-b480-db08d4459d07.png)
<!-- ![1](https://user-images.githubusercontent.com/86527202/144236273-484edc5b-7f5f-4041-b480-db08d4459d07.png) -->
### 2. Feed column name
#### 2. Feed column name
![2](https://user-images.githubusercontent.com/86527202/144236279-41904955-4990-4a23-bec6-b0953002eac6.png)
<!-- ![2](https://user-images.githubusercontent.com/86527202/144236279-41904955-4990-4a23-bec6-b0953002eac6.png) -->
### 3. Select Column type as 'Rollup'
#### 3. Select Column type as 'Rollup'
![3](https://user-images.githubusercontent.com/86527202/144236283-4596e3e1-3bf8-488f-bc9b-8ec1466a35c6.png)
<!-- ![3](https://user-images.githubusercontent.com/86527202/144236283-4596e3e1-3bf8-488f-bc9b-8ec1466a35c6.png) -->
### 4. Choose Child Table
#### 4. Choose Child Table
Table Employee in our example
![4](https://user-images.githubusercontent.com/86527202/144236284-301178d8-f452-4d1e-9dff-80dd9570c280.png)
<!-- ![4](https://user-images.githubusercontent.com/86527202/144236284-301178d8-f452-4d1e-9dff-80dd9570c280.png) -->
### 5. Choose on Child column
#### 5. Choose on Child column
Pick appropriate column for aggreagation
![5](https://user-images.githubusercontent.com/86527202/144236286-28547d74-feb8-4ad8-a872-7ba809e5db1e.png)
<!-- ![5](https://user-images.githubusercontent.com/86527202/144236286-28547d74-feb8-4ad8-a872-7ba809e5db1e.png) -->
### 6. Select Aggregate function
#### 6. Select Aggregate function
Aggregate function will be "count" in our case
![6](https://user-images.githubusercontent.com/86527202/144236288-34a567d5-a5e9-4a1e-b074-5ea633e799a3.png)
<!-- ![6](https://user-images.githubusercontent.com/86527202/144236288-34a567d5-a5e9-4a1e-b074-5ea633e799a3.png) -->
#### 7. Click on Save
![Screenshot 2022-09-09 at 1 03 49 PM](https://user-images.githubusercontent.com/86527202/189297619-4d5c815b-6c97-41fa-978e-9b645448e508.png)
<!-- ![7](https://user-images.githubusercontent.com/86527202/144236289-5872529a-ba47-428d-979e-fdefb92a1039.png) -->
### 7. Click on Save
Column `Employee Count` is populated with appropriate information
![7](https://user-images.githubusercontent.com/86527202/144236289-5872529a-ba47-428d-979e-fdefb92a1039.png)
![Screenshot 2022-09-09 at 1 07 45 PM](https://user-images.githubusercontent.com/86527202/189297662-c7ff1e3e-eec7-4108-a089-6c945b90b867.png)
### 8. Column TeamCount is populated with appropriate information
![8](https://user-images.githubusercontent.com/86527202/144236291-52855f92-ad8b-4be1-aa98-b5cfdb1ee108.png)
<!-- ![8](https://user-images.githubusercontent.com/86527202/144236291-52855f92-ad8b-4be1-aa98-b5cfdb1ee108.png) -->

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

@ -8,26 +8,28 @@ menuTitle: 'Sync Schema'
## How to sync schema changes to NocoDB
NocoDB allows you to sync schema changes if you have made changes outside NocoDB GUI. However, it has to be noted then you will have to bring your own schema migrations for moving from environment to others.
NocoDB allows you to sync schema changes if you have made changes outside NocoDB GUI. However, it has to be noted then you will have to bring your own schema migrations for moving from one environment to other.
Below are the steps to sync schema changes.
### 1. From the menu bar, click `Team & Settings`
### 1. From the `Project menu`, click `Team & Settings`
<img width="367" alt="image" src="https://user-images.githubusercontent.com/35857179/170426881-ba645392-24a2-4446-b501-0595a0887724.png">
<img width="390" alt="image" src="https://user-images.githubusercontent.com/35857179/189115289-07657c15-deab-435f-b0f9-2948007f8c65.png">
### 2. Click `Project Metadata` under SETTINGS and click `Metadata`
### 2. Click `Project Metadata` under SETTINGS, access `Metadata` tab
![image](https://user-images.githubusercontent.com/35857179/170427133-09faf93f-a41c-428b-b51c-fefe3fb45d9d.png)
![Screenshot 2022-09-13 at 10 37 17 AM](https://user-images.githubusercontent.com/86527202/189814111-56036958-c6e4-4560-af1e-9443380db080.png)
### 3. Changes carried outside GUI, identified by NocoDB are listed under `Sync state`
- If changes made to the database are not visible, click `Reload`
- Identified schema changes are identified for each table in `red`
- `Sync now` button gets activated, if Schema changes are identified by NocoDB
![image](https://user-images.githubusercontent.com/35857179/161957119-f66f22ad-9d37-45ed-84ca-35c99726078c.png)
![Screenshot 2022-09-13 at 10 42 12 AM](https://user-images.githubusercontent.com/86527202/189814648-ca28f28d-b0ed-4652-a5da-e6472bfd9407.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/161957119-f66f22ad-9d37-45ed-84ca-35c99726078c.png) -->
### 4. Click `Sync Now` to complete Schema sync procedure
<img width="1352" alt="image" src="https://user-images.githubusercontent.com/35857179/170428004-022dd436-0c58-41c5-b5e6-89d1d3ac87b0.png">
#### Notes
1. Column rename operation will be treated like `column delete` & `column create` operation.

123
packages/noco-docs/content/en/setup-and-usages/table-operations.md

@ -6,7 +6,7 @@ category: "Product"
menuTitle: "Table Operations"
---
Once you have created a new NocoDB project you can open it, In the browser, the URL would be like `example.com/dashboard/#/nc/project_id`.
Once you have created a new NocoDB project you can open it, In the browser, the URL would be like `example.com/dashboard/#/nc/<project_id>`.
## Table
@ -14,35 +14,48 @@ Once you have created a new NocoDB project you can open it, In the browser, the
Now you can start creating new tables by simply clicking one of the following options.
- Click the plus button next to Table menu
- Click Add / Import, then click Add new table
- Click `Add new table` button
- Hover `Add new table` button in table menu, click three dots, use Quick Import to create
- Drag and drop CSV, JSON or Excel file to import
<img width="632" alt="image" src="https://user-images.githubusercontent.com/35857179/168772379-63d7e92c-39ce-4d91-ac1e-279591833e0e.png">
<img width="1508" alt="image" src="https://user-images.githubusercontent.com/35857179/189051917-d6b07f21-845c-4519-a1c5-4b26bbfcf04b.png">
A modal will be popped up. Input the corresponding info and enable or disable default columns and click `Submit` button.
![table_create_modal](https://user-images.githubusercontent.com/61551451/126772859-5a301c45-d830-4df2-a05a-43b15dd77728.png)
<img width="1500" alt="image" src="https://user-images.githubusercontent.com/35857179/189052476-505c7e6d-ff67-4cbe-aec1-6b3eec374030.png">
Click Show more for advanced settings.
<alert>
Note: You can't disable the `id` column since NocoDB needs a primary column for every table. You can rename it after the creation.
</alert>
<img width="1500" alt="image" src="https://user-images.githubusercontent.com/35857179/189052642-ab77a791-fdd6-42f6-b2b6-fcc972859939.png">
After the successful submission, the table will be created and open as a new tab.
![table_created](https://user-images.githubusercontent.com/35857179/168411541-b0233cf1-4683-490b-bdec-f2546a2d9015.png)
<img width="1501" alt="image" src="https://user-images.githubusercontent.com/35857179/189052804-deea1ed7-6b62-4c00-8aca-fed00151d3c9.png">
### Table Rename
Right click on Table name on left hand project-tree menu, select `Rename`
<img width="651" alt="image" src="https://user-images.githubusercontent.com/35857179/189052896-2313dd1f-8baf-4cc3-8ef2-ff007d3ff920.png">
In modal popup, enter new table name and click `Submit` button
<img src="https://user-images.githubusercontent.com/86527202/144403447-1b2e4368-eb2b-40c0-901a-54e8adf9a80c.png" width="60%"/>
<img width="1507" alt="image" src="https://user-images.githubusercontent.com/35857179/189052935-c6403bd9-4b91-40ba-91d6-a34abfcfa21f.png">
### Table Delete
The table can be deleted using the `delete` icon present in the toolbar within the table tab.
Right click on Table name on left hand project-tree menu, select `Delete`
![image](https://user-images.githubusercontent.com/35857179/168411589-540f50d2-78e3-4d97-b17c-1b9fad9f90b7.png)
<img width="617" alt="image" src="https://user-images.githubusercontent.com/35857179/189053090-806c62d5-6028-444f-93eb-6ccb9345dd52.png">
Click Yes to confirm the table deletion
<img width="1506" alt="image" src="https://user-images.githubusercontent.com/35857179/189053138-54f6a85a-e9e3-4cad-b127-df19ccdd184e.png">
## Column
@ -50,34 +63,39 @@ The table can be deleted using the `delete` icon present in the toolbar within t
Click the `+` icon on the right corner of the table.
![Pasted_Image_23_07_21__4_39_PM](https://user-images.githubusercontent.com/61551451/126773798-4470d632-69e0-4f5f-803b-e3597715fe22.png)
<img width="352" alt="image" src="https://user-images.githubusercontent.com/35857179/189053971-a3d29b3b-1177-49fe-8178-8868528fe3e7.png">
After the click, it will show a menu and you can enter the column name and choose the column type ([Abstract type](./abstract-types)).
Click `Save`button to create the new column.
After the click, it will show a menu and you can enter the column name and choose the column type. (See [Column Types](./column-types) for the full list).
![image](https://user-images.githubusercontent.com/61551451/126774157-ae9af236-e1ad-4a54-adb7-1b96775cae57.png)
<img width="459" alt="image" src="https://user-images.githubusercontent.com/35857179/189073266-a0f19e2e-5dd2-4343-8c74-4ef709da272c.png">
& we have new column created as part of our table
![Pasted_Image_23_07_21__4_43_PM](https://user-images.githubusercontent.com/61551451/126774276-e947f510-2fe1-4595-afc1-a31d2c35a69a.png)
You can also click `Show more` for additional menu options.
> For more about Abstract type [click here](./abstract-types).
<img width="445" alt="image" src="https://user-images.githubusercontent.com/35857179/189075678-d18b799f-df13-4f78-a5a5-813e8d3277ae.png">
Click `Save` button to create the new column.
<img width="909" alt="image" src="https://user-images.githubusercontent.com/35857179/189075920-30acaf44-eba7-4fa6-ab93-a576ce88ef23.png">
### Column Edit
To edit column properties, click/hover on down arrow, select `Edit` from the menu.
<img src="https://user-images.githubusercontent.com/86527202/144404169-80d8b514-53cf-4bb1-8323-fd3cfda8816b.png" width="50%"/>
To edit column properties, click the down arrow, select `Edit` from the menu.
You will be able to edit column name & associated datatype using pop-up modal.
For additional menu options, click `Show more options`
<img width="230" alt="image" src="https://user-images.githubusercontent.com/35857179/189077129-dfb7a815-3fc7-41ea-b72c-e57f3c30a7f4.png">
<img src="https://user-images.githubusercontent.com/86527202/144404188-146ab0dc-bd2b-4902-9369-a34253e2fad6.png" width="40%"/>
You will be able to edit column name & associated datatype using pop-up modal. You can also click `Show more` for additional menu options.
<img width="497" alt="image" src="https://user-images.githubusercontent.com/35857179/189077270-7acdc818-3747-4307-93fb-e970cb7936f9.png">
### Column Delete
Column deletion can be done by using the `delete` option from the column header menu.
To delete a column, click the down arrow, select `Delete` from the menu.
<img width="256" alt="image" src="https://user-images.githubusercontent.com/35857179/189077566-c9376e4e-9ee8-4ffa-b437-1240894a30cd.png">
Click `Yes` to confirm the column deletion.
![Pasted_Image_23_07_21__6_49_PM](https://user-images.githubusercontent.com/61551451/126787679-562aaa22-14b3-4ff8-8057-b8219e057110.png)
<img width="1507" alt="image" src="https://user-images.githubusercontent.com/35857179/189077741-b2e271af-1f0a-4de8-8e99-acb349d3c6aa.png">
## Row
@ -86,17 +104,18 @@ For adding new values to the table we need new rows, new rows can be added in tw
### Row Add (Using Form)
- Click the `+` icon in the toolbar of the table tab.
<img src="https://user-images.githubusercontent.com/86527202/144405563-50573b1c-1bd3-43ea-8020-357fc7ef9e42.png" width="50%"/>
- Now it will open a modal Form to enter the values, provide the values and press the save button.
<img src="https://user-images.githubusercontent.com/61551451/126784347-b82f9dfd-4c6d-4d65-be07-80e051ff19de.png" width="75%">
<img width="1038" alt="image" src="https://user-images.githubusercontent.com/35857179/189079143-8f3e3dd6-9b62-4fb0-9a78-a57545026d11.png">
- Then you can enter the values and click `Save row`.
<img width="1498" alt="image" src="https://user-images.githubusercontent.com/35857179/189079268-5b1da462-624b-4cac-9820-e2ed3ed421af.png">
- After saving it will be there on your table.
![image](https://user-images.githubusercontent.com/61551451/126785340-e9b80ad0-ba06-4a22-8a01-876d829c9673.png)
<img width="1501" alt="image" src="https://user-images.githubusercontent.com/35857179/189079668-5f7b0b53-8d62-41b5-acc0-2fa38cd8a144.png">
### Row Add (Using Table Row at bottom of page)
- Click the bottom row of the table which contains `+` icon at the beginning.
<img src="https://user-images.githubusercontent.com/86527202/144405773-bb0d00ef-264d-4941-b01f-3b7f0b1fc54d.png" width="40%"/>
- Now it will add a new row in the table
- Click the bottom row of the table `+ Add new row`.
<img width="545" alt="image" src="https://user-images.githubusercontent.com/35857179/189079815-9a7ea5e3-4eb7-452e-99a8-78c271f2ad1f.png">
- A new empty row will be created
<img width="567" alt="image" src="https://user-images.githubusercontent.com/35857179/189080009-3aeb70b4-92b0-4702-acb9-e5e52e31855e.png">
### Row Edit
You can start editing by any of the following methods
@ -109,13 +128,17 @@ You can start editing by any of the following methods
Right-click on anywhere in the row and then from the context menu select `Delete Row` option.
Bulk delete is also possible by selecting multiple rows by using the checkbox in first column and then `Delete Selected Rows` options from the right click context menu.
<img src="https://user-images.githubusercontent.com/86527202/144406191-ccff1382-e808-44e8-babe-bd937faf1b3d.png" width="40%"/>
<img width="568" alt="image" src="https://user-images.githubusercontent.com/35857179/189081764-9f13c286-e02a-40d0-93ea-4b1362d96827.png">
## Quick Import
You can use Quick Import when you have data from external sources such as Airtable, CSV file or Microsoft Excel to an existing project by clicking `Add / Import` and choosing the corresponding options.
You can use Quick Import when you have data from external sources such as Airtable, CSV file or Microsoft Excel to an existing project by either
- Hover `Add new table` button in table menu, click three dots, use Quick Import to create
- Drag and drop CSV, JSON or Excel file to import
![image](https://user-images.githubusercontent.com/35857179/168772072-937b037b-32b3-4e5b-b982-5ee4b9a4959c.png)
<img width="1508" alt="image" src="https://user-images.githubusercontent.com/35857179/189051917-d6b07f21-845c-4519-a1c5-4b26bbfcf04b.png">
### Import Airtable into an existing project
@ -123,36 +146,38 @@ You can use Quick Import when you have data from external sources such as Airtab
### Import CSV data into an existing project
- Click `Add / Import` and click `CSV file`
- Drag & drop or select file to upload or specify Excel file URL
![image](https://user-images.githubusercontent.com/35857179/168412051-ed988659-011d-455b-ba32-be0a2e1184b0.png)
- You can revise the table name, column name and column type. By default, the first column will be chosen as <a href="./primary-value" target="_blank">Primary Value</a> and cannot be deleted.
![image](https://user-images.githubusercontent.com/35857179/168412069-aea8a8fb-09ab-4412-95b7-963bdbe24cfc.png)
- Click `Import CSV` to start importing process. The table will be created and the data will be imported.
![image](https://user-images.githubusercontent.com/35857179/168412172-9bb24ab9-da15-45cf-9b12-3af362fc604a.png)
- Hover `Add new table` button in table menu, click three dots, and click `CSV file`
- Drag & drop or select file to upload or specify CSV file URL
<img width="1508" alt="image" src="https://user-images.githubusercontent.com/35857179/189083344-79ac27a6-d32e-46e9-9d73-95f4ce8f37de.png">
- Click `Import`
<img width="1502" alt="image" src="https://user-images.githubusercontent.com/35857179/189083577-3c7fef66-0bf2-4d61-be22-dee365b93a8c.png">
- You can revise the table name by double clicking it, column name and column type. By default, the first column will be chosen as <a href="./primary-value" target="_blank">Primary Value</a> and cannot be deleted.
<img width="1506" alt="image" src="https://user-images.githubusercontent.com/35857179/189083667-cf9ce8a9-0126-478e-872d-b554ea9e0e87.png">
- Click `Import` to start importing process. The table will be created and the data will be imported.
<img width="1500" alt="image" src="https://user-images.githubusercontent.com/35857179/189085568-daac2690-2883-4ddd-8a51-ea27bda8630e.png">
### Import Excel data into an existing project
- Click `Add / Import` and click `Microsoft Excel`
- Hover `Add new table` button in table menu, click three dots, and click `Microsoft Excel`
- Drag & drop or select file to upload or specify Excel file URL
![image](https://user-images.githubusercontent.com/35857179/168412483-a12f7d90-1b91-48bb-96a7-2a16dc8c7b81.png)
<img width="1495" alt="image" src="https://user-images.githubusercontent.com/35857179/189088426-f0f585ae-a6ac-455c-a4ed-0a9b95b0f381.png">
- You can revise the table name, column name and column type. By default, the first column will be chosen as <a href="./primary-value" target="_blank">Primary Value</a> and cannot be deleted.
<alert>
Note: If your Excel file contains multiple sheets, each sheet will be stored in a separate table.
</alert>
![image](https://user-images.githubusercontent.com/35857179/168412465-e46b4fcf-ec1c-4d32-bb56-eb62516829f5.png)
- Click `Import Excel` to start importing process. The table(s) will be created and the data will be imported to the corresponding table(s).
![image](https://user-images.githubusercontent.com/35857179/168413233-adfb85e2-8d52-46d8-a754-e2ec9f8d3234.png)
<img width="1484" alt="image" src="https://user-images.githubusercontent.com/35857179/189093528-f3c9cc04-de4c-4a87-aae5-9429d1bd50df.png">
- Click `Import` to start importing process. The table(s) will be created and the data will be imported to the corresponding table(s).
<img width="1501" alt="image" src="https://user-images.githubusercontent.com/35857179/189093670-abd3e192-8ed2-481f-9add-ad0f30f3d862.png">
## Export Data
You can export your data from a table as a CSV file by clicking `More` and `Download as CSV`.
You can export your data from a table as a CSV file by clicking the down arrow next to Table name and hover on `Download`. Currently only CSV and XLSX formats are supported for export.
![image](https://user-images.githubusercontent.com/35857179/163556138-2aa0a782-12e9-49c7-aadf-b7778e91557f.png)
<img width="887" alt="image" src="https://user-images.githubusercontent.com/35857179/189094800-a77dedf7-1bad-4a68-abf4-626688e62524.png">
## Import Data
You can import your data in CSV format to a table by clicking `More` and `Upload CSV`.
You can import your data in CSV format to a table by clicking the down arrow next to Table name and hover on `Upload`. Currently only CSV format is supported for upload.
![image](https://user-images.githubusercontent.com/35857179/163556175-116b12c2-ca2e-4b54-a65a-39250541d873.png)
<img width="1095" alt="image" src="https://user-images.githubusercontent.com/35857179/189094939-33a4c87c-66d8-4951-98b4-886ead470ce0.png">

36
packages/noco-docs/content/en/setup-and-usages/team-and-auth.md

@ -6,16 +6,25 @@ category: 'Product'
menuTitle: 'Team & Auth'
---
Team & Auth can be found by clicking `Team & Settings` from the left navigation drawer and clicking `Team & Auth`.
# Accessing Team & Auth
- Click on `Team & Settings` from the `Project Menu`
- Access `Team & Auth` under `Settings`
![image](https://user-images.githubusercontent.com/35857179/161902474-fd06678c-a171-4237-b171-dc028b3753de.png)
![image](https://user-images.githubusercontent.com/35857179/161902746-aa59b8e5-06d2-4c07-ac60-c82f92b42752.png)
<img width="390" alt="image" src="https://user-images.githubusercontent.com/35857179/189115289-07657c15-deab-435f-b0f9-2948007f8c65.png">
![Screenshot 2022-09-13 at 10 52 55 AM](https://user-images.githubusercontent.com/86527202/189816444-1591fed2-52d5-4031-b462-f1ad2a72df20.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/161902746-aa59b8e5-06d2-4c07-ac60-c82f92b42752.png) -->
## How to Add a User
1. Go to `Team & Auth`, click on `New User`.
![image](https://user-images.githubusercontent.com/35857179/161903214-1e0f7ba0-6daf-4073-90c9-9d86a40c9f90.png)
1. Go to `Team & Auth`, click on `Invite Team`
![Screenshot 2022-09-13 at 10 52 55 AM](https://user-images.githubusercontent.com/86527202/189817510-089371d9-1a47-40fa-9dad-0c7b0cea2de0.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/161903214-1e0f7ba0-6daf-4073-90c9-9d86a40c9f90.png) -->
2. Enter the user's `E-mail`. Select `User Role`, and Click `Invite`.
@ -23,14 +32,25 @@ Team & Auth can be found by clicking `Team & Settings` from the left navigation
Tip: You can add multiple comma (,) seperated emails
</alert>
![image](https://user-images.githubusercontent.com/35857179/161903296-cd6ea0d5-193f-4e66-aa7a-4cfc468216af.png)
![Screenshot 2022-09-13 at 10 54 39 AM](https://user-images.githubusercontent.com/86527202/189817152-83fca866-7713-49ee-8068-d3eba1311353.png)
If you do not have an SMTP sender configured, make sure to copy the invite link and manually send it to your collaborator.
![image](https://user-images.githubusercontent.com/35857179/161903764-1c875441-87f4-4b25-a864-441a23c96cea.png)
![Screenshot 2022-09-13 at 10 54 22 AM](https://user-images.githubusercontent.com/86527202/189817156-f3dab634-dc25-4f9b-8126-865187aae254.png)
## How to Update user permissions
1. Use `Edit` <1> menu to assign a different role to existing user
2. Use `Delete` <2> menu to remove a user from accessing current project
![Screenshot 2022-09-13 at 11 06 16 AM](https://user-images.githubusercontent.com/86527202/189818302-80a05245-9dc1-4364-b380-7bd698e5b9e0.png)
------
## User Role Permissions
# User Role Permissions
### Advanced Options & Configurations
| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; Owner &nbsp; &nbsp;| &nbsp; &nbsp; Creator &nbsp; &nbsp; | &nbsp; &nbsp; Editor &nbsp; &nbsp;| Commenter | &nbsp; &nbsp; Viewer &nbsp; &nbsp;|

72
packages/noco-docs/content/en/setup-and-usages/views.md

@ -10,9 +10,17 @@ menuTitle: 'Views'
In a table, you can use different views to display your data. You can show specific fields in a View. You can also apply Sorting or Filtering to the View. Each View is independent, which means the configuration applying to View 1 will not apply to View 2.
To navigate different views, we can select the target one in the view sidebar. By default, Grid View will be created for you after creating the table.You can create multiple views with the same type as you wish, as long as they have unique View names.
To navigate different views, we can select the target one in the view sidebar. By default, Grid View will be created for you after creating the table. You can create multiple views of a type, as long as they have unique View names.
![image](https://user-images.githubusercontent.com/35857179/163340916-d1101709-2051-4d0e-9d86-dd14eced49e9.png)
## View Menu Bar
To work with `Views`, use View menu-bar on the right hand side -
- <1> Toggle View menu-bar.
- <2> Displays created view-list for the selected table
- Currently active view is high-lighted
- <3> Add new view to the list
![Screenshot 2022-09-09 at 2 56 15 PM](https://user-images.githubusercontent.com/86527202/189321194-303c4a8c-d9a1-4368-962c-c7596763efb6.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/163340916-d1101709-2051-4d0e-9d86-dd14eced49e9.png) -->
## View Types
@ -20,74 +28,82 @@ To navigate different views, we can select the target one in the view sidebar. B
Grid View, as a default type of view, allows you to display your data in a spreadsheet-like interface.
![image](https://user-images.githubusercontent.com/35857179/163343433-f6594d6e-5874-45ae-b403-5774247659bb.png)
![image](https://user-images.githubusercontent.com/86527202/189322133-04bddf2b-c885-49ca-aa8e-2a09ac755555.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/163343433-f6594d6e-5874-45ae-b403-5774247659bb.png) -->
### Form View
Form View allows you to arrange fields in a form to input data.
![image](https://user-images.githubusercontent.com/35857179/163355269-73d2a9d4-bafb-47c0-8c0d-d0e66503b47a.png)
https://user-images.githubusercontent.com/35857179/188585121-94d0260d-6dbd-4e34-9758-a1a3709fc416.png
<!-- ![image](https://user-images.githubusercontent.com/35857179/163355269-73d2a9d4-bafb-47c0-8c0d-d0e66503b47a.png) -->
You can show and hide some fields using drag-and-drop fashion.
You can drag-drop columns from the form to form-field-menu-bar as requried.
![image](https://user-images.githubusercontent.com/35857179/163355377-6b365472-efae-4f73-a103-5dde7c1f8ea7.png)
### Gallery View
Gallery View allows you to display images as thumbnails with other fields just like a gallery.
<!-- TODO: add screenshots -->
## View Permission Types
![image](https://user-images.githubusercontent.com/86527202/189322216-f8df0b69-5177-4ebc-be28-c11e3efb41a4.png)
We can apply permission to each View. By default, Collaborative Views will be used. To see or change the view type, check the first icon above the View sidebar.
![image](https://user-images.githubusercontent.com/35857179/163343598-fd81edea-f160-41ee-8bb2-3ef1eee5348d.png)
## View Permission Types
### Collaborative Views
We can apply permission to each View. By default, Collaborative Views will be used. To see or change the view type, expand `view-tool-bar-menu` as shown below.
Collaborative View allows you to work with your collaborators with edit permissions.
![Screenshot 2022-09-09 at 3 46 33 PM](https://user-images.githubusercontent.com/86527202/189328303-edbf35b5-f793-4e06-9dbf-89d045a38482.png)
<!-- ![Screenshot 2022-09-09 at 3 19 00 PM](https://user-images.githubusercontent.com/86527202/189323062-5be6bd3f-366a-4be2-8de0-df30fcd1808e.png) -->
<!-- ![image](https://user-images.githubusercontent.com/35857179/163343598-fd81edea-f160-41ee-8bb2-3ef1eee5348d.png) -->
![image](https://user-images.githubusercontent.com/35857179/163343959-7e2f43cb-1a1f-4f36-985c-ca91db262f98.png)
### Collaborative Views (default)
- Collaborators with edit permissions or higher can change the view configurations
<!-- ![image](https://user-images.githubusercontent.com/35857179/163343959-7e2f43cb-1a1f-4f36-985c-ca91db262f98.png) -->
### Locked Views
- No one can edit view configurations until it is Unlocked
- All collaborators can only READ data from such views
Locked View allows you to lock the current View so that no one can edit the View including applying operations such as Sorting or Filtering.
### Personal Views
- Only you can edit the view configuration.
- Your personal views are hidden for other collaborators
- Are not available currently; will be enabled in future release
<!-- ![image](https://user-images.githubusercontent.com/35857179/163343845-b07f9d3f-5a83-4dfd-8d45-9cc59b3512c3.png) -->
![image](https://user-images.githubusercontent.com/35857179/163343845-b07f9d3f-5a83-4dfd-8d45-9cc59b3512c3.png)
## View Operations
### Create a View
![Screenshot 2022-09-09 at 3 27 46 PM](https://user-images.githubusercontent.com/86527202/189325592-302054da-a755-4a92-a322-80aed184ca3b.png)
Click '+' in View sidebar.
### Create a View
![image](https://user-images.githubusercontent.com/35857179/163353610-ae85967c-91ac-404f-b3b3-bd122e09f492.png)
Click '+' in View-menu sidebar, as shown in <3>.
### Rename a View
Hover the target View, click the icon and enter the new name.
Double click on `view-name`, edit, <enter>.
![image](https://user-images.githubusercontent.com/35857179/163353802-1da52cec-ae17-4ced-8679-62d7180683ec.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/163353802-1da52cec-ae17-4ced-8679-62d7180683ec.png) -->
### Delete a View
Hover the target View and click the delete icon.
Hover the target View and click the delete icon, as shown in <2>.
<alert>
You cannot delete the very first Grid View.
You cannot delete the very first Grid View (termed as `Default view`).
</alert>
![image](https://user-images.githubusercontent.com/35857179/163359795-f4420402-b2a6-41d8-b48c-f0dea8b9abbe.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/163359795-f4420402-b2a6-41d8-b48c-f0dea8b9abbe.png) -->
### Duplicate a View
Hover the target View and click the icon and enter the new name.
Hover the target View and click the copy icon, as shown in <2>.
![image](https://user-images.githubusercontent.com/35857179/163353865-7275499e-c685-44f4-906c-ba08f0ee419e.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/163353865-7275499e-c685-44f4-906c-ba08f0ee419e.png) -->
### Reorder a View
Hover the target View and re-order it as needed by dragging and dropping the drag icon.
Hover the target View and re-order it as needed by drag-drop the drag icon, as shown in <1>.
![image](https://user-images.githubusercontent.com/35857179/163359674-c4aeff74-1cb4-498d-b79c-c6ddf84ad352.png)
<!-- ![image](https://user-images.githubusercontent.com/35857179/163359674-c4aeff74-1cb4-498d-b79c-c6ddf84ad352.png) -->

2
packages/nocodb/Dockerfile

@ -26,7 +26,7 @@ WORKDIR /usr/src/app
# Copying this separately prevents re-running npm ci on every code change.
COPY ./package*.json ./
COPY ./docker/main.js ./docker/main.js
#COPY ./docker/start.sh /usr/src/appEntry/start.s
#COPY ./docker/start.sh /usr/src/appEntry/start.sh
COPY ./docker/start-litestream.sh /usr/src/appEntry/start.sh
# install production dependencies,

21
scripts/cypress/integration/common/00_pre_configurations.js

@ -168,9 +168,7 @@ export const genTest = (apiType, dbType) => {
loginPage.signUp(roles.owner.credentials);
});
const createProject = (proj) => {
it(`Create ${proj.basic.name} project`, () => {
function cy_createProjectBlock(proj, apiType, dbType) {
// click home button
cy.get(".nc-noco-brand-icon").click();
cy.get(".ant-table-content").then((obj) => {
@ -238,11 +236,20 @@ export const genTest = (apiType, dbType) => {
}
}
});
}
// hack to disable dark mode
cy.fileHook();
const createProject = (proj) => {
it(`Create ${proj.basic.name} project`, () => {
if(dbType === "postgres") {
// wait for docker compose to start
cy.task(
'pgExecTest',
`SELECT 1+1`, {timeout: 120000}
).then(() => cy_createProjectBlock(proj, apiType, dbType));
}
else {
cy_createProjectBlock(proj, apiType, dbType);
}
});
};

6
scripts/cypress/integration/common/1b_table_column_operations.js

@ -83,7 +83,7 @@ export const genTest = (apiType, dbType) => {
cy.get(".nc-column-edit").should("not.be.visible");
// rename column and verify
cy.getActiveMenu().find('input.nc-column-name-input', { timeout: 3000 })
cy.getActiveMenu(".nc-dropdown-edit-column").find('input.nc-column-name-input', { timeout: 3000 })
.should('exist')
.clear()
.type(updatedColName);
@ -140,7 +140,7 @@ export const genTest = (apiType, dbType) => {
.rightclick({ force: true });
// delete row
cy.getActiveMenu()
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.find('.ant-dropdown-menu-item:contains("Delete Row")')
.first()
.click({ force: true });
@ -161,7 +161,7 @@ export const genTest = (apiType, dbType) => {
// delete selected rows
mainPage.getCell("Title", 3).rightclick({ force: true });
cy.getActiveMenu()
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Selected Rows")
.click({ force: true });

2
scripts/cypress/integration/common/1d_pg_table_view_drag_drop_reorder.js

@ -87,7 +87,7 @@ export const genTest = (apiType, dbType) => {
cy.snipActiveModal(`Modal_createView_${viewType}`);
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.getActiveModal(".nc-modal-view-create").find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}

2
scripts/cypress/integration/common/1d_table_view_drag_drop_reorder.js

@ -90,7 +90,7 @@ export const genTest = (apiType, dbType) => {
cy.snipActiveModal(`Modal_createView_${viewType}`);
// Pop up window, click Submit (accepting default name for view)
cy.getActiveModal().find("button:contains(Submit)").click();
cy.getActiveModal(".nc-modal-view-create").find("button:contains(Submit)").click();
cy.toastWait("View created successfully");
}

12
scripts/cypress/integration/common/2a_table_with_belongs_to_colulmn.js

@ -59,26 +59,26 @@ export const genTest = (apiType, dbType) => {
});
it("Expand Link record, validate", () => {
cy.getActiveModal()
cy.getActiveModal(".nc-modal-child-list")
.find("button:contains(Link to 'City')")
.click()
.then(() => {
// Link record form validation
cy.getActiveModal().contains("Link record").should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-link-record").contains("Link record").should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find(".nc-reload")
.should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-link-record")
.find('button:contains("Add new record")')
.should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-link-record")
.find(".ant-card")
.eq(0)
.contains("A Corua (La Corua)")
.should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-link-record")
.find("button.ant-modal-close")
.click();
// .then(() => {

16
scripts/cypress/integration/common/2b_table_with_m2m_column.js

@ -57,7 +57,7 @@ export const genTest = (apiType, dbType) => {
// cy.getActiveModal()
// .find("button:contains(Link to 'Film')")
// .should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-child-list")
.find(".ant-card")
.eq(0)
.contains("ACADEMY DINOSAUR")
@ -65,24 +65,24 @@ export const genTest = (apiType, dbType) => {
});
it('Expand "Link to" record, validate', () => {
cy.getActiveModal()
cy.getActiveModal(".nc-modal-child-list")
.find("button:contains(Link to 'Film')")
.click()
.then(() => {
// Link record form validation
cy.getActiveModal().contains("Link record").should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-link-record").contains("Link record").should("exist");
cy.getActiveModal(".nc-modal-link-record")
.find(".nc-reload")
.should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-link-record")
.find('button:contains("Add new record")')
.should("exist");
cy.getActiveModal()
cy.getActiveModal(".nc-modal-link-record")
.find(".ant-card")
.eq(0)
.contains("ACE GOLDFINGER")
.should("exist");
cy.getActiveModal().find("button.ant-modal-close").click();
cy.getActiveModal(".nc-modal-link-record").find("button.ant-modal-close").click();
});
});
@ -92,7 +92,7 @@ export const genTest = (apiType, dbType) => {
mainPage.getCell("Film List", 1).should("exist").trigger("mouseover").click();
cy.get('.nc-action-icon').eq(0).should('exist').click({ force: true });
cy.getActiveModal()
cy.getActiveModal(".nc-modal-child-list")
.find(".ant-card")
.eq(0)
.contains("ACADEMY DINOSAUR", { timeout: 2000 })

8
scripts/cypress/integration/common/3a_filter_sort_fields_operations.js

@ -82,7 +82,7 @@ export const genTest = (apiType, dbType) => {
it("Delete Row", () => {
// delete row added in previous step
mainPage.getCell("Country", 10).rightclick();
cy.getActiveMenu().contains("Delete Row").click();
cy.getActiveMenu(".nc-dropdown-grid-context-menu").contains("Delete Row").click();
// cy.toastWait('Deleted row successfully')
@ -99,7 +99,7 @@ export const genTest = (apiType, dbType) => {
mainPage.getPagination(5).click();
mainPage.getCell("Country", 9).rightclick({ force: true });
cy.getActiveMenu()
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Insert New Row")
.click({ force: true });
mainPage
@ -109,7 +109,7 @@ export const genTest = (apiType, dbType) => {
.type("Test Country-1{enter}");
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu()
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Insert New Row")
.click({ force: true });
mainPage
@ -142,7 +142,7 @@ export const genTest = (apiType, dbType) => {
.eq(11).click({ force: true });
mainPage.getCell("Country", 10).rightclick({ force: true });
cy.getActiveMenu()
cy.getActiveMenu(".nc-dropdown-grid-context-menu")
.contains("Delete Selected Rows")
.click({ force: true });

15
scripts/cypress/integration/common/3b_formula_column.js

@ -13,17 +13,6 @@ export const genTest = (apiType, dbType) => {
//
before(() => {
// loginPage.loginAndOpenProject(apiType, dbType)
mainPage.tabReset();
// open a table to work on views
//
// // kludge: wait for page load to finish
// cy.wait(1000);
// // close team & auth tab
// cy.get('button.ant-tabs-tab-remove').should('exist').click();
// cy.wait(1000);
cy.openTableTab("City", 25);
});
@ -59,7 +48,7 @@ export const genTest = (apiType, dbType) => {
force: true,
});
cy.getActiveMenu().find('input.nc-column-name-input', { timeout: 3000 })
cy.getActiveMenu(".nc-dropdown-grid-add-column").find('input.nc-column-name-input', { timeout: 3000 })
.should('exist')
.clear()
.type(columnName);
@ -91,7 +80,7 @@ export const genTest = (apiType, dbType) => {
cy.get(".nc-column-edit").click();
cy.get(".nc-column-edit").should("not.be.visible");
cy.getActiveMenu().find('input.nc-column-name-input', { timeout: 3000 })
cy.getActiveMenu(".nc-dropdown-edit-column").find('input.nc-column-name-input', { timeout: 3000 })
.should('exist')
.clear()
.type(newName);

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

Loading…
Cancel
Save