1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-17 18:32:35 +00:00

Resolve "Type-to-complete / enter-to-select value in Link to table fields"

This commit is contained in:
Bram Wiepjes 2024-07-17 18:24:35 +00:00
parent f931be08a1
commit c0b5feeee2
4 changed files with 117 additions and 76 deletions
changelog/entries/unreleased/feature
web-frontend/modules
core/assets/scss/components
database/components

View file

@ -0,0 +1,7 @@
{
"type": "feature",
"message": "Allow typing immediately in the grid for link row cell to search for a relationship.",
"issue_number": 193,
"bullet_points": [],
"created_at": "2024-07-16"
}

View file

@ -35,28 +35,6 @@
}
}
.select-row-modal__loading {
position: relative;
&::before {
content: '';
z-index: 4;
background-color: rgba(0, 0, 0, 0.2);
@include absolute(0, 0, 0, 0);
@include rounded($rounded-md);
}
&::after {
content: '';
z-index: 5;
margin: -7px auto auto -7px;
@include loading(14px);
@include absolute(50%, auto, auto, 50%);
}
}
.select-row-modal__search {
position: relative;
z-index: 1;
@ -89,3 +67,24 @@
border-bottom-right-radius: 6px;
overflow: hidden;
}
.select-row-modal__rows--loading {
position: relative;
&::before {
content: '';
z-index: 4;
background-color: rgba(0, 0, 0, 0.2);
@include absolute(0, 0, 0, 0);
}
&::after {
content: '';
z-index: 5;
margin: -7px auto auto -7px;
@include loading(14px);
@include absolute(50%, auto, auto, 50%);
}
}

View file

@ -1,42 +1,45 @@
<template>
<div>
<div v-if="!loaded" class="select-row-modal__initial-loading"></div>
<div v-if="loaded" :class="{ 'select-row-modal__loading': loading }">
<div class="select-row-modal__search">
<i class="iconoir-search select-row-modal__search-icon"></i>
<input
ref="search"
v-model="visibleSearch"
type="text"
:placeholder="$t('selectRowContent.search')"
class="select-row-modal__search-input"
@input="doSearch(visibleSearch, false)"
@keypress.enter="doSearch(visibleSearch, true)"
/>
</div>
<div class="select-row-modal__rows">
<SimpleGrid
:fixed-fields="[primary]"
:fields="fields"
:rows="rows"
:full-height="true"
:can-add-row="true"
:with-footer="true"
:show-hovered-row="true"
:selected-rows="selectedRows"
:show-row-id="true"
@add-row="$refs.rowCreateModal.show()"
@row-click="select($event)"
>
<template #footLeft>
<Paginator
:total-pages="totalPages"
:page="page"
@change-page="fetch"
></Paginator>
</template>
</SimpleGrid>
</div>
<div class="select-row-modal__search">
<i class="iconoir-search select-row-modal__search-icon"></i>
<input
ref="search"
v-model="visibleSearch"
type="text"
:placeholder="$t('selectRowContent.search')"
class="select-row-modal__search-input"
@input="doSearch(visibleSearch, false)"
@keydown.enter="doSearch(visibleSearch, true)"
/>
</div>
<div
class="select-row-modal__rows"
:class="{
'select-row-modal__rows--loading': loading || !metaDataLoaded,
}"
>
<SimpleGrid
v-if="metaDataLoaded && firstPageLoaded"
:fixed-fields="[primary]"
:fields="fields"
:rows="rows"
:full-height="true"
:can-add-row="true"
:with-footer="true"
:show-hovered-row="true"
:selected-rows="selectedRows"
:show-row-id="true"
@add-row="$refs.rowCreateModal.show()"
@row-click="select($event)"
>
<template #footLeft>
<Paginator
:total-pages="totalPages"
:page="page"
@change-page="fetch"
></Paginator>
</template>
</SimpleGrid>
</div>
<RowCreateModal
v-if="table"
@ -91,11 +94,21 @@ export default {
required: false,
default: () => [],
},
initialSearch: {
type: String,
required: false,
default: '',
},
},
data() {
return {
// Indicates if we're loading new rows.
loading: false,
loaded: false,
// Indicates if the metadata (fields, etc) has been loaded.
metaDataLoaded: false,
// Indicates if the page has loaded for the first time. We keep track of this
// state to show a non flickering loading state for the user.
firstPageLoaded: false,
primary: null,
fields: null,
rows: [],
@ -141,28 +154,25 @@ export default {
},
},
async mounted() {
// Focus the search field so the user may begin typing immediately.
this.$nextTick(() => {
this.focusSearch({})
})
// The first time we have to fetch the fields because they are unknown for this
// table.
if (!(await this.fetchFields(this.tableId))) {
return false
}
// We want to start with some initial data when the modal opens for the first time.
if (!(await this.fetch(1))) {
return false
}
await this.orderFieldsByFirstGridViewFieldOptions(this.tableId)
// Because most of the template depends on having some initial data we mark the
// state as loaded after that. Only a loading animation is shown if there isn't any
// Because the page data depends on having some initial metadata we mark the state
// as loaded after that. Only a loading animation is shown if there isn't any
// data.
this.loaded = true
this.metaDataLoaded = true
// Focus the search field so the user may begin typing immediately.
this.$nextTick(() => {
this.focusSearch({})
})
this.doSearch(this.visibleSearch, false)
this.$priorityBus.$on(
'start-search',
@ -246,6 +256,7 @@ export default {
if (this.searchDebounce) {
this.searchDebounce.cancel()
}
this.loading = true
if (immediate) {
search()
} else {
@ -258,8 +269,6 @@ export default {
* has been stored in the state then that will be remembered.
*/
async fetch(page) {
this.loading = true
try {
const { data } = await RowService(this.$client).fetchAll({
tableId: this.tableId,
@ -274,11 +283,12 @@ export default {
this.totalPages = Math.ceil(data.count / 10)
this.rows = data.results
this.loading = false
this.firstPageLoaded = true
return true
} catch (error) {
notifyIf(error, 'row')
this.$emit('hide')
this.loading = false
this.$emit('hide')
return false
}
},

View file

@ -72,6 +72,7 @@ import SelectRowModal from '@baserow/modules/database/components/row/SelectRowMo
import ForeignRowEditModal from '@baserow/modules/database/components/row/ForeignRowEditModal'
import { notifyIf } from '@baserow/modules/core/utils/error'
import { DatabaseApplicationType } from '@baserow/modules/database/applicationTypes'
import { isPrintableUnicodeCharacterKeyPress } from '@baserow/modules/core/utils/events'
export default {
name: 'GridViewFieldLinkRow',
@ -131,7 +132,31 @@ export default {
// While the field is selected we want to open the select row toast by pressing
// the enter key.
this.$el.keydownEvent = (event) => {
if (event.key === 'Enter' && !this.modalOpen) {
// If the tab or arrow keys are pressed we don't want to do anything because
// the GridViewField component will select the next field.
const ignoredKeys = [
'Tab',
'ArrowLeft',
'ArrowUp',
'ArrowRight',
'ArrowDown',
]
if (ignoredKeys.includes(event.key)) {
return
}
// If the space bar key is pressed, we don't want to do anything because it
// should open the row edit modal.
if (event.key === ' ') {
return
}
// When the enter key, or any printable character is pressed when not editing
// the value we want to show the select row modal.
if (
!this.modalOpen &&
(event.key === 'Enter' || isPrintableUnicodeCharacterKeyPress(event))
) {
this.showModal()
}
}