Browse Source

sync 2145

Signed-off-by: Raju Udava <86527202+dstala@users.noreply.github.com>
pull/6227/head
Raju Udava 1 year ago
parent
commit
e1958c6e15
  1. 24
      packages/nc-gui/components/dashboard/Sidebar.vue
  2. 35
      packages/nc-gui/components/dashboard/settings/data-sources/CreateBase.vue
  3. 10
      packages/nc-gui/components/dlg/ProjectDelete.vue
  4. 2
      packages/nc-gui/components/smartsheet/Gallery.vue
  5. 19
      packages/nc-gui/components/smartsheet/Kanban.vue
  6. 2
      packages/nc-gui/components/smartsheet/SharedMapMarkerPopup.vue
  7. 33
      packages/nc-gui/store/projects.ts
  8. 5
      packages/nc-gui/utils/virtualCell.ts
  9. 2
      packages/nocodb/src/modules/jobs/jobs/export-import/duplicate.processor.ts
  10. 34
      packages/nocodb/src/modules/jobs/jobs/export-import/export.service.ts
  11. 14
      packages/nocodb/src/modules/jobs/jobs/export-import/import.service.ts
  12. 10
      packages/nocodb/src/services/projects.service.ts

24
packages/nc-gui/components/dashboard/Sidebar.vue

@ -58,7 +58,7 @@ const navigateToSettings = () => {
height: isSharedBase ? '100%' : null,
}"
>
<div class="flex flex-col" :style="{ height: isSharedBase ? 'auto' : 'var(--sidebar-top-height)' }">
<div class="flex flex-col">
<div style="border-bottom-width: 1px" class="flex items-center px-1 nc-sidebar-header !border-0 py-1.25 pl-2">
<div class="flex flex-row flex-grow hover:bg-gray-100 pl-2 pr-1 py-0.5 rounded-md max-w-full">
<a
@ -86,8 +86,7 @@ const navigateToSettings = () => {
</div>
<template v-if="!isSharedBase">
<div class="w-full mt-2"></div>
<div class="h-17.5">
<div class="h-auto">
<div
v-if="isWorkspaceOwnerOrCreator"
role="button"
@ -119,18 +118,21 @@ const navigateToSettings = () => {
</div>
</WorkspaceCreateProjectBtn>
</div>
<div class="flex flex-grow"></div>
<div class="w-full mt-2"></div>
<div class="text-gray-500 mx-5 font-medium mb-1.5">{{ $t('objects.projects') }}</div>
<div
class="w-full border-b-1"
:class="{
'border-gray-200': !isTreeViewOnScrollTop,
'border-transparent': isTreeViewOnScrollTop,
}"
></div>
</template>
<div
class="w-full border-b-1"
:class="{
'border-gray-200': !isTreeViewOnScrollTop,
'border-transparent': isTreeViewOnScrollTop,
}"
></div>
</div>
<LazyDashboardTreeViewNew
class="flex-1"
:class="{
'nc-shared-base': isSharedBase,
}"

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

@ -225,12 +225,15 @@ function getConnectionConfig() {
const focusInvalidInput = () => {
form.value?.$el.querySelector('.ant-form-item-explain-error')?.parentNode?.parentNode?.querySelector('input')?.focus()
}
const isConnSuccess = ref(false)
const createBase = async () => {
try {
await validate()
isConnSuccess.value = false
} catch (e) {
focusInvalidInput()
isConnSuccess.value = false
return
}
@ -287,17 +290,7 @@ const testConnection = async () => {
if (result.code === 0) {
testSuccess.value = true
Modal.confirm({
title: t('msg.info.dbConnected'),
icon: null,
type: 'success',
okText: 'Ok & Add Base',
okType: 'primary',
cancelText: t('general.cancel'),
onOk: createBase,
style: 'top: 30%!important',
})
isConnSuccess.value = true
} else {
testSuccess.value = false
@ -374,6 +367,15 @@ watch(
</script>
<template>
<GeneralModal v-model:visible="isConnSuccess" class="!w-[25rem]">
<div class="flex flex-col h-full p-8">
<div class="text-lg font-semibold self-start mb-4">{{ t('msg.info.dbConnected') }}</div>
<div class="flex gap-x-2 mt-5 ml-7 pt-2.5 justify-end">
<NcButton key="back" type="secondary" @click="isConnSuccess = false">{{ $t('general.cancel') }}</NcButton>
<NcButton key="submit" type="primary" @click="createBase">Ok & Add Base</NcButton>
</div>
</div>
</GeneralModal>
<div class="create-base bg-white relative flex flex-col justify-center gap-2 w-full">
<h1 class="prose-2xl font-bold self-start mb-4 flex items-center gap-2">
New Base
@ -656,6 +658,17 @@ watch(
>
<a-input v-model:value="importURL" />
</a-modal>
<!-- connection succesfull modal -->
<GeneralModal v-model:visible="isConnSuccess" class="!w-[25rem]">
<div class="flex flex-col h-full p-8">
<div class="text-lg font-semibold self-start mb-4">{{ t('msg.info.dbConnected') }}</div>
<div class="flex gap-x-2 mt-5 ml-7 pt-2.5 justify-end">
<NcButton key="back" type="secondary" @click="isConnSuccess = false">{{ $t('general.cancel') }}</NcButton>
<NcButton key="submit" type="primary" @click="createBase">Ok & Add Base</NcButton>
</div>
</div>
</GeneralModal>
</div>
</template>

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

@ -1,4 +1,6 @@
<script lang="ts" setup>
import { navigateTo } from '#app'
const props = defineProps<{
visible: boolean
projectId: string
@ -11,7 +13,7 @@ const visible = useVModel(props, 'visible', emits)
const { closeTab } = useTabs()
const projectsStore = useProjects()
const { deleteProject } = projectsStore
const { deleteProject, navigateToFirstProjectOrHome } = projectsStore
const { projects } = storeToRefs(projectsStore)
const { refreshCommandPalette } = useCommandPalette()
@ -20,6 +22,8 @@ const project = computed(() => projects.value.get(props.projectId))
const isLoading = ref(false)
const { projectsList } = storeToRefs(projectsStore)
const onDelete = async () => {
if (!project.value) return
@ -33,6 +37,10 @@ const onDelete = async () => {
refreshCommandPalette()
visible.value = false
if (toBeDeletedProject.id === projectsStore.activeProjectId) {
await navigateToFirstProjectOrHome()
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
} finally {

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

@ -289,7 +289,7 @@ watch(
<div v-for="col in fieldsWithoutCover" :key="`record-${record.row.id}-${col.id}`">
<div
v-if="!isRowEmpty(record, col) || isLTAR(col.uidt)"
v-if="!isRowEmpty(record, col) || isLTAR(col.uidt, col.colOptions)"
class="flex flex-col space-y-1 px-4 mb-6 bg-gray-50 rounded-lg w-full"
>
<div class="flex flex-row w-full justify-start border-b-1 border-gray-100 py-2.5">

19
packages/nc-gui/components/smartsheet/Kanban.vue

@ -285,8 +285,11 @@ const kanbanListScrollHandler = useDebounceFn(async (e: any) => {
if (e.target.scrollTop + e.target.clientHeight + INFINITY_SCROLL_THRESHOLD >= e.target.scrollHeight) {
const stackTitle = e.target.getAttribute('data-stack-title')
const pageSize = appInfo.value.defaultLimit || 25
const page = Math.ceil(formattedData.value.get(stackTitle)!.length / pageSize)
await loadMoreKanbanData(stackTitle, { offset: page * pageSize })
const stack = formattedData.value.get(stackTitle)
if (stack) {
const page = Math.ceil(stack.length / pageSize)
await loadMoreKanbanData(stackTitle, { offset: page * pageSize })
}
}
})
@ -568,7 +571,7 @@ watch(
:key="`record-${record.row.id}-${col.id}`"
class="flex flex-col rounded-lg w-full"
>
<div v-if="!isRowEmpty(record, col) || isLTAR(col.uidt)">
<div v-if="!isRowEmpty(record, col) || isLTAR(col.uidt, col.colOptions)">
<!-- Smartsheet Header (Virtual) Cell -->
<div class="flex flex-row w-full justify-start pt-2">
<div class="w-full text-gray-400">
@ -587,14 +590,14 @@ watch(
:class="{ '!ml-[-12px] pl-3': col.uidt === UITypes.SingleSelect }"
>
<LazySmartsheetVirtualCell
v-if="isVirtualCol(col)"
v-if="col.title && isVirtualCol(col)"
v-model="record.row[col.title]"
class="text-sm pt-1 pl-5"
:column="col"
:row="record"
/>
<LazySmartsheetCell
v-else
v-else-if="col.title"
v-model="record.row[col.title]"
class="text-sm pt-1 pl-7.25"
:column="col"
@ -613,12 +616,12 @@ watch(
</a-layout-content>
<div class="!rounded-lg !px-3 pt-3">
<div v-if="formattedData.get(stack.title) && countByStack.get(stack.title) >= 0" class="text-center">
<div v-if="formattedData.get(stack.title)" class="text-center">
<!-- Stack Title -->
<!-- Record Count -->
<div class="nc-kanban-data-count text-gray-500">
{{ formattedData.get(stack.title).length }} / {{ countByStack.get(stack.title) }}
{{ formattedData.get(stack.title)!.length }} / {{ countByStack.get(stack.title) ?? 0 }}
{{ countByStack.get(stack.title) !== 1 ? $t('objects.records') : $t('objects.record') }}
</div>
@ -664,7 +667,7 @@ watch(
<component :is="iconMap.arrowDown" class="text-grey text-lg" />
</div>
<!-- Record Count -->
{{ formattedData.get(stack.title).length }} / {{ countByStack.get(stack.title) }}
{{ formattedData.get(stack.title)!.length }} / {{ countByStack.get(stack.title) }}
{{ countByStack.get(stack.title) !== 1 ? $t('objects.records') : $t('objects.record') }}
</div>
</div>

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

@ -64,7 +64,7 @@ useProvideSmartsheetRowStore(meta as Ref<TableType>, currentRow)
>
<div v-for="col in fields" :key="`record-${currentRow.row.id}-${col.id}`">
<div
v-if="!isRowEmpty(currentRow, col) || isLTAR(col.uidt)"
v-if="!isRowEmpty(currentRow, col) || isLTAR(col.uidt, colOptions)"
class="flex flex-col space-y-1 px-4 mb-6 bg-gray-50 rounded-lg w-full"
>
<div class="flex flex-row w-full justify-start border-b-1 border-gray-100 py-2.5">

33
packages/nc-gui/store/projects.ts

@ -86,7 +86,6 @@ export const useProjects = defineStore('projectsStore', () => {
await api.auth.projectUserUpdate(projectId, user.id, user as ProjectUserReqType)
}
const removeProjectUser = async (projectId: string, user: User) => {
await api.auth.projectUserRemove(projectId, user.id)
}
@ -126,18 +125,9 @@ export const useProjects = defineStore('projectsStore', () => {
isProjectsLoading.value = true
try {
const { list } = await $api.project.list(
page
? {
query: {
[page]: true,
},
baseURL: getBaseUrl(activeWorkspace?.id ?? workspace?.id),
}
: {
baseURL: getBaseUrl(activeWorkspace?.id ?? workspace?.id),
},
)
const { list } = await $api.project.list({
baseURL: getBaseUrl(activeWorkspace?.id ?? workspace?.id),
})
_projects = list
projects.value = _projects.reduce((acc, project) => {
@ -181,7 +171,13 @@ export const useProjects = defineStore('projectsStore', () => {
if (!force && isProjectPopulated(projectId)) return projects.value.get(projectId)
const _project = await api.project.read(projectId)
_project.meta = typeof _project.meta === 'string' ? JSON.parse(_project.meta) : {}
if (!_project) {
await navigateTo(`/`)
return
}
_project.meta = _project?.meta && typeof _project.meta === 'string' ? JSON.parse(_project.meta) : {}
const existingProject = projects.value.get(projectId) ?? ({} as any)
@ -291,6 +287,12 @@ export const useProjects = defineStore('projectsStore', () => {
loadProject(activeProjectId.value)
})
const navigateToFirstProjectOrHome = async () => {
// if active project id is deleted, navigate to first project or home page
if (projectsList.value?.length) await navigateToProject({ projectId: projectsList.value[0].id! })
else navigateTo('/')
}
return {
projects,
projectsList,
@ -315,7 +317,8 @@ export const useProjects = defineStore('projectsStore', () => {
createProjectUser,
updateProjectUser,
navigateToProject,
removeProjectUser
removeProjectUser,
navigateToFirstProjectOrHome,
}
})

5
packages/nc-gui/utils/virtualCell.ts

@ -1,7 +1,10 @@
import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isLinksOrLTAR } from 'nocodb-sdk'
export const isLTAR = (uidt: string, colOptions: unknown): colOptions is LinkToAnotherRecordType => isLinksOrLTAR(uidt)
export const isLTAR = (uidt: string | undefined, colOptions: unknown): colOptions is LinkToAnotherRecordType => {
if (!uidt) return false
return isLinksOrLTAR(uidt)
}
export const isHm = (column: ColumnType) =>
isLTAR(column.uidt!, column.colOptions) && column.colOptions.type === RelationTypes.HAS_MANY

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

@ -56,6 +56,7 @@ export class DuplicateProcessor {
modelIds: models.map((m) => m.id),
excludeViews,
excludeHooks,
excludeData,
});
elapsedTime(
@ -150,6 +151,7 @@ export class DuplicateProcessor {
modelIds: [modelId],
excludeViews,
excludeHooks,
excludeData,
})
)[0];

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

@ -23,9 +23,11 @@ export class ExportService {
modelIds: string[];
excludeViews?: boolean;
excludeHooks?: boolean;
excludeData?: boolean;
}) {
const { modelIds } = param;
const excludeData = param?.excludeData || false;
const excludeViews = param?.excludeViews || false;
const excludeHooks = param?.excludeHooks || false;
@ -41,6 +43,8 @@ export class ExportService {
for (const modelId of modelIds) {
const model = await Model.get(modelId);
let pgSerialLastVal;
if (!model)
return NcError.badRequest(`Model not found for id '${modelId}'`);
@ -67,6 +71,35 @@ export class ExportService {
for (const column of model.columns) {
await column.getColOptions();
// if data is not excluded, get currval for ai column (pg)
if (!excludeData) {
if (base.type === 'pg') {
if (column.ai) {
try {
const sqlClient = await NcConnectionMgrv2.getSqlClient(base);
const seq = await sqlClient.knex.raw(
`SELECT pg_get_serial_sequence('??', ?) as seq;`,
[model.table_name, column.column_name],
);
if (seq.rows.length > 0) {
const seqName = seq.rows[0].seq;
const res = await sqlClient.knex.raw(
`SELECT last_value as last FROM ${seqName};`,
);
if (res.rows.length > 0) {
pgSerialLastVal = res.rows[0].last;
}
}
} catch (e) {
this.logger.error(e);
}
}
}
}
if (column.colOptions) {
for (const [k, v] of Object.entries(column.colOptions)) {
switch (k) {
@ -235,6 +268,7 @@ export class ExportService {
prefix: project.prefix,
title: model.title,
table_name: clearPrefix(model.table_name, project.prefix),
pgSerialLastVal,
meta: model.meta,
columns: model.columns.map((column) => ({
id: idMap.get(column.id),

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

@ -32,6 +32,7 @@ import { HooksService } from '~/services/hooks.service';
import { ViewsService } from '~/services/views.service';
import NcPluginMgrv2 from '~/helpers/NcPluginMgrv2';
import { BulkDataAliasService } from '~/services/bulk-data-alias.service';
import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2';
@Injectable()
export class ImportService {
@ -152,6 +153,19 @@ export class ImportService {
(a) => a.column_name === col.column_name,
);
idMap.set(colRef.id, col.id);
// setval for auto increment column in pg
if (base.type === 'pg') {
if (modelData.pgSerialLastVal) {
if (col.ai) {
const sqlClient = await NcConnectionMgrv2.getSqlClient(base);
await sqlClient.knex.raw(
`SELECT setval(pg_get_serial_sequence('??', ?), ?);`,
[table.table_name, col.column_name, modelData.pgSerialLastVal],
);
}
}
}
}
tableReferences.set(modelData.id, table);

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

@ -35,11 +35,11 @@ export class ProjectsService {
user: { id: string; roles: Record<string, boolean> };
query?: any;
}) {
const projects =
extractRolesObj(param.user?.roles)[OrgUserRoles.SUPER_ADMIN] &&
!['shared', 'starred', 'recent'].some((k) => k in param.query)
? await Project.list(param.query)
: await ProjectUser.getProjectsList(param.user.id, param.query);
const projects = extractRolesObj(param.user?.roles)[
OrgUserRoles.SUPER_ADMIN
]
? await Project.list(param.query)
: await ProjectUser.getProjectsList(param.user.id, param.query);
return projects;
}

Loading…
Cancel
Save