mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-03-15 04:54:50 +00:00
Resolve "Edit row when clicking on the card in the gallery view"
This commit is contained in:
parent
ff8a0e3060
commit
3581250cb0
6 changed files with 136 additions and 11 deletions
web-frontend/modules
core/assets/scss/components/views
database
components
store/view
utils
|
@ -34,4 +34,14 @@
|
|||
|
||||
.gallery-view__card {
|
||||
@include absolute(0, auto, auto, 0);
|
||||
|
||||
& * {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&:not(.card--loading):hover {
|
||||
cursor: pointer;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.32);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
<template>
|
||||
<div class="card" :class="{ 'card--loading': loading }" v-on="$listeners">
|
||||
<div
|
||||
class="card"
|
||||
:class="{ 'card--loading': loading }"
|
||||
@click="$emit('click', $event)"
|
||||
@mousedown="$emit('mousedown', $event)"
|
||||
@mousemove="$emit('mousemove', $event)"
|
||||
>
|
||||
<div v-for="field in fields" :key="field.id" class="card__field">
|
||||
<div class="card__field-name">{{ field.name }}</div>
|
||||
<div class="card__field-value">
|
||||
|
|
|
@ -112,7 +112,7 @@ export default {
|
|||
* switch to that version to maintain reactivity between the two.
|
||||
*/
|
||||
rows(value) {
|
||||
const row = value.find((r) => r.id === this.rowId)
|
||||
const row = value.find((r) => r !== null && r.id === this.rowId)
|
||||
if (row === undefined && this.rowExists) {
|
||||
this.$store.dispatch('rowModal/doesNotExist')
|
||||
} else if (row !== undefined && !this.rowExists) {
|
||||
|
@ -122,7 +122,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
show(rowId, ...args) {
|
||||
const row = this.rows.find((r) => r.id === rowId)
|
||||
const row = this.rows.find((r) => r !== null && r.id === rowId)
|
||||
this.$store.dispatch('rowModal/open', {
|
||||
id: rowId,
|
||||
row: row || {},
|
||||
|
|
|
@ -16,20 +16,20 @@
|
|||
>
|
||||
<RowCard
|
||||
v-for="slot in buffer"
|
||||
v-show="slot.position !== undefined"
|
||||
v-show="slot.item !== undefined"
|
||||
:key="'card-' + slot.id"
|
||||
:fields="cardFields"
|
||||
:row="slot.item === null || slot.item === undefined ? {} : slot.item"
|
||||
:row="slot.item || {}"
|
||||
:loading="slot.item === null"
|
||||
class="gallery-view__card"
|
||||
:style="{
|
||||
width: cardWidth + 'px',
|
||||
height: slot.item === null ? cardHeight + 'px' : undefined,
|
||||
transform:
|
||||
slot.position !== undefined
|
||||
? `translateX(${slot.position.left}px) translateY(${slot.position.top}px)`
|
||||
: false,
|
||||
transform: `translateX(${slot.position.left || 0}px) translateY(${
|
||||
slot.position.top || 0
|
||||
}px)`,
|
||||
}"
|
||||
@click="slot.item && $refs.rowEditModal.show(slot.item.id)"
|
||||
></RowCard>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -43,6 +43,17 @@
|
|||
@field-updated="$emit('refresh', $event)"
|
||||
@field-deleted="$emit('refresh')"
|
||||
></RowCreateModal>
|
||||
<RowEditModal
|
||||
ref="rowEditModal"
|
||||
:table="table"
|
||||
:fields="fields"
|
||||
:primary="primary"
|
||||
:rows="allRows"
|
||||
:read-only="false"
|
||||
@update="updateValue"
|
||||
@field-updated="$emit('refresh', $event)"
|
||||
@field-deleted="$emit('refresh')"
|
||||
></RowEditModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -59,10 +70,12 @@ import {
|
|||
import { maxPossibleOrderValue } from '@baserow/modules/database/viewTypes'
|
||||
import RowCard from '@baserow/modules/database/components/card/RowCard'
|
||||
import RowCreateModal from '@baserow/modules/database/components/row/RowCreateModal'
|
||||
import RowEditModal from '@baserow/modules/database/components/row/RowEditModal'
|
||||
import { notifyIf } from '@baserow/modules/core/utils/error'
|
||||
|
||||
export default {
|
||||
name: 'GalleryView',
|
||||
components: { RowCard, RowCreateModal },
|
||||
components: { RowCard, RowCreateModal, RowEditModal },
|
||||
props: {
|
||||
primary: {
|
||||
type: Object,
|
||||
|
@ -327,6 +340,25 @@ export default {
|
|||
callback(error)
|
||||
}
|
||||
},
|
||||
async updateValue({ field, row, value, oldValue }) {
|
||||
try {
|
||||
await this.$store.dispatch(
|
||||
this.storePrefix + 'view/gallery/updateRowValue',
|
||||
{
|
||||
table: this.table,
|
||||
view: this.view,
|
||||
fields: this.fields,
|
||||
primary: this.primary,
|
||||
row,
|
||||
field,
|
||||
value,
|
||||
oldValue,
|
||||
}
|
||||
)
|
||||
} catch (error) {
|
||||
notifyIf(error, 'field')
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -169,6 +169,14 @@ export default ({ service, populateRow }) => {
|
|||
MOVE_ROW(state, { oldIndex, newIndex }) {
|
||||
state.rows.splice(newIndex, 0, state.rows.splice(oldIndex, 1)[0])
|
||||
},
|
||||
UPDATE_ROW(state, { row, values }) {
|
||||
const index = state.rows.findIndex(
|
||||
(item) => item !== null && item.id === row.id
|
||||
)
|
||||
if (index !== -1) {
|
||||
Object.assign(state.rows[index], values)
|
||||
}
|
||||
},
|
||||
UPDATE_ROW_AT_INDEX(state, { index, values }) {
|
||||
Object.assign(state.rows[index], values)
|
||||
},
|
||||
|
@ -570,6 +578,71 @@ export default ({ service, populateRow }) => {
|
|||
|
||||
commit('INSERT_ROW_AT_INDEX', { index, row })
|
||||
},
|
||||
/**
|
||||
* Updates the value of a row and make the updates to the store accordingly.
|
||||
*/
|
||||
async updateRowValue(
|
||||
{ commit, dispatch },
|
||||
{ table, view, row, field, fields, primary, value, oldValue }
|
||||
) {
|
||||
const fieldType = this.$registry.get('field', field._.type.type)
|
||||
const allFields = [primary].concat(fields)
|
||||
const newValues = {}
|
||||
const newValuesForUpdate = {}
|
||||
const oldValues = {}
|
||||
const fieldName = `field_${field.id}`
|
||||
newValues[fieldName] = value
|
||||
newValuesForUpdate[fieldName] = fieldType.prepareValueForUpdate(
|
||||
field,
|
||||
value
|
||||
)
|
||||
oldValues[fieldName] = oldValue
|
||||
|
||||
allFields.forEach((fieldToCall) => {
|
||||
const fieldType = this.$registry.get('field', fieldToCall._.type.type)
|
||||
const fieldToCallName = `field_${fieldToCall.id}`
|
||||
const currentFieldValue = row[fieldToCallName]
|
||||
const optimisticFieldValue = fieldType.onRowChange(
|
||||
row,
|
||||
field,
|
||||
value,
|
||||
oldValue,
|
||||
fieldToCall,
|
||||
currentFieldValue
|
||||
)
|
||||
|
||||
if (currentFieldValue !== optimisticFieldValue) {
|
||||
newValues[fieldToCallName] = optimisticFieldValue
|
||||
oldValues[fieldToCallName] = currentFieldValue
|
||||
}
|
||||
})
|
||||
|
||||
await dispatch('afterExistingRowUpdated', {
|
||||
view,
|
||||
fields,
|
||||
primary,
|
||||
row,
|
||||
values: newValues,
|
||||
})
|
||||
|
||||
try {
|
||||
const { data } = await RowService(this.$client).update(
|
||||
table.id,
|
||||
row.id,
|
||||
newValuesForUpdate
|
||||
)
|
||||
commit('UPDATE_ROW', { row, values: data })
|
||||
} catch (error) {
|
||||
dispatch('updatedExistingRow', {
|
||||
view,
|
||||
fields,
|
||||
primary,
|
||||
row,
|
||||
values: oldValues,
|
||||
})
|
||||
throw error
|
||||
}
|
||||
},
|
||||
/**
|
||||
* When an existing row is updated, the state in the store must also be updated.
|
||||
* Because we always receive the old and new state we can calculate if the row
|
||||
|
|
|
@ -103,7 +103,11 @@ export const recycleSlots = (slots, items, getPosition, min = items.length) => {
|
|||
}
|
||||
|
||||
const slotPosition = getPosition(item, position)
|
||||
Object.assign(slots[index].position, slotPosition)
|
||||
if (
|
||||
JSON.stringify(slotPosition) !== JSON.stringify(slots[index].position)
|
||||
) {
|
||||
slots[index].position = slotPosition
|
||||
}
|
||||
})
|
||||
|
||||
// The remaining empty slots must be cleared because they could contain old items.
|
||||
|
|
Loading…
Reference in a new issue