Browse Source

fix(nc-gui): update edit form field ui

pull/7664/head
Ramesh Mane 7 months ago
parent
commit
d37ac18b6d
  1. 332
      packages/nc-gui/components/smartsheet/Form.vue

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

@ -17,6 +17,7 @@ import {
inject, inject,
message, message,
onClickOutside, onClickOutside,
parseProp,
provide, provide,
reactive, reactive,
ref, ref,
@ -28,7 +29,6 @@ import {
useViewColumnsOrThrow, useViewColumnsOrThrow,
useViewData, useViewData,
watch, watch,
parseProp,
} from '#imports' } from '#imports'
provide(IsFormInj, ref(true)) provide(IsFormInj, ref(true))
@ -192,6 +192,7 @@ function onMoveCallback(event: any) {
} }
} }
// Todo: reorder visible form fields
function onMove(event: any, isVisibleFormFields = false) { function onMove(event: any, isVisibleFormFields = false) {
const { newIndex, element, oldIndex } = event.moved const { newIndex, element, oldIndex } = event.moved
@ -450,18 +451,20 @@ const onFormItemClick = (element: any) => {
</a-col> </a-col>
</a-row> </a-row>
<a-row v-else class="h-full flex" data-testid="nc-form-wrapper"> <div v-else class="h-full w-full flex" data-testid="nc-form-wrapper">
<a-col <div
v-if="formViewData" v-if="formViewData"
:span="isEditable ? 16 : 24" class="flex-1 h-full overflow-y-auto nc-form-scrollbar p-6 bg-gray-50"
class="h-full overflow-auto nc-form-scrollbar p-6 bg-gray-50"
:style="{background:(formViewData?.meta as Record<string,any>).theme_color}" :style="{background:(formViewData?.meta as Record<string,any>).theme_color}"
> >
<div class="h-[160px] bg-primary bg-opacity-75 border-gray-200 rounded-3xl"> <div class="h-[160px] bg-primary bg-opacity-75 border-gray-200 rounded-3xl">
<!-- for future implementation of cover image --> <!-- for future implementation of cover image -->
<LazyNuxtImg <LazyNuxtImg
class="h-full" class="h-full"
:src="`${appInfo.ncSiteUrl}/dltemp/KQahh21IPmhTKhVB/1708109400000/noco/pr5u10r2vcqirf2/mua2zr4vlyv3524/cvncb31si72grpm/X3yt8PX8ZFQEM5mluk.png`" :src="
formViewData.banner_image_url ??
'http://localhost:8080/dltemp/KBFMWX8l0BIabZ6E/1708117800000/noco/pr5u10r2vcqirf2/mua2zr4vlyv3524/cvncb31si72grpm/X3yt8PX8ZFQEM5mluk.png'
"
alt="form-banner'" alt="form-banner'"
placeholder placeholder
quality="75" quality="75"
@ -469,7 +472,7 @@ const onFormItemClick = (element: any) => {
</div> </div>
<a-card <a-card
class="!p-12 <xl:!p-8 border-gray-200 !rounded-3xl !mt-6 max-w-[688px] !mx-auto" class="!py-8 !lg:py-12 border-gray-200 !rounded-3xl !mt-6 max-w-[688px] !mx-auto"
:body-style="{ :body-style="{
margin: '0 auto', margin: '0 auto',
padding: '0px !important', padding: '0px !important',
@ -477,7 +480,7 @@ const onFormItemClick = (element: any) => {
> >
<a-form ref="formRef" :model="formState" class="nc-form" no-style> <a-form ref="formRef" :model="formState" class="nc-form" no-style>
<!-- form header --> <!-- form header -->
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4 px-8 lg:px-12">
<!-- Form logo --> <!-- Form logo -->
<div v-if="isEditable"> <div v-if="isEditable">
<div class="inline-block rounded-xl bg-gray-100 p-3"> <div class="inline-block rounded-xl bg-gray-100 p-3">
@ -520,7 +523,7 @@ const onFormItemClick = (element: any) => {
<!-- form description --> <!-- form description -->
<a-form-item v-if="isEditable" class="w-full"> <a-form-item v-if="isEditable" class="w-full">
<a-textarea <a-textarea
v-model:value="formViewData.subheading as string" v-model:value="formViewData.subheading"
class="w-full !border-0 !border-b-1 !border-dashed !rounded-none !border-gray-400" class="w-full !border-0 !border-b-1 !border-dashed !rounded-none !border-gray-400"
:style="{ :style="{
'borderRightWidth': '0px !important', 'borderRightWidth': '0px !important',
@ -551,7 +554,7 @@ const onFormItemClick = (element: any) => {
item-key="fk_column_id" item-key="fk_column_id"
draggable=".item" draggable=".item"
group="form-inputs" group="form-inputs"
class="h-full" class="h-full px-4 lg:px-6"
:move="onMoveCallback" :move="onMoveCallback"
:disabled="isLocked" :disabled="isLocked"
@change="onMove($event)" @change="onMove($event)"
@ -560,11 +563,17 @@ const onFormItemClick = (element: any) => {
> >
<template #item="{ element, index }"> <template #item="{ element, index }">
<div <div
class="color-transition nc-editable item cursor-pointer hover:(bg-primary bg-opacity-10 ring-1 ring-accent ring-opacity-100) px-4 lg:px-12 py-4 relative" class="nc-editable item cursor-pointer relative bg-white"
:class="[ :class="[
`nc-form-drag-${element.title.replaceAll(' ', '')}`, `nc-form-drag-${element.title.replaceAll(' ', '')}`,
{ {
'bg-primary bg-opacity-5 ring-0.5 ring-accent ring-opacity-100': activeRow === element.title, 'rounded-2xl overflow-hidden border-2': editEnabled,
},
{
'border-transparent hover:(bg-gray-50) p-4 lg:p-6': activeRow !== element.title,
},
{
'border-brand-500 my-1': activeRow === element.title,
}, },
{ {
'!hover:bg-white !ring-0 !cursor-auto': isLocked, '!hover:bg-white !ring-0 !cursor-auto': isLocked,
@ -573,19 +582,34 @@ const onFormItemClick = (element: any) => {
data-testid="nc-form-fields" data-testid="nc-form-fields"
@click="onFormItemClick(element)" @click="onFormItemClick(element)"
> >
<div <div v-if="activeRow !== element.title">
v-if="isUIAllowed('viewFieldEdit') && !isRequired(element, element.required) && !isLocked" <div>
class="absolute flex top-2 right-2" <span data-testid="nc-form-field-title">
> {{ element.label || element.title }}
<component </span>
:is="iconMap.eyeSlash" <span v-if="element.required" class="text-red-500">&nbsp;*</span>
class="opacity-0 nc-field-remove-icon" </div>
data-testid="nc-field-remove-icon"
@click.stop="showOrHideColumn(element, !element.show)" <div class="nc-form-help-text text-gray-500 text-sm mt-2" data-testid="nc-form-help-text">
/> {{ element.description }}
</div>
</div> </div>
<div v-if="activeRow === element.title" class="flex flex-col gap-3 mb-3"> <!-- Field Header -->
<div v-if="activeRow === element.title" class="flex gap-3 items-center px-3 py-2 bg-gray-50">
<component :is="iconMap.drag" class="flex-none cursor-move !h-4 !w-4 text-gray-600" />
<div class="flex-1 flex items-center">
<SmartsheetHeaderVirtualCellIcon v-if="element && isVirtualCol(element)" :column-meta="element" />
<SmartsheetHeaderCellIcon v-else :column-meta="element" />
<NcTooltip class="truncate flex-1" show-on-truncate-only>
<template #title> {{ element.label || element.title }} </template>
<span data-testid="nc-form-field-title">
{{ element.label || element.title }}
</span>
<span v-if="element.required" class="text-red-500">&nbsp;*</span>
</NcTooltip>
</div>
<div class="flex gap-2 items-center"> <div class="flex gap-2 items-center">
<span <span
class="text-gray-500 mr-2 nc-form-input-required" class="text-gray-500 mr-2 nc-form-input-required"
@ -599,7 +623,6 @@ const onFormItemClick = (element: any) => {
> >
{{ $t('general.required') }} {{ $t('general.required') }}
</span> </span>
<a-switch <a-switch
v-model:checked="element.required" v-model:checked="element.required"
v-e="['a:form-view:field:mark-required']" v-e="['a:form-view:field:mark-required']"
@ -607,124 +630,124 @@ const onFormItemClick = (element: any) => {
@change="updateColMeta(element)" @change="updateColMeta(element)"
/> />
</div> </div>
</div>
<a-form-item v-if="columnSupportsScanning(element.uidt)" class="my-0 w-1/2 !mb-1"> <!-- Field Body -->
<div class="flex gap-2 items-center">
<span <div class="nc-form-field-body" :class="activeRow === element.title ? 'p-4 lg:p-6' : ''">
class="text-gray-500 mr-2 nc-form-input-required" <template v-if="activeRow === element.title">
data-testid="nc-form-input-enable-scanner" <a-form-item v-if="columnSupportsScanning(element.uidt)" class="my-0 !mb-1">
@click=" <div class="flex gap-2 items-center">
() => { <span
element.general.enable_scanner = !element.general.enable_scanner class="text-gray-500 mr-2 nc-form-input-required"
updateColMeta(element) data-testid="nc-form-input-enable-scanner"
} @click="
" () => {
element.general.enable_scanner = !element.general.enable_scanner
updateColMeta(element)
}
"
>
{{ $t('general.enableScanner') }}
</span>
<a-switch
v-model:checked="element.enable_scanner"
v-e="['a:form-view:field:mark-enable-scaner']"
size="small"
@change="updateColMeta(element)"
/>
</div>
</a-form-item>
<a-form-item class="my-0 !mb-2">
<a-input
v-model:value="element.label"
type="text"
class="form-meta-input nc-form-input-label"
data-testid="nc-form-input-label"
:placeholder="$t('msg.info.formInput')"
@change="updateColMeta(element)"
> >
{{ $t('general.enableScanner') }} </a-input>
</span> </a-form-item>
<a-switch <a-form-item class="!my-0 !mb-3">
v-model:checked="element.enable_scanner" <a-input
v-e="['a:form-view:field:mark-enable-scaner']" v-model:value="element.description"
size="small" type="text"
class="form-meta-input text-sm nc-form-input-help-text"
data-testid="nc-form-input-help-text"
:placeholder="$t('msg.info.formHelpText')"
@change="updateColMeta(element)" @change="updateColMeta(element)"
/> />
</div> </a-form-item>
</a-form-item> </template>
<div :class="activeRow !== element.title ? 'mt-2' : ''">
<a-form-item class="my-0 w-1/2 !mb-1"> <a-form-item
<a-input v-if="isVirtualCol(element)"
v-model:value="element.label" :name="element.title"
type="text" class="!my-0 nc-input-required-error nc-form-input-item"
class="form-meta-input nc-form-input-label" :rules="[
data-testid="nc-form-input-label" {
:placeholder="$t('msg.info.formInput')" required: isRequired(element, element.required),
@change="updateColMeta(element)" message: `${element.label || element.title} is required`,
},
]"
> >
</a-input> <LazySmartsheetVirtualCell
</a-form-item> v-model="formState[element.title]"
:row="row"
<a-form-item class="mt-2 mb-0 w-1/2"> class="nc-input"
<a-input :class="`nc-form-input-${element.title.replaceAll(' ', '')}`"
v-model:value="element.description" :data-testid="`nc-form-input-${element.title.replaceAll(' ', '')}`"
type="text" :column="element"
class="form-meta-input text-sm nc-form-input-help-text" @click.stop.prevent
data-testid="nc-form-input-help-text" />
:placeholder="$t('msg.info.formHelpText')" </a-form-item>
@change="updateColMeta(element)"
/> <a-form-item
</a-form-item> v-else
</div> :name="element.title"
class="!my-0 nc-input-required-error nc-form-input-item"
<div> :rules="[
<LazySmartsheetHeaderVirtualCell {
v-if="isVirtualCol(element)" required: isRequired(element, element.required),
:column="{ ...element, title: element.label || element.title }" message: `${element.label || element.title} is required`,
:required="isRequired(element, element.required)" },
:hide-menu="true" ]"
data-testid="nc-form-input-label" >
/> <LazySmartsheetDivDataCell class="relative">
<LazySmartsheetCell
<LazySmartsheetHeaderCell v-model="formState[element.title]"
v-else class="nc-input truncate"
:column="{ ...element, title: element.label || element.title }" :class="`nc-form-input-${element.title.replaceAll(' ', '')}`"
:required="isRequired(element, element.required)" :data-testid="`nc-form-input-${element.title.replaceAll(' ', '')}`"
:hide-menu="true" :column="element"
data-testid="nc-form-input-label" :edit-enabled="editEnabled[index]"
/> @click="editEnabled[index] = true"
@cancel="editEnabled[index] = false"
@update:edit-enabled="editEnabled[index] = $event"
@click.stop.prevent
/>
</LazySmartsheetDivDataCell>
</a-form-item>
</div>
</div> </div>
<a-form-item <!-- Field Settings -->
v-if="isVirtualCol(element)" <div
:name="element.title" v-if="activeRow === element.title && false"
class="!mb-0 nc-input-required-error nc-form-input-item" class="nc-form-field-settings border-t border-gray-200 p-4 lg:p-6"
:rules="[
{
required: isRequired(element, element.required),
message: `${element.label || element.title} is required`,
},
]"
>
<LazySmartsheetVirtualCell
v-model="formState[element.title]"
:row="row"
class="nc-input"
:class="`nc-form-input-${element.title.replaceAll(' ', '')}`"
:data-testid="`nc-form-input-${element.title.replaceAll(' ', '')}`"
:column="element"
@click.stop.prevent
/>
</a-form-item>
<a-form-item
v-else
:name="element.title"
class="!mb-0 nc-input-required-error nc-form-input-item"
:rules="[
{
required: isRequired(element, element.required),
message: `${element.label || element.title} is required`,
},
]"
> >
<LazySmartsheetDivDataCell class="relative"> <!-- Todo: Show on conditions, options limit,... -->
<LazySmartsheetCell <div class="flex items-start gap-3 px-3 py-2 border-1 border-gray-200 rounded-lg">
v-model="formState[element.title]" <a-switch v-e="['a:form-view:field:show-on-condition']" size="small" />
class="nc-input truncate" <div>
:class="`nc-form-input-${element.title.replaceAll(' ', '')}`" <div class="font-medium text-gray-800">Show on condtions</div>
:data-testid="`nc-form-input-${element.title.replaceAll(' ', '')}`" <div class="text-gray-500">Shows field only when conditions are met</div>
:column="element" </div>
:edit-enabled="editEnabled[index]" </div>
@click="editEnabled[index] = true"
@cancel="editEnabled[index] = false"
@update:edit-enabled="editEnabled[index] = $event"
@click.stop.prevent
/>
</LazySmartsheetDivDataCell>
</a-form-item>
<div class="nc-form-help-text text-gray-500 text-xs truncate" data-testid="nc-form-input-help-text-label">
{{ element.description }}
</div> </div>
</div> </div>
</template> </template>
@ -739,7 +762,7 @@ const onFormItemClick = (element: any) => {
</template> </template>
</Draggable> </Draggable>
<div class="flex justify-between items-center mt-6"> <div class="flex justify-between items-center mt-6 !px-8 !lg:px-12">
<NcButton <NcButton
html-type="reset" html-type="reset"
type="secondary" type="secondary"
@ -764,7 +787,7 @@ const onFormItemClick = (element: any) => {
</div> </div>
</a-form> </a-form>
<template v-if="!parseProp(formViewData?.meta).hide_branding"> <div v-if="!parseProp(formViewData?.meta).hide_branding" class="px-8 lg:px-12">
<a-divider v-if="!isLocked" class="!my-8" /> <a-divider v-if="!isLocked" class="!my-8" />
<!-- Nocodb Branding --> <!-- Nocodb Branding -->
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
@ -772,10 +795,10 @@ const onFormItemClick = (element: any) => {
<img src="~assets/img/icons/64x64.png" alt="NocoDB" class="w-6" /> <img src="~assets/img/icons/64x64.png" alt="NocoDB" class="w-6" />
<div class="text-sm text-gray-700">NocoDB Forms</div> <div class="text-sm text-gray-700">NocoDB Forms</div>
</div> </div>
</template> </div>
</a-card> </a-card>
</a-col> </div>
<a-col v-if="isEditable" :span="8" class="h-full nc-form-left-drawer border-l border-gray-200"> <div v-if="isEditable" class="h-full w-full max-w-[384px] nc-form-left-drawer border-l border-gray-200">
<Splitpanes horizontal class="w-full nc-form-right-splitpane"> <Splitpanes horizontal class="w-full nc-form-right-splitpane">
<Pane min-size="30" size="50" class="nc-form-right-splitpane-item p-2 md:p-4 flex flex-col space-y-4 !min-h-200px"> <Pane min-size="30" size="50" class="nc-form-right-splitpane-item p-2 md:p-4 flex flex-col space-y-4 !min-h-200px">
<div class="flex flex-wrap justify-between items-center gap-2"> <div class="flex flex-wrap justify-between items-center gap-2">
@ -958,7 +981,7 @@ const onFormItemClick = (element: any) => {
<!-- {{ $t('msg.info.showMessage') }} --> <!-- {{ $t('msg.info.showMessage') }} -->
</div> </div>
<a-textarea <a-textarea
v-model:value="formViewData.success_msg as string" v-model:value="formViewData.success_msg"
:rows="3" :rows="3"
hide-details hide-details
class="nc-form-after-submit-msg !rounded-lg !px-3 !py-1" class="nc-form-after-submit-msg !rounded-lg !px-3 !py-1"
@ -972,7 +995,7 @@ const onFormItemClick = (element: any) => {
<div class="flex items-center"> <div class="flex items-center">
<!-- Show "Submit Another Form" button --> <!-- Show "Submit Another Form" button -->
<a-switch <a-switch
v-model:checked="formViewData.submit_another_form as boolean" v-model:checked="formViewData.submit_another_form"
v-e="[`a:form-view:submit-another-form`]" v-e="[`a:form-view:submit-another-form`]"
size="small" size="small"
class="nc-form-checkbox-submit-another-form" class="nc-form-checkbox-submit-another-form"
@ -985,7 +1008,7 @@ const onFormItemClick = (element: any) => {
<div class="flex items-center"> <div class="flex items-center">
<!-- Show a blank form after 5 seconds --> <!-- Show a blank form after 5 seconds -->
<a-switch <a-switch
v-model:checked="formViewData.show_blank_form as boolean" v-model:checked="formViewData.show_blank_form"
v-e="[`a:form-view:show-blank-form`]" v-e="[`a:form-view:show-blank-form`]"
size="small" size="small"
class="nc-form-checkbox-show-blank-form" class="nc-form-checkbox-show-blank-form"
@ -996,7 +1019,7 @@ const onFormItemClick = (element: any) => {
<span class="ml-4">{{ $t('msg.info.showBlankForm') }}</span> <span class="ml-4">{{ $t('msg.info.showBlankForm') }}</span>
</div> </div>
<div class="mb-12 flex items-center"> <div class="flex items-center">
<a-switch <a-switch
v-model:checked="emailMe" v-model:checked="emailMe"
v-e="[`a:form-view:email-me`]" v-e="[`a:form-view:email-me`]"
@ -1016,8 +1039,8 @@ const onFormItemClick = (element: any) => {
</div> </div>
</Pane> </Pane>
</Splitpanes> </Splitpanes>
</a-col> </div>
</a-row> </div>
</template> </template>
</div> </div>
</template> </template>
@ -1042,15 +1065,18 @@ const onFormItemClick = (element: any) => {
} }
} }
.form-meta-input::placeholder { .form-meta-input {
@apply text-[#3d3d3d] italic; @apply !rounded-lg !text-sm;
&::placeholder {
@apply !text-gray-500;
}
} }
.nc-form-input-label, .nc-form-input-label {
@apply !px-4 !py-2;
}
.nc-form-input-help-text { .nc-form-input-help-text {
&::placeholder { @apply !px-3 !py-1;
@apply !text-gray-500 !text-xs;
}
} }
.nc-form-help-text, .nc-form-help-text,
@ -1101,4 +1127,8 @@ const onFormItemClick = (element: any) => {
:deep(.nc-form-theme-color-picker .color-selector) { :deep(.nc-form-theme-color-picker .color-selector) {
@apply !text-white; @apply !text-white;
} }
:deep(.nc-form-field-body .nc-cell) {
@apply my-0;
}
</style> </style>

Loading…
Cancel
Save