Browse Source

fix: Group-by initial menu to be made similar to Sort #7156

pull/7173/head
Ramesh Mane 1 year ago
parent
commit
0e421be2db
  1. 117
      packages/nc-gui/components/smartsheet/toolbar/CreateGroupBy.vue
  2. 103
      packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue

117
packages/nc-gui/components/smartsheet/toolbar/CreateGroupBy.vue

@ -0,0 +1,117 @@
<script lang="ts" setup>
import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn } from 'nocodb-sdk'
const props = defineProps<{
// As we need to focus search box when the parent is opened
isParentOpen: boolean
}>()
const emits = defineEmits(['created'])
const { isParentOpen } = toRefs(props)
const inputRef = ref()
const search = ref('')
const activeFieldIndex = ref(-1)
const activeView = inject(ActiveViewInj, ref())
const meta = inject(MetaInj, ref())
const { showSystemFields, metaColumnById } = useViewColumnsOrThrow()
const { groupBy } = useViewGroupBy(activeView)
const options = computed<ColumnType[]>(
() =>
meta.value?.columns
?.filter((c: ColumnType) => {
if (c.uidt === UITypes.Links) {
return true
}
if (isSystemColumn(metaColumnById?.value?.[c.id!])) {
return (
/** hide system columns if not enabled */
showSystemFields.value
)
} else if (c.uidt === UITypes.QrCode || c.uidt === UITypes.Barcode || c.uidt === UITypes.ID) {
return false
} else {
/** ignore hasmany and manytomany relations if it's using within group menu */
return !(isLinksOrLTAR(c) && (c.colOptions as LinkToAnotherRecordType).type !== RelationTypes.BELONGS_TO)
/** ignore virtual fields which are system fields ( mm relation ) and qr code fields */
}
})
.filter((c: ColumnType) => !groupBy.value.find((g) => g.column?.id === c.id))
.filter((c: ColumnType) => c.title?.toLowerCase().includes(search.value.toLowerCase())) ?? [],
)
const onClick = (column: ColumnType) => {
emits('created', column)
}
watch(
isParentOpen,
() => {
if (!isParentOpen.value) return
setTimeout(() => {
inputRef.value?.focus()
}, 100)
},
{
immediate: true,
},
)
onMounted(() => {
search.value = ''
activeFieldIndex.value = -1
})
const onArrowDown = () => {
activeFieldIndex.value = Math.min(activeFieldIndex.value + 1, options.value.length - 1)
}
const onArrowUp = () => {
activeFieldIndex.value = Math.max(activeFieldIndex.value - 1, 0)
}
</script>
<template>
<div
class="flex flex-col w-full pt-4 pb-2 min-w-64 nc-group-create-modal"
@keydown.arrow-down.prevent="onArrowDown"
@keydown.arrow-up.prevent="onArrowUp"
@keydown.enter.prevent="onClick(options[activeFieldIndex])"
>
<div class="flex pb-3 px-4 border-b-1 border-gray-100">
<!-- Todo language for selectFieldToGroup -->
<input ref="inputRef" v-model="search" class="w-full focus:outline-none" :placeholder="$t('msg.selectFieldToGroup')" />
</div>
<div class="flex-col w-full max-h-100 max-w-76 nc-scrollbar-md !overflow-y-auto">
<div v-if="!options.length" class="flex text-gray-500 px-4 py-2.25">{{ $t('general.empty') }}</div>
<div
v-for="(option, index) in options"
:key="index"
v-e="['c:sort:add:column:select']"
class="flex flex-row h-10 items-center gap-x-1.5 px-2.5 hover:bg-gray-100 cursor-pointer nc-group-column-search-item"
:class="{
'bg-gray-100': activeFieldIndex === index,
}"
@click="onClick(option)"
>
<SmartsheetHeaderIcon :column="option" />
<NcTooltip class="truncate">
<template #title> {{ option.title }}</template>
<span>
{{ option.title }}
</span>
</NcTooltip>
</div>
</div>
</div>
</template>

103
packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { ColumnType, LinkToAnotherRecordType, LookupType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk'
import { RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn } from 'nocodb-sdk'
import {
ActiveViewInj,
IsLockedInj,
@ -24,7 +24,7 @@ const meta = inject(MetaInj, ref())
const view = inject(ActiveViewInj, ref())
const isLocked = inject(IsLockedInj, ref(false))
const { gridViewCols, updateGridViewColumn } = useViewColumnsOrThrow()
const { gridViewCols, updateGridViewColumn, metaColumnById, showSystemFields } = useViewColumnsOrThrow()
const { $e } = useNuxtApp()
@ -52,7 +52,10 @@ const groupedByColumnIds = computed(() => groupBy.value.map((g) => g.fk_column_i
const { eventBus } = useSmartsheetStoreOrThrow()
const { isMobileMode } = useGlobal()
const supportedLookups = ref([])
const supportedLookups = ref<string[]>([])
const showCreateGroupBy = ref(false)
const fieldsToGroupBy = computed(() => {
const fields = meta.value?.columns || []
@ -61,7 +64,7 @@ const fieldsToGroupBy = computed(() => {
if (excludedGroupingUidt.includes(field.uidt as UITypes)) return false
if (field.uidt === UITypes.Lookup) {
return supportedLookups.value.includes(field.id)
return field.id && supportedLookups.value.includes(field.id)
}
return true
@ -78,6 +81,28 @@ const columnByID = computed(() =>
}, {} as Record<string, ColumnType>),
)
const availableColumns = computed(() => {
return columns.value
?.filter((c: ColumnType) => {
if (c.uidt === UITypes.Links) {
return true
}
if (isSystemColumn(metaColumnById?.value?.[c.id!])) {
return (
/** hide system columns if not enabled */
showSystemFields.value
)
} else if (c.uidt === UITypes.QrCode || c.uidt === UITypes.Barcode || c.uidt === UITypes.ID) {
return false
} else {
/** ignore hasmany and manytomany relations if it's using within sort menu */
return !(isLinksOrLTAR(c) && (c.colOptions as LinkToAnotherRecordType).type !== RelationTypes.BELONGS_TO)
/** ignore virtual fields which are system fields ( mm relation ) and qr code fields */
}
})
.filter((c) => !groupBy.value.find((g) => g.fk_column_id === c.id))
})
const getColumnUidtByID = (key?: string) => {
if (!key) return ''
return columnByID.value[key]?.uidt || ''
@ -126,8 +151,10 @@ const saveGroupBy = async () => {
}
}
const addFieldToGroupBy = async () => {
_groupBy.value.push({ fk_column_id: undefined, sort: 'asc', order: _groupBy.value.length + 1 })
const addFieldToGroupBy = (column: ColumnType) => {
_groupBy.value.push({ fk_column_id: column.id, sort: 'asc', order: _groupBy.value.length + 1 })
saveGroupBy()
showCreateGroupBy.value = false
}
const removeFieldFromGroupBy = async (index: string | number) => {
@ -137,17 +164,13 @@ const removeFieldFromGroupBy = async (index: string | number) => {
}
_groupBy.value.splice(+index, 1)
await saveGroupBy()
if (_groupBy.value.length === 0) {
addFieldToGroupBy()
}
}
watch(open, () => {
if (open.value) {
_groupBy.value = [...groupBy.value]
if (_groupBy.value.length === 0) {
addFieldToGroupBy()
}
} else {
showCreateGroupBy.value = false
}
})
@ -157,27 +180,29 @@ const loadAllowedLookups = async () => {
for (const col of meta.value?.columns || []) {
if (col.uidt !== UITypes.Lookup) continue
let nextCol = col
let nextCol: ColumnType | undefined = col
// check the lookup column is supported type or not
while (nextCol && nextCol.uidt === UITypes.Lookup) {
const lookupRelation = (await getMeta(nextCol.fk_model_id))?.columns?.find(
(c) => c.id === (nextCol.colOptions as LookupType).fk_relation_column_id,
const lookupRelation = (await getMeta(nextCol.fk_model_id as string))?.columns?.find(
(c) => c.id === (nextCol?.colOptions as LookupType).fk_relation_column_id,
)
const relatedTableMeta = await getMeta((lookupRelation.colOptions as LinkToAnotherRecordType).fk_related_model_id)
const relatedTableMeta = await getMeta(
(lookupRelation?.colOptions as LinkToAnotherRecordType).fk_related_model_id as string,
)
nextCol = relatedTableMeta?.columns?.find(
(c) => c.id === (nextCol.colOptions as LinkToAnotherRecordType).fk_lookup_column_id,
(c) => c.id === ((nextCol?.colOptions as LookupType).fk_lookup_column_id as string),
)
// if next column is same as root lookup column then break the loop
// since it's going to be a circular loop, and ignore the column
if (nextCol.id === col.id) {
if (nextCol?.id === col.id) {
break
}
}
if (nextCol.uidt !== UITypes.Attachment) filteredLookupCols.push(col.id)
if (nextCol?.uidt !== UITypes.Attachment && col.id) filteredLookupCols.push(col.id)
}
supportedLookups.value = filteredLookupCols
@ -218,7 +243,9 @@ watch(meta, async () => {
</a-button>
</div>
<template #overlay>
<SmartsheetToolbarCreateGroupBy v-if="!_groupBy.length" :is-parent-open="open" @created="addFieldToGroupBy" />
<div
v-else
:class="{ ' min-w-[400px]': _groupBy.length }"
class="flex flex-col bg-white overflow-auto menu-filter-dropdown max-h-[max(80vh,500px)] py-6 pl-6"
data-testid="nc-group-by-menu"
@ -265,23 +292,31 @@ watch(meta, async () => {
</a-tooltip>
</template>
</div>
<NcButton
v-if="fieldsToGroupBy.length > _groupBy.length && _groupBy.length < 3"
v-e="['c:group-by:add']"
class="nc-add-group-btn"
style="width: fit-content"
size="small"
type="text"
:disabled="groupedByColumnIds.length < _groupBy.length"
@click.stop="addFieldToGroupBy()"
<NcDropdown
v-if="availableColumns.length && fieldsToGroupBy.length > _groupBy.length && _groupBy.length < 3"
v-model:visible="showCreateGroupBy"
:trigger="['click']"
overlay-class-name="nc-toolbar-dropdown"
>
<div class="flex gap-1 items-center" :class="{ 'text-brand-500': groupedByColumnIds.length >= _groupBy.length }">
<div class="flex">
{{ $t('activity.addSubGroup') }}
<NcButton
v-e="['c:group-by:add']"
class="nc-add-group-btn !text-brand-500"
style="width: fit-content"
size="small"
type="text"
@click.stop="showCreateGroupBy = true"
>
<div class="flex gap-1 items-center">
<div class="flex">
{{ $t('activity.addSubGroup') }}
</div>
<GeneralIcon icon="plus" />
</div>
<GeneralIcon icon="plus" />
</div>
</NcButton>
</NcButton>
<template #overlay>
<SmartsheetToolbarCreateGroupBy :is-parent-open="showCreateGroupBy" @created="addFieldToGroupBy" />
</template>
</NcDropdown>
</div>
</template>
</NcDropdown>

Loading…
Cancel
Save