mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-11 07:51:20 +00:00
Merge branch '336-make-the-tables-orderable' into 'develop'
Resolve "Make the tables orderable" Closes #336 See merge request bramw/baserow!251
This commit is contained in:
commit
7e1fd1c184
20 changed files with 350 additions and 16 deletions
backend
src/baserow/contrib/database
api/tables
table
ws/table
tests/baserow/contrib/database
web-frontend/modules
|
@ -8,6 +8,11 @@ ERROR_TABLE_DOES_NOT_EXIST = (
|
|||
HTTP_404_NOT_FOUND,
|
||||
"The requested table does not exist.",
|
||||
)
|
||||
ERROR_TABLE_NOT_IN_DATABASE = (
|
||||
"ERROR_TABLE_NOT_IN_DATABASE",
|
||||
HTTP_400_BAD_REQUEST,
|
||||
"The table id {e.table_id} does not belong to the database.",
|
||||
)
|
||||
ERROR_INVALID_INITIAL_TABLE_DATA = (
|
||||
"ERROR_INVALID_INITIAL_TABLE_DATA",
|
||||
HTTP_400_BAD_REQUEST,
|
||||
|
|
|
@ -52,3 +52,9 @@ class TableUpdateSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = Table
|
||||
fields = ("name",)
|
||||
|
||||
|
||||
class OrderTablesSerializer(serializers.Serializer):
|
||||
table_ids = serializers.ListField(
|
||||
child=serializers.IntegerField(), help_text="Table ids in the desired order."
|
||||
)
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from .views import TablesView, TableView
|
||||
from .views import TablesView, TableView, OrderTablesView
|
||||
|
||||
|
||||
app_name = "baserow.contrib.database.api.tables"
|
||||
|
||||
urlpatterns = [
|
||||
url(r"database/(?P<database_id>[0-9]+)/$", TablesView.as_view(), name="list"),
|
||||
url(
|
||||
r"database/(?P<database_id>[0-9]+)/order/$",
|
||||
OrderTablesView.as_view(),
|
||||
name="order",
|
||||
),
|
||||
url(r"(?P<table_id>[0-9]+)/$", TableView.as_view(), name="item"),
|
||||
]
|
||||
|
|
|
@ -20,13 +20,20 @@ from baserow.contrib.database.table.models import Table
|
|||
from baserow.contrib.database.table.handler import TableHandler
|
||||
from baserow.contrib.database.table.exceptions import (
|
||||
TableDoesNotExist,
|
||||
TableNotInDatabase,
|
||||
InvalidInitialTableData,
|
||||
InitialTableDataLimitExceeded,
|
||||
)
|
||||
|
||||
from .serializers import TableSerializer, TableCreateSerializer, TableUpdateSerializer
|
||||
from .serializers import (
|
||||
TableSerializer,
|
||||
TableCreateSerializer,
|
||||
TableUpdateSerializer,
|
||||
OrderTablesSerializer,
|
||||
)
|
||||
from .errors import (
|
||||
ERROR_TABLE_DOES_NOT_EXIST,
|
||||
ERROR_TABLE_NOT_IN_DATABASE,
|
||||
ERROR_INVALID_INITIAL_TABLE_DATA,
|
||||
ERROR_INITIAL_TABLE_DATA_LIMIT_EXCEEDED,
|
||||
)
|
||||
|
@ -248,3 +255,52 @@ class TableView(APIView):
|
|||
|
||||
TableHandler().delete_table(request.user, TableHandler().get_table(table_id))
|
||||
return Response(status=204)
|
||||
|
||||
|
||||
class OrderTablesView(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
@extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="database_id",
|
||||
location=OpenApiParameter.PATH,
|
||||
type=OpenApiTypes.INT,
|
||||
description="Updates the order of the tables in the database related "
|
||||
"to the provided value.",
|
||||
),
|
||||
],
|
||||
tags=["Database tables"],
|
||||
operation_id="order_database_tables",
|
||||
description=(
|
||||
"Changes the order of the provided table ids to the matching position that "
|
||||
"the id has in the list. If the authorized user does not belong to the "
|
||||
"group it will be ignored. The order of the not provided tables will be "
|
||||
"set to `0`."
|
||||
),
|
||||
request=OrderTablesSerializer,
|
||||
responses={
|
||||
204: None,
|
||||
400: get_error_schema(
|
||||
["ERROR_USER_NOT_IN_GROUP", "ERROR_TABLE_NOT_IN_DATABASE"]
|
||||
),
|
||||
404: get_error_schema(["ERROR_APPLICATION_DOES_NOT_EXIST"]),
|
||||
},
|
||||
)
|
||||
@validate_body(OrderTablesSerializer)
|
||||
@transaction.atomic
|
||||
@map_exceptions(
|
||||
{
|
||||
ApplicationDoesNotExist: ERROR_APPLICATION_DOES_NOT_EXIST,
|
||||
UserNotInGroup: ERROR_USER_NOT_IN_GROUP,
|
||||
TableNotInDatabase: ERROR_TABLE_NOT_IN_DATABASE,
|
||||
}
|
||||
)
|
||||
def post(self, request, data, database_id):
|
||||
"""Updates to order of the tables in a table."""
|
||||
|
||||
database = CoreHandler().get_application(
|
||||
database_id, base_queryset=Database.objects
|
||||
)
|
||||
TableHandler().order_tables(request.user, database, data["table_ids"])
|
||||
return Response(status=204)
|
||||
|
|
|
@ -2,6 +2,18 @@ class TableDoesNotExist(Exception):
|
|||
"""Raised when trying to get a table that doesn't exist."""
|
||||
|
||||
|
||||
class TableNotInDatabase(Exception):
|
||||
"""Raised when a provided table does not belong to a database."""
|
||||
|
||||
def __init__(self, table_id=None, *args, **kwargs):
|
||||
self.table_id = table_id
|
||||
super().__init__(
|
||||
f"The table {table_id} does not belong to the database.",
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
class InvalidInitialTableData(Exception):
|
||||
"""Raised when the provided initial table data does not contain a column or row."""
|
||||
|
||||
|
|
|
@ -15,10 +15,11 @@ from baserow.contrib.database.fields.field_types import (
|
|||
from .models import Table
|
||||
from .exceptions import (
|
||||
TableDoesNotExist,
|
||||
TableNotInDatabase,
|
||||
InvalidInitialTableData,
|
||||
InitialTableDataLimitExceeded,
|
||||
)
|
||||
from .signals import table_created, table_updated, table_deleted
|
||||
from .signals import table_created, table_updated, table_deleted, tables_reordered
|
||||
|
||||
|
||||
class TableHandler:
|
||||
|
@ -257,6 +258,34 @@ class TableHandler:
|
|||
|
||||
return table
|
||||
|
||||
def order_tables(self, user, database, order):
|
||||
"""
|
||||
Updates the order of the tables in the given database. The order of the views
|
||||
that are not in the `order` parameter set set to `0`.
|
||||
|
||||
:param user: The user on whose behalf the tables are ordered.
|
||||
:type user: User
|
||||
:param database: The database of which the views must be updated.
|
||||
:type database: Database
|
||||
:param order: A list containing the table ids in the desired order.
|
||||
:type order: list
|
||||
:raises TableNotInDatabase: If one of the table ids in the order does not belong
|
||||
to the database.
|
||||
"""
|
||||
|
||||
group = database.group
|
||||
group.has_user(user, raise_error=True)
|
||||
|
||||
queryset = Table.objects.filter(database_id=database.id)
|
||||
table_ids = [table["id"] for table in queryset.values("id")]
|
||||
|
||||
for table_id in order:
|
||||
if table_id not in table_ids:
|
||||
raise TableNotInDatabase(table_id)
|
||||
|
||||
Table.order_objects(queryset, order)
|
||||
tables_reordered.send(self, database=database, order=order, user=user)
|
||||
|
||||
def delete_table(self, user, table):
|
||||
"""
|
||||
Deletes an existing table instance if the user has access to the related group.
|
||||
|
|
|
@ -4,3 +4,4 @@ from django.dispatch import Signal
|
|||
table_created = Signal()
|
||||
table_updated = Signal()
|
||||
table_deleted = Signal()
|
||||
tables_reordered = Signal()
|
||||
|
|
|
@ -46,3 +46,18 @@ def table_deleted(sender, table_id, table, user, **kwargs):
|
|||
getattr(user, "web_socket_id", None),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@receiver(table_signals.tables_reordered)
|
||||
def tables_reordered(sender, database, order, user, **kwargs):
|
||||
transaction.on_commit(
|
||||
lambda: broadcast_to_group.delay(
|
||||
database.group_id,
|
||||
{
|
||||
"type": "tables_reordered",
|
||||
"database_id": database.id,
|
||||
"order": order,
|
||||
},
|
||||
getattr(user, "web_socket_id", None),
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import pytest
|
||||
|
||||
from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_404_NOT_FOUND
|
||||
from rest_framework.status import (
|
||||
HTTP_200_OK,
|
||||
HTTP_204_NO_CONTENT,
|
||||
HTTP_400_BAD_REQUEST,
|
||||
HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
from django.shortcuts import reverse
|
||||
from django.conf import settings
|
||||
|
@ -345,6 +350,69 @@ def test_update_table(api_client, data_fixture):
|
|||
assert response.json()["error"] == "ERROR_TABLE_DOES_NOT_EXIST"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_order_tables(api_client, data_fixture):
|
||||
user, token = data_fixture.create_user_and_token(
|
||||
email="test@test.nl", password="password", first_name="Test1"
|
||||
)
|
||||
database_1 = data_fixture.create_database_application(user=user)
|
||||
database_2 = data_fixture.create_database_application()
|
||||
table_1 = data_fixture.create_database_table(database=database_1, order=1)
|
||||
table_2 = data_fixture.create_database_table(database=database_1, order=2)
|
||||
table_3 = data_fixture.create_database_table(database=database_1, order=3)
|
||||
|
||||
response = api_client.post(
|
||||
reverse("api:database:tables:order", kwargs={"database_id": database_2.id}),
|
||||
{"table_ids": []},
|
||||
format="json",
|
||||
HTTP_AUTHORIZATION=f"JWT {token}",
|
||||
)
|
||||
assert response.status_code == HTTP_400_BAD_REQUEST
|
||||
assert response.json()["error"] == "ERROR_USER_NOT_IN_GROUP"
|
||||
|
||||
response = api_client.post(
|
||||
reverse("api:database:tables:order", kwargs={"database_id": 999999}),
|
||||
{"table_ids": []},
|
||||
format="json",
|
||||
HTTP_AUTHORIZATION=f"JWT {token}",
|
||||
)
|
||||
assert response.status_code == HTTP_404_NOT_FOUND
|
||||
assert response.json()["error"] == "ERROR_APPLICATION_DOES_NOT_EXIST"
|
||||
|
||||
response = api_client.post(
|
||||
reverse("api:database:tables:order", kwargs={"database_id": database_1.id}),
|
||||
{"table_ids": [0]},
|
||||
format="json",
|
||||
HTTP_AUTHORIZATION=f"JWT {token}",
|
||||
)
|
||||
assert response.status_code == HTTP_400_BAD_REQUEST
|
||||
assert response.json()["error"] == "ERROR_TABLE_NOT_IN_DATABASE"
|
||||
|
||||
response = api_client.post(
|
||||
reverse("api:database:tables:order", kwargs={"database_id": database_1.id}),
|
||||
{"table_ids": ["test"]},
|
||||
format="json",
|
||||
HTTP_AUTHORIZATION=f"JWT {token}",
|
||||
)
|
||||
assert response.status_code == HTTP_400_BAD_REQUEST
|
||||
assert response.json()["error"] == "ERROR_REQUEST_BODY_VALIDATION"
|
||||
|
||||
response = api_client.post(
|
||||
reverse("api:database:tables:order", kwargs={"database_id": database_1.id}),
|
||||
{"table_ids": [table_3.id, table_2.id, table_1.id]},
|
||||
format="json",
|
||||
HTTP_AUTHORIZATION=f"JWT {token}",
|
||||
)
|
||||
assert response.status_code == HTTP_204_NO_CONTENT
|
||||
|
||||
table_1.refresh_from_db()
|
||||
table_2.refresh_from_db()
|
||||
table_3.refresh_from_db()
|
||||
assert table_1.order == 3
|
||||
assert table_2.order == 2
|
||||
assert table_3.order == 1
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_delete_table(api_client, data_fixture):
|
||||
user, token = data_fixture.create_user_and_token()
|
||||
|
|
|
@ -11,6 +11,7 @@ from baserow.contrib.database.table.models import Table
|
|||
from baserow.contrib.database.table.handler import TableHandler
|
||||
from baserow.contrib.database.table.exceptions import (
|
||||
TableDoesNotExist,
|
||||
TableNotInDatabase,
|
||||
InvalidInitialTableData,
|
||||
InitialTableDataLimitExceeded,
|
||||
)
|
||||
|
@ -258,6 +259,58 @@ def test_update_database_table(send_mock, data_fixture):
|
|||
assert table.name == "Test 1"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@patch("baserow.contrib.database.table.signals.tables_reordered.send")
|
||||
def test_order_tables(send_mock, data_fixture):
|
||||
user = data_fixture.create_user()
|
||||
user_2 = data_fixture.create_user()
|
||||
database = data_fixture.create_database_application(user=user)
|
||||
table_1 = data_fixture.create_database_table(database=database, order=1)
|
||||
table_2 = data_fixture.create_database_table(database=database, order=2)
|
||||
table_3 = data_fixture.create_database_table(database=database, order=3)
|
||||
|
||||
handler = TableHandler()
|
||||
|
||||
with pytest.raises(UserNotInGroup):
|
||||
handler.order_tables(user=user_2, database=database, order=[])
|
||||
|
||||
with pytest.raises(TableNotInDatabase):
|
||||
handler.order_tables(user=user, database=database, order=[0])
|
||||
|
||||
handler.order_tables(
|
||||
user=user, database=database, order=[table_3.id, table_2.id, table_1.id]
|
||||
)
|
||||
table_1.refresh_from_db()
|
||||
table_2.refresh_from_db()
|
||||
table_3.refresh_from_db()
|
||||
assert table_1.order == 3
|
||||
assert table_2.order == 2
|
||||
assert table_3.order == 1
|
||||
|
||||
send_mock.assert_called_once()
|
||||
assert send_mock.call_args[1]["database"].id == database.id
|
||||
assert send_mock.call_args[1]["user"].id == user.id
|
||||
assert send_mock.call_args[1]["order"] == [table_3.id, table_2.id, table_1.id]
|
||||
|
||||
handler.order_tables(
|
||||
user=user, database=database, order=[table_1.id, table_3.id, table_2.id]
|
||||
)
|
||||
table_1.refresh_from_db()
|
||||
table_2.refresh_from_db()
|
||||
table_3.refresh_from_db()
|
||||
assert table_1.order == 1
|
||||
assert table_2.order == 3
|
||||
assert table_3.order == 2
|
||||
|
||||
handler.order_tables(user=user, database=database, order=[table_1.id])
|
||||
table_1.refresh_from_db()
|
||||
table_2.refresh_from_db()
|
||||
table_3.refresh_from_db()
|
||||
assert table_1.order == 1
|
||||
assert table_2.order == 0
|
||||
assert table_3.order == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@patch("baserow.contrib.database.table.signals.table_deleted.send")
|
||||
def test_delete_database_table(send_mock, data_fixture):
|
||||
|
|
|
@ -34,6 +34,22 @@ def test_table_updated(mock_broadcast_to_group, data_fixture):
|
|||
assert args[0][1]["table"]["id"] == table.id
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
@patch("baserow.contrib.database.ws.table.signals.broadcast_to_group")
|
||||
def test_tables_reordered(mock_broadcast_to_channel_group, data_fixture):
|
||||
user = data_fixture.create_user()
|
||||
database = data_fixture.create_database_application(user=user)
|
||||
table = data_fixture.create_database_table(database=database)
|
||||
TableHandler().order_tables(user=user, database=database, order=[table.id])
|
||||
|
||||
mock_broadcast_to_channel_group.delay.assert_called_once()
|
||||
args = mock_broadcast_to_channel_group.delay.call_args
|
||||
assert args[0][0] == table.database.group_id
|
||||
assert args[0][1]["type"] == "tables_reordered"
|
||||
assert args[0][1]["database_id"] == database.id
|
||||
assert args[0][1]["order"] == [table.id]
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
@patch("baserow.contrib.database.ws.table.signals.broadcast_to_group")
|
||||
def test_table_deleted(mock_broadcast_to_users, data_fixture):
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* Made it possible to import a JSON file when creating a table.
|
||||
* Made it possible to order the views by drag and drop.
|
||||
* Made it possible to order the groups by drag and drop.
|
||||
* Made it possible to order the tables by drag and drop.
|
||||
|
||||
## Released (2021-05-11)
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
}
|
||||
|
||||
.tree__subs {
|
||||
position: relative;
|
||||
list-style: none;
|
||||
padding: 0 0 2px 0;
|
||||
margin: 0;
|
||||
|
@ -131,12 +132,12 @@
|
|||
|
||||
.tree__sub-link {
|
||||
@extend %tree_sub-size;
|
||||
@extend %ellipsis;
|
||||
|
||||
color: $color-primary-900;
|
||||
display: block;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
color: $color-primary-500;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ export default {
|
|||
* process.
|
||||
*/
|
||||
bind(el, binding) {
|
||||
el.sortableId = binding.value.id
|
||||
binding.def.update(el, binding)
|
||||
el.sortableAutoScrolling = false
|
||||
|
||||
const mousedownElement = binding.value.handle
|
||||
|
@ -88,6 +88,8 @@ export default {
|
|||
},
|
||||
update(el, binding) {
|
||||
el.sortableId = binding.value.id
|
||||
el.sortableMarginLeft = binding.value.marginLeft
|
||||
el.sortableMarginRight = binding.value.marginRight
|
||||
},
|
||||
/**
|
||||
* Called when the user moves the mouse when the dragging of the element has
|
||||
|
@ -147,8 +149,12 @@ export default {
|
|||
parentRect.top +
|
||||
parent.scrollTop
|
||||
const left = elementRect.left - parentRect.left
|
||||
indicator.style.left = left + 'px'
|
||||
indicator.style.width = elementRect.width + 'px'
|
||||
indicator.style.left = left + (el.sortableMarginLeft || 0) + 'px'
|
||||
indicator.style.width =
|
||||
elementRect.width -
|
||||
(el.sortableMarginLeft || 0) -
|
||||
(el.sortableMarginRight || 0) +
|
||||
'px'
|
||||
indicator.style.top = top + 'px'
|
||||
|
||||
// If the user is not already auto scrolling, which happens while dragging and
|
||||
|
|
|
@ -18,8 +18,14 @@
|
|||
<template v-if="application._.selected" #body>
|
||||
<ul class="tree__subs">
|
||||
<SidebarItem
|
||||
v-for="table in application.tables"
|
||||
v-for="table in orderedTables"
|
||||
:key="table.id"
|
||||
v-sortable="{
|
||||
id: table.id,
|
||||
update: orderTables,
|
||||
marginLeft: 34,
|
||||
marginRight: 10,
|
||||
}"
|
||||
:database="application"
|
||||
:table="table"
|
||||
></SidebarItem>
|
||||
|
@ -51,6 +57,13 @@ export default {
|
|||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
orderedTables() {
|
||||
return this.application.tables
|
||||
.map((table) => table)
|
||||
.sort((a, b) => a.order - b.order)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async selected(application) {
|
||||
try {
|
||||
|
@ -59,6 +72,17 @@ export default {
|
|||
notifyIf(error, 'group')
|
||||
}
|
||||
},
|
||||
async orderTables(order, oldOrder) {
|
||||
try {
|
||||
await this.$store.dispatch('table/order', {
|
||||
database: this.application,
|
||||
order,
|
||||
oldOrder,
|
||||
})
|
||||
} catch (error) {
|
||||
notifyIf(error, 'table')
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
<template>
|
||||
<li class="tree__sub" :class="{ active: table._.selected }">
|
||||
<a class="tree__sub-link" @click.prevent="selectTable(database, table)">
|
||||
<Editable
|
||||
ref="rename"
|
||||
:value="table.name"
|
||||
@change="renameTable(database, table, $event)"
|
||||
></Editable>
|
||||
<a class="tree__sub-link" @click="selectTable(database, table)">
|
||||
<div>
|
||||
<Editable
|
||||
ref="rename"
|
||||
:value="table.name"
|
||||
@change="renameTable(database, table, $event)"
|
||||
></Editable>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
v-show="!database._.loading"
|
||||
class="tree__options"
|
||||
@click="$refs.context.toggle($event.currentTarget, 'bottom', 'right', 0)"
|
||||
@mousedown.stop
|
||||
>
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
</a>
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
:class="{ active: isTableActive(table) }"
|
||||
>
|
||||
<a class="tree__sub-link" @click="selectTable(application, table)">
|
||||
{{ table.name }}
|
||||
<div>
|
||||
{{ table.name }}
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
@ -27,6 +27,13 @@ export const registerRealtimeEvents = (realtime) => {
|
|||
}
|
||||
})
|
||||
|
||||
realtime.registerEvent('tables_reordered', ({ store, app }, data) => {
|
||||
const database = store.getters['application/get'](data.database_id)
|
||||
if (database !== undefined) {
|
||||
store.commit('table/ORDER_TABLES', { database, order: data.order })
|
||||
}
|
||||
})
|
||||
|
||||
realtime.registerEvent('table_deleted', ({ store }, data) => {
|
||||
const database = store.getters['application/get'](data.database_id)
|
||||
if (database !== undefined) {
|
||||
|
|
|
@ -17,6 +17,11 @@ export default (client) => {
|
|||
update(tableId, values) {
|
||||
return client.patch(`/database/tables/${tableId}/`, values)
|
||||
},
|
||||
order(databaseId, order) {
|
||||
return client.post(`/database/tables/database/${databaseId}/order/`, {
|
||||
table_ids: order,
|
||||
})
|
||||
},
|
||||
delete(tableId) {
|
||||
return client.delete(`/database/tables/${tableId}/`)
|
||||
},
|
||||
|
|
|
@ -27,6 +27,12 @@ export const mutations = {
|
|||
UPDATE_ITEM(state, { table, values }) {
|
||||
Object.assign(table, table, values)
|
||||
},
|
||||
ORDER_TABLES(state, { database, order }) {
|
||||
database.tables.forEach((table) => {
|
||||
const index = order.findIndex((value) => value === table.id)
|
||||
table.order = index === -1 ? 0 : index + 1
|
||||
})
|
||||
},
|
||||
SET_SELECTED(state, { database, table }) {
|
||||
Object.values(database.tables).forEach((item) => {
|
||||
item._.selected = false
|
||||
|
@ -107,6 +113,19 @@ export const actions = {
|
|||
forceUpdate({ commit }, { database, table, values }) {
|
||||
commit('UPDATE_ITEM', { database, table, values })
|
||||
},
|
||||
/**
|
||||
* Updates the order of all the tables in a database.
|
||||
*/
|
||||
async order({ commit, getters }, { database, order, oldOrder }) {
|
||||
commit('ORDER_TABLES', { database, order })
|
||||
|
||||
try {
|
||||
await TableService(this.$client).order(database.id, order)
|
||||
} catch (error) {
|
||||
commit('ORDER_TABLES', { database, order: oldOrder })
|
||||
throw error
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Deletes an existing application.
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue