mirror of https://github.com/nocodb/nocodb
Browse Source
* feat: one-to-one relation - wip * feat: one-to-one relation * feat: one-to-one relation - link, unlink, list, excluded list, single query * fix: pass proper fk value * feat: add non-single-query support * feat: filter, sort and delete * fix: ui - keep only one as linked record in ui - similar to bt * fix: initial column name correction * fix: field modal related fixes * fix: nested insert related bugs * fix: nested insert corrections * fix: formula support * fix: delete cell data * fix: invalid offset issue * fix: form submit issue * fix: return first element - oo relation * fix: Lookup column rendering * fix: add link api correction * fix: sort and group by menu correction * chore: lint * refactor: spacing between radio buttons * fix: undo/redo support with delete key * fix: formula related issues * fix: duplicate related issues * fix: ui label and icon color * chore: lint * chore: reset page if offset is beyond offset(temporary solution) * refactor: suggested review changes * refactor: suggested review changes * chore: lint * fix: missing await Signed-off-by: Pranav C <pranavxc@gmail.com> * refactor: add comments Signed-off-by: Pranav C <pranavxc@gmail.com> --------- Signed-off-by: Pranav C <pranavxc@gmail.com>pull/7921/head
Pranav C
7 months ago
committed by
GitHub
42 changed files with 1306 additions and 138 deletions
Before Width: | Height: | Size: 631 B After Width: | Height: | Size: 628 B |
@ -0,0 +1,150 @@
|
||||
<script setup lang="ts"> |
||||
import type { ColumnType } from 'nocodb-sdk' |
||||
import type { Ref } from 'vue' |
||||
import { |
||||
ActiveCellInj, |
||||
CellValueInj, |
||||
ColumnInj, |
||||
IsFormInj, |
||||
IsUnderLookupInj, |
||||
ReadonlyInj, |
||||
ReloadRowDataHookInj, |
||||
RowInj, |
||||
computed, |
||||
createEventHook, |
||||
inject, |
||||
ref, |
||||
useProvideLTARStore, |
||||
useRoles, |
||||
useSelectedCellKeyupListener, |
||||
useSmartsheetRowStoreOrThrow, |
||||
} from '#imports' |
||||
|
||||
const column = inject(ColumnInj)! |
||||
|
||||
const reloadRowTrigger = inject(ReloadRowDataHookInj, createEventHook()) |
||||
|
||||
const cellValue = inject(CellValueInj, ref<any>(null)) |
||||
|
||||
const row = inject(RowInj)! |
||||
|
||||
const active = inject(ActiveCellInj)! |
||||
|
||||
const readOnly = inject(ReadonlyInj, ref(false)) |
||||
|
||||
const isForm = inject(IsFormInj, ref(false)) |
||||
|
||||
const isUnderLookup = inject(IsUnderLookupInj, ref(false)) |
||||
|
||||
const { isUIAllowed } = useRoles() |
||||
|
||||
const listItemsDlg = ref(false) |
||||
|
||||
const { state, isNew, removeLTARRef } = useSmartsheetRowStoreOrThrow() |
||||
|
||||
const { relatedTableMeta, loadRelatedTableMeta, relatedTableDisplayValueProp, relatedTableDisplayValuePropId, unlink } = |
||||
useProvideLTARStore(column as Ref<Required<ColumnType>>, row, isNew, reloadRowTrigger.trigger) |
||||
|
||||
await loadRelatedTableMeta() |
||||
|
||||
const addIcon = computed(() => (cellValue?.value ? 'expand' : 'plus')) |
||||
|
||||
const value = computed(() => { |
||||
if (cellValue?.value) { |
||||
return cellValue?.value |
||||
} else if (isNew.value) { |
||||
return state?.value?.[column?.value.title as string] |
||||
} |
||||
return null |
||||
}) |
||||
|
||||
const unlinkRef = async (rec: Record<string, any>) => { |
||||
if (isNew.value) { |
||||
await removeLTARRef(rec, column?.value as ColumnType) |
||||
} else { |
||||
await unlink(rec) |
||||
} |
||||
} |
||||
|
||||
useSelectedCellKeyupListener(active, (e: KeyboardEvent) => { |
||||
switch (e.key) { |
||||
case 'Enter': |
||||
listItemsDlg.value = true |
||||
e.stopPropagation() |
||||
break |
||||
} |
||||
}) |
||||
|
||||
const belongsToColumn = computed( |
||||
() => |
||||
relatedTableMeta.value?.columns?.find((c: any) => c.title === relatedTableDisplayValueProp.value) as ColumnType | undefined, |
||||
) |
||||
|
||||
const plusBtnRef = ref<HTMLElement | null>(null) |
||||
|
||||
watch([listItemsDlg], () => { |
||||
if (!listItemsDlg.value) { |
||||
plusBtnRef.value?.focus() |
||||
} |
||||
}) |
||||
</script> |
||||
|
||||
<template> |
||||
<div class="flex w-full chips-wrapper items-center" :class="{ active }"> |
||||
<div class="nc-cell-field chips flex items-center flex-1"> |
||||
<template v-if="value && (relatedTableDisplayValueProp || relatedTableDisplayValuePropId)"> |
||||
<VirtualCellComponentsItemChip |
||||
:item="value" |
||||
:value=" |
||||
!Array.isArray(value) && typeof value === 'object' |
||||
? value[relatedTableDisplayValueProp] ?? value[relatedTableDisplayValuePropId] |
||||
: value |
||||
" |
||||
:column="belongsToColumn" |
||||
:show-unlink-button="true" |
||||
@unlink="unlinkRef(value)" |
||||
/> |
||||
</template> |
||||
</div> |
||||
|
||||
<div |
||||
v-if="!readOnly && (isUIAllowed('dataEdit') || isForm) && !isUnderLookup" |
||||
ref="plusBtnRef" |
||||
class="flex justify-end group gap-1 min-h-[30px] items-center" |
||||
tabindex="0" |
||||
@keydown.enter.stop="listItemsDlg = true" |
||||
> |
||||
<GeneralIcon |
||||
:icon="addIcon" |
||||
class="select-none !text-md text-gray-700 nc-action-icon nc-plus invisible group-hover:visible group-focus:visible" |
||||
@click.stop="listItemsDlg = true" |
||||
/> |
||||
</div> |
||||
|
||||
<LazyVirtualCellComponentsUnLinkedItems |
||||
v-if="listItemsDlg" |
||||
v-model="listItemsDlg" |
||||
:column="belongsToColumn" |
||||
@attach-record="listItemsDlg = true" |
||||
/> |
||||
</div> |
||||
</template> |
||||
|
||||
<style scoped lang="scss"> |
||||
.nc-action-icon { |
||||
@apply cursor-pointer; |
||||
} |
||||
|
||||
.chips-wrapper:hover, |
||||
.chips-wrapper.active { |
||||
.nc-action-icon { |
||||
@apply inline-block; |
||||
} |
||||
} |
||||
|
||||
.chips-wrapper:hover { |
||||
.nc-action-icon { |
||||
@apply visible; |
||||
} |
||||
} |
||||
</style> |
Loading…
Reference in new issue