Browse Source

feat(nc-gui): form view v2 setup

pull/7664/head
Ramesh Mane 9 months ago
parent
commit
45b8a9f7fe
  1. 373
      packages/nc-gui/components/smartsheet/Form.vue
  2. 2
      packages/nc-gui/components/tabs/Smartsheet.vue

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

@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import { Pane, Splitpanes } from 'splitpanes'
import 'splitpanes/dist/splitpanes.css'
import { RelationTypes, UITypes, ViewTypes, getSystemColumns, isLinksOrLTAR, isVirtualCol } from 'nocodb-sdk' import { RelationTypes, UITypes, ViewTypes, getSystemColumns, isLinksOrLTAR, isVirtualCol } from 'nocodb-sdk'
import type { Permission } from '#imports' import type { Permission } from '#imports'
import { import {
@ -113,6 +115,8 @@ const activeRow = ref('')
const editEnabled = ref<boolean[]>([]) const editEnabled = ref<boolean[]>([])
const searchQuery = ref('')
const { t } = useI18n() const { t } = useI18n()
const { betaFeatureToggleState } = useBetaFeatureToggle() const { betaFeatureToggleState } = useBetaFeatureToggle()
@ -402,6 +406,7 @@ const onFormItemClick = (element: any) => {
</script> </script>
<template> <template>
<div class="h-full">
<template v-if="isMobileMode"> <template v-if="isMobileMode">
<div class="pl-6 pr-[120px] py-6 bg-white flex-col justify-start items-start gap-2.5 inline-flex"> <div class="pl-6 pr-[120px] py-6 bg-white flex-col justify-start items-start gap-2.5 inline-flex">
<div class="text-gray-500 text-5xl font-semibold leading-16"> <div class="text-gray-500 text-5xl font-semibold leading-16">
@ -440,130 +445,17 @@ const onFormItemClick = (element: any) => {
</a-row> </a-row>
<a-row v-else class="h-full flex" data-testid="nc-form-wrapper"> <a-row v-else class="h-full flex" data-testid="nc-form-wrapper">
<a-col v-if="isEditable" :span="8" class="shadow p-2 md:p-4 h-full overflow-auto scrollbar-thin-dull nc-form-left-drawer"> <a-col v-if="formViewData" :span="isEditable ? 16 : 24" class="h-full overflow-auto scrollbar-thin-dull p-6 bg-gray-50">
<div class="flex flex-wrap gap-2"> <div class="h-[160px] bg-primary bg-opacity-75 border-gray-200 rounded-3xl">
<div class="flex-1 text-lg">
{{ $t('objects.fields') }}
</div>
<div class="flex flex-wrap gap-2 mb-4">
<NcButton
v-if="hiddenColumns.length"
type="secondary"
class="nc-form-add-all"
data-testid="nc-form-add-all"
:disabled="isLocked"
@click="addAllColumns"
>
<!-- Add all -->
{{ $t('general.addAll') }}
</NcButton>
<NcButton
v-if="localColumns.length"
type="secondary"
class="nc-form-remove-all"
data-testid="nc-form-remove-all"
:disabled="isLocked"
@click="removeAllColumns"
>
<!-- Remove all -->
{{ $t('general.removeAll') }}
</NcButton>
</div>
</div>
<Draggable
:list="hiddenColumns"
item-key="id"
draggable=".item"
group="form-inputs"
:disabled="isLocked"
class="flex flex-col gap-2"
@start="drag = true"
@end="drag = false"
>
<template #item="{ element, index }">
<a-card
size="small"
class="!border-0 color-transition cursor-pointer item hover:(bg-primary ring-1 ring-accent ring-opacity-100) bg-opacity-10 !rounded !shadow-lg"
:class="{
'!bg-gray-50 !hover:bg-gray-50 !hover:ring-transparent !cursor-not-allowed': isLocked,
}"
:data-testid="`nc-form-hidden-column-${element.label || element.title}`"
@mousedown="moved = false"
@mousemove="moved = false"
@mouseup="handleMouseUp(element, index)"
>
<div class="flex">
<div class="flex flex-1">
<LazySmartsheetHeaderVirtualCell
v-if="isVirtualCol(element)"
:column="{ ...element, title: element.label || element.title }"
:required="isRequired(element, element.required)"
:hide-menu="true"
/>
<LazySmartsheetHeaderCell
v-else
:column="{ ...element, title: element.label || element.title }"
:required="isRequired(element, element.required)"
:hide-menu="true"
/>
</div>
</div>
</a-card>
</template>
<template v-if="!isLocked" #footer>
<div
class="my-4 select-none border-dashed border-2 border-gray-400 py-3 text-gray-400 text-center nc-drag-n-drop-to-hide"
data-testid="nc-drag-n-drop-to-hide"
>
<!-- Drag and drop fields here to hide -->
{{ $t('msg.info.dragDropHide') }}
</div>
<a-dropdown
v-model:visible="showColumnDropdown"
:trigger="['click']"
overlay-class-name="nc-dropdown-form-add-column"
>
<button type="button" class="group w-full mt-2" @click.stop="showColumnDropdown = true">
<span class="flex items-center flex-wrap justify-center gap-2 prose-sm text-gray-400">
<component :is="iconMap.plus" class="color-transition transform group-hover:(text-accent scale-125)" />
<!-- Add new field to this table -->
<span class="color-transition group-hover:text-primary break-words">
{{ $t('activity.addField') }}
</span>
</span>
</button>
<template #overlay>
<SmartsheetColumnEditOrAddProvider
v-if="showColumnDropdown"
@submit="submitCallback"
@cancel="showColumnDropdown = false"
@click.stop
@keydown.stop
/>
</template>
</a-dropdown>
</template>
</Draggable>
</a-col>
<a-col v-if="formViewData" :span="isEditable ? 16 : 24" class="h-full overflow-auto scrollbar-thin-dull">
<div class="h-[200px] bg-primary bg-opacity-75">
<!-- for future implementation of cover image --> <!-- for future implementation of cover image -->
</div> </div>
<a-card <a-card
class="p-4 border-none" class="p-4 border-none !mt-6 max-w-[688px] !mx-auto"
:body-style="{ :body-style="{
maxWidth: 'max(50vw, 700px)', maxWidth: 'max(50vw, 700px)',
margin: '0 auto', margin: '0 auto',
marginTop: '-200px',
padding: '0px', padding: '0px',
}" }"
> >
@ -836,30 +728,194 @@ const onFormItemClick = (element: any) => {
</a-form> </a-form>
<a-divider v-if="!isLocked" /> <a-divider v-if="!isLocked" />
</a-card>
</a-col>
<a-col v-if="isEditable" :span="8" class="h-full nc-form-left-drawer border-l border-gray-200">
<Splitpanes horizontal class="w-full nc-form-right-splitpane">
<Pane min-size="40%" size="50" class="nc-form-right-splitpane-item p-2 md:p-4 flex flex-col space-y-4">
<div class="flex flex-wrap justify-between items-center gap-2">
<div class="flex gap-3">
<div class="text-base font-bold text-gray-900">
<!-- {{ $t('objects.fields') }} -->
Form Fields
</div>
<NcBadge color="border-gray-200" class=""> 22/26 Field </NcBadge>
</div>
<div v-if="isEditable && !isLocked" class="px-4 flex flex-col gap-2"> <a-dropdown
v-model:visible="showColumnDropdown"
:trigger="['click']"
overlay-class-name="nc-dropdown-form-add-column"
>
<NcButton
v-if="hiddenColumns.length"
type="secondary"
size="small"
class="nc-form-add-field"
data-testid="nc-form-add-field"
@click.stop="showColumnDropdown = true"
>
<div class="flex gap-2 items-center">
<component :is="iconMap.plus" class="color-transition transform group-hover:(text-accent scale-125)" />
<span> Add Field </span>
</div>
</NcButton>
<template #overlay>
<SmartsheetColumnEditOrAddProvider
v-if="showColumnDropdown"
@submit="submitCallback"
@cancel="showColumnDropdown = false"
@click.stop
@keydown.stop
/>
</template>
</a-dropdown>
<!-- <NcButton
v-if="hiddenColumns.length"
type="secondary"
class="nc-form-add-all"
data-testid="nc-form-add-all"
:disabled="isLocked"
@click="addAllColumns"
>
Add all
{{ $t('general.addAll') }}
</NcButton>
<NcButton
v-if="localColumns.length"
type="secondary"
class="nc-form-remove-all"
data-testid="nc-form-remove-all"
:disabled="isLocked"
@click="removeAllColumns"
>
Remove all
{{ $t('general.removeAll') }}
</NcButton> -->
</div>
<div>
<a-input
v-model:value="searchQuery"
data-testid="nc-form-field-search-input"
class="!h-9 !px-3 !py-1 !rounded-lg"
:placeholder="$t('placeholder.searchFields') + '...'"
>
<template #prefix>
<GeneralIcon icon="search" class="mr-2 h-4 w-4 text-gray-500 group-hover:text-black" />
</template>
<template #suffix>
<GeneralIcon
v-if="searchQuery.length > 0"
icon="close"
class="ml-2 h-4 w-4 text-gray-500 group-hover:text-black"
data-testid="nc-form-field-clear-search"
@click="searchQuery = ''"
/>
</template>
</a-input>
</div>
<div class="nc-form-fields-list border-1 border-gray-200 rounded-lg overflow-y-auto">
<div
v-if="!hiddenColumns?.filter((el) => el.title.toLowerCase().includes(searchQuery.toLowerCase())).length"
class="px-0.5 py-2 text-gray-500 text-center"
>
{{ $t('title.noFieldsFound') }}
</div>
<Draggable
v-else
v-model="hiddenColumns"
item-key="id"
@change="onMove($event)"
:style="{ height: 'calc(100% - 64px)' }"
>
<template #item="{ element: field }">
<div
v-if="field.title.toLowerCase().includes(searchQuery.toLowerCase())"
:key="field.id"
class="p-2 flex flex-row items-center border-b-1 last:border-none first:rounded-t-lg border-gray-200"
:data-testid="`nc-form-field-item-${field.title}`"
@click.stop
>
<component :is="iconMap.drag" class="flex-none cursor-move !h-4 !w-4 text-gray-600 mr-1" />
<div
class="flex-1 flex items-center justify-between cursor-pointer"
@click="
() => {
field.show = !field.show
}
"
>
<div class="flex-1 flex items-center">
<SmartsheetHeaderVirtualCellIcon v-if="field && isVirtualCol(field)" :column-meta="field" />
<SmartsheetHeaderCellIcon v-else :column-meta="field" />
<NcTooltip class="truncate flex-1 ml-1" show-on-truncate-only>
<template #title> {{ field.title }} </template>
<span data-testid="nc-field-title">
{{ field.title }}
</span>
</NcTooltip>
</div>
<NcSwitch :checked="field.show" />
</div>
</div>
</template>
<template #header>
<div
key="nc-form-show-all-fields"
class="w-full px-2 py-2 flex flex-row items-center border-b-1 rounded-t-lg border-gray-200 bg-gray-50 sticky top-0 z-100 overflow-hidden"
data-testid="nc"
@click.stop
>
<div class="w-4 h-4 flex-none mr-2"></div>
<div class="flex-1 flex flex-row items-center truncate cursor-pointer">
<div class="flex-1 font-base">Select all fields</div>
<NcSwitch :checked="true" />
</div>
</div>
</template>
</Draggable>
</div>
</Pane>
<Pane
v-if="isEditable && !isLocked && formViewData"
min-size="20%"
size="35"
class="nc-form-right-splitpane-item p-2 md:p-4 flex flex-col space-y-4 !overflow-y-auto nc-scrollbar-x-lg"
>
<!-- After form is submitted --> <!-- After form is submitted -->
<div class="text-lg text-gray-700"> <div class="text-base font-bold text-gray-900">
{{ $t('msg.info.afterFormSubmitted') }} Post Form Submission Settings
<!-- {{ $t('msg.info.afterFormSubmitted') }} -->
</div> </div>
<!-- Show this message --> <!-- Show this message -->
<div class="text-gray-500 text-bold">{{ $t('msg.info.showMessage') }}:</div> <div>
<div class="text-gray-800 mb-2">
Display Message
<!-- {{ $t('msg.info.showMessage') }} -->
</div>
<a-textarea <a-textarea
v-model:value="formViewData.success_msg" v-model:value="formViewData.success_msg as string"
:rows="3" :rows="3"
hide-details hide-details
class="nc-form-after-submit-msg" class="nc-form-after-submit-msg !rounded-lg !px-3 !py-1"
data-testid="nc-form-after-submit-msg" data-testid="nc-form-after-submit-msg"
@change="updateView" @change="updateView"
/> />
</div>
<!-- Other options --> <!-- Other options -->
<div class="flex flex-col gap-2 mt-4"> <div class="flex flex-col gap-3">
<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" v-model:checked="formViewData.submit_another_form as boolean"
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"
@ -872,7 +928,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" v-model:checked="formViewData.show_blank_form as boolean"
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"
@ -900,11 +956,64 @@ const onFormItemClick = (element: any) => {
</span> </span>
</div> </div>
</div> </div>
</Pane>
<!-- <Draggable
:list="hiddenColumns"
item-key="id"
draggable=".item"
group="form-inputs"
:disabled="isLocked"
class="flex flex-col gap-2"
@start="drag = true"
@end="drag = false"
>
<template #item="{ element, index }">
<a-card
size="small"
class="!border-0 color-transition cursor-pointer item hover:(bg-primary ring-1 ring-accent ring-opacity-100) bg-opacity-10 !rounded !shadow-lg"
:class="{
'!bg-gray-50 !hover:bg-gray-50 !hover:ring-transparent !cursor-not-allowed': isLocked,
}"
:data-testid="`nc-form-hidden-column-${element.label || element.title}`"
@mousedown="moved = false"
@mousemove="moved = false"
@mouseup="handleMouseUp(element, index)"
>
<div class="flex">
<div class="flex flex-1">
<LazySmartsheetHeaderVirtualCell
v-if="isVirtualCol(element)"
:column="{ ...element, title: element.label || element.title }"
:required="isRequired(element, element.required)"
:hide-menu="true"
/>
<LazySmartsheetHeaderCell
v-else
:column="{ ...element, title: element.label || element.title }"
:required="isRequired(element, element.required)"
:hide-menu="true"
/>
</div>
</div> </div>
</a-card> </a-card>
</a-col> </template>
<template v-if="!isLocked" #footer>
<div
class="my-4 select-none border-dashed border-2 border-gray-400 py-3 text-gray-400 text-center nc-drag-n-drop-to-hide"
data-testid="nc-drag-n-drop-to-hide"
>
{{ $t('msg.info.dragDropHide') }}
</div>
</template>
</Draggable> -->
</Splitpanes></a-col
>
</a-row> </a-row>
</template> </template>
</div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
@ -967,4 +1076,14 @@ const onFormItemClick = (element: any) => {
@apply !border-none; @apply !border-none;
} }
} }
:deep(.nc-form-right-splitpane .splitpanes__splitter) {
@apply !border-b-1 !border-gray-200;
::after {
content: 'e945';
}
}
.nc-form-fields-list {
}
</style> </style>

2
packages/nc-gui/components/tabs/Smartsheet.vue

@ -171,7 +171,7 @@ watch([activeViewTitleOrId, activeTableId], () => {
<div style="height: calc(100% - var(--topbar-height))"> <div style="height: calc(100% - var(--topbar-height))">
<div v-if="openedViewsTab === 'view'" class="flex flex-col h-full flex-1 min-w-0"> <div v-if="openedViewsTab === 'view'" class="flex flex-col h-full flex-1 min-w-0">
<LazySmartsheetToolbar v-if="!isForm" /> <LazySmartsheetToolbar v-if="!isForm" />
<div class="flex flex-row w-full" style="height: calc(100% - var(--topbar-height))"> <div class="flex flex-row w-full" :style="{ height: isForm ? '100%' : 'calc(100% - var(--topbar-height))' }">
<Transition name="layout" mode="out-in"> <Transition name="layout" mode="out-in">
<div v-if="openedViewsTab === 'view'" class="flex flex-1 min-h-0 w-3/4"> <div v-if="openedViewsTab === 'view'" class="flex flex-1 min-h-0 w-3/4">
<div class="h-full flex-1 min-w-0 min-h-0 bg-white"> <div class="h-full flex-1 min-w-0 min-h-0 bg-white">

Loading…
Cancel
Save