From ac434c0258b0f105e2aa6046d716060d44c5658d Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa Date: Fri, 22 Sep 2023 15:23:14 +0000 Subject: [PATCH 01/25] fix: Improved dark scrollbar style and moved sidebar button css to a common css --- packages/nc-gui/assets/style.scss | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index 5dee33bf42..db39bda82e 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -79,6 +79,11 @@ main { width: 4px; height: 4px; } + + &::-webkit-scrollbar-track { + -webkit-border-radius: 10px; + border-radius: 10px; + } &::-webkit-scrollbar-track-piece { width: 0px; } @@ -86,11 +91,14 @@ main { @apply bg-transparent; } &::-webkit-scrollbar-thumb { + -webkit-border-radius: 10px; + border-radius: 10px; + width: 4px; - @apply bg-gray-200; + @apply bg-gray-300; } &::-webkit-scrollbar-thumb:hover { - @apply bg-gray-300; + @apply bg-gray-400; } } @@ -583,3 +591,7 @@ input[type='number'] { .ant-pagination .ant-pagination-item-link-icon { @apply !block !py-1.5; } + +.nc-button.ant-btn.nc-sidebar-node-btn { + @apply opacity-0 group-hover:(opacity-100) text-gray-600 hover:(bg-gray-400 bg-opacity-20 text-gray-900) duration-100; +} \ No newline at end of file From b77dac0c9425ebf0a6e8f14cafeb4fc08efab135 Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa Date: Fri, 22 Sep 2023 15:23:14 +0000 Subject: [PATCH 02/25] fix: Improved sidebar scrollbar layout and resiable bar placement --- packages/nc-gui/components/dashboard/Sidebar.vue | 2 +- packages/nc-gui/components/dashboard/View.vue | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/components/dashboard/Sidebar.vue b/packages/nc-gui/components/dashboard/Sidebar.vue index fe8c5907bc..164c11e554 100644 --- a/packages/nc-gui/components/dashboard/Sidebar.vue +++ b/packages/nc-gui/components/dashboard/Sidebar.vue @@ -43,7 +43,7 @@ onUnmounted(() => {
From fedfdb59f845a52232e20f209d680756673e79e3 Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa Date: Fri, 22 Sep 2023 15:23:15 +0000 Subject: [PATCH 08/25] fix: Added views in left sidebar --- .../dashboard/TreeView/CreateViewBtn.vue | 127 ++++++ .../dashboard/TreeView/TableList.vue | 7 +- .../dashboard/TreeView/TableNode.vue | 280 ++++++++----- .../dashboard/TreeView/ViewsList.vue | 392 ++++++++++++++++++ .../dashboard/TreeView/ViewsNode.vue | 296 +++++++++++++ packages/nc-gui/components/dlg/ViewCreate.vue | 140 ++++--- .../components/smartsheet/sidebar/MenuTop.vue | 2 +- .../smartsheet/toolbar/ViewInfo.vue | 15 +- packages/nc-gui/context/index.ts | 1 + 9 files changed, 1080 insertions(+), 180 deletions(-) create mode 100644 packages/nc-gui/components/dashboard/TreeView/CreateViewBtn.vue create mode 100644 packages/nc-gui/components/dashboard/TreeView/ViewsList.vue create mode 100644 packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue diff --git a/packages/nc-gui/components/dashboard/TreeView/CreateViewBtn.vue b/packages/nc-gui/components/dashboard/TreeView/CreateViewBtn.vue new file mode 100644 index 0000000000..7c3e8a4466 --- /dev/null +++ b/packages/nc-gui/components/dashboard/TreeView/CreateViewBtn.vue @@ -0,0 +1,127 @@ + + + + + diff --git a/packages/nc-gui/components/dashboard/TreeView/TableList.vue b/packages/nc-gui/components/dashboard/TreeView/TableList.vue index 6f8beef505..c372fea1cd 100644 --- a/packages/nc-gui/components/dashboard/TreeView/TableList.vue +++ b/packages/nc-gui/components/dashboard/TreeView/TableList.vue @@ -26,10 +26,6 @@ const tables = computed(() => projectTables.value.get(project.value.id!) ?? []) const { $api } = useNuxtApp() -const { openTable } = useTableNew({ - projectId: project.value.id!, -}) - const tablesById = computed(() => tables.value.reduce>((acc, table) => { acc[table.id!] = table @@ -153,7 +149,7 @@ const availableTables = computed(() => { v-for="table of availableTables" :key="table.id" v-e="['a:table:open']" - class="nc-tree-item text-sm cursor-pointer group" + class="nc-tree-item text-sm" :data-order="table.order" :data-id="table.id" :data-testid="`tree-view-table-${table.title}`" @@ -163,7 +159,6 @@ const availableTables = computed(() => { :data-title="table.title" :data-base-id="base?.id" :data-type="table.type" - @click="openTable(table)" >
diff --git a/packages/nc-gui/components/dashboard/TreeView/TableNode.vue b/packages/nc-gui/components/dashboard/TreeView/TableNode.vue index 95d2930103..7d4e2b1192 100644 --- a/packages/nc-gui/components/dashboard/TreeView/TableNode.vue +++ b/packages/nc-gui/components/dashboard/TreeView/TableNode.vue @@ -20,6 +20,10 @@ const project = toRef(props, 'project') const table = toRef(props, 'table') const baseIndex = toRef(props, 'baseIndex') +const { openTable } = useTableNew({ + projectId: project.value.id!, +}) + const route = useRoute() const { isUIAllowed } = useRoles() @@ -34,9 +38,13 @@ useTableNew({ }) const projectRole = inject(ProjectRoleInj) +provide(SidebarTableInj, table) const { setMenuContext, openRenameTableDialog, duplicateTable } = inject(TreeViewInj)! +const { loadViews: _loadViews } = useViewsStore() +const { activeView } = storeToRefs(useViewsStore()) + // todo: temp const { projectTables } = storeToRefs(useTablesStore()) const tables = computed(() => projectTables.value.get(project.value.id!) ?? []) @@ -73,80 +81,127 @@ const { isSharedBase } = useProject() const canUserEditEmote = computed(() => { return isUIAllowed('tableIconEdit', { roles: projectRole?.value }) }) + +const isExpanded = ref(false) +const isLoading = ref(false) + +const onExpand = async () => { + if (isExpanded.value) { + isExpanded.value = false + return + } + + isLoading.value = true + try { + await _loadViews({ tableId: table.value.id, ignoreLoading: true }) + } catch (e) { + message.error(await extractSdkResponseErrorMsg(e)) + } finally { + isLoading.value = false + isExpanded.value = true + } +} + +watch( + () => activeView.value?.id, + () => { + if (!activeView.value) return + + if (activeView.value?.fk_model_id === table.value?.id) { + isExpanded.value = true + } + }, + { + immediate: true, + }, +) + +const isTableOpened = computed(() => { + return openedTableId.value === table.value?.id && activeView.value?.is_default +}) diff --git a/packages/nc-gui/components/dashboard/TreeView/ViewsList.vue b/packages/nc-gui/components/dashboard/TreeView/ViewsList.vue new file mode 100644 index 0000000000..1a586c1cc1 --- /dev/null +++ b/packages/nc-gui/components/dashboard/TreeView/ViewsList.vue @@ -0,0 +1,392 @@ + + + + + diff --git a/packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue b/packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue new file mode 100644 index 0000000000..74daf9a809 --- /dev/null +++ b/packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue @@ -0,0 +1,296 @@ + + + diff --git a/packages/nc-gui/components/dlg/ViewCreate.vue b/packages/nc-gui/components/dlg/ViewCreate.vue index 185d5bb2e2..1e1ba17cad 100644 --- a/packages/nc-gui/components/dlg/ViewCreate.vue +++ b/packages/nc-gui/components/dlg/ViewCreate.vue @@ -14,7 +14,7 @@ interface Props { groupingFieldColumnId?: string geoDataFieldColumnId?: string views: ViewType[] - meta: TableType + tableId: string } interface Emits { @@ -31,10 +31,20 @@ interface Form { fk_geo_data_col_id: string | null } -const { views = [], meta, selectedViewId, groupingFieldColumnId, geoDataFieldColumnId, ...props } = defineProps() +const props = withDefaults(defineProps(), { + selectedViewId: undefined, + groupingFieldColumnId: undefined, + geoDataFieldColumnId: undefined, +}) const emits = defineEmits() +const { getMeta } = useMetas() + +const { views, selectedViewId, groupingFieldColumnId, geoDataFieldColumnId, tableId } = toRefs(props) + +const meta = ref() + const inputEl = ref() const formValidator = ref() @@ -64,7 +74,7 @@ const viewNameRules = [ { validator: (_: unknown, v: string) => new Promise((resolve, reject) => { - views.every((v1) => v1.title !== v) ? resolve(true) : reject(new Error(`View name should be unique`)) + views.value.every((v1) => v1.title !== v) ? resolve(true) : reject(new Error(`View name should be unique`)) }), message: 'View name should be unique', }, @@ -97,52 +107,13 @@ watch( function init() { form.title = `Untitled ${capitalize(typeAlias.value)}` - const repeatCount = views.filter((v) => v.title.startsWith(form.title)).length + const repeatCount = views.value.filter((v) => v.title.startsWith(form.title)).length if (repeatCount) { form.title = `${form.title} ${repeatCount}` } - if (selectedViewId) { - form.copy_from_id = selectedViewId - } - - // preset the grouping field column - if (props.type === ViewTypes.KANBAN) { - viewSelectFieldOptions.value = meta - .columns!.filter((el) => el.uidt === UITypes.SingleSelect) - .map((field) => { - return { - value: field.id, - label: field.title, - } - }) - - if (groupingFieldColumnId) { - // take from the one from copy view - form.fk_grp_col_id = groupingFieldColumnId - } else { - // take the first option - form.fk_grp_col_id = viewSelectFieldOptions.value?.[0]?.value as string - } - } - - if (props.type === ViewTypes.MAP) { - viewSelectFieldOptions.value = meta - .columns!.filter((el) => el.uidt === UITypes.GeoData) - .map((field) => { - return { - value: field.id, - label: field.title, - } - }) - - if (geoDataFieldColumnId) { - // take from the one from copy view - form.fk_geo_data_col_id = geoDataFieldColumnId - } else { - // take the first option - form.fk_geo_data_col_id = viewSelectFieldOptions.value?.[0]?.value as string - } + if (selectedViewId.value) { + form.copy_from_id = selectedViewId?.value } nextTick(() => { @@ -165,9 +136,7 @@ async function onSubmit() { } if (isValid && form.type) { - const _meta = unref(meta) - - if (!_meta || !_meta.id) return + if (!tableId.value) return try { let data: GridType | KanbanType | GalleryType | FormType | MapType | null = null @@ -176,19 +145,19 @@ async function onSubmit() { switch (form.type) { case ViewTypes.GRID: - data = await api.dbView.gridCreate(_meta.id, form) + data = await api.dbView.gridCreate(tableId.value, form) break case ViewTypes.GALLERY: - data = await api.dbView.galleryCreate(_meta.id, form) + data = await api.dbView.galleryCreate(tableId.value, form) break case ViewTypes.FORM: - data = await api.dbView.formCreate(_meta.id, form) + data = await api.dbView.formCreate(tableId.value, form) break case ViewTypes.KANBAN: - data = await api.dbView.kanbanCreate(_meta.id, form) + data = await api.dbView.kanbanCreate(tableId.value, form) break case ViewTypes.MAP: - data = await api.dbView.mapCreate(_meta.id, form) + data = await api.dbView.mapCreate(tableId.value, form) } if (data) { @@ -208,6 +177,60 @@ async function onSubmit() { }, 500) } } + +const isMetaLoading = ref(false) + +onMounted(async () => { + if (props.type === ViewTypes.KANBAN || props.type === ViewTypes.MAP) { + isMetaLoading.value = true + try { + meta.value = (await getMeta(tableId.value))! + + if (props.type === ViewTypes.MAP) { + viewSelectFieldOptions.value = meta + .value!.columns!.filter((el) => el.uidt === UITypes.GeoData) + .map((field) => { + return { + value: field.id, + label: field.title, + } + }) + + if (geoDataFieldColumnId.value) { + // take from the one from copy view + form.fk_geo_data_col_id = geoDataFieldColumnId.value + } else { + // take the first option + form.fk_geo_data_col_id = viewSelectFieldOptions.value?.[0]?.value as string + } + } + + // preset the grouping field column + if (props.type === ViewTypes.KANBAN) { + viewSelectFieldOptions.value = meta.value + .columns!.filter((el) => el.uidt === UITypes.SingleSelect) + .map((field) => { + return { + value: field.id, + label: field.title, + } + }) + + if (groupingFieldColumnId.value) { + // take from the one from copy view + form.fk_grp_col_id = groupingFieldColumnId.value + } else { + // take the first option + form.fk_grp_col_id = viewSelectFieldOptions.value?.[0]?.value as string + } + } + } catch (e) { + console.error(e) + } finally { + isMetaLoading.value = false + } + } +}) - diff --git a/packages/nc-gui/components/smartsheet/sidebar/MenuTop.vue b/packages/nc-gui/components/smartsheet/sidebar/MenuTop.vue deleted file mode 100644 index 200af9f5e6..0000000000 --- a/packages/nc-gui/components/smartsheet/sidebar/MenuTop.vue +++ /dev/null @@ -1,389 +0,0 @@ - - - - - diff --git a/packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue b/packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue deleted file mode 100644 index fbe9942c92..0000000000 --- a/packages/nc-gui/components/smartsheet/sidebar/RenameableMenuItem.vue +++ /dev/null @@ -1,292 +0,0 @@ - - - diff --git a/packages/nc-gui/components/smartsheet/sidebar/index.vue b/packages/nc-gui/components/smartsheet/sidebar/index.vue deleted file mode 100644 index 7f3a858fd6..0000000000 --- a/packages/nc-gui/components/smartsheet/sidebar/index.vue +++ /dev/null @@ -1,281 +0,0 @@ - - - - - diff --git a/packages/nc-gui/components/tabs/Smartsheet.vue b/packages/nc-gui/components/tabs/Smartsheet.vue index ec71154ebe..a25a9c1493 100644 --- a/packages/nc-gui/components/tabs/Smartsheet.vue +++ b/packages/nc-gui/components/tabs/Smartsheet.vue @@ -160,38 +160,31 @@ const onDrop = async (event: DragEvent) => { {{ activeTable?.title }} @@ -46,7 +42,7 @@ const { activeTable } = storeToRefs(useTablesStore()) - {{ selectedView?.title }} + {{ selectedView?.is_default ? $t('title.defaultView') : selectedView?.title }} diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index 95f950458b..c10a000d64 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -281,7 +281,8 @@ "resetPasswordMenu": "Reset Password", "tokens": "Tokens", "userManagement": "User Management", - "licence": "Licence" + "licence": "Licence", + "defaultView": "Default View" }, "labels": { "searchProjects": "Search Projects", From 85fb294f7ab036c21083bf52cca73f60b7e01644 Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa Date: Fri, 22 Sep 2023 15:23:16 +0000 Subject: [PATCH 13/25] fix: Added isDefaultBase util to FE --- .../components/dashboard/TreeView/ViewsList.vue | 2 +- .../components/dashboard/TreeView/ViewsNode.vue | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/nc-gui/components/dashboard/TreeView/ViewsList.vue b/packages/nc-gui/components/dashboard/TreeView/ViewsList.vue index 7a27b1f028..611b2f3ebe 100644 --- a/packages/nc-gui/components/dashboard/TreeView/ViewsList.vue +++ b/packages/nc-gui/components/dashboard/TreeView/ViewsList.vue @@ -4,8 +4,8 @@ import { ViewTypes } from 'nocodb-sdk' import type { SortableEvent } from 'sortablejs' import Sortable from 'sortablejs' import type { Menu as AntMenu } from 'ant-design-vue' -import { isDefaultBase as _isDefaultBase } from '~/utils/baseUtils' import { + isDefaultBase as _isDefaultBase, extractSdkResponseErrorMsg, message, onMounted, diff --git a/packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue b/packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue index dc658f3236..6ef21b6b8b 100644 --- a/packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue +++ b/packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue @@ -2,8 +2,17 @@ import type { VNodeRef } from '@vue/runtime-core' import type { KanbanType, ViewType, ViewTypes } from 'nocodb-sdk' import type { WritableComputedRef } from '@vue/reactivity' -import { isDefaultBase as _isDefaultBase } from '~/utils/baseUtils' -import { IsLockedInj, inject, message, onKeyStroke, useDebounceFn, useNuxtApp, useRoles, useVModel } from '#imports' +import { + IsLockedInj, + isDefaultBase as _isDefaultBase, + inject, + message, + onKeyStroke, + useDebounceFn, + useNuxtApp, + useRoles, + useVModel, +} from '#imports' interface Props { view: ViewType From 178f9deb6a7ca1e3a845384c2d651742ab0f62b9 Mon Sep 17 00:00:00 2001 From: Muhammed Mustafa Date: Fri, 22 Sep 2023 15:23:17 +0000 Subject: [PATCH 14/25] fix: Delete modal centered --- packages/nc-gui/components/general/DeleteModal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nc-gui/components/general/DeleteModal.vue b/packages/nc-gui/components/general/DeleteModal.vue index 61eaed3145..4c3c18f520 100644 --- a/packages/nc-gui/components/general/DeleteModal.vue +++ b/packages/nc-gui/components/general/DeleteModal.vue @@ -40,7 +40,7 @@ onKeyStroke('Enter', () => {