diff --git a/packages/nc-gui/components/cell/Currency.vue b/packages/nc-gui/components/cell/Currency.vue index b91e51f173..cfd2f0bbea 100644 --- a/packages/nc-gui/components/cell/Currency.vue +++ b/packages/nc-gui/components/cell/Currency.vue @@ -107,7 +107,7 @@ onMounted(() => { v-model="vModel" type="number" class="nc-cell-field h-full border-none rounded-md py-1 outline-none focus:outline-none focus:ring-0" - :class="isForm && !isEditColumn ? 'flex flex-1' : 'w-full'" + :class="isForm && !isEditColumn && !hidePrefix ? 'flex flex-1' : 'w-full'" :placeholder="placeholder" :disabled="readOnly" @blur="onBlur" diff --git a/packages/nc-gui/components/smartsheet/Form.vue b/packages/nc-gui/components/smartsheet/Form.vue index cd9085a3ae..e97b6898a6 100644 --- a/packages/nc-gui/components/smartsheet/Form.vue +++ b/packages/nc-gui/components/smartsheet/Form.vue @@ -93,15 +93,24 @@ const { clearValidate, fieldMappings, isValidRedirectUrl, + loadAllviewFilters, + allViewFilters, + checkFieldVisibility, } = useProvideFormViewStore(meta, view, formViewData, updateFormView, isEditable) const { preFillFormSearchParams } = storeToRefs(useViewsStore()) const reloadEventHook = inject(ReloadViewDataHookInj, createEventHook()) -reloadEventHook.on(async () => { - await Promise.all([loadFormView(), loadReleatedMetas()]) - setFormData() +reloadEventHook.on(async (params) => { + if (params?.isFormFieldFilters) { + setTimeout(() => { + checkFieldVisibility() + }, 100) + } else { + await Promise.all([loadFormView(), loadReleatedMetas()]) + setFormData() + } }) const { fields, showAll, hideAll } = useViewColumnsOrThrow() @@ -303,10 +312,16 @@ const updatePreFillFormSearchParams = useDebounceFn(() => { async function submitForm() { if (isLocked.value || !isUIAllowed('dataInsert')) return - for (const col of visibleColumns.value) { - if (isRequired(col, col.required) && formState.value[col.title] === undefined) { + for (const col of localColumns.value) { + if (col.show && col.title && isRequired(col, col.required) && formState.value[col.title] === undefined) { formState.value[col.title] = null } + + // handle filter out conditionally hidden field data + if ((!col.visible || !col.show) && col.title) { + delete formState.value[col.title] + delete state.value[col.title] + } } try { @@ -417,6 +432,8 @@ async function onMove(event: any, isVisibleFormFields = false) { return 0 }) + checkFieldVisibility() + $e('a:form-view:reorder') } @@ -520,6 +537,8 @@ function setFormData() { .filter((f) => !hiddenColTypes.includes(f.uidt) && !systemFieldsIds.value.includes(f.fk_column_id)) .sort((a, b) => a.order - b.order) .map((c) => ({ ...c, required: !!c.required })) + + checkFieldVisibility() } async function updateEmail() { @@ -687,6 +706,13 @@ async function loadReleatedMetas() { ) } +const updateActiveFieldDescription = (value) => { + if (!activeField.value || activeField.value?.description === value) return + + activeField.value.description = value + updateColMeta(activeField.value) +} + onMounted(async () => { if (imageCropperData.value.src) { URL.revokeObjectURL(imageCropperData.value.imageConfig.src) @@ -696,9 +722,10 @@ onMounted(async () => { isLoadingFormView.value = true - await Promise.all([loadFormView(), loadReleatedMetas()]) + await Promise.all([loadFormView(), loadReleatedMetas(), loadAllviewFilters()]) setFormData() + isLoadingFormView.value = false }) @@ -762,8 +789,8 @@ watch(activeField, (newValue, oldValue) => { } }) -watch([focusLabel, activeField], () => { - if (activeField && focusLabel.value) { +watch(focusLabel, () => { + if (activeField.value && focusLabel.value) { nextTick(() => { focusLabel.value?.focus() }) @@ -1214,13 +1241,34 @@ useEventListener( /> -
- - {{ element.label || element.title }} - -  * + + + + + + + +
+ + {{ element.label || element.title }} + +  * +
- +
+ +
@@ -1423,13 +1473,13 @@ useEventListener( /> @@ -1559,8 +1609,12 @@ useEventListener( class="flex-1 flex items-center cursor-pointer max-w-[calc(100%_-_40px)]" @click.prevent="onFormItemClick(field, true)" > - - + +
@@ -1588,9 +1642,13 @@ useEventListener( )
-  * + + +  * + +
+ +
@@ -2009,6 +2067,32 @@ useEventListener( } } } + +.icon-fade-enter-active, +.icon-fade-leave-active { + transition: opacity 0.5s ease, transform 0.5s ease; /* Added scaling transition */ + position: absolute; +} + +.icon-fade-enter-from { + opacity: 0; + transform: scale(0.5); /* Start smaller and scale up */ +} + +.icon-fade-enter-to { + opacity: 1; + transform: scale(1); /* Scale to full size */ +} + +.icon-fade-leave-from { + opacity: 1; + transform: scale(1); /* Start at full size */ +} + +.icon-fade-leave-to { + opacity: 0; + transform: scale(0.5); /* Scale down and fade out */ +} + + diff --git a/packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue b/packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue index d9990ffda3..7988db2571 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/ColumnFilter.vue @@ -15,7 +15,12 @@ interface Props { isOpen?: boolean rootMeta?: any linkColId?: string + parentColId?: string actionBtnType?: 'text' | 'secondary' + /** Custom filter function */ + filterOption?: (column: ColumnType) => boolean + visibilityError?: Record + disableAddNewFilter?: boolean } const props = withDefaults(defineProps(), { @@ -27,7 +32,10 @@ const props = withDefaults(defineProps(), { webHook: false, link: false, linkColId: undefined, + parentColId: undefined, actionBtnType: 'text', + visibilityError: () => ({}), + disableAddNewFilter: false, }) const emit = defineEmits(['update:filtersLength', 'update:draftFilter', 'update:modelValue']) @@ -40,7 +48,19 @@ const draftFilter = useVModel(props, 'draftFilter', emit) const modelValue = useVModel(props, 'modelValue', emit) -const { nestedLevel, parentId, autoSave, hookId, showLoading, webHook, link, linkColId } = toRefs(props) +const { + nestedLevel, + parentId, + autoSave, + hookId, + showLoading, + webHook, + link, + linkColId, + parentColId, + visibilityError, + disableAddNewFilter, +} = toRefs(props) const nested = computed(() => nestedLevel.value > 0) @@ -63,7 +83,7 @@ const isPublic = inject(IsPublicInj, ref(false)) const { $e } = useNuxtApp() -const { nestedFilters } = useSmartsheetStoreOrThrow() +const { nestedFilters, isForm } = useSmartsheetStoreOrThrow() const currentFilters = modelValue.value || (!link.value && !webHook.value && nestedFilters.value) || [] @@ -72,7 +92,10 @@ const columns = computed(() => meta.value?.columns) const fieldsToFilter = computed(() => (columns.value || []).filter((c) => { if (link.value && isSystemColumn(c) && !c.pk && !isCreatedOrLastModifiedTimeCol(c)) return false - return !excludedFilterColUidt.includes(c.uidt as UITypes) + + const customFilter = props.filterOption ? props.filterOption(c) : true + + return !excludedFilterColUidt.includes(c.uidt as UITypes) && customFilter }), ) @@ -96,7 +119,11 @@ const { parentId, computed(() => autoSave.value), () => { - reloadDataHook.trigger({ shouldShowLoading: showLoading.value, offset: 0 }) + reloadDataHook.trigger({ + shouldShowLoading: showLoading.value, + offset: 0, + isFormFieldFilters: isForm.value && !webHook.value, + }) reloadAggregate?.trigger() }, currentFilters, @@ -105,6 +132,7 @@ const { link.value, linkColId, fieldsToFilter, + parentColId, ) const { getPlanLimit } = useWorkspace() @@ -247,7 +275,7 @@ const applyChanges = async (hookOrColId?: string, nested = false, isConditionSup for (const nestedFilter of localNestedFilters.value) { if (nestedFilter.parentId) { - await nestedFilter.applyChanges(hookOrColId, true) + await nestedFilter.applyChanges(hookOrColId, true, undefined) } } } @@ -525,56 +553,59 @@ const changeToDynamic = async (filter, i) => { data-testid="nc-filter" class="menu-filter-dropdown w-min" :class="{ - 'max-h-[max(80vh,500px)] min-w-112 py-2 pl-4': !nested, + 'max-h-[max(80vh,500px)] min-w-122 py-2 pl-4': !nested, + '!min-w-127.5': isForm && !webHook, '!min-w-full !w-full !pl-0': !nested && webHook, 'min-w-full': nested, }" > -
+
- - + + + +