Browse Source

Nc fix(nc-gui): Bug fixes (#7979)

* fix(nc-gui): hide form field label if field title & label is same

* fix(nc-gui): text area truncate issue in form prefilled readonly

* fix(nc-gui): reset form state if user hide the select type prefilled option from limit options

* fix(nc-gui): in form view on click sidebar form field make active edit field

* fix(nc-gui): rating icon update issue in edit column modal
pull/7969/head
Ramesh Mane 7 months ago committed by GitHub
parent
commit
e5a018de25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      packages/nc-gui/components/cell/Rating.vue
  2. 28
      packages/nc-gui/components/cell/TextArea.vue
  3. 171
      packages/nc-gui/components/smartsheet/Form.vue
  4. 27
      packages/nc-gui/components/smartsheet/form/LimitOptions.vue

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

@ -78,6 +78,7 @@ watch(rateDomRef, () => {
:count="ratingMeta.max"
:class="readOnly ? 'pointer-events-none' : ''"
:style="`color: ${ratingMeta.color}; padding: ${isExpandedFormOpen ? '0px 8px' : '0px 5px'};`"
:key="ratingMeta.icon.full"
@keydown="onKeyPress"
>
<template #character>

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

@ -36,9 +36,13 @@ const rowHeight = inject(RowHeightInj, ref(1 as const))
const isForm = inject(IsFormInj, ref(false))
const readOnly = inject(ReadonlyInj, ref(false))
const { showNull } = useGlobal()
const vModel = useVModel(props, 'modelValue', emits)
const vModel = useVModel(props, 'modelValue', emits, {
shouldEmit: () => !readOnly.value,
})
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
@ -77,8 +81,6 @@ const inputWrapperRef = ref<HTMLElement | null>(null)
const inputRef = ref<HTMLTextAreaElement | null>(null)
const readOnly = inject(ReadonlyInj)
watch(isVisible, () => {
if (isVisible.value) {
setTimeout(() => {
@ -211,8 +213,22 @@ watch(inputWrapperRef, () => {
}"
>
<div v-if="isForm && isRichMode" class="w-full">
<div class="w-full relative pt-11 w-full px-0 pb-1">
<LazyCellRichText v-model:value="vModel" class="border-t-1 border-gray-100 !max-h-50" :autofocus="false" show-menu />
<div
class="w-full relative w-full px-0 pb-1"
:class="{
'pt-11': !readOnly,
}"
>
<LazyCellRichText
v-model:value="vModel"
class="!max-h-50"
:class="{
'border-t-1 border-gray-100': !readOnly,
}"
:autofocus="false"
show-menu
:read-only="readOnly"
/>
</div>
</div>
@ -233,7 +249,7 @@ watch(inputWrapperRef, () => {
<LazyCellRichText v-model:value="vModel" sync-value-change read-only />
</div>
<textarea
v-else-if="editEnabled && !isVisible"
v-else-if="(editEnabled && !isVisible) || isForm"
:ref="focus"
v-model="vModel"
:rows="isForm ? 5 : 4"

171
packages/nc-gui/components/smartsheet/Form.vue

@ -186,6 +186,8 @@ const focusLabel = ref<HTMLTextAreaElement>()
const searchQuery = ref('')
const autoScrollFormField = ref(false)
const { t } = useI18n()
const { betaFeatureToggleState } = useBetaFeatureToggle()
@ -444,7 +446,7 @@ function setFormData() {
localColumns.value = col
.filter((f) => !hiddenColTypes.includes(f.uidt) && !systemFieldsIds.value.includes(f.fk_column_id))
.sort((a, b) => a.order - b.order)
.map((c) => ({ ...c, label: c.label || c.title, required: !!c.required }))
.map((c) => ({ ...c, required: !!c.required }))
}
function isRequired(_columnObj: Record<string, any>, required = false) {
@ -519,9 +521,13 @@ const columnSupportsScanning = (elementType: UITypes) =>
betaFeatureToggleState.show &&
[UITypes.SingleLineText, UITypes.Number, UITypes.Email, UITypes.URL, UITypes.LongText].includes(elementType)
const onFormItemClick = (element: any) => {
const onFormItemClick = (element: any, sidebarClick: boolean = false) => {
if (isLocked.value || !isEditable) return
if (sidebarClick) {
autoScrollFormField.value = true
}
activeRow.value = element.id
}
@ -643,6 +649,16 @@ const onFocusActiveFieldLabel = (e: FocusEvent) => {
;(e.target as HTMLTextAreaElement).select()
}
const updateFieldTitle = (value: string) => {
if (!activeField.value) return
if (activeField.value.title === value) {
activeField.value.label = null
} else {
activeField.value.label = value
}
}
const updateSelectFieldLayout = (value: boolean) => {
if (!activeField.value) return
@ -702,17 +718,31 @@ watch(
},
)
watch(activeField, (newValue) => {
if (newValue) {
const field = document.querySelector(`.nc-form-field-item-${CSS.escape(newValue?.title?.replaceAll(' ', ''))}`)
const handleAutoScrollFormField = (title: string, isSidebar: boolean) => {
const field = document.querySelector(
`${isSidebar ? '.nc-form-field-item-' : '.nc-form-drag-'}${CSS.escape(title?.replaceAll(' ', ''))}`,
)
if (field) {
setTimeout(() => {
field?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}, 50)
}
if (field) {
setTimeout(() => {
field?.scrollIntoView({ behavior: 'smooth', block: 'center' })
}, 50)
}
}
watch(activeField, (newValue, oldValue) => {
if (newValue && autoScrollFormField.value) {
nextTick(() => {
handleAutoScrollFormField(newValue.title, false)
})
} else if (oldValue) {
nextTick(() => {
handleAutoScrollFormField(oldValue.title, true)
})
}
autoScrollFormField.value = false
dropdownStates.value = {
...dropdownStates.value,
showColumnMenu: false,
@ -756,10 +786,11 @@ useEventListener(
document,
'mousedown',
(e: MouseEvent) => {
console.log('e.target', e.target)
if (
(draggableRef.value?.targetDomElement && draggableRef.value?.targetDomElement.contains(e.target)) ||
(e.target as HTMLElement)?.closest(
'.nc-form-right-panel, [class*="dropdown"], .nc-form-rich-text-field, .ant-modal, .ant-modal-wrap, .nc-share-base-button',
'.nc-form-right-panel, [class*="dropdown"], .nc-form-rich-text-field, .ant-modal, .ant-modal-wrap, .nc-share-base-button, .nc-form-right-sidebar-content-resizable-wrapper .splitpanes__splitter',
)
) {
return
@ -1360,7 +1391,7 @@ useEventListener(
<a-textarea
ref="focusLabel"
v-model:value="activeField.label"
:value="activeField.label || activeField.title"
:rows="1"
auto-size
hide-details
@ -1369,6 +1400,7 @@ useEventListener(
:placeholder="$t('msg.info.formInput')"
@focus="onFocusActiveFieldLabel"
@keydown.enter.prevent
@update:value="updateFieldTitle"
@change="updateColMeta(activeField)"
/>
@ -1427,26 +1459,29 @@ useEventListener(
</div>
<!-- Limit options -->
<div v-if="isSelectTypeCol(activeField.uidt)" class="flex items-start justify-between gap-3">
<div class="flex items-center gap-3">
<div class="flex-1">
<div class="font-medium text-gray-800">{{ $t('labels.limitOptions') }}</div>
<div class="text-gray-500 mt-2">{{ $t('labels.limitOptionsSubtext') }}.</div>
<div v-if="activeField.meta.isLimitOption" class="mt-3">
<LazySmartsheetFormLimitOptions
v-model:model-value="activeField.meta.limitOptions"
:column="activeField"
:is-required="isRequired(activeField, activeField.required)"
@update:model-value="updateColMeta(activeField)"
></LazySmartsheetFormLimitOptions>
</div>
<div v-if="isSelectTypeCol(activeField.uidt)" class="w-full flex items-start justify-between gap-3">
<div class="flex-1 max-w-[calc(100%_-_40px)]">
<div class="font-medium text-gray-800">{{ $t('labels.limitOptions') }}</div>
<div class="text-gray-500 mt-2">{{ $t('labels.limitOptionsSubtext') }}.</div>
<div v-if="activeField.meta.isLimitOption" class="mt-3">
<LazySmartsheetFormLimitOptions
v-model:model-value="activeField.meta.limitOptions"
:form-field-state="formState[activeField.title] || ''"
:column="activeField"
:is-required="isRequired(activeField, activeField.required)"
@update:model-value="updateColMeta(activeField)"
@update:form-field-state="(value)=>{
formState[activeField!.title] = value
}"
></LazySmartsheetFormLimitOptions>
</div>
</div>
<a-switch
v-model:checked="activeField.meta.isLimitOption"
v-e="['a:form-view:field:limit-options']"
size="small"
class="nc-form-switch-focus"
class="flex-none nc-form-switch-focus"
@change="updateColMeta(activeField)"
/>
</div>
@ -1581,57 +1616,69 @@ useEventListener(
<div
v-if="field.title.toLowerCase().includes(searchQuery.toLowerCase())"
:key="field.id"
class="w-full px-2 py-1.5 flex flex-row items-center border-b-1 last:border-none border-gray-200"
class="w-full px-2 flex flex-row items-center border-b-1 last:border-none border-gray-200"
:class="[
`nc-form-field-item-${field.title.replaceAll(' ', '')}`,
`${activeRow === field.id ? 'bg-brand-50 font-medium' : 'hover:bg-gray-50'}`,
]"
:data-testid="`nc-form-field-item-${field.title}`"
>
<component :is="iconMap.drag" class="flex-none cursor-move !h-4 !w-4 text-gray-600 mr-1" />
<div class="py-1.5 flex items-center">
<component :is="iconMap.drag" class="flex-none cursor-move !h-4 !w-4 text-gray-600 mr-1" />
</div>
<div
class="flex-1 flex items-center justify-between cursor-pointer max-w-[calc(100%_-_20px)]"
@click="showOrHideColumn(field, !field.show, true)"
class="flex-1 flex items-center justify-between cursor-pointer max-w-[calc(100%_-_20px)] py-1.5"
>
<SmartsheetHeaderVirtualCellIcon v-if="field && isVirtualCol(field)" :column-meta="field" />
<SmartsheetHeaderCellIcon v-else :column-meta="field" />
<div class="flex-1 flex items-center justify-start max-w-[calc(100%_-_68px)] mr-4">
<div class="w-full flex items-center">
<div class="ml-1 inline-flex" :class="field.label?.trim() ? 'max-w-1/2' : 'max-w-[95%]'">
<NcTooltip class="truncate text-sm" :disabled="drag" show-on-truncate-only>
<template #title>
<div class="text-center">
{{ field.title }}
</div>
</template>
<span data-testid="nc-field-title"> {{ field.title }} </span>
</NcTooltip>
</div>
<div
v-if="field.label?.trim()"
class="truncate inline-flex text-xs font-normal text-gray-700"
>
<span>&nbsp;(</span>
<NcTooltip class="truncate" :disabled="drag" show-on-truncate-only>
<template #title>
<div class="text-center">
{{ field.label }}
</div>
</template>
<span data-testid="nc-field-title ">{{ field.label?.trim() }}</span>
</NcTooltip>
<span>)</span>
<div
class="flex-1 flex items-center cursor-pointer max-w-[calc(100%_-_40px)]"
@click.prevent="onFormItemClick(field, true)"
>
<SmartsheetHeaderVirtualCellIcon v-if="field && isVirtualCol(field)" :column-meta="field" />
<SmartsheetHeaderCellIcon v-else :column-meta="field" />
<div class="flex-1 flex items-center justify-start max-w-[calc(100%_-_28px)]">
<div class="w-full flex items-center">
<div class="ml-1 inline-flex" :class="field.label?.trim() ? 'max-w-1/2' : 'max-w-[95%]'">
<NcTooltip class="truncate text-sm" :disabled="drag" show-on-truncate-only>
<template #title>
<div class="text-center">
{{ field.title }}
</div>
</template>
<span data-testid="nc-field-title"> {{ field.title }} </span>
</NcTooltip>
</div>
<div
v-if="field.label?.trim()"
class="truncate inline-flex text-xs font-normal text-gray-700"
>
<span>&nbsp;(</span>
<NcTooltip class="truncate" :disabled="drag" show-on-truncate-only>
<template #title>
<div class="text-center">
{{ field.label }}
</div>
</template>
<span data-testid="nc-field-title ">{{ field.label?.trim() }}</span>
</NcTooltip>
<span>)</span>
</div>
<span v-if="isRequired(field, field.required)" class="text-red-500 text-sm align-top"
>&nbsp;*</span
>
</div>
<span v-if="isRequired(field, field.required)" class="text-red-500 text-sm align-top"
>&nbsp;*</span
>
</div>
</div>
<a-switch
:checked="!!field.show"
:disabled="field.required || isLocked || !isEditable"
class="nc-switch"
class="flex-none nc-switch"
size="small"
@change="
(value) => {
showOrHideColumn(field, value, true)
}
"
/>
</div>
</div>

27
packages/nc-gui/components/smartsheet/form/LimitOptions.vue

@ -8,15 +8,16 @@ import { MetaInj, iconMap } from '#imports'
const props = defineProps<{
modelValue: FormFieldsLimitOptionsType[]
formFieldState?: string | null
column: ColumnType
isRequired?: boolean
}>()
const emit = defineEmits(['update:modelValue'])
const emits = defineEmits(['update:modelValue', 'update:formFieldState'])
const meta = inject(MetaInj)!
const column = toRef(props, 'column')
const { column, formFieldState } = toRefs(props)
const basesStore = useBases()
@ -55,7 +56,7 @@ const vModel = computed({
.sort((a, b) => a.order - b.order)
if ((props.modelValue || []).length !== collaborators.length) {
emit(
emits(
'update:modelValue',
collaborators.map((o) => ({ id: o.id, order: o.order, show: o.show })),
)
@ -78,7 +79,7 @@ const vModel = computed({
})
if ((props.modelValue || []).length !== ((column.value.colOptions as SelectOptionsType)?.options || []).length) {
emit(
emits(
'update:modelValue',
updateModelValue.map((o) => ({ id: o.id, order: o.order, show: o.show })),
)
@ -88,10 +89,24 @@ const vModel = computed({
return []
},
set: (val) => {
emit(
const fieldState = (formFieldState.value || '').split(',')
const optionsToRemoveFromFieldState: string[] = []
emits(
'update:modelValue',
val.map((o) => ({ id: o.id, order: o.order, show: o.show })),
val.map((o) => {
if (!o.show) {
if (column.value.uidt === UITypes.User && fieldState.includes(o.id)) {
optionsToRemoveFromFieldState.push(o.id)
} else if (o?.title && fieldState.includes(o.title)) {
optionsToRemoveFromFieldState.push(o.title)
}
}
return { id: o.id, order: o.order, show: o.show }
}),
)
emits('update:formFieldState', fieldState.filter((o) => !optionsToRemoveFromFieldState.includes(o)).join(','))
},
})

Loading…
Cancel
Save