1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-20 03:46:14 +00:00

Resolve "Ordering fields per grid view"

This commit is contained in:
Bram Wiepjes 2021-03-12 13:46:22 +00:00
parent 6cbe108f48
commit 9728b64df0
18 changed files with 457 additions and 11 deletions
backend
src/baserow/contrib/database
tests/baserow/contrib/database
changelog.md
web-frontend/modules

View file

@ -17,6 +17,14 @@ grid_view_field_options_schema = {
'example': True, 'example': True,
'description': 'Whether or not the field should be hidden in the ' 'description': 'Whether or not the field should be hidden in the '
'current view.' 'current view.'
},
'order': {
'type': 'integer',
'example': 0,
'description': 'The position that the field has within the view, '
'lowest first. If there is another field with the '
'same order value then the field with the lowest '
'id must be shown first.'
} }
} }
}, },

View file

@ -101,7 +101,7 @@ class GridViewSerializer(serializers.ModelSerializer):
class GridViewFieldOptionsSerializer(serializers.ModelSerializer): class GridViewFieldOptionsSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = GridViewFieldOptions model = GridViewFieldOptions
fields = ('width', 'hidden') fields = ('width', 'hidden', 'order')
class GridViewFilterSerializer(serializers.Serializer): class GridViewFilterSerializer(serializers.Serializer):

View file

@ -0,0 +1,18 @@
# Generated by Django 2.2.11 on 2021-03-09 18:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('database', '0026_auto_20210125_1454'),
]
operations = [
migrations.AddField(
model_name='gridviewfieldoptions',
name='order',
field=models.SmallIntegerField(default=32767),
),
]

View file

@ -160,7 +160,7 @@ class ViewHandler:
:param user: The user on whose behalf the request is made. :param user: The user on whose behalf the request is made.
:type user: User :type user: User
:param grid_view: The grid view for which the field options need to be updated. :param grid_view: The grid view for which the field options need to be updated.
:type grid_view: Model :type grid_view: GridView
:param field_options: A dict with the field ids as the key and a dict :param field_options: A dict with the field ids as the key and a dict
containing the values that need to be updated as value. containing the values that need to be updated as value.
:type field_options: dict :type field_options: dict

View file

@ -159,6 +159,9 @@ class GridViewFieldOptions(models.Model):
# abstraction in the web-frontend. # abstraction in the web-frontend.
width = models.PositiveIntegerField(default=200) width = models.PositiveIntegerField(default=200)
hidden = models.BooleanField(default=False) hidden = models.BooleanField(default=False)
# The default value is the maximum value of the small integer field because a newly
# created field must always be last.
order = models.SmallIntegerField(default=32767)
class Meta: class Meta:
ordering = ('field_id',) ordering = ('field_id',)

View file

@ -226,8 +226,10 @@ def test_list_rows_include_field_options(api_client, data_fixture):
assert len(response_json['field_options']) == 2 assert len(response_json['field_options']) == 2
assert response_json['field_options'][str(text_field.id)]['width'] == 200 assert response_json['field_options'][str(text_field.id)]['width'] == 200
assert response_json['field_options'][str(text_field.id)]['hidden'] is False assert response_json['field_options'][str(text_field.id)]['hidden'] is False
assert response_json['field_options'][str(text_field.id)]['order'] == 32767
assert response_json['field_options'][str(number_field.id)]['width'] == 200 assert response_json['field_options'][str(number_field.id)]['width'] == 200
assert response_json['field_options'][str(number_field.id)]['hidden'] is False assert response_json['field_options'][str(number_field.id)]['hidden'] is False
assert response_json['field_options'][str(number_field.id)]['order'] == 32767
@pytest.mark.django_db @pytest.mark.django_db
@ -385,16 +387,20 @@ def test_patch_grid_view(api_client, data_fixture):
assert len(response_json['field_options']) == 2 assert len(response_json['field_options']) == 2
assert response_json['field_options'][str(text_field.id)]['width'] == 300 assert response_json['field_options'][str(text_field.id)]['width'] == 300
assert response_json['field_options'][str(text_field.id)]['hidden'] is True assert response_json['field_options'][str(text_field.id)]['hidden'] is True
assert response_json['field_options'][str(text_field.id)]['order'] == 32767
assert response_json['field_options'][str(number_field.id)]['width'] == 200 assert response_json['field_options'][str(number_field.id)]['width'] == 200
assert response_json['field_options'][str(number_field.id)]['hidden'] is False assert response_json['field_options'][str(number_field.id)]['hidden'] is False
assert response_json['field_options'][str(number_field.id)]['order'] == 32767
options = grid.get_field_options() options = grid.get_field_options()
assert len(options) == 2 assert len(options) == 2
assert options[0].field_id == text_field.id assert options[0].field_id == text_field.id
assert options[0].width == 300 assert options[0].width == 300
assert options[0].hidden is True assert options[0].hidden is True
assert options[0].order == 32767
assert options[1].field_id == number_field.id assert options[1].field_id == number_field.id
assert options[1].width == 200 assert options[1].width == 200
assert options[1].hidden is False assert options[1].hidden is False
assert options[1].order == 32767
url = reverse('api:database:views:grid:list', kwargs={'view_id': grid.id}) url = reverse('api:database:views:grid:list', kwargs={'view_id': grid.id})
response = api_client.patch( response = api_client.patch(

View file

@ -14,8 +14,10 @@ def test_grid_view_get_field_options(data_fixture):
assert len(field_options) == 2 assert len(field_options) == 2
assert field_options[0].field_id == field_1.id assert field_options[0].field_id == field_1.id
assert field_options[0].width == 200 assert field_options[0].width == 200
assert field_options[0].order == 32767
assert field_options[1].field_id == field_2.id assert field_options[1].field_id == field_2.id
assert field_options[1].width == 200 assert field_options[1].width == 200
assert field_options[1].order == 32767
field_3 = data_fixture.create_text_field(table=table) field_3 = data_fixture.create_text_field(table=table)

View file

@ -6,6 +6,7 @@
* Refactored the GridView component and improved interface speed. * Refactored the GridView component and improved interface speed.
* Prevent websocket reconnect when the connection closes without error. * Prevent websocket reconnect when the connection closes without error.
* Added gunicorn worker test to the CI pipeline. * Added gunicorn worker test to the CI pipeline.
* Made it possible to re-order fields in a grid view.
* Show the number of filters and sorts active in the header of a grid view. * Show the number of filters and sorts active in the header of a grid view.
* The first user to sign-up after installation now gets given staff status. * The first user to sign-up after installation now gets given staff status.

View file

@ -466,3 +466,17 @@
padding-left: 10px; padding-left: 10px;
} }
} }
.grid-view__field-dragging {
@include absolute(0, auto);
z-index: 4;
background-color: rgba(0, 0, 0, 0.08);
}
.grid-view__field-target {
@include absolute(0, auto, 48px, auto);
z-index: 5;
border-left: solid 1px $color-primary-900;
}

View file

@ -53,6 +53,7 @@
:table="table" :table="table"
:view="view" :view="view"
:include-add-field="true" :include-add-field="true"
:can-order-fields="true"
:style="{ left: leftWidth + 'px' }" :style="{ left: leftWidth + 'px' }"
@refresh="$emit('refresh', $event)" @refresh="$emit('refresh', $event)"
@row-hover="setRowHover($event.row, $event.value)" @row-hover="setRowHover($event.row, $event.value)"
@ -64,6 +65,7 @@
@unselected="unselectedCell($event)" @unselected="unselectedCell($event)"
@select-next="selectNextCell($event)" @select-next="selectNextCell($event)"
@edit-modal="$refs.rowEditModal.show($event.id)" @edit-modal="$refs.rowEditModal.show($event.id)"
@scroll="scroll($event.pixelY, $event.pixelX)"
></GridViewSection> ></GridViewSection>
<Context ref="rowContext"> <Context ref="rowContext">
<ul class="context__menu"> <ul class="context__menu">

View file

@ -0,0 +1,259 @@
<template>
<div v-show="dragging">
<div
class="grid-view__field-dragging"
:style="{ width: draggingWidth + 'px', left: draggingLeft + 'px' }"
></div>
<div
class="grid-view__field-target"
:style="{ left: targetLeft + 'px' }"
></div>
</div>
</template>
<script>
import { notifyIf } from '@baserow/modules/core/utils/error'
import gridViewHelpers from '@baserow/modules/database/mixins/gridViewHelpers'
export default {
name: 'GridViewFieldDragging',
mixins: [gridViewHelpers],
props: {
view: {
type: Object,
required: true,
},
fields: {
type: Array,
required: true,
},
containerWidth: {
type: Number,
required: true,
},
},
data() {
return {
// Indicates if the user is dragging a field to another position.
dragging: false,
// The field object that is being dragged.
field: null,
// The id of the field where the dragged field must be placed after.
targetFieldId: null,
// The horizontal starting position of the mouse.
mouseStart: 0,
// The horizontal scrollbar offset starting position.
scrollStart: 0,
// The width of the dragging animation, this is equal to the width of the field.
draggingWidth: 0,
// The position of the dragging animation.
draggingLeft: 0,
// The position of the target indicator where the field is going to be moved to.
targetLeft: 0,
// The mouse move event.
lastMoveEvent: null,
// Indicates if the user is auto scrolling at the moment.
autoScrolling: false,
}
},
beforeDestroy() {
this.cancel()
},
methods: {
getFieldLeft(id) {
let left = 0
for (let i = 0; i < this.fields.length; i++) {
if (this.fields[i].id === id) {
break
}
left += this.getFieldWidth(this.fields[i].id)
}
return left
},
/**
* Called when the field dragging must start. It will register the global mouse
* move, mouse up events and keyup events so that the user can drag the field to
* the correct position.
*/
start(field, event) {
this.field = field
this.targetFieldId = field.id
this.dragging = true
this.mouseStart = event.clientX
this.scrollStart = this.$parent.$el.scrollLeft
this.draggingLeft = 0
this.targetLeft = 0
this.$el.moveEvent = (event) => this.move(event)
window.addEventListener('mousemove', this.$el.moveEvent)
this.$el.upEvent = (event) => this.up(event)
window.addEventListener('mouseup', this.$el.upEvent)
this.$el.keydownEvent = (event) => {
if (event.keyCode === 27) {
// When the user presses the escape key we want to cancel the action
this.cancel(event)
}
}
document.body.addEventListener('keydown', this.$el.keydownEvent)
this.move(event, false)
},
/**
* The move method is called when every time the user moves the mouse while
* dragging a field. It can also be called while auto scrolling.
*/
move(event = null, startAutoScroll = true) {
if (event !== null) {
event.preventDefault()
this.lastMoveEvent = event
} else {
event = this.lastMoveEvent
}
// This is the horizontally scrollable element.
const element = this.$parent.$el
this.draggingWidth = this.getFieldWidth(this.field.id)
// Calculate the left position of the dragging animation. This is the transparent
// overlay that has the same width as the field.
this.draggingLeft = Math.min(
this.getFieldLeft(this.field.id) +
event.clientX -
this.mouseStart +
this.$parent.$el.scrollLeft -
this.scrollStart,
this.containerWidth - this.draggingWidth
)
// Calculate which after which field we want to place the field that is currently
// being dragged. This is named the target. We also calculate what position the
// field would have for visualisation purposes.
const mouseLeft =
event.clientX -
element.getBoundingClientRect().left +
element.scrollLeft
let left = 0
for (let i = 0; i < this.fields.length; i++) {
const width = this.getFieldWidth(this.fields[i].id)
const nextWidth =
i + 1 < this.fields.length
? this.getFieldWidth(this.fields[i + 1].id)
: width
const leftHalf = left + Math.floor(width / 2)
const rightHalf = left + width + Math.floor(nextWidth / 2)
if (i === 0 && mouseLeft < leftHalf) {
this.targetFieldId = 0
// The value 1 makes sure it is visible instead of falling outside of the
// view port.
this.targetLeft = 1
break
}
if (mouseLeft > leftHalf && mouseLeft < rightHalf) {
this.targetFieldId = this.fields[i].id
this.targetLeft = left + width
break
}
left += width
}
// If the user is not already auto scrolling, which happens while dragging and
// moving the element outside of the view port at the left or right side, we
// might need to initiate that process.
if (!this.autoScrolling || !startAutoScroll) {
const relativeLeft = this.draggingLeft - element.scrollLeft
const relativeRight = relativeLeft + this.getFieldWidth(this.field.id)
const maxScrollLeft = element.scrollWidth - element.clientWidth
let speed = 0
if (relativeLeft < 0 && element.scrollLeft > 0) {
// If the dragging animation falls out of the left side of the viewport we
// need to auto scroll to the left.
speed = -Math.ceil(Math.min(Math.abs(relativeLeft), 100) / 20)
} else if (
relativeRight > element.clientWidth &&
element.scrollLeft < maxScrollLeft
) {
// If the dragging animation falls out of the right side of the viewport we
// need to auto scroll to the right.
speed = Math.ceil(
Math.min(relativeRight - element.clientWidth, 100) / 20
)
}
// If the speed is either a position or negative, so not 0, we know that we
// need to start auto scrolling.
if (speed !== 0) {
this.autoScrolling = true
this.$emit('scroll', { pixelY: 0, pixelX: speed })
this.$el.scrollTimeout = setTimeout(() => {
this.move(null, false)
}, 1)
} else {
this.autoScrolling = false
}
}
},
/**
* Can be called when the current dragging state needs to be stopped. It will
* remove all the created event listeners and timeouts.
*/
cancel() {
this.dragging = false
window.removeEventListener('mousemove', this.$el.moveEvent)
window.removeEventListener('mouseup', this.$el.upEvent)
document.body.addEventListener('keydown', this.$el.keydownEvent)
clearTimeout(this.$el.scrollTimeout)
},
/**
* Called when the user releases the mouse on a the desired position. It will
* calculate the new position of the field in the list and if it has changed
* position, then the order in the field options is updated accordingly.
*/
async up(event) {
event.preventDefault()
this.cancel()
// We don't need to do anything if the field needs to be placed after itself
// because that wouldn't change the position.
if (this.field.id === this.targetFieldId) {
return
}
const oldOrder = this.fields.map((field) => field.id)
// Create an array of field ids in the correct order excluding the field that
// needs to be repositioned because that one will be added later.
const newOrder = this.fields
.filter((field) => field.id !== this.field.id)
.map((field) => field.id)
if (this.targetFieldId === 0) {
// If the target field id is 0 the field needs to be moved to the beginning.
newOrder.unshift(this.field.id)
} else {
// Calculate after which field the field that needs to be repositioned needs to
// be placed.
const targetIndex = newOrder.findIndex(
(id) => id === this.targetFieldId
)
newOrder.splice(targetIndex + 1, 0, this.field.id)
}
// Check if the new order differs from the old order. If that is not the case we
// don't need to update the field options because nothing will be changed.
if (JSON.stringify(oldOrder) === JSON.stringify(newOrder)) {
return
}
try {
await this.$store.dispatch('view/grid/updateFieldOptionsOrder', {
gridId: this.view.id,
order: newOrder,
})
} catch (error) {
notifyIf(error, 'view')
}
},
},
}
</script>

View file

@ -9,6 +9,7 @@
view.sortings.findIndex((sort) => sort.field === field.id) !== -1, view.sortings.findIndex((sort) => sort.field === field.id) !== -1,
}" }"
:style="{ width: width + 'px' }" :style="{ width: width + 'px' }"
@mousedown="startDragging($event, field)"
> >
<div <div
class="grid-view__description" class="grid-view__description"
@ -22,6 +23,7 @@
ref="contextLink" ref="contextLink"
class="grid-view__description-options" class="grid-view__description-options"
@click="$refs.context.toggle($refs.contextLink, 'bottom', 'right', 0)" @click="$refs.context.toggle($refs.contextLink, 'bottom', 'right', 0)"
@mousedown.stop
> >
<i class="fas fa-caret-down"></i> <i class="fas fa-caret-down"></i>
</a> </a>
@ -132,6 +134,11 @@ export default {
required: false, required: false,
}, },
}, },
data() {
return {
dragging: false,
}
},
computed: { computed: {
width() { width() {
return this.getFieldWidth(this.field.id) return this.getFieldWidth(this.field.id)
@ -210,6 +217,10 @@ export default {
notifyIf(error, 'view') notifyIf(error, 'view')
} }
}, },
startDragging(event, field) {
event.preventDefault()
this.$emit('dragging', { field, event })
},
}, },
} }
</script> </script>

View file

@ -1,5 +1,5 @@
<template> <template>
<div :class="{ dragging: dragging }" @mousedown="start($event)"></div> <div :class="{ dragging: dragging }" @mousedown.stop="start($event)"></div>
</template> </template>
<script> <script>

View file

@ -14,6 +14,7 @@
:filters="view.filters" :filters="view.filters"
:include-field-width-handles="includeFieldWidthHandles" :include-field-width-handles="includeFieldWidthHandles"
@refresh="$emit('refresh', $event)" @refresh="$emit('refresh', $event)"
@dragging="$emit('dragging', $event)"
></GridViewFieldType> ></GridViewFieldType>
<div <div
v-if="includeAddField" v-if="includeAddField"

View file

@ -9,6 +9,10 @@
:include-row-details="includeRowDetails" :include-row-details="includeRowDetails"
:include-add-field="includeAddField" :include-add-field="includeAddField"
@refresh="$emit('refresh', $event)" @refresh="$emit('refresh', $event)"
@dragging="
canOrderFields &&
$refs.fieldDragging.start($event.field, $event.event)
"
></GridViewHead> ></GridViewHead>
<div ref="body" class="grid-view__body"> <div ref="body" class="grid-view__body">
<div class="grid-view__body-inner"> <div class="grid-view__body-inner">
@ -34,6 +38,13 @@
<slot name="foot"></slot> <slot name="foot"></slot>
</div> </div>
</div> </div>
<GridViewFieldDragging
ref="fieldDragging"
:view="view"
:fields="visibleFields"
:container-width="width"
@scroll="$emit('scroll', $event)"
></GridViewFieldDragging>
</div> </div>
</template> </template>
@ -42,7 +53,9 @@ import GridViewHead from '@baserow/modules/database/components/view/grid/GridVie
import GridViewPlaceholder from '@baserow/modules/database/components/view/grid/GridViewPlaceholder' import GridViewPlaceholder from '@baserow/modules/database/components/view/grid/GridViewPlaceholder'
import GridViewRows from '@baserow/modules/database/components/view/grid/GridViewRows' import GridViewRows from '@baserow/modules/database/components/view/grid/GridViewRows'
import GridViewRowAdd from '@baserow/modules/database/components/view/grid/GridViewRowAdd' import GridViewRowAdd from '@baserow/modules/database/components/view/grid/GridViewRowAdd'
import GridViewFieldDragging from '@baserow/modules/database/components/view/grid/GridViewFieldDragging'
import gridViewHelpers from '@baserow/modules/database/mixins/gridViewHelpers' import gridViewHelpers from '@baserow/modules/database/mixins/gridViewHelpers'
import { GridViewType } from '@baserow/modules/database/viewTypes'
export default { export default {
name: 'GridViewSection', name: 'GridViewSection',
@ -51,6 +64,7 @@ export default {
GridViewPlaceholder, GridViewPlaceholder,
GridViewRows, GridViewRows,
GridViewRowAdd, GridViewRowAdd,
GridViewFieldDragging,
}, },
mixins: [gridViewHelpers], mixins: [gridViewHelpers],
props: { props: {
@ -81,16 +95,49 @@ export default {
required: false, required: false,
default: () => false, default: () => false,
}, },
canOrderFields: {
type: Boolean,
required: false,
default: () => false,
},
}, },
computed: { computed: {
/**
* Returns only the visible fields in the correct order.
*/
visibleFields() { visibleFields() {
return this.fields.filter((field) => { return this.fields
const exists = Object.prototype.hasOwnProperty.call( .filter((field) => {
this.fieldOptions, const exists = Object.prototype.hasOwnProperty.call(
field.id this.fieldOptions,
) field.id
return !exists || (exists && !this.fieldOptions[field.id].hidden) )
}) return !exists || (exists && !this.fieldOptions[field.id].hidden)
})
.sort((a, b) => {
const orderA = this.fieldOptions[a.id]
? this.fieldOptions[a.id].order
: GridViewType.getMaxPossibleOrderValue()
const orderB = this.fieldOptions[b.id]
? this.fieldOptions[b.id].order
: GridViewType.getMaxPossibleOrderValue()
// First by order.
if (orderA > orderB) {
return 1
} else if (orderA < orderB) {
return -1
}
// Then by id.
if (a.id < b.id) {
return -1
} else if (a.id > b.id) {
return 1
} else {
return 0
}
})
}, },
/** /**
* Calculates the total width of the whole section based on the fields and the * Calculates the total width of the whole section based on the fields and the

View file

@ -224,10 +224,20 @@ export const actions = {
/** /**
* Remove the field from the items without calling the server. * Remove the field from the items without calling the server.
*/ */
forceDelete({ commit, dispatch }, field) { async forceDelete(context, field) {
const { commit, dispatch } = context
// Also delete the related filters if there are any. // Also delete the related filters if there are any.
dispatch('view/fieldDeleted', { field }, { root: true }) dispatch('view/fieldDeleted', { field }, { root: true })
commit('DELETE_ITEM', field.id) commit('DELETE_ITEM', field.id)
// Call the field delete event on all the registered views because they might
// need to change things in loaded data. For example the grid field will remove the
// field options of that field.
const fieldType = this.$registry.get('field', field.type)
for (const viewType of Object.values(this.$registry.getAll('view'))) {
await viewType.fieldDeleted(context, field, fieldType)
}
}, },
} }

View file

@ -4,6 +4,7 @@ import _ from 'lodash'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
import { uuid } from '@baserow/modules/core/utils/string' import { uuid } from '@baserow/modules/core/utils/string'
import { clone } from '@baserow/modules/core/utils/object'
import GridService from '@baserow/modules/database/services/view/grid' import GridService from '@baserow/modules/database/services/view/grid'
import RowService from '@baserow/modules/database/services/row' import RowService from '@baserow/modules/database/services/row'
import { import {
@ -235,6 +236,11 @@ export const mutations = {
}) })
} }
}, },
DELETE_FIELD_OPTIONS(state, fieldId) {
if (Object.prototype.hasOwnProperty.call(state.fieldOptions, fieldId)) {
delete state.fieldOptions[fieldId]
}
},
SET_ROW_HOVER(state, { row, value }) { SET_ROW_HOVER(state, { row, value }) {
row._.hover = value row._.hover = value
}, },
@ -899,6 +905,47 @@ export const actions = {
forceUpdateAllFieldOptions({ commit }, fieldOptions) { forceUpdateAllFieldOptions({ commit }, fieldOptions) {
commit('UPDATE_ALL_FIELD_OPTIONS', fieldOptions) commit('UPDATE_ALL_FIELD_OPTIONS', fieldOptions)
}, },
/**
* Updates the order of all the available field options. The provided order parameter
* should be an array containing the field ids in the correct order.
*/
async updateFieldOptionsOrder(
{ commit, getters, dispatch },
{ gridId, order }
) {
const oldFieldOptions = clone(getters.getAllFieldOptions)
const newFieldOptions = clone(getters.getAllFieldOptions)
// Update the order of the field options that have not been provided in the order.
// They will get a position that places them after the provided field ids.
let i = 0
Object.keys(newFieldOptions).forEach((fieldId) => {
if (!order.includes(parseInt(fieldId))) {
newFieldOptions[fieldId].order = order.length + i
i++
}
})
// Update create the field options and set the correct order value.
order.forEach((fieldId, index) => {
const id = fieldId.toString()
if (Object.prototype.hasOwnProperty.call(newFieldOptions, id)) {
newFieldOptions[fieldId.toString()].order = index
}
})
return await dispatch('updateAllFieldOptions', {
gridId,
oldFieldOptions,
newFieldOptions,
})
},
/**
* Deletes the field options of the provided field id if they exist.
*/
forceDeleteFieldOptions({ commit }, fieldId) {
commit('DELETE_FIELD_OPTIONS', fieldId)
},
setRowHover({ commit }, { row, value }) { setRowHover({ commit }, { row, value }) {
commit('SET_ROW_HOVER', { row, value }) commit('SET_ROW_HOVER', { row, value })
}, },

View file

@ -112,6 +112,12 @@ export class ViewType extends Registerable {
*/ */
fieldCreated(context, table, field, fieldType) {} fieldCreated(context, table, field, fieldType) {}
/**
* Method that is called when a field has been deleted. This can be useful to
* maintain data integrity.
*/
fieldDeleted(context, field, fieldType) {}
/** /**
* Method that is called when a field has been changed. This can be useful to * Method that is called when a field has been changed. This can be useful to
* maintain data integrity by updating the values. * maintain data integrity by updating the values.
@ -154,6 +160,10 @@ export class ViewType extends Registerable {
} }
export class GridViewType extends ViewType { export class GridViewType extends ViewType {
static getMaxPossibleOrderValue() {
return 32767
}
static getType() { static getType() {
return 'grid' return 'grid'
} }
@ -194,12 +204,19 @@ export class GridViewType extends ViewType {
values: { values: {
width: 200, width: 200,
hidden: false, hidden: false,
order: GridViewType.getMaxPossibleOrderValue(),
}, },
}, },
{ root: true } { root: true }
) )
} }
async fieldDeleted({ dispatch }, field, fieldType) {
await dispatch('view/grid/forceDeleteFieldOptions', field.id, {
root: true,
})
}
isCurrentView(store, tableId) { isCurrentView(store, tableId) {
const table = store.getters['table/getSelected'] const table = store.getters['table/getSelected']
const grid = store.getters['view/getSelected'] const grid = store.getters['view/getSelected']