diff --git a/packages/nc-gui/assets/img/placeholder/no-search-result-found.png b/packages/nc-gui/assets/img/placeholder/no-search-result-found.png new file mode 100644 index 0000000000..26d270c3cf Binary files /dev/null and b/packages/nc-gui/assets/img/placeholder/no-search-result-found.png differ diff --git a/packages/nc-gui/assets/style.scss b/packages/nc-gui/assets/style.scss index 0687d9ea7a..718be11a0b 100644 --- a/packages/nc-gui/assets/style.scss +++ b/packages/nc-gui/assets/style.scss @@ -37,7 +37,7 @@ body { } .rc-virtual-list-holder-inner { - @apply !px-1.5 + @apply !px-1.5; } .ant-layout-header { height: var(--topbar-height) !important; @@ -51,13 +51,17 @@ main { @apply m-0 h-full w-full bg-white; } - .nc-input-md { @apply !rounded-lg !py-2 !px-3 mb-1; } .mobile { - .nc-scrollbar-md, .nc-scrollbar-lg, .nc-scrollbar-x-md, .nc-scrollbar-dark-md, .nc-scrollbar-x-md-dark, .nc-scrollbar-x-lg { + .nc-scrollbar-md, + .nc-scrollbar-lg, + .nc-scrollbar-x-md, + .nc-scrollbar-dark-md, + .nc-scrollbar-x-md-dark, + .nc-scrollbar-x-lg { &::-webkit-scrollbar { width: 0px; } @@ -116,7 +120,6 @@ main { overflow-x: auto !important; scrollbar-width: thin !important; - &::-webkit-scrollbar { width: 4px; height: 4px; @@ -131,7 +134,6 @@ main { -webkit-border-radius: 10px; border-radius: 10px; - width: 4px; @apply bg-gray-200; } @@ -145,7 +147,6 @@ main { overflow-x: hidden; scrollbar-width: thin !important; - &::-webkit-scrollbar { width: 4px; height: 4px; @@ -177,7 +178,6 @@ main { overflow-x: auto !important; scrollbar-width: thin !important; - &::-webkit-scrollbar { width: 4px; height: 4px; @@ -192,14 +192,11 @@ main { -webkit-border-radius: 10px; border-radius: 10px; - width: 4px; - background-color: rgba(0, 0, 0, 0.3) - + background-color: rgba(0, 0, 0, 0.3); } &::-webkit-scrollbar-thumb:hover { - background-color: rgba(0, 0, 0, 0.4) - + background-color: rgba(0, 0, 0, 0.4); } } @@ -220,7 +217,6 @@ main { -webkit-border-radius: 10px; border-radius: 10px; - width: 8px; @apply bg-gray-200; } @@ -255,11 +251,11 @@ a { .rc-virtual-list-scrollbar { @apply !w-1; } - - .rc-virtual-list-scrollbar-thumb{ + + .rc-virtual-list-scrollbar-thumb { @apply !bg-gray-200; - &:hover{ + &:hover { @apply !bg-gray-300; } } @@ -465,9 +461,9 @@ a { .ant-dropdown-menu-submenu { @apply !py-0; - - &.ant-dropdown-menu-submenu-popup{ - @apply border-1 border-gray-200 + + &.ant-dropdown-menu-submenu-popup { + @apply border-1 border-gray-200; } .ant-dropdown-menu, .ant-menu { @@ -545,11 +541,11 @@ a { @apply bg-gray-300 bg-opacity-20; } -.ant-select-item-option:hover{ +.ant-select-item-option:hover { @apply !bg-gray-100; } -.ant-select-item-option-selected{ +.ant-select-item-option-selected { @apply !bg-white; } /* Hide the element with id nc-selected-item-icon */ @@ -658,7 +654,7 @@ a { } .nc-toolbar-dropdown { - @apply !rounded-2xl; + @apply !rounded-lg; } input[type='number'] { @@ -712,7 +708,8 @@ input[type='number'] { .nc-emoji { @apply xs:(text-lg); } - .material-symbols, .nc-icon { + .material-symbols, + .nc-icon { @apply !xs:(text-xl -mt-0.25); } @@ -729,7 +726,6 @@ input[type='number'] { @apply opacity-0 group-hover:(opacity-100) text-gray-600 hover:(bg-gray-400 bg-opacity-20 text-gray-900) duration-100; } - .nc-button.ant-btn.nc-sidebar-node-btn.nc-sidebar-expand { @apply xs:(opacity-100 hover:bg-gray-50); @@ -740,18 +736,18 @@ input[type='number'] { .ant-message-notice-content { @apply !rounded-md; - .ant-message-custom-content{ + .ant-message-custom-content { @apply flex items-center; } } -svg.nc-cell-icon, svg.nc-virtual-cell-icon { +svg.nc-cell-icon, +svg.nc-virtual-cell-icon { @apply w-1em h-1em flex-none; font-size: 1rem; } - -// For select type field list layout +// For select type field list layout .nc-field-layout-list { @apply !flex !flex-col !items-start w-full !space-y-0.5 !max-w-full; @@ -786,3 +782,21 @@ svg.nc-cell-icon, svg.nc-virtual-cell-icon { } } +.nc-toolbar-dropdown-search-field-input { + @apply !rounded-lg; + + .nc-search-icon { + @apply text-gray-400; + } + + &:hover .nc-search-icon, + &.ant-input-affix-wrapper-focused .nc-search-icon { + @apply text-gray-800; + } +} + +// switch - on tab focus show outline +.ant-switch:focus-visible, +.ant-switch-checked:focus-visible { + box-shadow: 0 0 0 2px #fff, 0 0 0 4px #3366ff; +} diff --git a/packages/nc-gui/components/nc/Select.vue b/packages/nc-gui/components/nc/Select.vue index 1335ddd4d5..bd109bdcf2 100644 --- a/packages/nc-gui/components/nc/Select.vue +++ b/packages/nc-gui/components/nc/Select.vue @@ -106,7 +106,7 @@ const onChange = (value: string) => { } .nc-select-dropdown { - @apply !rounded-xl py-1.5; + @apply !rounded-lg py-1.5; .rc-virtual-list-holder { overflow-y: auto; @@ -129,7 +129,7 @@ const onChange = (value: string) => { } &::-webkit-scrollbar-thumb { width: 4px; - @apply bg-gray-300; + @apply bg-gray-300 rounded-md; } &::-webkit-scrollbar-thumb:hover { @apply bg-gray-400; diff --git a/packages/nc-gui/components/nc/Switch.vue b/packages/nc-gui/components/nc/Switch.vue index f5e9c6076b..2de69aa5ff 100644 --- a/packages/nc-gui/components/nc/Switch.vue +++ b/packages/nc-gui/components/nc/Switch.vue @@ -1,5 +1,5 @@ - - - - - - {{ $t('general.empty') }} - - - - {{ option.title }} - - {{ option.title }} - - - - + + diff --git a/packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue b/packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue index e8111f44cb..9cb46111cd 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue @@ -11,12 +11,6 @@ const emits = defineEmits(['created']) const { isParentOpen } = toRefs(props) -const inputRef = ref() - -const search = ref('') - -const activeFieldIndex = ref(-1) - const activeView = inject(ActiveViewInj, ref()) const meta = inject(MetaInj, ref()) @@ -55,72 +49,22 @@ const options = computed( /** ignore virtual fields which are system fields ( mm relation ) and qr code fields */ } }) - .filter((c: ColumnType) => !sorts.value.find((s) => s.fk_column_id === c.id)) - .filter((c: ColumnType) => c.title?.toLowerCase().includes(search.value.toLowerCase())) ?? [], + .filter((c: ColumnType) => !sorts.value.find((s) => s.fk_column_id === c.id)) ?? [], ) const onClick = (column: ColumnType) => { emits('created', column) } - -watch( - isParentOpen, - () => { - if (!isParentOpen.value) return - - setTimeout(() => { - inputRef.value?.focus() - }, 100) - }, - { - immediate: true, - }, -) - -onMounted(() => { - search.value = '' - activeFieldIndex.value = -1 -}) - -const onArrowDown = () => { - activeFieldIndex.value = Math.min(activeFieldIndex.value + 1, options.value.length - 1) -} - -const onArrowUp = () => { - activeFieldIndex.value = Math.max(activeFieldIndex.value - 1, 0) -} - - - - - - {{ $t('general.empty') }} - - - - {{ option.title }} - - {{ option.title }} - - - - + + diff --git a/packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue b/packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue index 48afcc01f1..afc2a95c17 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue @@ -94,8 +94,8 @@ if (!localValue.value && allowEmpty !== true) { > - - + + +import type { ColumnType } from 'nocodb-sdk' + +const props = defineProps<{ + // As we need to focus search box when the parent is opened + isParentOpen: boolean + toolbarMenu: 'groupBy' | 'sort' | 'globalSearch' + searchInputPlaceholder?: string + selectedOptionId?: string + options: ColumnType[] + showSelectedOption?: boolean +}>() + +const emits = defineEmits<{ selected: [ColumnType] }>() + +const { isParentOpen, toolbarMenu, searchInputPlaceholder, selectedOptionId, options, showSelectedOption } = toRefs(props) + +const searchQuery = ref('') + +const filteredOptions = computed( + () => options.value?.filter((c: ColumnType) => c.title?.toLowerCase().includes(searchQuery.value.toLowerCase())) ?? [], +) + +const inputRef = ref() + +const activeFieldIndex = ref(-1) + +const configByToolbarMenu = computed(() => { + switch (toolbarMenu.value) { + case 'groupBy': + return { + selectOptionEvent: ['c:group-by:add:column:select'], + optionClassName: 'nc-group-by-column-search-item', + } + case 'sort': + return { + selectOptionEvent: ['c:sort:add:column:select'], + optionClassName: 'nc-sort-column-search-item', + } + case 'globalSearch': + return { + selectOptionEvent: ['c:search:field:select'], + optionClassName: '', + } + default: + return { + selectOptionEvent: undefined, + optionClassName: '', + } + } +}) + +const onClick = (column: ColumnType) => { + if (!column) return + + emits('selected', column) +} + +const handleAutoScrollOption = () => { + const option = document.querySelector('.nc-field-list-option-active') + + if (option) { + setTimeout(() => { + option?.scrollIntoView({ behavior: 'smooth', block: 'center' }) + }, 50) + } +} + +const onArrowDown = () => { + activeFieldIndex.value = Math.min(activeFieldIndex.value + 1, filteredOptions.value.length - 1) + handleAutoScrollOption() +} + +const onArrowUp = () => { + activeFieldIndex.value = Math.max(activeFieldIndex.value - 1, 0) + handleAutoScrollOption() +} + +const handleKeydownEnter = () => { + if (filteredOptions.value[activeFieldIndex.value]) { + onClick(filteredOptions.value[activeFieldIndex.value]) + } else if (filteredOptions.value[0]) { + onClick(filteredOptions.value[activeFieldIndex.value]) + } +} + +onMounted(() => { + searchQuery.value = '' + activeFieldIndex.value = -1 +}) + +watch( + isParentOpen, + () => { + if (!isParentOpen.value) return + + searchQuery.value = '' + setTimeout(() => { + inputRef.value?.focus() + }, 100) + }, + { + immediate: true, + }, +) + + + + + + + + + + + + + + {{ options.length ? $t('title.noResultsMatchedYourSearch') : 'The list is empty' }} + + + + + + + {{ option.title }} + + {{ option.title }} + + + + + + + + + + + diff --git a/packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue b/packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue index 6e85fe1ed0..3417ca3b48 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue @@ -300,6 +300,19 @@ const showSystemField = computed({ }, }) +const isDragging = ref(false) + +const fieldsMenuSearchRef = ref() + +watch(open, (value) => { + if (!value) return + + filterQuery.value = '' + setTimeout(() => { + fieldsMenuSearchRef.value?.focus() + }, 100) +}) + useMenuCloseOnEsc(open) @@ -337,42 +350,60 @@ useMenuCloseOnEsc(open) - + Select cover image field - - - + + - - - - - + - {{ $t('title.noFieldsFound') }} + + + {{ $t('title.noResultsMatchedYourSearch') }} - + { field.show = !field.show @@ -396,8 +427,8 @@ useMenuCloseOnEsc(open) } " > - - + + {{ field.title }} @@ -438,54 +469,32 @@ useMenuCloseOnEsc(open) - + - - - - - {{ filteredFieldList[0].title }} - {{ filteredFieldList[0].title }} - - - - - - - - {{ showAllColumns ? $t('title.hideAll') : $t('general.showAll') }} {{ $t('objects.fields').toLowerCase() }} + + + {{ showAllColumns ? 'Hide all' : 'Show all' }} fields - {{ showSystemField ? $t('title.hideSystemFields') : $t('activity.showSystemFields') }} + {{ showSystemField ? 'Hide system fields' : 'Show system fields' }} @@ -494,15 +503,16 @@ useMenuCloseOnEsc(open) diff --git a/packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue b/packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue index e704057798..3ebee777f8 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue @@ -251,19 +251,14 @@ watch(meta, async () => { /> - + { :key="j" :value="option.value" > - + {{ option.text }} { - + { > { diff --git a/packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue b/packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue index 7f60d6c14c..dca7f557ac 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue @@ -94,7 +94,7 @@ useMenuCloseOnEsc(open) diff --git a/packages/nc-gui/components/smartsheet/toolbar/SearchData.vue b/packages/nc-gui/components/smartsheet/toolbar/SearchData.vue index 657ab38b92..dccfe83b9a 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/SearchData.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/SearchData.vue @@ -1,13 +1,12 @@ - - - - {{ displayColumnLabel }} - - - - - - - - - - {{ op.label }} - {{ op.label }} - - - - - - + + + {{ displayColumnLabel }} + + + + + + + + + { :bordered="false" data-testid="search-data-input" @press-enter="onPressEnter" - @focus="isFocused = true" - @blur="isFocused = false" > diff --git a/packages/nc-gui/components/smartsheet/toolbar/SortListMenu.vue b/packages/nc-gui/components/smartsheet/toolbar/SortListMenu.vue index 27d43d10e2..baf0e0b180 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/SortListMenu.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/SortListMenu.vue @@ -139,13 +139,8 @@ onMounted(() => { - - + + { v-model:value="sort.direction" class="shrink grow-0 nc-sort-dir-select" :label="$t('labels.operation')" - dropdown-class-name="sort-dir-dropdown nc-dropdown-sort-dir" + dropdown-class-name="sort-dir-dropdown nc-dropdown-sort-dir !rounded-lg" @click.stop @select="saveOrUpdate(sort, i)" > @@ -170,7 +165,7 @@ onMounted(() => { v-e="['c:sort:operation:select']" :value="option.value" > - + {{ option.text }} { v-if="availableColumns.length" v-model:visible="showCreateSort" :trigger="['click']" - class="mt-3" overlay-class-name="nc-toolbar-dropdown" > { - + diff --git a/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue b/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue index dbba7ac319..262310b531 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/ViewActionMenu.vue @@ -153,7 +153,10 @@ const onDelete = async () => { > {{ $t('labels.clickToCopyViewID') }} - + {{ $t('labels.viewIdColon', { diff --git a/packages/nc-gui/composables/useViewColumns.ts b/packages/nc-gui/composables/useViewColumns.ts index fe1dc9cda7..6664b1fe28 100644 --- a/packages/nc-gui/composables/useViewColumns.ts +++ b/packages/nc-gui/composables/useViewColumns.ts @@ -220,7 +220,12 @@ const [useProvideViewColumns, useViewColumns] = useInjectionState( const filteredFieldList = computed(() => { return ( fields.value?.filter((field: Field) => { - if (metaColumnById?.value?.[field.fk_column_id!]?.pv) return true + if ( + metaColumnById?.value?.[field.fk_column_id!]?.pv && + (!filterQuery.value || field.title.toLowerCase().includes(filterQuery.value.toLowerCase())) + ) { + return true + } // hide system columns if not enabled if (!showSystemFields.value && isSystemColumn(metaColumnById?.value?.[field.fk_column_id!])) { diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index f91f51549f..3c185cee08 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -433,7 +433,8 @@ }, "selectFieldsFromRightPannelToAddHere": "Select fields from right panel to add here", "noOptionsFound": "No options found", - "surveyFormSubmitConfirmMsg": "Are you sure you want to submit this form?" + "surveyFormSubmitConfirmMsg": "Are you sure you want to submit this form?", + "noResultsMatchedYourSearch": "Your search did not yield any matching results." }, "labels": { "selectYear": "Select Year", diff --git a/packages/nc-gui/windi.config.ts b/packages/nc-gui/windi.config.ts index f4aa6f022b..a67886ec28 100644 --- a/packages/nc-gui/windi.config.ts +++ b/packages/nc-gui/windi.config.ts @@ -46,6 +46,8 @@ export default defineConfig({ 'color-transition': 'transition-colors duration-100 ease-in', 'scrollbar-thin-primary': 'scrollbar scrollbar-thin scrollbar-thumb-rounded scrollbar-thumb-primary scrollbar-track-white', 'scrollbar-thin-dull': 'scrollbar scrollbar-thin scrollbar-thumb-rounded-md scrollbar-thumb-gray-100 scrollbar-track-white', + 'nc-scrollbar-thin': + 'scrollbar scrollbar-thin scrollbar-thumb-gray-200 hover:scrollbar-thumb-gray-300 scrollbar-track-transparent', }, theme: { diff --git a/tests/playwright/pages/Dashboard/common/Toolbar/Groupby.ts b/tests/playwright/pages/Dashboard/common/Toolbar/Groupby.ts index 10d48b34be..e6e7f73e55 100644 --- a/tests/playwright/pages/Dashboard/common/Toolbar/Groupby.ts +++ b/tests/playwright/pages/Dashboard/common/Toolbar/Groupby.ts @@ -93,14 +93,14 @@ export class ToolbarGroupByPage extends BasePage { await this.rootPage .locator('.nc-group-by-create-modal') - .locator('.nc-group-by-column-search-item >> div', { hasText: regexTitle }) + .locator('.nc-group-by-column-search-item', { hasText: regexTitle }) .scrollIntoViewIfNeeded(); // select column const selectColumn = async () => await this.rootPage .locator('.nc-group-by-create-modal') - .locator('.nc-group-by-column-search-item >> div', { hasText: regexTitle }) + .locator('.nc-group-by-column-search-item', { hasText: regexTitle }) .click({ force: true }); await this.waitForResponse({