Browse Source

Merge branch 'develop' into mvp-mobile-layout-and-code-scanner

pull/5114/head
Daniel Spaude 1 year ago
parent
commit
53610a5a70
No known key found for this signature in database
GPG Key ID: 654A3D1FA4F35FFE
  1. 41
      .github/workflows/ci-cd.yml
  2. 1
      packages/nc-gui/components.d.ts
  3. 6
      packages/nc-gui/components/account/UserList.vue
  4. 1
      packages/nc-gui/components/cell/SingleSelect.vue
  5. 1
      packages/nc-gui/components/cell/TextArea.vue
  6. 3
      packages/nc-gui/components/cell/attachment/utils.ts
  7. 8
      packages/nc-gui/components/dashboard/TreeView.vue
  8. 2
      packages/nc-gui/components/dashboard/settings/AppStore.vue
  9. 4
      packages/nc-gui/components/dashboard/settings/AuditTab.vue
  10. 20
      packages/nc-gui/components/dashboard/settings/DataSources.vue
  11. 6
      packages/nc-gui/components/dashboard/settings/Metadata.vue
  12. 6
      packages/nc-gui/components/dashboard/settings/Misc.vue
  13. 3
      packages/nc-gui/components/dashboard/settings/UIAcl.vue
  14. 5
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  15. 5
      packages/nc-gui/components/dashboard/settings/data-sources/EditBase.vue
  16. 7
      packages/nc-gui/components/dlg/AirtableImport.vue
  17. 3
      packages/nc-gui/components/dlg/QuickImport.vue
  18. 5
      packages/nc-gui/components/dlg/TableRename.vue
  19. 4
      packages/nc-gui/components/erd/View.vue
  20. 4
      packages/nc-gui/components/general/HelpAndSupport.vue
  21. 4
      packages/nc-gui/components/general/MiniSidebar.vue
  22. 3
      packages/nc-gui/components/smartsheet/ApiSnippet.vue
  23. 3
      packages/nc-gui/components/smartsheet/Cell.vue
  24. 16
      packages/nc-gui/components/smartsheet/column/LinkedToAnotherRecordOptions.vue
  25. 4
      packages/nc-gui/components/smartsheet/column/LookupOptions.vue
  26. 4
      packages/nc-gui/components/smartsheet/column/RollupOptions.vue
  27. 3
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  28. 3
      packages/nc-gui/components/smartsheet/header/CellIcon.ts
  29. 24
      packages/nc-gui/components/smartsheet/header/Menu.vue
  30. 5
      packages/nc-gui/components/smartsheet/sidebar/index.vue
  31. 6
      packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue
  32. 3
      packages/nc-gui/components/smartsheet/toolbar/ExportSubActions.vue
  33. 2
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  34. 4
      packages/nc-gui/components/smartsheet/toolbar/FilterInput.vue
  35. 3
      packages/nc-gui/components/smartsheet/toolbar/MoreActions.vue
  36. 4
      packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue
  37. 3
      packages/nc-gui/components/smartsheet/toolbar/ShareView.vue
  38. 2
      packages/nc-gui/components/smartsheet/toolbar/SharedViewList.vue
  39. 1
      packages/nc-gui/components/smartsheet/toolbar/SortListMenu.vue
  40. 3
      packages/nc-gui/components/smartsheet/toolbar/ViewActions.vue
  41. 8
      packages/nc-gui/components/tabs/auth/ApiTokenManagement.vue
  42. 8
      packages/nc-gui/components/tabs/auth/UserManagement.vue
  43. 14
      packages/nc-gui/components/tabs/auth/user-management/ShareBase.vue
  44. 3
      packages/nc-gui/components/tabs/auth/user-management/UsersModal.vue
  45. 5
      packages/nc-gui/components/template/Editor.vue
  46. 30
      packages/nc-gui/components/webhook/Editor.vue
  47. 5
      packages/nc-gui/components/webhook/List.vue
  48. 5
      packages/nc-gui/composables/useColumnCreateStore.ts
  49. 5
      packages/nc-gui/composables/useExpandedFormStore.ts
  50. 1
      packages/nc-gui/composables/useGlobal/state.ts
  51. 1
      packages/nc-gui/composables/useGlobal/types.ts
  52. 27
      packages/nc-gui/composables/useKanbanViewStore.ts
  53. 3
      packages/nc-gui/composables/useLTARStore.ts
  54. 15
      packages/nc-gui/composables/useMapViewDataStore.ts
  55. 4
      packages/nc-gui/composables/useMetas.ts
  56. 9
      packages/nc-gui/composables/useSharedFormViewStore.ts
  57. 36
      packages/nc-gui/composables/useSharedView.ts
  58. 3
      packages/nc-gui/composables/useSmartsheetRowStore.ts
  59. 18
      packages/nc-gui/composables/useSmartsheetStore.ts
  60. 4
      packages/nc-gui/composables/useTable.ts
  61. 12
      packages/nc-gui/composables/useViewColumns.ts
  62. 10
      packages/nc-gui/composables/useViewData.ts
  63. 13
      packages/nc-gui/composables/useViewFilters.ts
  64. 5
      packages/nc-gui/composables/useViewSorts.ts
  65. 5
      packages/nc-gui/nuxt.config.ts
  66. 1936
      packages/nc-gui/package-lock.json
  67. 5
      packages/nc-gui/package.json
  68. 8
      packages/nc-gui/pages/[projectType]/[projectId]/index.vue
  69. 6
      packages/nc-gui/pages/[projectType]/[projectId]/index/index.vue
  70. 5
      packages/nc-gui/pages/[projectType]/[projectId]/index/index/[type]/[title]/[[viewTitle]].vue
  71. 5
      packages/nc-gui/pages/[projectType]/[projectId]/index/index/index.vue
  72. 5
      packages/nc-gui/pages/account/index.vue
  73. 6
      packages/nc-gui/pages/account/index/[page].vue
  74. 6
      packages/nc-gui/pages/index/index/[projectId].vue
  75. 9
      packages/nc-gui/store/project.ts
  76. 21
      packages/nc-gui/store/tab.ts
  77. 5440
      packages/nocodb-sdk/src/lib/Api.ts
  78. 7
      packages/nocodb-sdk/src/lib/formulaHelpers.ts
  79. 1
      packages/nocodb/package.json
  80. 3
      packages/nocodb/src/lib/Noco.ts
  81. 7
      packages/nocodb/src/lib/controllers/apiToken.ctl.ts
  82. 17
      packages/nocodb/src/lib/controllers/audit.ctl.ts
  83. 14
      packages/nocodb/src/lib/controllers/base.ctl.ts
  84. 5
      packages/nocodb/src/lib/controllers/dbData/data.ctl.ts
  85. 4
      packages/nocodb/src/lib/controllers/dbData/dataAliasNested.ctl.ts
  86. 3
      packages/nocodb/src/lib/controllers/dbData/helpers.ts
  87. 37
      packages/nocodb/src/lib/controllers/filter.ctl.ts
  88. 18
      packages/nocodb/src/lib/controllers/hook.ctl.ts
  89. 91
      packages/nocodb/src/lib/controllers/hookFilter.ctl.ts
  90. 4
      packages/nocodb/src/lib/controllers/metaDiff.ctl.ts
  91. 2
      packages/nocodb/src/lib/controllers/modelVisibility.ctl.ts
  92. 2
      packages/nocodb/src/lib/controllers/orgLicense.ctl.ts
  93. 20
      packages/nocodb/src/lib/controllers/orgUser.ctl.ts
  94. 13
      packages/nocodb/src/lib/controllers/plugin.ctl.ts
  95. 1
      packages/nocodb/src/lib/controllers/project.ctl.ts
  96. 39
      packages/nocodb/src/lib/controllers/projectUser.ctl.ts
  97. 2
      packages/nocodb/src/lib/controllers/publicControllers/publicData.ctl.ts
  98. 17
      packages/nocodb/src/lib/controllers/sort.ctl.ts
  99. 3
      packages/nocodb/src/lib/controllers/table.ctl.ts
  100. 12
      packages/nocodb/src/lib/controllers/user/initStrategies.ts
  101. Some files were not shown because too many files have changed in this diff Show More

41
.github/workflows/ci-cd.yml

@ -63,6 +63,47 @@ jobs:
- name: run unit tests
working-directory: ./packages/nocodb
run: npm run test:unit
unit-tests-pg:
runs-on: ubuntu-20.04
timeout-minutes: 40
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
steps:
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16.15.0
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache node modules
uses: actions/cache@v3
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: setup pg
working-directory: ./
run: docker-compose -f ./tests/playwright/scripts/docker-compose-playwright-pg.yml up -d &
- name: install dependencies nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm install
- name: build nocodb-sdk
working-directory: ./packages/nocodb-sdk
run: npm run build:main
- name: Install dependencies
working-directory: ./packages/nocodb
run: npm install
- name: run unit tests
working-directory: ./packages/nocodb
run: npm run test:unit:pg
playwright-mysql-1:
if: ${{ github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'trigger-CI') || !github.event.pull_request.draft }}
uses: ./.github/workflows/playwright-test-workflow.yml

1
packages/nc-gui/components.d.ts vendored

@ -188,6 +188,7 @@ declare module '@vue/runtime-core' {
MdiFunction: typeof import('~icons/mdi/function')['default']
MdiGestureDoubleTap: typeof import('~icons/mdi/gesture-double-tap')['default']
MdiGithub: typeof import('~icons/mdi/github')['default']
MdiGpsFixed: typeof import('~icons/mdi/gps-fixed')['default']
MdiGraphOutline: typeof import('~icons/mdi/graph-outline')['default']
MdiHeart: typeof import('~icons/mdi/heart')['default']
MdiHook: typeof import('~icons/mdi/hook')['default']

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

@ -1,6 +1,6 @@
<script lang="ts" setup>
import { Modal, message } from 'ant-design-vue'
import type { RequestParams, UserType } from 'nocodb-sdk'
import type { OrgUserReqType, RequestParams, UserType } from 'nocodb-sdk'
import { Role, extractSdkResponseErrorMsg, useApi, useCopy, useDashboard, useNuxtApp } from '#imports'
import type { User } from '~/lib'
@ -42,9 +42,11 @@ const loadUsers = async (page = currentPage, limit = currentLimit) => {
query: searchText.value,
},
} as RequestParams)
if (!response) return
pagination.total = response.pageInfo.totalRows ?? 0
pagination.pageSize = 10
users = response.list as UserType[]
@ -59,7 +61,7 @@ const updateRole = async (userId: string, roles: Role) => {
try {
await api.orgUsers.update(userId, {
roles,
} as unknown as UserType)
} as OrgUserReqType)
message.success(t('msg.success.roleUpdated'))
$e('a:org-user:role-updated', { role: roles })

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

@ -19,6 +19,7 @@ import {
isDrawerOrModalExist,
ref,
useEventListener,
useProject,
useRoles,
useSelectedCellKeyupListener,
watch,

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

@ -45,6 +45,7 @@ const focus: VNodeRef = (el) => (el as HTMLTextAreaElement)?.focus()
<span v-else>{{ vModel }}</span>
</template>
<style>
textarea:focus {
box-shadow: none;

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

@ -13,6 +13,7 @@ import {
isImage,
message,
ref,
storeToRefs,
useApi,
useAttachment,
useFileDialog,
@ -51,7 +52,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
/** for image carousel */
const selectedImage = ref()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { api, isLoading } = useApi()

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

@ -17,6 +17,7 @@ import {
reactive,
ref,
resolveComponent,
storeToRefs,
useDialog,
useGlobal,
useNuxtApp,
@ -37,9 +38,12 @@ const { addTab, updateTab } = useTabs()
const { $api, $e } = useNuxtApp()
const { bases, tables, loadTables, isSharedBase } = useProject()
const projectStore = useProject()
const { activeTab } = useTabs()
const { loadTables } = projectStore
const { bases, tables, isSharedBase } = storeToRefs(projectStore)
const { activeTab } = storeToRefs(useTabs())
const { deleteTable } = useTable()

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

@ -20,7 +20,7 @@ const fetchPluginApps = async () => {
apps = plugins.map((p) => ({
...p,
tags: p.tags ? p.tags.split(',') : [],
parsedInput: p.input && JSON.parse(p.input),
parsedInput: p.input && JSON.parse(p.input as string),
}))
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))

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

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

20
packages/nc-gui/components/dashboard/settings/DataSources.vue

@ -7,7 +7,7 @@ import Metadata from './Metadata.vue'
import UIAcl from './UIAcl.vue'
import Erd from './Erd.vue'
import { ClientType, DataSourcesSubTab } from '~/lib'
import { useNuxtApp, useProject } from '#imports'
import { storeToRefs, useNuxtApp, useProject } from '#imports'
interface Props {
state: string
@ -19,16 +19,24 @@ const props = defineProps<Props>()
const emits = defineEmits(['update:state', 'update:reload', 'awaken'])
const vState = useVModel(props, 'state', emits)
const vReload = useVModel(props, 'reload', emits)
const { $api, $e } = useNuxtApp()
const { project, loadProject } = useProject()
const projectStore = useProject()
const { loadProject } = projectStore
const { project } = storeToRefs(projectStore)
let sources = $ref<BaseType[]>([])
let activeBaseId = $ref('')
let metadiffbases = $ref<string[]>([])
let clientType = $ref<ClientType>(ClientType.MYSQL)
let isReloading = $ref(false)
let forceAwakened = $ref(false)
async function loadBases() {
@ -38,8 +46,8 @@ async function loadBases() {
isReloading = true
vReload.value = true
const baseList = await $api.base.list(project.value?.id)
if (baseList.bases.list && baseList.bases.list.length) {
sources = baseList.bases.list
if (baseList.list && baseList.list.length) {
sources = baseList.list
}
} catch (e) {
console.error(e)
@ -245,7 +253,7 @@ watch(
@click="baseAction(sources[0].id, DataSourcesSubTab.Metadata)"
>
<div class="flex items-center gap-2 text-gray-600 font-light">
<a-tooltip v-if="metadiffbases.includes(sources[0].id as string)">
<a-tooltip v-if="metadiffbases.includes(sources[0].id)">
<template #title>Out of sync</template>
<MdiDatabaseAlert class="text-lg group-hover:text-accent text-primary" />
</a-tooltip>
@ -314,7 +322,7 @@ watch(
@click="baseAction(base.id, DataSourcesSubTab.Metadata)"
>
<div class="flex items-center gap-2 text-gray-600 font-light">
<a-tooltip v-if="metadiffbases.includes(base.id as string)">
<a-tooltip v-if="metadiffbases.includes(base.id)">
<template #title>Out of sync</template>
<MdiDatabaseAlert class="text-lg group-hover:text-accent text-primary" />
</a-tooltip>

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

@ -1,5 +1,5 @@
<script setup lang="ts">
import { Empty, extractSdkResponseErrorMsg, h, message, useI18n, useNuxtApp, useProject } from '#imports'
import { Empty, extractSdkResponseErrorMsg, h, message, storeToRefs, useI18n, useNuxtApp, useProject } from '#imports'
const props = defineProps<{
baseId: string
@ -9,7 +9,9 @@ const emit = defineEmits(['baseSynced'])
const { $api } = useNuxtApp()
const { project, loadTables } = useProject()
const projectStore = useProject()
const { loadTables } = projectStore
const { project } = storeToRefs(projectStore)
const { t } = useI18n()

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

@ -1,10 +1,12 @@
<script setup lang="ts">
import type { CheckboxChangeEvent } from 'ant-design-vue/es/checkbox/interface'
import { useGlobal, useProject, watch } from '#imports'
import { storeToRefs, useGlobal, useProject, watch } from '#imports'
const { includeM2M, showNull } = useGlobal()
const { project, updateProject, projectMeta, loadTables, hasEmptyOrNullFilters } = useProject()
const projectStore = useProject()
const { updateProject, loadTables, hasEmptyOrNullFilters } = projectStore
const { project, projectMeta } = storeToRefs(projectStore)
watch(includeM2M, async () => await loadTables())

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

@ -6,6 +6,7 @@ import {
h,
message,
onMounted,
storeToRefs,
useGlobal,
useI18n,
useNuxtApp,
@ -20,7 +21,7 @@ const { t } = useI18n()
const { $api, $e } = useNuxtApp()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { includeM2M } = useGlobal()

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

@ -20,6 +20,7 @@ import {
projectTitleValidator,
readFile,
ref,
storeToRefs,
useApi,
useGlobal,
useI18n,
@ -33,7 +34,9 @@ const emit = defineEmits(['baseCreated'])
const { appInfo } = useGlobal()
const { project, loadProject } = useProject()
const projectStore = useProject()
const { loadProject } = projectStore
const { project } = storeToRefs(projectStore)
const useForm = Form.useForm

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

@ -19,6 +19,7 @@ import {
projectTitleValidator,
readFile,
ref,
storeToRefs,
useApi,
useI18n,
useNuxtApp,
@ -31,7 +32,9 @@ const props = defineProps<{
const emit = defineEmits(['baseUpdated'])
const { project, loadProject } = useProject()
const projectStore = useProject()
const { loadProject } = projectStore
const { project } = storeToRefs(projectStore)
const useForm = Form.useForm

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

@ -12,6 +12,7 @@ import {
onBeforeUnmount,
onMounted,
ref,
storeToRefs,
useGlobal,
useNuxtApp,
useProject,
@ -31,7 +32,11 @@ const baseURL = appInfo.ncSiteUrl
const { $state } = useNuxtApp()
const { project, loadTables } = useProject()
const projectStore = useProject()
const { loadTables } = projectStore
const { project } = storeToRefs(projectStore)
const showGoToDashboardButton = ref(false)

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

@ -18,6 +18,7 @@ import {
message,
reactive,
ref,
storeToRefs,
useI18n,
useProject,
useVModel,
@ -37,7 +38,7 @@ const emit = defineEmits(['update:modelValue'])
const { t } = useI18n()
const { tables } = useProject()
const { tables } = storeToRefs(useProject())
const activeKey = ref('uploadTab')

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

@ -8,6 +8,7 @@ import {
message,
nextTick,
reactive,
storeToRefs,
useI18n,
useMetas,
useNuxtApp,
@ -38,7 +39,9 @@ const dialogShow = useVModel(props, 'modelValue', emit)
const { updateTab } = useTabs()
const { loadTables, tables, project, isMysql, isMssql, isPg } = useProject()
const projectStore = useProject()
const { loadTables, isMysql, isMssql, isPg } = projectStore
const { project } = storeToRefs(projectStore)
const inputEl = $ref<ComponentPublicInstance>()

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

@ -2,11 +2,11 @@
import type { LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import type { ERDConfig } from './utils'
import { reactive, ref, useMetas, useProject, watch } from '#imports'
import { reactive, ref, storeToRefs, useMetas, useProject, watch } from '#imports'
const props = defineProps<{ table?: TableType; baseId?: string }>()
const { tables: projectTables } = useProject()
const { tables: projectTables } = storeToRefs(useProject())
const { metas, getMeta } = useMetas()

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

@ -1,11 +1,11 @@
<script lang="ts" setup>
import { ref, useGlobal, useProject, useRoute } from '#imports'
import { ref, storeToRefs, useGlobal, useProject, useRoute } from '#imports'
const showDrawer = ref(false)
const { appInfo } = useGlobal()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const route = useRoute()

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

@ -1,11 +1,11 @@
<script lang="ts" setup>
import { computed, navigateTo, useGlobal, useProject, useRoute, useSidebar } from '#imports'
import { computed, navigateTo, storeToRefs, useGlobal, useProject, useRoute, useSidebar } from '#imports'
const { signOut, signedIn, user, currentVersion } = useGlobal()
const { isOpen } = useSidebar('nc-mini-sidebar', { isOpen: true })
const { project } = useProject()
const { project } = storeToRefs(useProject())
const route = useRoute()

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

@ -6,6 +6,7 @@ import {
inject,
message,
ref,
storeToRefs,
useCopy,
useGlobal,
useI18n,
@ -24,7 +25,7 @@ const emits = defineEmits(['update:modelValue'])
const { t } = useI18n()
const { project } = $(useProject())
const { project } = $(storeToRefs(useProject()))
const { appInfo, token } = $(useGlobal())

3
packages/nc-gui/components/smartsheet/Cell.vue

@ -39,6 +39,7 @@ import {
isYear,
provide,
ref,
storeToRefs,
toRef,
useDebounceFn,
useProject,
@ -85,7 +86,7 @@ const isLocked = inject(IsLockedInj, ref(false))
const { currentRow } = useSmartsheetRowStoreOrThrow()
const { sqlUis } = useProject()
const { sqlUis } = storeToRefs(useProject())
const sqlUi = ref(column.value?.base_id ? sqlUis.value[column.value?.base_id] : Object.values(sqlUis.value)[0])

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

@ -1,6 +1,6 @@
<script setup lang="ts">
import { ModelTypes, MssqlUi, SqliteUi } from 'nocodb-sdk'
import { MetaInj, inject, ref, useProject, useVModel } from '#imports'
import { MetaInj, inject, ref, storeToRefs, useProject, useVModel } from '#imports'
import MdiPlusIcon from '~icons/mdi/plus-circle-outline'
import MdiMinusIcon from '~icons/mdi/minus-circle-outline'
@ -10,13 +10,15 @@ const props = defineProps<{
const emit = defineEmits(['update:value'])
const { appInfo } = $(useGlobal())
const vModel = useVModel(props, 'value', emit)
const meta = $(inject(MetaInj, ref()))
const { setAdditionalValidations, validateInfos, onDataTypeChange, sqlUi } = useColumnCreateStoreOrThrow()
const { tables } = $(useProject())
const { tables } = $(storeToRefs(useProject()))
setAdditionalValidations({
childId: [{ required: true, message: 'Required' }],
@ -31,10 +33,10 @@ if (!vModel.value.childTable) vModel.value.childTable = meta?.table_name
if (!vModel.value.parentTable) vModel.value.parentTable = vModel.value.rtn || ''
if (!vModel.value.parentColumn) vModel.value.parentColumn = vModel.value.rcn || ''
if (!vModel.value.type) vModel.value.type = 'hm'
if (!vModel.value.type) vModel.value.type = 'mm'
if (!vModel.value.onUpdate) vModel.value.onUpdate = onUpdateDeleteOptions[0]
if (!vModel.value.onDelete) vModel.value.onDelete = onUpdateDeleteOptions[0]
if (!vModel.value.virtual) vModel.value.virtual = sqlUi === SqliteUi
if (!vModel.value.virtual) vModel.value.virtual = appInfo.isCloud || sqlUi === SqliteUi
if (!vModel.value.alias) vModel.value.alias = vModel.value.column_name
const advancedOptions = $(ref(false))
@ -55,7 +57,7 @@ const filterOption = (value: string, option: { key: string }) => option.key.toLo
<div class="border-2 p-6">
<a-form-item v-bind="validateInfos.type" class="nc-ltar-relation-type">
<a-radio-group v-model:value="vModel.type" name="type" v-bind="validateInfos.type">
<a-radio value="hm">Has Many</a-radio>
<a-radio value="hm" :disabled="appInfo.isCloud">Has Many</a-radio>
<a-radio value="mm">Many To Many</a-radio>
</a-radio-group>
</a-form-item>
@ -127,7 +129,9 @@ const filterOption = (value: string, option: { key: string }) => option.key.toLo
<div class="flex flex-row">
<a-form-item>
<a-checkbox v-model:checked="vModel.virtual" name="virtual" @change="onDataTypeChange">Virtual Relation</a-checkbox>
<a-checkbox v-model:checked="vModel.virtual" :disabled="appInfo.isCloud" name="virtual" @change="onDataTypeChange"
>Virtual Relation</a-checkbox
>
</a-form-item>
</div>
</div>

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

@ -3,7 +3,7 @@ import { onMounted } from '@vue/runtime-core'
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes, isSystemColumn } from 'nocodb-sdk'
import { getRelationName } from './utils'
import { MetaInj, inject, ref, useColumnCreateStoreOrThrow, useMetas, useProject, useVModel } from '#imports'
import { MetaInj, inject, ref, storeToRefs, useColumnCreateStoreOrThrow, useMetas, useProject, useVModel } from '#imports'
const props = defineProps<{
value: any
@ -17,7 +17,7 @@ const meta = $(inject(MetaInj, ref()))
const { setAdditionalValidations, validateInfos, onDataTypeChange, isEdit } = useColumnCreateStoreOrThrow()
const { tables } = $(useProject())
const { tables } = $(storeToRefs(useProject()))
const { metas } = $(useMetas())

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

@ -3,7 +3,7 @@ import { onMounted } from '@vue/runtime-core'
import type { ColumnType, LinkToAnotherRecordType, TableType } from 'nocodb-sdk'
import { UITypes, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { getRelationName } from './utils'
import { MetaInj, inject, ref, useColumnCreateStoreOrThrow, useMetas, useProject, useVModel } from '#imports'
import { MetaInj, inject, ref, storeToRefs, useColumnCreateStoreOrThrow, useMetas, useProject, useVModel } from '#imports'
const props = defineProps<{
value: any
@ -17,7 +17,7 @@ const meta = $(inject(MetaInj, ref()))
const { setAdditionalValidations, validateInfos, onDataTypeChange, isEdit } = useColumnCreateStoreOrThrow()
const { tables } = $(useProject())
const { tables } = $(storeToRefs(useProject()))
const { metas } = $(useMetas())

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

@ -333,8 +333,7 @@ export default {
:ref="i ? null : (el) => (cellWrapperEl = el)"
class="!bg-white rounded px-1 min-h-[35px] flex items-center mt-2 relative"
>
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="row.row[col.title]" :row="row"
:column="col" />
<LazySmartsheetVirtualCell v-if="isVirtualCol(col)" v-model="row.row[col.title]" :row="row" :column="col" />
<LazySmartsheetCell
v-else

3
packages/nc-gui/components/smartsheet/header/CellIcon.ts

@ -30,6 +30,7 @@ import {
isTime,
isURL,
isYear,
storeToRefs,
toRef,
useProject,
} from '#imports'
@ -123,7 +124,7 @@ export default defineComponent({
const column = inject(ColumnInj, columnMeta)
const { sqlUis } = useProject()
const { sqlUis } = storeToRefs(useProject())
const sqlUi = ref(column.value?.base_id ? sqlUis.value[column.value?.base_id] : Object.values(sqlUis.value)[0])

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

@ -1,5 +1,5 @@
<script lang="ts" setup>
import type { LinkToAnotherRecordType } from 'nocodb-sdk'
import type { ColumnReqType, LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, UITypes } from 'nocodb-sdk'
import {
ActiveViewInj,
@ -9,8 +9,6 @@ import {
Modal,
ReloadViewDataHookInj,
SmartsheetStoreEvents,
defineEmits,
defineProps,
extractSdkResponseErrorMsg,
getUniqueColumnName,
inject,
@ -62,7 +60,7 @@ const deleteColumn = () =>
}
$e('a:column:delete')
} catch (e) {
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
},
@ -95,7 +93,7 @@ const sortByColumn = async (direction: 'asc' | 'desc') => {
})
eventBus.emit(SmartsheetStoreEvents.SORT_RELOAD)
reloadDataHook?.trigger()
} catch (e) {
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
@ -107,7 +105,7 @@ const duplicateColumn = async () => {
const duplicateColumnName = getUniqueColumnName(`${column!.value.title}_copy`, meta!.value!.columns!)
// construct column create payload
switch (column.value.uidt) {
switch (column?.value.uidt) {
case UITypes.LinkToAnotherRecord:
case UITypes.Lookup:
case UITypes.Rollup:
@ -144,14 +142,14 @@ const duplicateColumn = async () => {
}
try {
const gridViewColumnList = await $api.dbViewColumn.list(view.value?.id as string)
const gridViewColumnList = (await $api.dbViewColumn.list(view.value?.id as string)).list
const currentColumnIndex = gridViewColumnList.findIndex((f) => f.fk_column_id === column!.value.id)
let newColumnOrder
if (currentColumnIndex === gridViewColumnList.length - 1) {
newColumnOrder = gridViewColumnList[currentColumnIndex].order + 1
newColumnOrder = gridViewColumnList[currentColumnIndex].order! + 1
} else {
newColumnOrder = (gridViewColumnList[currentColumnIndex].order! + gridViewColumnList[currentColumnIndex + 1]?.order) / 2
newColumnOrder = (gridViewColumnList[currentColumnIndex].order! + gridViewColumnList[currentColumnIndex + 1].order!) / 2
}
await $api.dbTableColumn.create(meta!.value!.id!, {
@ -161,7 +159,7 @@ const duplicateColumn = async () => {
order: newColumnOrder,
view_id: view.value?.id as string,
},
})
} as ColumnReqType)
await getMeta(meta!.value!.id!, true)
eventBus.emit(SmartsheetStoreEvents.FIELD_RELOAD)
@ -175,7 +173,7 @@ const duplicateColumn = async () => {
// add column before or after current column
const addColumn = async (before = false) => {
const gridViewColumnList = await $api.dbViewColumn.list(view.value?.id as string)
const gridViewColumnList = (await $api.dbViewColumn.list(view.value?.id as string)).list
const currentColumnIndex = gridViewColumnList.findIndex((f) => f.fk_column_id === column!.value.id)
@ -204,11 +202,11 @@ const addColumn = async (before = false) => {
// hide the field in view
const hideField = async () => {
const gridViewColumnList = await $api.dbViewColumn.list(view.value?.id as string)
const gridViewColumnList = (await $api.dbViewColumn.list(view.value?.id as string)).list
const currentColumn = gridViewColumnList.find((f) => f.fk_column_id === column!.value.id)
await $api.dbViewColumn.update(view.value.id, currentColumn.id, { show: false })
await $api.dbViewColumn.update(view.value!.id!, currentColumn!.id!, { show: false })
eventBus.emit(SmartsheetStoreEvents.FIELD_RELOAD)
}
</script>

5
packages/nc-gui/components/smartsheet/sidebar/index.vue

@ -8,6 +8,7 @@ import {
inject,
ref,
resolveComponent,
storeToRefs,
useDialog,
useGlobal,
useNuxtApp,
@ -25,11 +26,11 @@ const activeView = inject(ActiveViewInj, ref())
const { isMobileMode } = useGlobal()
const { activeTab } = useTabs()
const { activeTab } = storeToRefs(useTabs())
const { views, loadViews, isLoading } = useViews(meta)
const { lastOpenedViewMap } = useProject()
const { lastOpenedViewMap } = storeToRefs(useProject())
const setLastOpenedViewId = (viewId?: string) => {
if (viewId && activeTab.value?.id) {

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

@ -199,7 +199,11 @@ defineExpose({
<template>
<div
class="p-4 menu-filter-dropdown bg-gray-50 !border"
:class="{ 'min-w-[430px]': filters.length, 'shadow max-h-[max(80vh,500px)] overflow-auto': !nested, 'border-1 w-full': nested }"
:class="{
'min-w-[430px]': filters.length,
'shadow max-h-[max(80vh,500px)] overflow-auto': !nested,
'border-1 w-full': nested,
}"
>
<div
v-if="filters && filters.length"

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

@ -10,6 +10,7 @@ import {
inject,
message,
ref,
storeToRefs,
useI18n,
useNuxtApp,
useProject,
@ -22,7 +23,7 @@ const isPublicView = inject(IsPublicInj, ref(false))
const fields = inject(FieldsInj, ref([]))
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { $api } = useNuxtApp()

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

@ -127,13 +127,11 @@ const coverImageColumnId = computed({
) {
if (activeView.value?.type === ViewTypes.GALLERY) {
await $api.dbView.galleryUpdate(activeView.value?.id, {
...activeView.value?.view,
fk_cover_image_col_id: val,
})
;(activeView.value.view as GalleryType).fk_cover_image_col_id = val
} else if (activeView.value?.type === ViewTypes.KANBAN) {
await $api.dbView.kanbanUpdate(activeView.value?.id, {
...activeView.value?.view,
fk_cover_image_col_id: val,
})
;(activeView.value.view as KanbanType).fk_cover_image_col_id = val

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

@ -1,5 +1,6 @@
<script setup lang="ts">
import type { ColumnType } from 'nocodb-sdk'
import { storeToRefs } from 'pinia'
import {
ColumnInj,
EditModeInj,
@ -83,7 +84,8 @@ const checkTypeFunctions = {
type FilterType = keyof typeof checkTypeFunctions
const { sqlUi } = $(useProject())
// todo: replace with sqlUis
const { sqlUi } = $(storeToRefs(useProject()))
const abstractType = $computed(() => (column.value?.dt && sqlUi ? sqlUi.getAbstractType(column.value) : null))

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

@ -1,6 +1,7 @@
<script lang="ts" setup>
import type { RequestParams } from 'nocodb-sdk'
import { ExportTypes } from 'nocodb-sdk'
import { storeToRefs } from 'pinia'
import {
ActiveViewInj,
FieldsInj,
@ -27,7 +28,7 @@ const isPublicView = inject(IsPublicInj, ref(false))
const isView = false
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { $api } = useNuxtApp()

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

@ -1,8 +1,8 @@
<script setup lang="ts">
import type { GridType } from 'nocodb-sdk'
import { ActiveViewInj, IsLockedInj, inject, ref, useMenuCloseOnEsc } from '#imports'
import { ActiveViewInj, IsLockedInj, inject, ref, storeToRefs, useMenuCloseOnEsc } from '#imports'
const { isSharedBase } = useProject()
const { isSharedBase } = storeToRefs(useProject())
const view = inject(ActiveViewInj, ref())

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

@ -9,6 +9,7 @@ import {
message,
projectThemeColors,
ref,
storeToRefs,
useCopy,
useDashboard,
useI18n,
@ -32,7 +33,7 @@ const { dashboardUrl } = useDashboard()
const { isUIAllowed } = useUIPermission()
const { isSharedBase } = useProject()
const { isSharedBase } = storeToRefs(useProject())
const { isMobileMode } = useGlobal()

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

@ -34,7 +34,7 @@ const { dashboardUrl } = useDashboard()
const sharedViewList = ref<SharedViewType[]>()
const loadSharedViewsList = async () => {
sharedViewList.value = await $api.dbViewShare.list(meta.value?.id as string)
sharedViewList.value = (await $api.dbViewShare.list(meta.value?.id as string)).list as SharedViewType[]
// todo: show active view in list separately
// const index = sharedViewList.value.findIndex((v) => {

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

@ -30,7 +30,6 @@ const removeIcon = ref<HTMLElement>()
const addSort = () => {
_addSort()
nextTick(() => {
console.log(removeIcon.value)
removeIcon.value?.[removeIcon.value?.length - 1]?.$el?.scrollIntoView()
})
}

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

@ -9,6 +9,7 @@ import {
inject,
message,
ref,
storeToRefs,
useI18n,
useMenuCloseOnEsc,
useNuxtApp,
@ -60,7 +61,7 @@ const quickImportDialogs: Record<typeof quickImportDialogTypes[number], Ref<bool
const { isUIAllowed } = useUIPermission()
const { isSharedBase } = useProject()
const { isSharedBase } = storeToRefs(useProject())
const meta = inject(MetaInj, ref())

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

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { ApiTokenType } from 'nocodb-sdk'
import { extractSdkResponseErrorMsg, message, onMounted, useCopy, useI18n, useNuxtApp, useProject } from '#imports'
import { extractSdkResponseErrorMsg, message, onMounted, storeToRefs, useCopy, useI18n, useNuxtApp, useProject } from '#imports'
interface ApiToken extends ApiTokenType {
show?: boolean
@ -10,7 +10,7 @@ const { t } = useI18n()
const { $api, $e } = useNuxtApp()
const { project } = $(useProject())
const { project } = $(storeToRefs(useProject()))
const { copy } = useCopy()
@ -25,7 +25,7 @@ let selectedTokenData = $ref<ApiToken>({})
const loadApiTokens = async () => {
if (!project?.id) return
tokensInfo = await $api.apiToken.list(project.id)
tokensInfo = (await $api.apiToken.list(project.id)).list
}
const openNewTokenModal = () => {
@ -40,7 +40,7 @@ const copyToken = async (token: string | undefined) => {
await copy(token)
// Copied to clipboard
message.info(t('msg.info.copiedToClipboard'))
} catch (e) {
} catch (e: any) {
message.error(e.message)
}
$e('c:api-token:copy')

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

@ -7,6 +7,7 @@ import {
onBeforeMount,
projectRoleTagColors,
ref,
storeToRefs,
useApi,
useCopy,
useDashboard,
@ -24,7 +25,7 @@ const { $e } = useNuxtApp()
const { api } = useApi()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { copy } = useCopy()
@ -76,6 +77,11 @@ const inviteUser = async (user: User) => {
try {
if (!project.value?.id) return
if (!user.roles) {
// mark it as editor by default
user.roles = 'editor'
}
await api.auth.projectUserAdd(project.value.id, user)
// Successfully added user to project

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

@ -1,5 +1,15 @@
<script setup lang="ts">
import { extractSdkResponseErrorMsg, message, onMounted, useCopy, useDashboard, useI18n, useNuxtApp, useProject } from '#imports'
import {
extractSdkResponseErrorMsg,
message,
onMounted,
storeToRefs,
useCopy,
useDashboard,
useI18n,
useNuxtApp,
useProject,
} from '#imports'
interface ShareBase {
uuid?: string
@ -22,7 +32,7 @@ let base = $ref<null | ShareBase>(null)
const showEditBaseDropdown = $ref(false)
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { copy } = useCopy()

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

@ -9,6 +9,7 @@ import {
projectRoleTagColors,
projectRoles,
ref,
storeToRefs,
useActiveKeyupListener,
useCopy,
useDashboard,
@ -37,7 +38,7 @@ const emit = defineEmits(['closed', 'reload'])
const { t } = useI18n()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { isMobileMode } = useGlobal()

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

@ -24,6 +24,7 @@ import {
parseStringDate,
reactive,
ref,
storeToRefs,
useI18n,
useNuxtApp,
useProject,
@ -67,7 +68,9 @@ const { $api } = useNuxtApp()
const { addTab } = useTabs()
const { sqlUis, project, loadTables } = useProject()
const projectStrore = useProject()
const { loadTables } = projectStrore
const { sqlUis, project } = storeToRefs(projectStrore)
const sqlUi = ref(sqlUis.value[baseId] || Object.values(sqlUis.value)[0])

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

@ -13,6 +13,7 @@ import {
reactive,
ref,
useApi,
useGlobal,
useI18n,
useNuxtApp,
watch,
@ -32,6 +33,8 @@ const { $e } = useNuxtApp()
const { api, isLoading: loading } = useApi()
const { appInfo } = $(useGlobal())
const meta = inject(MetaInj, ref())
const useForm = Form.useForm
@ -170,16 +173,20 @@ const eventList = [
{ text: ['After', 'Delete'], value: ['after', 'delete'] },
]
const notificationList = [
{ type: 'URL' },
{ type: 'Email' },
{ type: 'Slack' },
{ type: 'Microsoft Teams' },
{ type: 'Discord' },
{ type: 'Mattermost' },
{ type: 'Twilio' },
{ type: 'Whatsapp Twilio' },
]
const notificationList = computed(() => {
return appInfo.isCloud
? [{ type: 'URL' }]
: [
{ type: 'URL' },
{ type: 'Email' },
{ type: 'Slack' },
{ type: 'Microsoft Teams' },
{ type: 'Discord' },
{ type: 'Mattermost' },
{ type: 'Twilio' },
{ type: 'Whatsapp Twilio' },
]
})
const methodList = [
{ title: 'GET' },
@ -306,6 +313,7 @@ async function onEventChange() {
}
async function loadPluginList() {
if (appInfo.isCloud) return
try {
const plugins = (await api.plugin.list()).list!
@ -651,9 +659,9 @@ onMounted(loadPluginList)
</a-checkbox>
<LazySmartsheetToolbarColumnFilter
class="mt-4"
v-if="hook.condition"
ref="filterRef"
class="mt-4"
:auto-save="false"
:show-loading="false"
:hook-id="hook.id"

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

@ -1,4 +1,5 @@
<script setup lang="ts">
import type { HookType } from 'nocodb-sdk'
import { MetaInj, extractSdkResponseErrorMsg, inject, message, onMounted, ref, useI18n, useNuxtApp } from '#imports'
const emit = defineEmits(['edit', 'add'])
@ -13,9 +14,9 @@ const meta = inject(MetaInj, ref())
async function loadHooksList() {
try {
const hookList = (await $api.dbTableWebhook.list(meta.value?.id as string)).list as Record<string, any>[]
const hookList = (await $api.dbTableWebhook.list(meta.value?.id as string)).list as HookType[]
hooks.value = hookList.map((hook) => {
hook.notification = hook.notification && JSON.parse(hook.notification)
hook.notification = typeof hook.notification === 'string' ? JSON.parse(hook.notification) : hook.notification
return hook
})
} catch (e: any) {

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

@ -10,6 +10,7 @@ import {
extractSdkResponseErrorMsg,
message,
ref,
storeToRefs,
useI18n,
useMetas,
useNuxtApp,
@ -27,7 +28,9 @@ interface ValidationsObj {
const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState(
(meta: Ref<TableType | undefined>, column: Ref<ColumnType | undefined>) => {
const { project, sqlUis, isMysql: isMysqlFunc, isPg: isPgFunc, isMssql: isMssqlFunc } = useProject()
const projectStore = useProject()
const { isMysql: isMysqlFunc, isPg: isPgFunc, isMssql: isMssqlFunc } = projectStore
const { project, sqlUis } = storeToRefs(projectStore)
const { $api } = useNuxtApp()

5
packages/nc-gui/composables/useExpandedFormStore.ts

@ -11,6 +11,7 @@ import {
message,
populateInsertObject,
ref,
storeToRefs,
useApi,
useI18n,
useInjectionState,
@ -42,7 +43,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
const changedColumns = ref(new Set<string>())
const { project } = useProject()
const { project } = storeToRefs(useProject())
const rowStore = useProvideSmartsheetRowStore(meta, row)
@ -103,7 +104,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
fk_model_id: meta.value.id as string,
comments_only: commentsOnly.value,
})
)?.reverse?.() || []
).list?.reverse?.() || []
}
const isYou = (email: string) => {

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

@ -100,6 +100,7 @@ export function useGlobalState(storageKey = 'nocodb-gui-v2'): State {
version: '0.0.0',
ncAttachmentFieldSize: 20,
ncMaxAttachmentsAllowed: 10,
isCloud: false,
})
/** reactive token payload */

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

@ -22,6 +22,7 @@ export interface AppInfo {
ee?: boolean
ncAttachmentFieldSize: number
ncMaxAttachmentsAllowed: number
isCloud: boolean
}
export interface StoredState {

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

@ -13,6 +13,7 @@ import {
message,
provide,
ref,
storeToRefs,
useApi,
useFieldQuery,
useI18n,
@ -40,7 +41,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
const { api } = useApi()
const { project } = useProject()
const { project, sqlUis } = storeToRefs(useProject())
const { $e, $api } = useNuxtApp()
@ -56,8 +57,6 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
const { search } = useFieldQuery()
const { sqlUis } = useProject()
const sqlUi = ref(
(meta.value as TableType)?.base_id ? sqlUis.value[(meta.value as TableType).base_id!] : Object.values(sqlUis.value)[0],
)
@ -154,7 +153,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
)
}
for (const data of groupData) {
for (const data of groupData ?? []) {
const key = data.key
formattedData.value.set(key, formatData(data.value.list))
countByStack.value.set(key, data.value.pageInfo.totalRows || 0)
@ -168,17 +167,26 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
where = `(${groupingField.value},is,null)`
}
if (xWhere.value) {
where = `${where} and ${xWhere.value}`
}
const response = !isPublic.value
? await api.dbViewRow.list('noco', project.value.id!, meta.value!.id!, viewMeta.value!.id!, {
...{ where: xWhere.value },
...params,
...(isUIAllowed('sortSync') ? {} : { sortArrJson: JSON.stringify(sorts.value) }),
...(isUIAllowed('filterSync') ? {} : { filterArrJson: JSON.stringify(nestedFilters.value) }),
where,
})
: await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value, offset: params.offset })
: await fetchSharedViewData({
...params,
sortsArr: sorts.value,
filtersArr: nestedFilters.value,
offset: params.offset,
where,
})
formattedData.value.set(stackTitle, [...formattedData.value.get(stackTitle)!, ...formatData(response.list)])
formattedData.value.set(stackTitle, [...formattedData.value.get(stackTitle)!, ...formatData(response!.list!)])
}
async function loadKanbanMeta() {
@ -300,10 +308,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
async function updateKanbanMeta(updateObj: Partial<KanbanType>) {
if (!viewMeta?.value?.id || !isUIAllowed('xcDatatableEditable')) return
await $api.dbView.kanbanUpdate(viewMeta.value.id, {
...kanbanMetaData.value,
...updateObj,
})
await $api.dbView.kanbanUpdate(viewMeta.value.id, updateObj)
}
async function insertRow(row: Record<string, any>, rowIndex = formattedData.value.get(null)!.length) {

3
packages/nc-gui/composables/useLTARStore.ts

@ -11,6 +11,7 @@ import {
message,
reactive,
ref,
storeToRefs,
useI18n,
useInjectionState,
useMetas,
@ -38,7 +39,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
// state
const { metas, getMeta } = useMetas()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { $api } = useNuxtApp()

15
packages/nc-gui/composables/useMapViewDataStore.ts

@ -1,7 +1,7 @@
import { reactive } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import type { ColumnType, MapType, PaginatedType, TableType, ViewType } from 'nocodb-sdk'
import { IsPublicInj, ref, useInjectionState, useMetas, useProject } from '#imports'
import { IsPublicInj, ref, storeToRefs, useInjectionState, useMetas, useProject } from '#imports'
import type { Row } from '~/lib'
const storedValue = localStorage.getItem('geodataToggleState')
@ -23,7 +23,7 @@ const formatData = (list: Record<string, any>[]) =>
const [useProvideMapViewStore, useMapViewStore] = useInjectionState(
(
meta: Ref<TableType | undefined>,
viewMeta: Ref<ViewType | MapType | undefined> | ComputedRef<(ViewType & { id: string }) | undefined>,
viewMeta: Ref<(ViewType | MapType | undefined) & { id: string }> | ComputedRef<(ViewType & { id: string }) | undefined>,
shared = false,
where?: ComputedRef<string | undefined>,
) => {
@ -35,7 +35,7 @@ const [useProvideMapViewStore, useMapViewStore] = useInjectionState(
const { api } = useApi()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { $api } = useNuxtApp()
@ -88,15 +88,12 @@ const [useProvideMapViewStore, useMapViewStore] = useInjectionState(
})
: await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value })
formattedData.value = formatData(res.list)
formattedData.value = formatData(res!.list)
}
async function updateMapMeta(updateObj: Partial<MapType>) {
if (!viewMeta?.value?.id || !isUIAllowed('xcDatatableEditable')) return
await $api.dbView.mapUpdate(viewMeta.value.id, {
...mapMetaData.value,
...updateObj,
})
await $api.dbView.mapUpdate(viewMeta.value.id, updateObj)
}
const { getMeta } = useMetas()
@ -107,7 +104,7 @@ const [useProvideMapViewStore, useMapViewStore] = useInjectionState(
{
metaValue = meta.value,
viewMetaValue = viewMeta.value,
}: { metaValue?: MapType; viewMetaValue?: ViewType | MapType } = {},
}: { metaValue?: MapType & { id: string }; viewMetaValue?: (ViewType | MapType) & { id: string } } = {},
) {
const row = currentRow.row
if (currentRow.rowMeta) currentRow.rowMeta.saving = true

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

@ -1,12 +1,12 @@
import { message } from 'ant-design-vue'
import type { WatchStopHandle } from 'vue'
import type { TableInfoType, TableType } from 'nocodb-sdk'
import { extractSdkResponseErrorMsg, useNuxtApp, useProject, useState, watch } from '#imports'
import { extractSdkResponseErrorMsg, storeToRefs, useNuxtApp, useProject, useState, watch } from '#imports'
export function useMetas() {
const { $api } = useNuxtApp()
const { tables } = useProject()
const { tables } = storeToRefs(useProject())
const metas = useState<{ [idOrTitle: string]: TableType | any }>('metas', () => ({}))

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

@ -12,10 +12,12 @@ import {
message,
provide,
ref,
storeToRefs,
useApi,
useI18n,
useInjectionState,
useMetas,
useProject,
useProvideSmartsheetRowStore,
watch,
} from '#imports'
@ -43,7 +45,8 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share
const { metas, setMeta } = useMetas()
const { project } = useProject()
const projectStore = useProject()
const { project } = storeToRefs(projectStore)
const { t } = useI18n()
@ -88,14 +91,14 @@ const [useProvideSharedFormStore, useSharedFormStore] = useInjectionState((share
// if project is not defined then set it with an object containing base
if (!project.value?.bases)
project.value = {
projectStore.setProject({
bases: [
{
id: viewMeta.base_id,
type: viewMeta.client,
},
],
}
})
const relatedMetas = { ...viewMeta.relatedMetas }

36
packages/nc-gui/composables/useSharedView.ts

@ -1,13 +1,13 @@
import type { ExportTypes, FilterType, KanbanType, PaginatedType, RequestParams, SortType, TableType, ViewType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import { computed, useGlobal, useMetas, useNuxtApp, useState } from '#imports'
import { computed, storeToRefs, useGlobal, useMetas, useNuxtApp, useState } from '#imports'
export function useSharedView() {
const nestedFilters = ref<(FilterType & { status?: 'update' | 'delete' | 'create'; parentId?: string })[]>([])
const { appInfo } = $(useGlobal())
const { project } = useProject()
const { project } = storeToRefs(useProject())
const appInfoDefaultLimit = appInfo.defaultLimit || 25
@ -56,7 +56,7 @@ export function useSharedView() {
}
if (localPassword) password.value = localPassword
sharedView.value = { title: '', ...viewMeta }
sharedView.value = { title: '', ...viewMeta } as ViewType
meta.value = { ...viewMeta.model }
let order = 1
@ -83,29 +83,34 @@ export function useSharedView() {
Object.keys(relatedMetas).forEach((key) => setMeta(relatedMetas[key]))
}
const fetchSharedViewData = async ({
sortsArr,
filtersArr,
offset,
}: {
const fetchSharedViewData = async (param: {
sortsArr: SortType[]
filtersArr: FilterType[]
fields?: any[]
sort?: any[]
where?: string
/** Query params for nested data */
nested?: any
offset?: number
}) => {
if (!sharedView.value) return
if (!sharedView.value)
return {
list: [],
pageInfo: {},
}
if (!offset) {
if (!param.offset) {
const page = paginationData.value.page || 1
const pageSize = paginationData.value.pageSize || appInfoDefaultLimit
offset = (page - 1) * pageSize
param.offset = (page - 1) * pageSize
}
const { data } = await $api.public.dataList(
return await $api.public.dataList(
sharedView.value.uuid!,
{
offset,
filterArrJson: JSON.stringify(filtersArr ?? nestedFilters.value),
sortArrJson: JSON.stringify(sortsArr ?? sorts.value),
...param,
filterArrJson: JSON.stringify(param.filtersArr ?? nestedFilters.value),
sortArrJson: JSON.stringify(param.sortsArr ?? sorts.value),
} as any,
{
headers: {
@ -113,7 +118,6 @@ export function useSharedView() {
},
},
)
return data
}
const fetchSharedViewGroupedData = async (

3
packages/nc-gui/composables/useSmartsheetRowStore.ts

@ -13,6 +13,7 @@ import {
isMm,
message,
ref,
storeToRefs,
unref,
useI18n,
useInjectionState,
@ -28,7 +29,7 @@ const [useProvideSmartsheetRowStore, useSmartsheetRowStore] = useInjectionState(
const { t } = useI18n()
const { project } = useProject()
const { project } = storeToRefs(useProject())
const { metas } = useMetas()

18
packages/nc-gui/composables/useSmartsheetStore.ts

@ -1,7 +1,17 @@
import { ViewTypes } from 'nocodb-sdk'
import type { FilterType, KanbanType, SortType, TableType, ViewType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { computed, ref, unref, useEventBus, useFieldQuery, useInjectionState, useNuxtApp, useProject } from '#imports'
import {
computed,
ref,
storeToRefs,
unref,
useEventBus,
useFieldQuery,
useInjectionState,
useNuxtApp,
useProject,
} from '#imports'
import type { SmartsheetStoreEvents } from '~/lib'
const [useProvideSmartsheetStore, useSmartsheetStore] = useInjectionState(
@ -14,7 +24,9 @@ const [useProvideSmartsheetStore, useSmartsheetStore] = useInjectionState(
) => {
const { $api } = useNuxtApp()
const { sqlUis } = useProject()
const projectStore = useProject()
const { sqlUis } = storeToRefs(projectStore)
const sqlUi = ref(
(meta.value as TableType)?.base_id ? sqlUis.value[(meta.value as TableType).base_id!] : Object.values(sqlUis.value)[0],
@ -51,7 +63,7 @@ const [useProvideSmartsheetStore, useSmartsheetStore] = useInjectionState(
})
const isSqlView = computed(() => (meta.value as TableType)?.type === 'view')
const sorts = ref<Required<SortType>[]>((unref(initialSorts) as Required<SortType>[]) ?? [])
const sorts = ref<SortType[]>(unref(initialSorts) ?? [])
const nestedFilters = ref<FilterType[]>(unref(initialFilters) ?? [])
return {

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

@ -7,6 +7,7 @@ import {
generateUniqueTitle as generateTitle,
message,
reactive,
storeToRefs,
useI18n,
useMetas,
useNuxtApp,
@ -32,7 +33,8 @@ export function useTable(onTableCreate?: (tableMeta: TableType) => void, baseId?
const { loadTables } = useProject()
const { closeTab } = useTabs()
const { sqlUis, project, tables } = useProject()
const projectStore = useProject()
const { sqlUis, project, tables } = storeToRefs(projectStore)
const sqlUi = computed(() => (baseId && sqlUis.value[baseId] ? sqlUis.value[baseId] : Object.values(sqlUis.value)[0]))

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

@ -1,7 +1,7 @@
import { ViewTypes, isSystemColumn } from 'nocodb-sdk'
import type { ColumnType, MapType, TableType, ViewType } from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue'
import { IsPublicInj, computed, inject, ref, useNuxtApp, useProject, useUIPermission, watch } from '#imports'
import { IsPublicInj, computed, inject, ref, storeToRefs, useNuxtApp, useProject, useUIPermission, watch } from '#imports'
import type { Field } from '~/lib'
export function useViewColumns(
@ -19,7 +19,7 @@ export function useViewColumns(
const { isUIAllowed } = useUIPermission()
const { isSharedBase } = useProject()
const { isSharedBase } = storeToRefs(useProject())
const isLocalMode = computed(
() => isPublic.value || !isUIAllowed('hideAllColumns') || !isUIAllowed('showAllColumns') || isSharedBase.value,
@ -35,13 +35,13 @@ export function useViewColumns(
const metaColumnById = computed<Record<string, ColumnType>>(() => {
if (!meta.value?.columns) return {}
return meta.value.columns.reduce(
return (meta.value.columns as ColumnType[]).reduce(
(acc, curr) => ({
...acc,
[curr.id!]: curr,
}),
{},
)
) as Record<string, ColumnType>
})
const loadViewColumns = async () => {
@ -50,7 +50,7 @@ export function useViewColumns(
let order = 1
if (view.value?.id) {
const data = (isPublic.value ? meta.value?.columns : await $api.dbViewColumn.list(view.value.id)) as any[]
const data = (isPublic.value ? meta.value?.columns : (await $api.dbViewColumn.list(view.value.id)).list) as any[]
const fieldById = data.reduce<Record<string, any>>((acc, curr) => {
curr.show = !!curr.show
@ -162,7 +162,7 @@ export function useViewColumns(
const showSystemFields = computed({
get() {
return view.value?.show_system_fields || false
return (view.value?.show_system_fields as boolean) || false
},
set(v: boolean) {
if (view?.value?.id) {

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

@ -12,6 +12,7 @@ import {
message,
populateInsertObject,
ref,
storeToRefs,
until,
useApi,
useGlobal,
@ -26,7 +27,7 @@ import {
} from '#imports'
import type { Row } from '~/lib'
const formatData = (list: Row[]) =>
const formatData = (list: Record<string, any>[]) =>
list.map((row) => ({
row: { ...row },
oldRow: { ...row },
@ -58,7 +59,7 @@ export function useViewData(
const _paginationData = ref<PaginatedType>({ page: 1, pageSize: appInfoDefaultLimit })
const aggCommentCount = ref<{ row_id: string; count: number }[]>([])
const aggCommentCount = ref<{ row_id: string; count: string }[]>([])
const galleryData = ref<GalleryType>()
@ -70,7 +71,7 @@ export function useViewData(
const isPublic = inject(IsPublicInj, ref(false))
const { project, isSharedBase } = useProject()
const { project, isSharedBase } = storeToRefs(useProject())
const { sharedView, fetchSharedViewData, paginationData: sharedPaginationData } = useSharedView()
@ -182,7 +183,7 @@ export function useViewData(
for (const row of formattedData.value) {
const id = extractPkFromRow(row.row, meta.value?.columns as ColumnType[])
row.rowMeta.commentCount = aggCommentCount.value?.find((c: Record<string, any>) => c.row_id === id)?.count || 0
row.rowMeta.commentCount = +(aggCommentCount.value?.find((c: Record<string, any>) => c.row_id === id)?.count || 0)
}
}
@ -197,6 +198,7 @@ export function useViewData(
where: where?.value,
})
: await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value })
formattedData.value = formatData(response.list)
paginationData.value = response.pageInfo

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

@ -11,6 +11,7 @@ import {
inject,
message,
ref,
storeToRefs,
useDebounceFn,
useMetas,
useNuxtApp,
@ -35,7 +36,7 @@ export function useViewFilters(
const { nestedFilters } = useSmartsheetStoreOrThrow()
const { projectMeta } = useProject()
const { projectMeta } = storeToRefs(useProject())
const isPublic = inject(IsPublicInj, ref(false))
@ -161,6 +162,7 @@ export function useViewFilters(
const placeholderFilter = (): Filter => {
return {
// TODO: fix type
comparison_op: comparisonOpList(options.value?.[0].uidt as UITypes).filter((compOp) =>
isComparisonOpAllowed({ fk_column_id: options.value?.[0].id }, compOp),
)?.[0].value,
@ -180,16 +182,15 @@ export function useViewFilters(
try {
if (hookId) {
if (parentId) {
filters.value = await $api.dbTableFilter.childrenRead(parentId)
filters.value = (await $api.dbTableFilter.childrenRead(parentId)).list as Filter[]
} else {
// todo: return type is incorrect
filters.value = (await $api.dbTableWebhookFilter.read(hookId!)) as unknown as Filter[]
filters.value = (await $api.dbTableWebhookFilter.read(hookId!)).list as Filter[]
}
} else {
if (parentId) {
filters.value = await $api.dbTableFilter.childrenRead(parentId)
filters.value = (await $api.dbTableFilter.childrenRead(parentId)).list as Filter[]
} else {
filters.value = await $api.dbTableFilter.read(view.value!.id!)
filters.value = (await $api.dbTableFilter.read(view.value!.id!)).list as Filter[]
}
}
} catch (e: any) {

5
packages/nc-gui/composables/useViewSorts.ts

@ -7,6 +7,7 @@ import {
inject,
message,
ref,
storeToRefs,
useNuxtApp,
useProject,
useSharedView,
@ -24,7 +25,7 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
const { isUIAllowed } = useUIPermission()
const { isSharedBase } = useProject()
const { isSharedBase } = storeToRefs(useProject())
const reloadHook = inject(ReloadViewDataHookInj)
@ -49,7 +50,7 @@ export function useViewSorts(view: Ref<ViewType | undefined>, reloadData?: () =>
}
}
if (!view?.value) return
sorts.value = (await $api.dbTableSort.list(view.value!.id!)).sorts?.list || []
sorts.value = (await $api.dbTableSort.list(view.value!.id!)).list as SortType[]
} catch (e: any) {
console.error(e)
message.error(await extractSdkResponseErrorMsg(e))

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

@ -12,7 +12,7 @@ import PurgeIcons from 'vite-plugin-purge-icons'
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
modules: ['@vueuse/nuxt', 'nuxt-windicss', '@nuxt/image-edge'],
modules: ['@vueuse/nuxt', 'nuxt-windicss', '@nuxt/image-edge', '@pinia/nuxt'],
ssr: false,
@ -190,7 +190,7 @@ export default defineNuxtConfig({
},
imports: {
dirs: ['./context', './utils/**', './lib', './composables/**'],
dirs: ['./context', './utils/**', './lib', './composables/**', './store/**'],
imports: [
{ name: 'useI18n', from: 'vue-i18n' },
{ name: 'message', from: 'ant-design-vue/es' },
@ -198,6 +198,7 @@ export default defineNuxtConfig({
{ name: 'Empty', from: 'ant-design-vue/es' },
{ name: 'Form', from: 'ant-design-vue/es' },
{ name: 'useJwt', from: '@vueuse/integrations/useJwt' },
{ name: 'storeToRefs', from: 'pinia' },
],
},
})

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

File diff suppressed because it is too large Load Diff

5
packages/nc-gui/package.json

@ -33,6 +33,7 @@
"dependencies": {
"@ckpack/vue-color": "^1.2.0",
"@iconify/vue": "^4.0.1",
"@pinia/nuxt": "^0.4.7",
"@types/file-saver": "^2.0.5",
"@vue-flow/additional-components": "^1.2.0",
"@vue-flow/core": "^1.3.0",
@ -56,6 +57,7 @@
"monaco-editor": "^0.33.0",
"nocodb-sdk": "file:../nocodb-sdk",
"papaparse": "^5.3.2",
"pinia": "^2.0.33",
"qrcode": "^1.5.1",
"socket.io-client": "^4.5.1",
"sortablejs": "^1.15.0",
@ -127,5 +129,8 @@
"vite-plugin-purge-icons": "^0.9.0",
"vitest": "^0.18.0",
"windicss": "^3.5.6"
},
"overrides": {
"vue": "latest"
}
}

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

@ -18,6 +18,7 @@ import {
projectThemeColors,
ref,
resolveComponent,
storeToRefs,
useCopy,
useDialog,
useGlobal,
@ -47,7 +48,10 @@ const router = useRouter()
const { appInfo, token, signOut, signedIn, user, currentVersion, isMobileMode, setIsMobileMode } = useGlobal()
const { project, isSharedBase, loadProjectMetaInfo, projectMetaInfo, saveTheme, loadProject, reset } = useProject()
const projectStore = useProject()
const { loadProjectMetaInfo, saveTheme, loadProject, reset } = projectStore
const { project, isSharedBase, projectMetaInfo } = storeToRefs(projectStore)
const { clearTabs, addTab } = useTabs()
@ -595,9 +599,7 @@ useEventListener(document, 'keydown', async (e: KeyboardEvent) => {
v-model:open-key="openDialogKey"
v-model:data-sources-state="dataSourcesState"
/>
<NuxtPage :page-key="$route.params.projectId" />
<LazyGeneralPreviewAs float />
</div>
</NuxtLayout>

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

@ -2,9 +2,11 @@
import { Icon } from '@iconify/vue'
import type { TabItem } from '~/lib'
import { TabType } from '~/lib'
import { TabMetaInj, iconMap, provide, useGlobal, useSidebar, useTabs } from '#imports'
import { TabMetaInj, iconMap, provide, storeToRefs, useGlobal, useSidebar, useTabs } from '#imports'
const { tabs, activeTabIndex, activeTab, closeTab } = useTabs()
const tabStore = useTabs()
const { closeTab } = tabStore
const { tabs, activeTabIndex, activeTab } = storeToRefs(tabStore)
const { isLoading, isMobileMode } = useGlobal()

5
packages/nc-gui/pages/[projectType]/[projectId]/index/index/[type]/[title]/[[viewTitle]].vue

@ -1,10 +1,11 @@
<script setup lang="ts">
import type { TabItem } from '~/lib'
import { TabMetaInj, computed, inject, ref, until, useMetas, useProject, useRoute } from '#imports'
import { TabMetaInj, computed, inject, ref, storeToRefs, until, useMetas, useProject, useRoute } from '#imports'
const { getMeta } = useMetas()
const { tables } = useProject()
const projectStore = useProject()
const { tables } = storeToRefs(projectStore)
const route = useRoute()

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

@ -5,6 +5,7 @@ import {
message,
ref,
resolveComponent,
storeToRefs,
useDialog,
useDropZone,
useFileDialog,
@ -20,7 +21,9 @@ const { isOverDropZone } = useDropZone(dropZone, onDrop)
const { files, open, reset } = useFileDialog()
const { bases, isSharedBase } = useProject()
const projectStore = useProject()
const { bases, isSharedBase } = storeToRefs(projectStore)
const { isUIAllowed } = useUIPermission()

5
packages/nc-gui/pages/account/index.vue

@ -2,8 +2,11 @@
import { navigateTo, useUIPermission } from '#imports'
const { isUIAllowed } = useUIPermission()
const $route = useRoute()
const { appInfo } = useGlobal()
const selectedKeys = computed(() => [
/^\/account\/users\/?$/.test($route.fullPath)
? isUIAllowed('superAdminUserManagement')
@ -68,7 +71,7 @@ const openKeys = ref([/^\/account\/users/.test($route.fullPath) && 'users'])
</div>
</a-menu-item>
<a-menu-item
v-if="isUIAllowed('appStore')"
v-if="isUIAllowed('appStore') && !appInfo.isCloud"
key="apps"
class="group active:(!ring-0) hover:(!bg-primary !bg-opacity-25)"
@click="navigateTo('/account/apps')"

6
packages/nc-gui/pages/account/index/[page].vue

@ -1,7 +1,11 @@
<script setup lang="ts">
const { appInfo } = useGlobal()
</script>
<template>
<AccountUserManagement v-if="$route.params.page === 'users'" />
<AccountToken v-else-if="$route.params.page === 'tokens'" />
<AccountAppStore v-else-if="$route.params.page === 'apps'" />
<AccountAppStore v-else-if="$route.params.page === 'apps' && !appInfo.isCloud" />
<AccountLicense v-else-if="$route.params.page === 'license'" />
<span v-else></span>
</template>

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

@ -10,13 +10,17 @@ import {
projectTitleValidator,
reactive,
ref,
storeToRefs,
useProject,
useRoute,
} from '#imports'
const route = useRoute()
const { project, loadProject, updateProject, isLoading } = useProject()
const projectStore = useProject()
const { loadProject, updateProject } = projectStore
const { project, isLoading } = storeToRefs(projectStore)
const nameValidationRules = [
{

9
packages/nc-gui/composables/useProject.ts → packages/nc-gui/store/project.ts

@ -1,11 +1,11 @@
import type { BaseType, OracleUi, ProjectType, TableType } from 'nocodb-sdk'
import { SqlUiFactory } from 'nocodb-sdk'
import { isString } from '@vueuse/core'
import { defineStore } from 'pinia'
import {
ClientType,
computed,
createEventHook,
createSharedComposable,
ref,
useApi,
useGlobal,
@ -16,7 +16,7 @@ import {
} from '#imports'
import type { ProjectMetaInfo, ThemeConfig } from '~/lib'
export const useProject = createSharedComposable(() => {
export const useProject = defineStore('projectStore', () => {
const { $e } = useNuxtApp()
const { api, isLoading } = useApi()
@ -186,6 +186,10 @@ export const useProject = createSharedComposable(() => {
setTheme()
}
const setProject = (projectVal: ProjectType) => {
project.value = projectVal
}
watch(
() => route.params.projectType,
(n) => {
@ -217,5 +221,6 @@ export const useProject = createSharedComposable(() => {
lastOpenedViewMap,
isXcdbBase,
hasEmptyOrNullFilters,
setProject,
}
})

21
packages/nc-gui/composables/useTabs.ts → packages/nc-gui/store/tab.ts

@ -1,5 +1,6 @@
import type { WritableComputedRef } from '@vue/reactivity'
import { computed, createSharedComposable, navigateTo, ref, useProject, useRouter, watch } from '#imports'
import { defineStore } from 'pinia'
import { computed, navigateTo, ref, useProject, useRouter, watch } from '#imports'
import type { TabItem } from '~/lib'
import { TabType } from '~/lib'
@ -10,14 +11,14 @@ function getPredicate(key: Partial<TabItem>) {
(!('type' in key) || tab.type === key.type)
}
export const useTabs = createSharedComposable(() => {
export const useTabs = defineStore('tabStore', () => {
const tabs = ref<TabItem[]>([])
const router = useRouter()
const route = $(router.currentRoute)
const { bases, tables } = useProject()
const projectStore = useProject()
const projectType = $computed(() => route.params.projectType as string)
@ -26,14 +27,14 @@ export const useTabs = createSharedComposable(() => {
get() {
const routeName = route.name as string
if (routeName.startsWith('projectType-projectId-index-index-type-title-viewTitle') && tables.value.length) {
if (routeName.startsWith('projectType-projectId-index-index-type-title-viewTitle') && projectStore.tables.length) {
const tab: TabItem = { type: route.params.type as TabType, title: route.params.title as string }
const currentTable = tables.value.find((t) => t.id === tab.title || t.title === tab.title)
const currentTable = projectStore.tables.find((t) => t.id === tab.title || t.title === tab.title)
if (!currentTable) return -1
const currentBase = bases.value.find((b) => b.id === currentTable.base_id)
const currentBase = projectStore.bases.find((b) => b.id === currentTable.base_id)
tab.id = currentTable.id
@ -44,7 +45,7 @@ export const useTabs = createSharedComposable(() => {
tab.meta = currentTable.meta
// append base alias to tab title if duplicate titles exist on other bases
if (tables.value.find((t) => t.title === currentTable?.title && t.base_id !== currentTable?.base_id))
if (projectStore.tables.find((t) => t.title === currentTable?.title && t.base_id !== currentTable?.base_id))
tab.title = `${tab.title}${currentBase?.alias ? ` (${currentBase.alias})` : ``}`
if (index === -1) {
@ -91,13 +92,13 @@ export const useTabs = createSharedComposable(() => {
}
// if tab not found add it
else {
const currentTable = tables.value.find((t) => t.id === tabMeta.id || t.title === tabMeta.id)
const currentBase = bases.value.find((b) => b.id === currentTable?.base_id)
const currentTable = projectStore.tables.find((t) => t.id === tabMeta.id || t.title === tabMeta.id)
const currentBase = projectStore.bases.find((b) => b.id === currentTable?.base_id)
tabMeta.meta = currentTable?.meta
// append base alias to tab title if duplicate titles exist on other bases
if (tables.value.find((t) => t.title === currentTable?.title && t.base_id !== currentTable?.base_id))
if (projectStore.tables.find((t) => t.title === currentTable?.title && t.base_id !== currentTable?.base_id))
tabMeta.title = `${tabMeta.title}${currentBase?.alias ? ` (${currentBase.alias})` : ``}`
tabs.value = [...(tabs.value || []), tabMeta]

5440
packages/nocodb-sdk/src/lib/Api.ts

File diff suppressed because it is too large Load Diff

7
packages/nocodb-sdk/src/lib/formulaHelpers.ts

@ -179,9 +179,8 @@ export function jsepTreeToFormula(node) {
if (node.type === 'Literal') {
if (typeof node.value === 'string') {
return '"' + node.value + '"';
return String.raw`"${escapeDoubleQuotes(node.value)}"`;
}
return '' + node.value;
}
@ -214,3 +213,7 @@ export function jsepTreeToFormula(node) {
return '';
}
function escapeDoubleQuotes(v: string) {
return v.replace(/"/g, '\\"');
}

1
packages/nocodb/package.json

@ -30,6 +30,7 @@
"unit-test": "cross-env TS_NODE_PROJECT=tsconfig.json mocha --require ts-node/register 'src/__tests__/unit/**/*.test.ts' --recursive --check-leaks --exit",
"local:test:unit": "cross-env TS_NODE_PROJECT=./tests/unit/tsconfig.json mocha -r ts-node/register tests/unit/index.test.ts --recursive --timeout 300000 --exit --delay",
"test:unit": "cross-env TS_NODE_PROJECT=./tests/unit/tsconfig.json mocha -r ts-node/register tests/unit/index.test.ts --recursive --timeout 300000 --exit --delay",
"test:unit:pg": "cp tests/unit/.pg.env tests/unit/.env; cross-env TS_NODE_PROJECT=./tests/unit/tsconfig.json mocha -r ts-node/register tests/unit/index.test.ts --recursive --timeout 300000 --exit --delay",
"test:lint": "tslint --project . && prettier \"src/**/*.ts\" --list-different",
"watch": "run-s clean build:main && run-p \"build:main -- -w\" \"test:unit -- --watch\"",
"clean": "trash build src/test",

3
packages/nocodb/src/lib/Noco.ts

@ -2,7 +2,6 @@
import fs from 'fs';
import path from 'path';
import { promisify } from 'util';
import * as Sentry from '@sentry/node';
import bodyParser from 'body-parser';
import clear from 'clear';
@ -14,14 +13,12 @@ import morgan from 'morgan';
import NcToolGui from 'nc-lib-gui';
import requestIp from 'request-ip';
import { v4 as uuidv4 } from 'uuid';
import { T } from 'nc-help';
import mkdirp from 'mkdirp';
import { NC_LICENSE_KEY } from './constants';
import Migrator from './db/sql-migrator/lib/KnexMigrator';
import Store from './models/Store';
import NcConfigFactory from './utils/NcConfigFactory';
import NcProjectBuilderCE from './v1-legacy/NcProjectBuilder';
import NcProjectBuilderEE from './v1-legacy/NcProjectBuilderEE';
import NcMetaImplCE from './meta/NcMetaIOImpl';

7
packages/nocodb/src/lib/controllers/apiToken.ctl.ts

@ -1,11 +1,16 @@
import { Router } from 'express';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import { PagedResponseImpl } from '../meta/helpers/PagedResponse';
import { apiTokenService } from '../services';
import type { Request, Response } from 'express';
export async function apiTokenList(req: Request, res: Response) {
res.json(await apiTokenService.apiTokenList({ userId: req['user'].id }));
res.json(
new PagedResponseImpl(
await apiTokenService.apiTokenList({ userId: req['user'].id })
)
);
}
export async function apiTokenCreate(req: Request, res: Response) {

17
packages/nocodb/src/lib/controllers/audit.ctl.ts

@ -25,13 +25,18 @@ export async function auditRowUpdate(req: Request<any, any>, res) {
}
export async function commentList(req: Request<any, any, any>, res) {
res.json(await Audit.commentsList(req.query));
res.json(
new PagedResponseImpl(await auditService.commentList({ query: req.query }))
);
}
export async function auditList(req: Request, res: Response) {
res.json(
new PagedResponseImpl(
await Audit.projectAuditList(req.params.projectId, req.query),
await auditService.auditList({
query: req.query,
projectId: req.params.projectId,
}),
{
count: await Audit.projectAuditCount(req.params.projectId),
...req.query,
@ -42,7 +47,7 @@ export async function auditList(req: Request, res: Response) {
export async function commentsCount(req: Request<any, any, any>, res) {
res.json(
await Audit.commentsCount({
await auditService.commentsCount({
fk_model_id: req.query.fk_model_id as string,
ids: req.query.ids as string[],
})
@ -50,24 +55,30 @@ export async function commentsCount(req: Request<any, any, any>, res) {
}
const router = Router({ mergeParams: true });
router.get(
'/api/v1/db/meta/audits/comments',
ncMetaAclMw(commentList, 'commentList')
);
router.post(
'/api/v1/db/meta/audits/comments',
ncMetaAclMw(commentRow, 'commentRow')
);
router.post(
'/api/v1/db/meta/audits/rows/:rowId/update',
ncMetaAclMw(auditRowUpdate, 'auditRowUpdate')
);
router.get(
'/api/v1/db/meta/audits/comments/count',
ncMetaAclMw(commentsCount, 'commentsCount')
);
router.get(
'/api/v1/db/meta/projects/:projectId/audits',
ncMetaAclMw(auditList, 'auditList')
);
export default router;

14
packages/nocodb/src/lib/controllers/base.ctl.ts

@ -1,7 +1,6 @@
import { PagedResponseImpl } from '../meta/helpers/PagedResponse';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import { baseService } from '../services';
import type Base from '../models/Base';
import type { BaseListType } from 'nocodb-sdk';
@ -32,13 +31,12 @@ async function baseList(
projectId: req.params.projectId,
});
res // todo: pagination
.json({
bases: new PagedResponseImpl(bases, {
count: bases.length,
limit: bases.length,
}),
});
res.json(
new PagedResponseImpl(bases, {
count: bases.length,
limit: bases.length,
})
);
}
export async function baseDelete(

5
packages/nocodb/src/lib/controllers/dbData/data.ctl.ts

@ -118,10 +118,9 @@ async function relationDataDelete(req, res) {
cookie: req,
});
res.json({ msg: 'success' });
res.json({ msg: 'The relation data has been deleted successfully' });
}
//@ts-ignore
async function relationDataAdd(req, res) {
await dataService.relationDataAdd({
viewId: req.params.viewId,
@ -131,7 +130,7 @@ async function relationDataAdd(req, res) {
cookie: req,
});
res.json({ msg: 'success' });
res.json({ msg: 'The relation data has been created successfully' });
}
const router = Router({ mergeParams: true });

4
packages/nocodb/src/lib/controllers/dbData/dataAliasNested.ctl.ts

@ -77,7 +77,7 @@ async function relationDataRemove(req, res) {
refRowId: req.params.refRowId,
});
res.json({ msg: 'success' });
res.json({ msg: 'The relation data has been deleted successfully' });
}
//@ts-ignore
@ -92,7 +92,7 @@ async function relationDataAdd(req, res) {
refRowId: req.params.refRowId,
});
res.json({ msg: 'success' });
res.json({ msg: 'The relation data has been created successfully' });
}
const router = Router({ mergeParams: true });

3
packages/nocodb/src/lib/controllers/dbData/helpers.ts

@ -7,13 +7,12 @@ import Model from '../../models/Model';
import View from '../../models/View';
import Base from '../../models/Base';
import NcConnectionMgrv2 from '../../utils/common/NcConnectionMgrv2';
import Column from '../../models/Column';
import { dataService } from '../../services';
import type LookupColumn from '../../models/LookupColumn';
import type LinkToAnotherRecordColumn from '../../models/LinkToAnotherRecordColumn';
import type { Request } from 'express';
export async function getViewAndModelFromRequestByAliasOrId(
req:
| Request<{ projectName: string; tableName: string; viewName?: string }>

37
packages/nocodb/src/lib/controllers/filter.ctl.ts

@ -1,32 +1,33 @@
import { Router } from 'express';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import { PagedResponseImpl } from '../meta/helpers/PagedResponse';
import { filterService } from '../services';
import type { FilterReqType } from 'nocodb-sdk';
import type { FilterListType, FilterReqType } from 'nocodb-sdk';
import type { Request, Response } from 'express';
// @ts-ignore
export async function filterGet(req: Request, res: Response) {
res.json(await filterService.filterGet({ filterId: req.params.filterId }));
}
// @ts-ignore
export async function filterList(req: Request, res: Response) {
export async function filterList(req: Request, res: Response<FilterListType>) {
res.json(
await filterService.filterList({
viewId: req.params.viewId,
})
new PagedResponseImpl(
await filterService.filterList({
viewId: req.params.viewId,
})
)
);
}
// @ts-ignore
export async function filterChildrenRead(req: Request, res: Response) {
const filter = await filterService.filterChildrenList({
filterId: req.params.filterParentId,
});
res.json(filter);
res.json(
new PagedResponseImpl(
await filterService.filterChildrenList({
filterId: req.params.filterParentId,
})
)
);
}
export async function filterCreate(req: Request<any, any, FilterReqType>, res) {
@ -54,9 +55,11 @@ export async function filterDelete(req: Request, res: Response) {
export async function hookFilterList(req: Request, res: Response) {
res.json(
await filterService.hookFilterList({
hookId: req.params.hookId,
})
new PagedResponseImpl(
await filterService.hookFilterList({
hookId: req.params.hookId,
})
)
);
}

18
packages/nocodb/src/lib/controllers/hook.ctl.ts

@ -11,7 +11,6 @@ export async function hookList(
req: Request<any, any, any>,
res: Response<HookListType>
) {
// todo: pagination
res.json(
new PagedResponseImpl(
await hookService.hookList({ tableId: req.params.tableId })
@ -51,18 +50,17 @@ export async function hookTest(req: Request<any, any>, res: Response) {
hookTest: req.body,
tableId: req.params.tableId,
});
res.json({ msg: 'Success' });
res.json({ msg: 'The hook has been tested successfully' });
}
export async function tableSampleData(req: Request, res: Response) {
res // todo: pagination
.json(
await hookService.tableSampleData({
tableId: req.params.tableId,
// todo: replace any with type
operation: req.params.operation as any,
})
);
res.json(
await hookService.tableSampleData({
tableId: req.params.tableId,
// todo: replace any with type
operation: req.params.operation as any,
})
);
}
const router = Router({ mergeParams: true });

91
packages/nocodb/src/lib/controllers/hookFilter.ctl.ts

@ -1,91 +0,0 @@
import { Router } from 'express';
import { T } from 'nc-help';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import { hookFilterService } from '../services';
import type { Request, Response } from 'express';
export async function filterGet(req: Request, res: Response) {
const filter = await hookFilterService.filterGet({
hookId: req.params.hookId,
});
res.json(filter);
}
export async function filterList(req: Request, res: Response) {
const filter = await hookFilterService.filterList({
hookId: req.params.hookId,
});
res.json(filter);
}
export async function filterChildrenRead(req: Request, res: Response) {
const filter = await hookFilterService.filterChildrenRead({
hookId: req.params.hookId,
filterParentId: req.params.filterParentId,
});
res.json(filter);
}
export async function filterCreate(req: Request<any, any>, res) {
const filter = await hookFilterService.filterCreate({
filter: req.body,
hookId: req.params.hookId,
});
res.json(filter);
}
export async function filterUpdate(req, res) {
const filter = await hookFilterService.filterUpdate({
filterId: req.params.filterId,
filter: req.body,
hookId: req.params.hookId,
});
res.json(filter);
}
export async function filterDelete(req: Request, res: Response) {
const filter = await hookFilterService.filterDelete({
filterId: req.params.filterId,
});
T.emit('evt', { evt_type: 'hookFilter:deleted' });
res.json(filter);
}
const router = Router({ mergeParams: true });
router.get(
'/hooks/:hookId/filters/',
metaApiMetrics,
ncMetaAclMw(filterList, 'filterList')
);
router.post(
'/hooks/:hookId/filters/',
metaApiMetrics,
ncMetaAclMw(filterCreate, 'filterCreate')
);
router.get(
'/hooks/:hookId/filters/:filterId',
metaApiMetrics,
ncMetaAclMw(filterGet, 'filterGet')
);
router.patch(
'/hooks/:hookId/filters/:filterId',
metaApiMetrics,
ncMetaAclMw(filterUpdate, 'filterUpdate')
);
router.delete(
'/hooks/:hookId/filters/:filterId',
metaApiMetrics,
ncMetaAclMw(filterDelete, 'filterDelete')
);
router.get(
'/hooks/:hookId/filters/:filterParentId/children',
metaApiMetrics,
ncMetaAclMw(filterChildrenRead, 'filterChildrenRead')
);
export default router;

4
packages/nocodb/src/lib/controllers/metaDiff.ctl.ts

@ -18,7 +18,7 @@ export async function baseMetaDiff(req, res) {
export async function metaDiffSync(req, res) {
await metaDiffService.metaDiffSync({ projectId: req.params.projectId });
res.json({ msg: 'success' });
res.json({ msg: 'The meta has been synchronized successfully' });
}
export async function baseMetaDiffSync(req, res) {
@ -27,7 +27,7 @@ export async function baseMetaDiffSync(req, res) {
baseId: req.params.baseId,
});
res.json({ msg: 'success' });
res.json({ msg: 'The base meta has been synchronized successfully' });
}
const router = Router();

2
packages/nocodb/src/lib/controllers/modelVisibility.ctl.ts

@ -9,7 +9,7 @@ async function xcVisibilityMetaSetAll(req, res) {
projectId: req.params.projectId,
});
res.json({ msg: 'success' });
res.json({ msg: 'UI ACL has been created successfully' });
}
const router = Router({ mergeParams: true });

2
packages/nocodb/src/lib/controllers/orgLicense.ctl.ts

@ -10,7 +10,7 @@ async function licenseGet(_req, res) {
async function licenseSet(req, res) {
await orgLicenseService.licenseSet({ key: req.body.key });
res.json({ msg: 'License key saved' });
res.json({ msg: 'The license key has been saved' });
}
const router = Router({ mergeParams: true });

20
packages/nocodb/src/lib/controllers/orgUser.ctl.ts

@ -2,13 +2,21 @@ import { Router } from 'express';
import { OrgUserRoles } from 'nocodb-sdk';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { PagedResponseImpl } from '../meta/helpers/PagedResponse';
import { orgUserService } from '../services';
import { User } from '../models';
async function userList(req, res) {
res.json(
await orgUserService.userList({
query: req.query,
})
new PagedResponseImpl(
await orgUserService.userList({
query: req.query,
}),
{
...req.query,
count: await User.count(req.query),
}
)
);
}
@ -25,7 +33,7 @@ async function userDelete(req, res) {
await orgUserService.userDelete({
userId: req.params.userId,
});
res.json({ msg: 'success' });
res.json({ msg: 'The user has been deleted successfully' });
}
async function userAdd(req, res) {
@ -49,7 +57,7 @@ async function userInviteResend(req, res): Promise<any> {
req,
});
res.json({ msg: 'success' });
res.json({ msg: 'The invitation has been sent to the user' });
}
async function generateResetUrl(req, res) {
@ -71,7 +79,7 @@ async function appSettingsSet(req, res) {
settings: req.body,
});
res.json({ msg: 'Settings saved' });
res.json({ msg: 'The app settings have been saved' });
}
const router = Router({ mergeParams: true });

13
packages/nocodb/src/lib/controllers/plugin.ctl.ts

@ -17,6 +17,7 @@ export async function pluginTest(req: Request<any, any>, res: Response) {
export async function pluginRead(req: Request, res: Response) {
res.json(await pluginService.pluginRead({ pluginId: req.params.pluginId }));
}
export async function pluginUpdate(
req: Request<any, any, PluginType>,
res: Response
@ -27,36 +28,48 @@ export async function pluginUpdate(
});
res.json(plugin);
}
export async function isPluginActive(req: Request, res: Response) {
res.json(
await pluginService.isPluginActive({ pluginTitle: req.params.pluginTitle })
);
}
const blockInCloudMw = (_req, res, next) => {
if (process.env.NC_CLOUD === 'true') {
res.status(403).send('Not allowed');
} else next();
};
const router = Router({ mergeParams: true });
router.get(
'/api/v1/db/meta/plugins',
blockInCloudMw,
metaApiMetrics,
ncMetaAclMw(pluginList, 'pluginList')
);
router.post(
'/api/v1/db/meta/plugins/test',
metaApiMetrics,
blockInCloudMw,
ncMetaAclMw(pluginTest, 'pluginTest')
);
router.get(
'/api/v1/db/meta/plugins/:pluginId',
metaApiMetrics,
blockInCloudMw,
ncMetaAclMw(pluginRead, 'pluginRead')
);
router.patch(
'/api/v1/db/meta/plugins/:pluginId',
metaApiMetrics,
blockInCloudMw,
ncMetaAclMw(pluginUpdate, 'pluginUpdate')
);
router.get(
'/api/v1/db/meta/plugins/:pluginTitle/status',
metaApiMetrics,
blockInCloudMw,
ncMetaAclMw(isPluginActive, 'isPluginActive')
);
export default router;

1
packages/nocodb/src/lib/controllers/project.ctl.ts

@ -9,7 +9,6 @@ import Noco from '../Noco';
import Project from '../models/Project';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import Filter from '../models/Filter';
import { projectService } from '../services';
import type { ProjectListType } from 'nocodb-sdk';
import type { ProjectType } from 'nocodb-sdk';

39
packages/nocodb/src/lib/controllers/projectUser.ctl.ts

@ -22,16 +22,16 @@ async function userInvite(req, res): Promise<any> {
);
}
// @ts-ignore
async function projectUserUpdate(req, res, next): Promise<any> {
res.json(
await projectUserService.projectUserUpdate({
projectUser: req.body,
projectId: req.params.projectId,
userId: req.params.userId,
req,
})
);
async function projectUserUpdate(req, res): Promise<any> {
await projectUserService.projectUserUpdate({
projectUser: req.body,
projectId: req.params.projectId,
userId: req.params.userId,
req,
});
res.json({
msg: 'The user has been updated successfully',
});
}
async function projectUserDelete(req, res): Promise<any> {
@ -41,19 +41,20 @@ async function projectUserDelete(req, res): Promise<any> {
req,
});
res.json({
msg: 'success',
msg: 'The user has been deleted successfully',
});
}
async function projectUserInviteResend(req, res): Promise<any> {
res.json(
await projectUserService.projectUserInviteResend({
projectId: req.params.projectId,
userId: req.params.userId,
projectUser: req.body,
req,
})
);
await projectUserService.projectUserInviteResend({
projectId: req.params.projectId,
userId: req.params.userId,
projectUser: req.body,
req,
});
res.json({
msg: 'The invitation has been sent to the user',
});
}
const router = Router({ mergeParams: true });

2
packages/nocodb/src/lib/controllers/publicControllers/publicData.ctl.ts

@ -11,7 +11,7 @@ export async function dataList(req: Request, res: Response) {
password: req.headers?.['xc-password'] as string,
sharedViewUuid: req.params.sharedViewUuid,
});
res.json({ data: pagedResponse });
res.json(pagedResponse);
}
// todo: Handle the error case where view doesnt belong to model

17
packages/nocodb/src/lib/controllers/sort.ctl.ts

@ -2,25 +2,23 @@ import { Router } from 'express';
import { PagedResponseImpl } from '../meta/helpers/PagedResponse';
import ncMetaAclMw from '../meta/helpers/ncMetaAclMw';
import { metaApiMetrics } from '../meta/helpers/apiMetrics';
import { sortService } from '../services';
import type { SortListType, SortReqType } from 'nocodb-sdk';
import type { Request, Response } from 'express';
// @ts-ignore
export async function sortList(
req: Request<any, any, any>,
res: Response<SortListType>
) {
const sortList = await sortService.sortList({
viewId: req.params.viewId,
});
res.json({
sorts: new PagedResponseImpl(sortList),
});
res.json(
new PagedResponseImpl(
await sortService.sortList({
viewId: req.params.viewId,
})
)
);
}
// @ts-ignore
export async function sortCreate(req: Request<any, any, SortReqType>, res) {
const sort = await sortService.sortCreate({
sort: req.body,
@ -43,6 +41,7 @@ export async function sortDelete(req: Request, res: Response) {
});
res.json(sort);
}
export async function sortGet(req: Request, res: Response) {
const sort = await sortService.sortGet({
sortId: req.params.sortId,

3
packages/nocodb/src/lib/controllers/table.ctl.ts

@ -58,14 +58,13 @@ export async function tableReorder(req: Request, res: Response) {
);
}
// todo: move to table service
export async function tableUpdate(req: Request<any, any>, res) {
await tableService.tableUpdate({
tableId: req.params.tableId,
table: req.body,
projectId: (req as any).ncProjectId,
});
res.json({ msg: 'success' });
res.json({ msg: 'The table has been updated successfully' });
}
const router = Router({ mergeParams: true });

12
packages/nocodb/src/lib/controllers/user/initStrategies.ts

@ -5,6 +5,12 @@ import passport from 'passport';
import passportJWT from 'passport-jwt';
import { Strategy as AuthTokenStrategy } from 'passport-auth-token';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import bcrypt from 'bcryptjs';
import NocoCache from '../../cache/NocoCache';
import { ApiToken, Plugin, Project, ProjectUser, User } from '../../models';
import Noco from '../../Noco';
import { CacheGetType, CacheScope } from '../../utils/globals';
import { userService } from '../../services';
const ExtractJwt = passportJWT.ExtractJwt;
const JwtStrategy = passportJWT.Strategy;
@ -13,12 +19,6 @@ const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader('xc-auth'),
};
import bcrypt from 'bcryptjs';
import NocoCache from '../../cache/NocoCache';
import { ApiToken, Plugin, Project, ProjectUser, User } from '../../models';
import Noco from '../../Noco';
import { CacheGetType, CacheScope } from '../../utils/globals';
import { userService } from '../../services';
const PassportLocalStrategy = require('passport-local').Strategy;
export function initStrategies(router): void {

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

Loading…
Cancel
Save