Browse Source

feat(nc-gui): list option for single & multiselect field

pull/7729/head
Ramesh Mane 7 months ago
parent
commit
bfc13045d2
  1. 347
      packages/nc-gui/components/cell/MultiSelect.vue
  2. 2
      packages/nc-gui/components/cell/SingleSelect.vue
  3. 2
      packages/nc-gui/components/smartsheet/Form.vue

347
packages/nc-gui/components/cell/MultiSelect.vue

@ -353,154 +353,194 @@ const onFocus = () => {
<template>
<div
class="nc-cell-field nc-multi-select h-full w-full flex items-center"
:class="{ 'read-only': readOnly }"
:class="{ 'read-only': readOnly, readOnly, 'max-w-full': isForm }"
@click="toggleMenu"
>
<div
v-if="!active"
class="flex flex-wrap"
:style="{
'display': '-webkit-box',
'max-width': '100%',
'-webkit-line-clamp': rowHeight || 1,
'-webkit-box-orient': 'vertical',
'overflow': 'hidden',
}"
>
<template v-for="selectedOpt of selectedOpts" :key="selectedOpt.value">
<a-tag class="rounded-tag max-w-full" :color="selectedOpt.color">
<span
:style="{
'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(selectedOpt.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ selectedOpt.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ selectedOpt.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</template>
<div v-if="!isEditColumn && isForm && parseProp(column.meta)?.isList" class="w-full max-w-full">
<a-checkbox-group v-model:value="vModel" class="nc-field-layout-list">
<a-checkbox
v-for="op of options"
:key="op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
>
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-checkbox>
</a-checkbox-group>
</div>
<a-select
v-else
ref="aselect"
v-model:value="vModel"
mode="multiple"
class="w-full overflow-hidden"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:bordered="false"
clear-icon
:show-search="!isMobileMode"
:show-arrow="editAllowed && !readOnly"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-multi-select-cell !min-w-200px ${isOpen ? 'active' : ''}`"
@search="search"
@keydown="onKeyDown"
@focus="onFocus"
@blur="isOpen = false"
>
<template #suffixIcon>
<GeneralIcon icon="arrowDown" class="text-gray-700 nc-select-expand-btn" />
</template>
<a-select-option
v-for="op of options"
:key="op.id || op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
@click.stop
<template v-else>
<div
v-if="!active"
class="flex flex-wrap"
:style="{
'display': '-webkit-box',
'max-width': '100%',
'-webkit-line-clamp': rowHeight || 1,
'-webkit-box-orient': 'vertical',
'overflow': 'hidden',
}"
>
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
<a-select-option
v-if="searchVal && isOptionMissing && !isPublic && !disableOptionCreation && isUIAllowed('fieldEdit')"
:key="searchVal"
:value="searchVal"
<template v-for="selectedOpt of selectedOpts" :key="selectedOpt.value">
<a-tag class="rounded-tag max-w-full" :color="selectedOpt.color">
<span
:style="{
'color': tinycolor.isReadable(selectedOpt.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(selectedOpt.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ selectedOpt.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ selectedOpt.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</template>
</div>
<a-select
v-else
ref="aselect"
v-model:value="vModel"
mode="multiple"
class="w-full overflow-hidden"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
:bordered="false"
clear-icon
:show-search="!isMobileMode"
:show-arrow="editAllowed && !readOnly"
:open="isOpen && editAllowed"
:disabled="readOnly || !editAllowed"
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-multi-select-cell !min-w-200px ${isOpen ? 'active' : ''}`"
@search="search"
@keydown="onKeyDown"
@focus="onFocus"
@blur="isOpen = false"
>
<div class="flex gap-2 text-gray-500 items-center h-full">
<component :is="iconMap.plusThick" class="min-w-4" />
<div class="text-xs whitespace-normal">
{{ $t('msg.selectOption.createNewOptionNamed') }} <strong>{{ searchVal }}</strong>
</div>
</div>
</a-select-option>
<template #tagRender="{ value: val, onClose }">
<a-tag
v-if="options.find((el) => el.title === val)"
class="rounded-tag nc-selected-option"
:style="{ display: 'flex', alignItems: 'center' }"
:color="options.find((el) => el.title === val)?.color"
:closable="editAllowed && (vModel.length > 1 || !column?.rqd)"
:close-icon="h(MdiCloseCircle, { class: ['ms-close-icon'] })"
@click="onTagClick($event, onClose)"
@close="onClose"
<template #suffixIcon>
<GeneralIcon icon="arrowDown" class="text-gray-700 nc-select-expand-btn" />
</template>
<a-select-option
v-for="op of options"
:key="op.id || op.title"
:value="op.title"
:data-testid="`select-option-${column.title}-${location === 'filter' ? 'filter' : rowIndex}`"
:class="`nc-select-option-${column.title}-${op.title}`"
@click.stop
>
<span
:style="{
'color': tinycolor.isReadable(options.find((el) => el.title === val)?.color || '#ccc', '#fff', {
level: 'AA',
size: 'large',
})
? '#fff'
: tinycolor
.mostReadable(options.find((el) => el.title === val)?.color || '#ccc', ['#0b1d05', '#fff'])
.toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
<a-tag class="rounded-tag max-w-full" :color="op.color">
<span
:style="{
'color': tinycolor.isReadable(op.color || '#ccc', '#fff', { level: 'AA', size: 'large' })
? '#fff'
: tinycolor.mostReadable(op.color || '#ccc', ['#0b1d05', '#fff']).toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
<NcTooltip class="truncate max-w-full" show-on-truncate-only>
<template #title>
{{ op.title }}
</template>
<span
class="text-ellipsis overflow-hidden"
:style="{
wordBreak: 'keep-all',
whiteSpace: 'nowrap',
display: 'inline',
}"
>
{{ op.title }}
</span>
</NcTooltip>
</span>
</a-tag>
</a-select-option>
<a-select-option
v-if="searchVal && isOptionMissing && !isPublic && !disableOptionCreation && isUIAllowed('fieldEdit')"
:key="searchVal"
:value="searchVal"
>
<div class="flex gap-2 text-gray-500 items-center h-full">
<component :is="iconMap.plusThick" class="min-w-4" />
<div class="text-xs whitespace-normal">
{{ $t('msg.selectOption.createNewOptionNamed') }} <strong>{{ searchVal }}</strong>
</div>
</div>
</a-select-option>
<template #tagRender="{ value: val, onClose }">
<a-tag
v-if="options.find((el) => el.title === val)"
class="rounded-tag nc-selected-option"
:style="{ display: 'flex', alignItems: 'center' }"
:color="options.find((el) => el.title === val)?.color"
:closable="editAllowed && (vModel.length > 1 || !column?.rqd)"
:close-icon="h(MdiCloseCircle, { class: ['ms-close-icon'] })"
@click="onTagClick($event, onClose)"
@close="onClose"
>
{{ val }}
</span>
</a-tag>
</template>
</a-select>
<span
:style="{
'color': tinycolor.isReadable(options.find((el) => el.title === val)?.color || '#ccc', '#fff', {
level: 'AA',
size: 'large',
})
? '#fff'
: tinycolor
.mostReadable(options.find((el) => el.title === val)?.color || '#ccc', ['#0b1d05', '#fff'])
.toHex8String(),
'font-size': '13px',
}"
:class="{ 'text-sm': isKanban }"
>
{{ val }}
</span>
</a-tag>
</template>
</a-select>
</template>
</div>
</template>
@ -570,6 +610,31 @@ const onFocus = () => {
:deep(.ant-select-selection-search-input) {
@apply !text-xs;
}
.nc-field-layout-list {
@apply !flex !flex-col !items-start w-full !space-y-0.5 !max-w-full;
:deep(.ant-checkbox-wrapper) {
@apply !m-0 !h-9 !mr-0 !flex !items-center w-full !max-w-full pl-2 rounded-lg hover:bg-gray-100;
&:hover {
.ant-checkbox-checked:after {
@apply !rounded;
}
}
.ant-checkbox {
@apply !top-0;
& + span {
@apply !flex !pl-4 max-w-[calc(100%_-_16px)];
}
.ant-checkbox-checked:after,
.ant-checkbox-inner {
@apply !rounded;
}
}
}
}
</style>
<style lang="scss">

2
packages/nc-gui/components/cell/SingleSelect.vue

@ -276,7 +276,7 @@ const onFocus = () => {
@click="toggleMenu"
@keydown.enter.stop.prevent="toggleMenu"
>
<div v-if="!isEditColumn && isForm && parseProp(column.meta)?.isList" class="max-w-full">
<div v-if="!isEditColumn && isForm && parseProp(column.meta)?.isList" class="w-full max-w-full">
<a-radio-group v-model:value="vModel" class="nc-field-layout-list">
<a-radio
v-for="op of options"

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

@ -1502,7 +1502,7 @@ useEventListener(
@apply !bg-white rounded-lg border-solid border-1 border-gray-200 focus-within:border-brand-500;
}
&.layout-list {
@apply h-auto !pl-0;
@apply h-auto !pl-0 !py-1;
}
&.nc-cell-rating,
&.nc-cell-geodata {

Loading…
Cancel
Save