diff --git a/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue b/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue index 5f6c190554..8e03ad9746 100644 --- a/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue +++ b/packages/nc-gui/components/smartsheet/column/EditOrAdd.vue @@ -81,6 +81,10 @@ const columnToValidate = [UITypes.Email, UITypes.URL, UITypes.PhoneNumber] const onlyNameUpdateOnEditColumns = [UITypes.LinkToAnotherRecord, UITypes.Lookup, UITypes.Rollup, UITypes.Links] +// To close column type dropdown on escape and +// close modal only when the type popup is close +const isColumnTypeOpen = ref(false) + const geoDataToggleCondition = (t: { name: UITypes }) => { if (!appInfo.value.ee) return true @@ -199,6 +203,8 @@ onMounted(() => { }) const handleEscape = (event: KeyboardEvent): void => { + if (isColumnTypeOpen.value) return + if (event.key === 'Escape') emit('cancel') } @@ -206,6 +212,16 @@ const isFieldsTab = computed(() => { return openedViewsTab.value === 'field' }) +const onDropdownChange = (value: boolean) => { + if (value) { + isColumnTypeOpen.value = value + } else { + setTimeout(() => { + isColumnTypeOpen.value = value + }, 300) + } +} + if (props.fromTableExplorer) { watch( formState, @@ -224,7 +240,7 @@ if (props.fromTableExplorer) { 'bg-white': !props.fromTableExplorer, 'w-[400px]': !props.embedMode, '!w-146': isTextArea(formState) && formState.meta?.richMode, - '!w-[600px]': formState.uidt === UITypes.Formula && !props.embedMode, + '!w-116 overflow-visible': formState.uidt === UITypes.Formula && !props.embedMode, '!w-[500px]': formState.uidt === UITypes.Attachment && !props.embedMode && !appInfo.ee, 'shadow-lg border-1 border-gray-200 shadow-gray-300 rounded-xl p-6': !embedMode, }" @@ -275,6 +291,7 @@ if (props.fromTableExplorer) { class="nc-column-type-input !rounded" :disabled="isKanban || readOnly" dropdown-class-name="nc-dropdown-column-type border-1 !rounded-md border-gray-200" + @dropdown-visible-change="onDropdownChange" @change="onUidtOrIdTypeChange" @dblclick="showDeprecated = !showDeprecated" > diff --git a/packages/nc-gui/components/smartsheet/column/FormulaOptions.vue b/packages/nc-gui/components/smartsheet/column/FormulaOptions.vue index e52df87238..bb9191caf2 100644 --- a/packages/nc-gui/components/smartsheet/column/FormulaOptions.vue +++ b/packages/nc-gui/components/smartsheet/column/FormulaOptions.vue @@ -55,6 +55,8 @@ const supportedColumns = computed( ) const { getMeta } = useMetas() +const suggestionPreviewed = ref | undefined>() + const validators = { formula_raw: [ { @@ -93,6 +95,8 @@ const formulaRef = ref() const sugListRef = ref() +const variableListRef = ref<(typeof AntListItem)[]>([]) + const sugOptionsRef = ref<(typeof AntListItem)[]>([]) const wordToComplete = ref('') @@ -116,6 +120,7 @@ const suggestionsList = computed(() => { description: formulas[fn].description, syntax: formulas[fn].syntax, examples: formulas[fn].examples, + docsUrl: formulas[fn].docsUrl, })), ...supportedColumns.value .filter((c) => { @@ -149,6 +154,14 @@ const acTree = computed(() => { return ref }) +const suggestedFormulas = computed(() => { + return suggestion.value.filter((s) => s && s.type !== 'column') +}) + +const variableList = computed(() => { + return suggestion.value.filter((s) => s && s.type === 'column') +}) + function isCurlyBracketBalanced() { // count number of opening curly brackets and closing curly brackets const cntCurlyBrackets = (formulaRef.value.$el.value.match(/\{|}/g) || []).reduce( @@ -196,6 +209,11 @@ function handleInput() { suggestion.value = acTree.value .complete(wordToComplete.value) ?.sort((x: Record, y: Record) => sortOrder[x.type] - sortOrder[y.type]) + + if (suggestion.value.length > 0 && suggestion.value[0].type !== 'column') { + suggestionPreviewed.value = suggestion.value[0] + } + if (!isCurlyBracketBalanced()) { suggestion.value = suggestion.value.filter((v) => v.type === 'column') } @@ -203,14 +221,21 @@ function handleInput() { } function selectText() { - if (suggestion.value && selected.value > -1 && selected.value < suggestion.value.length) { - appendText(suggestion.value[selected.value]) + if (suggestion.value && selected.value > -1 && selected.value < suggestionsList.value.length) { + if (selected.value < suggestedFormulas.value.length) { + appendText(suggestedFormulas.value[selected.value]) + } else { + appendText(variableList.value[selected.value + suggestedFormulas.value.length]) + } } + + selected.value = 0 } function suggestionListUp() { if (suggestion.value) { selected.value = --selected.value > -1 ? selected.value : suggestion.value.length - 1 + suggestionPreviewed.value = suggestedFormulas.value[selected.value] scrollToSelectedOption() } } @@ -218,6 +243,8 @@ function suggestionListUp() { function suggestionListDown() { if (suggestion.value) { selected.value = ++selected.value % suggestion.value.length + suggestionPreviewed.value = suggestedFormulas.value[selected.value] + scrollToSelectedOption() } } @@ -226,9 +253,9 @@ function scrollToSelectedOption() { nextTick(() => { if (sugOptionsRef.value[selected.value]) { try { - sugListRef.value.$el.scrollTo({ - top: sugOptionsRef.value[selected.value].$el.offsetTop, - behavior: 'smooth', + sugOptionsRef.value[selected.value].$el.scrollIntoView({ + block: 'nearest', + inline: 'start', }) } catch (e) {} } @@ -256,8 +283,52 @@ onMounted(() => {