mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Record Cards
Summary: Adds a new Record Card view section to each non-summary table, which can be from opened from various parts of the Grist UI to view and edit records in a popup card view. Work is still ongoing, so the feature is locked away behind a flag; follow-up work is planned to finish up the implementation and add end-to-end tests. Test Plan: Python and server tests. Browser tests will be included in a follow-up. Reviewers: jarek, paulfitz Reviewed By: jarek Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D4114
This commit is contained in:
@@ -141,6 +141,9 @@ class MetaTableExtras(object):
|
||||
def isRaw(rec, table):
|
||||
return rec.tableRef.rawViewSectionRef == rec
|
||||
|
||||
def isRecordCard(rec, table):
|
||||
return rec.tableRef.recordCardViewSectionRef == rec
|
||||
|
||||
class _grist_Filters(object):
|
||||
def setAutoRemove(rec, table):
|
||||
"""Marks the filter for removal if its column no longer exists."""
|
||||
|
||||
@@ -1235,3 +1235,57 @@ def migration39(tdset):
|
||||
if 'description' not in tdset.all_tables['_grist_Views_section'].columns:
|
||||
doc_actions.append(add_column('_grist_Views_section', 'description', 'Text'))
|
||||
return tdset.apply_doc_actions(doc_actions)
|
||||
|
||||
@migration(schema_version=40)
|
||||
def migration40(tdset):
|
||||
"""
|
||||
Adds a recordCardViewSectionRef column to _grist_Tables, populating it
|
||||
for each non-summary table in _grist_Tables that has a rawViewSectionRef.
|
||||
"""
|
||||
doc_actions = [
|
||||
add_column(
|
||||
'_grist_Tables',
|
||||
'recordCardViewSectionRef',
|
||||
'Ref:_grist_Views_section'
|
||||
),
|
||||
]
|
||||
|
||||
tables = list(actions.transpose_bulk_action(tdset.all_tables["_grist_Tables"]))
|
||||
columns = list(actions.transpose_bulk_action(tdset.all_tables["_grist_Tables_column"]))
|
||||
|
||||
new_view_section_id = next_id(tdset, "_grist_Views_section")
|
||||
|
||||
for table in sorted(tables, key=lambda t: t.tableId):
|
||||
if not table.rawViewSectionRef or table.summarySourceTable:
|
||||
continue
|
||||
|
||||
table_columns = [
|
||||
col for col in columns
|
||||
if table.id == col.parentId and is_visible_column(col.colId)
|
||||
]
|
||||
table_columns.sort(key=lambda c: c.parentPos)
|
||||
fields = {
|
||||
"parentId": [new_view_section_id] * len(table_columns),
|
||||
"colRef": [col.id for col in table_columns],
|
||||
"parentPos": [col.parentPos for col in table_columns],
|
||||
}
|
||||
field_ids = [None] * len(table_columns)
|
||||
|
||||
doc_actions += [
|
||||
actions.AddRecord("_grist_Views_section", new_view_section_id, {
|
||||
"tableRef": table.id,
|
||||
"parentId": 0,
|
||||
"parentKey": "single",
|
||||
"title": "",
|
||||
"defaultWidth": 100,
|
||||
"borderWidth": 1,
|
||||
}),
|
||||
actions.UpdateRecord("_grist_Tables", table.id, {
|
||||
"recordCardViewSectionRef": new_view_section_id,
|
||||
}),
|
||||
actions.BulkAddRecord("_grist_Views_section_field", field_ids, fields),
|
||||
]
|
||||
|
||||
new_view_section_id += 1
|
||||
|
||||
return tdset.apply_doc_actions(doc_actions)
|
||||
|
||||
@@ -15,7 +15,7 @@ import six
|
||||
|
||||
import actions
|
||||
|
||||
SCHEMA_VERSION = 39
|
||||
SCHEMA_VERSION = 40
|
||||
|
||||
def make_column(col_id, col_type, formula='', isFormula=False):
|
||||
return {
|
||||
@@ -58,6 +58,7 @@ def schema_create_actions():
|
||||
make_column("onDemand", "Bool"),
|
||||
|
||||
make_column("rawViewSectionRef", "Ref:_grist_Views_section"),
|
||||
make_column("recordCardViewSectionRef", "Ref:_grist_Views_section"),
|
||||
]),
|
||||
|
||||
# All columns in all user tables.
|
||||
|
||||
@@ -202,7 +202,8 @@ class SummaryActions(object):
|
||||
encode_summary_table_name(source_table.tableId, groupby_col_ids),
|
||||
[get_colinfo_dict(ci, with_id=True) for ci in groupby_colinfo + formula_colinfo],
|
||||
summarySourceTableRef=source_table.id,
|
||||
raw_section=True)
|
||||
raw_section=True,
|
||||
record_card_section=False)
|
||||
summary_table = self.docmodel.tables.table.get_record(result['id'])
|
||||
created = True
|
||||
# Note that in this case, _get_or_add_columns() below should not add any new columns,
|
||||
|
||||
@@ -223,15 +223,15 @@ class TestColumnActions(test_engine.EngineTestCase):
|
||||
Field(2, colRef=12),
|
||||
Field(3, colRef=13),
|
||||
]),
|
||||
Section(4, parentKey="record", tableRef=2, fields=[
|
||||
Field(10, colRef=15),
|
||||
Field(11, colRef=16),
|
||||
Field(12, colRef=17),
|
||||
Section(5, parentKey="record", tableRef=2, fields=[
|
||||
Field(13, colRef=15),
|
||||
Field(14, colRef=16),
|
||||
Field(15, colRef=17),
|
||||
]),
|
||||
Section(6, parentKey="record", tableRef=3, fields=[
|
||||
Field(16, colRef=18),
|
||||
Field(17, colRef=20),
|
||||
Field(18, colRef=21),
|
||||
Section(7, parentKey="record", tableRef=3, fields=[
|
||||
Field(19, colRef=18),
|
||||
Field(20, colRef=20),
|
||||
Field(21, colRef=21),
|
||||
]),
|
||||
]),
|
||||
View(2, sections=[
|
||||
@@ -311,14 +311,14 @@ class TestColumnActions(test_engine.EngineTestCase):
|
||||
Field(2, colRef=12),
|
||||
Field(3, colRef=13),
|
||||
]),
|
||||
Section(4, parentKey="record", tableRef=2, fields=[
|
||||
Field(10, colRef=15),
|
||||
Field(12, colRef=17),
|
||||
Section(5, parentKey="record", tableRef=2, fields=[
|
||||
Field(13, colRef=15),
|
||||
Field(15, colRef=17),
|
||||
]),
|
||||
Section(6, parentKey="record", tableRef=3, fields=[
|
||||
Field(16, colRef=18),
|
||||
Field(17, colRef=20),
|
||||
Field(18, colRef=21),
|
||||
Section(7, parentKey="record", tableRef=3, fields=[
|
||||
Field(19, colRef=18),
|
||||
Field(20, colRef=20),
|
||||
Field(21, colRef=21),
|
||||
]),
|
||||
]),
|
||||
View(2, sections=[
|
||||
@@ -368,13 +368,13 @@ class TestColumnActions(test_engine.EngineTestCase):
|
||||
Section(1, parentKey="record", tableRef=1, fields=[
|
||||
Field(3, colRef=13),
|
||||
]),
|
||||
Section(4, parentKey="record", tableRef=2, fields=[
|
||||
Field(10, colRef=15),
|
||||
Field(12, colRef=17),
|
||||
Section(5, parentKey="record", tableRef=2, fields=[
|
||||
Field(13, colRef=15),
|
||||
Field(15, colRef=17),
|
||||
]),
|
||||
Section(6, parentKey="record", tableRef=4, fields=[
|
||||
Field(17, colRef=23),
|
||||
Field(18, colRef=24),
|
||||
Section(7, parentKey="record", tableRef=4, fields=[
|
||||
Field(20, colRef=23),
|
||||
Field(21, colRef=24),
|
||||
]),
|
||||
]),
|
||||
View(2, sections=[
|
||||
@@ -420,14 +420,14 @@ class TestColumnActions(test_engine.EngineTestCase):
|
||||
self.init_sample_data()
|
||||
|
||||
# Add sortSpecs to ViewSections.
|
||||
self.apply_user_action(['BulkUpdateRecord', '_grist_Views_section', [2, 3, 4],
|
||||
self.apply_user_action(['BulkUpdateRecord', '_grist_Views_section', [2, 3, 5],
|
||||
{'sortColRefs': ['[15, -16]', '[-15, 16, 17]', '[19]']}
|
||||
])
|
||||
self.assertTableData('_grist_Views_section', cols="subset", rows="subset", data=[
|
||||
["id", "sortColRefs" ],
|
||||
[2, '[15, -16]' ],
|
||||
[3, '[-15, 16, 17]'],
|
||||
[4, '[19]' ],
|
||||
[5, '[19]' ],
|
||||
])
|
||||
|
||||
# Remove column, and check that the correct sortColRefs items are removed.
|
||||
@@ -436,7 +436,7 @@ class TestColumnActions(test_engine.EngineTestCase):
|
||||
["id", "sortColRefs"],
|
||||
[2, '[15]' ],
|
||||
[3, '[-15, 17]' ],
|
||||
[4, '[19]' ],
|
||||
[5, '[19]' ],
|
||||
])
|
||||
|
||||
# Update sortColRefs for next test.
|
||||
@@ -450,5 +450,5 @@ class TestColumnActions(test_engine.EngineTestCase):
|
||||
["id", "sortColRefs"],
|
||||
[2, '[]' ],
|
||||
[3, '[-16]' ],
|
||||
[4, '[]' ],
|
||||
[5, '[]' ],
|
||||
])
|
||||
|
||||
@@ -53,6 +53,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 0],
|
||||
[2, 25, 0],
|
||||
[3, 25, 0],
|
||||
])
|
||||
self.assertTableData("Favorites", cols="subset", data=[
|
||||
["id", "favorite"],
|
||||
@@ -70,6 +71,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
[1, 25, 0],
|
||||
[2, 25, 0],
|
||||
[3, 25, 0],
|
||||
[4, 25, 0],
|
||||
])
|
||||
|
||||
# Set display formula for 'favorite' column.
|
||||
@@ -86,7 +88,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
# A single "gristHelper_Display2" column should be added with the requested formula, since both
|
||||
# require the same formula. The fields' colRefs should be set to the new column.
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 1, None, '$favorite.network'])
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 3, None, '$favorite.network'])
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 4, None, '$favorite.network'])
|
||||
self.assertTableData("_grist_Tables_column", cols="subset", rows=(lambda r: r.id >= 25), data=[
|
||||
["id", "colId", "parentId", "displayCol", "formula"],
|
||||
[25, "favorite", 2, 26, ""],
|
||||
@@ -97,13 +99,14 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 27],
|
||||
[2, 25, 0],
|
||||
[3, 25, 27],
|
||||
[3, 25, 0],
|
||||
[4, 25, 27],
|
||||
])
|
||||
|
||||
# Change display formula for a field.
|
||||
# Since the field is changing to use a formula not yet held by a display column,
|
||||
# a new display column should be added with the desired formula.
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 3, None, '$favorite.viewers'])
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 4, None, '$favorite.viewers'])
|
||||
self.assertTableData("_grist_Tables_column", cols="subset", rows=(lambda r: r.id >= 25), data=[
|
||||
["id", "colId", "parentId", "displayCol", "formula"],
|
||||
[25, "favorite", 2, 26, ""],
|
||||
@@ -115,13 +118,14 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 27],
|
||||
[2, 25, 0],
|
||||
[3, 25, 28],
|
||||
[3, 25, 0],
|
||||
[4, 25, 28],
|
||||
])
|
||||
|
||||
# Remove a field.
|
||||
# This should also remove the display column used by that field, since it is not used
|
||||
# by any other fields.
|
||||
self.apply_user_action(['RemoveRecord', '_grist_Views_section_field', 3])
|
||||
self.apply_user_action(['RemoveRecord', '_grist_Views_section_field', 4])
|
||||
self.assertTableData("_grist_Tables_column", cols="subset", rows=(lambda r: r.id >= 25), data=[
|
||||
["id", "colId", "parentId", "displayCol", "formula"],
|
||||
[25, "favorite", 2, 26, ""],
|
||||
@@ -132,6 +136,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 27],
|
||||
[2, 25, 0],
|
||||
[3, 25, 0],
|
||||
])
|
||||
|
||||
# Add a new column with a formula.
|
||||
@@ -145,7 +150,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
'parentId': 3,
|
||||
'colRef': 25
|
||||
}])
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 6, None, '$favorite.viewers'])
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 8, None, '$favorite.viewers'])
|
||||
self.assertTableData("_grist_Tables_column", cols="subset", rows=(lambda r: r.id >= 25), data=[
|
||||
["id", "colId", "parentId", "displayCol", "formula"],
|
||||
[25, "favorite", 2, 26, ""],
|
||||
@@ -158,17 +163,19 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 27],
|
||||
[2, 25, 0],
|
||||
[3, 28, 0], # fav_viewers field
|
||||
[4, 28, 0], # fav_viewers field
|
||||
[5, 28, 0], # fav_viewers field
|
||||
[6, 25, 29] # re-added field w/ display col
|
||||
[3, 25, 0],
|
||||
[4, 28, 0], # fav_viewers field
|
||||
[5, 28, 0], # fav_viewers field
|
||||
[6, 28, 0], # fav_viewers field
|
||||
[7, 28, 0], # re-added field w/ display col
|
||||
[8, 25, 29], # fav_viewers field
|
||||
])
|
||||
|
||||
# Change the display formula for a field to be the same as the other field, then remove
|
||||
# the field.
|
||||
# The display column should not be removed since it is still in use.
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 6, None, '$favorite.network'])
|
||||
self.apply_user_action(['RemoveRecord', '_grist_Views_section_field', 6])
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 8, None, '$favorite.network'])
|
||||
self.apply_user_action(['RemoveRecord', '_grist_Views_section_field', 8])
|
||||
self.assertTableData("_grist_Tables_column", cols="subset", rows=(lambda r: r.id >= 25), data=[
|
||||
["id", "colId", "parentId", "displayCol", "formula"],
|
||||
[25, "favorite", 2, 26, ""],
|
||||
@@ -180,9 +187,11 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 27],
|
||||
[2, 25, 0],
|
||||
[3, 28, 0],
|
||||
[3, 25, 0],
|
||||
[4, 28, 0],
|
||||
[5, 28, 0],
|
||||
[6, 28, 0],
|
||||
[7, 28, 0],
|
||||
])
|
||||
|
||||
# Clear field display formula, then set it again.
|
||||
@@ -199,9 +208,11 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 0],
|
||||
[2, 25, 0],
|
||||
[3, 28, 0],
|
||||
[3, 25, 0],
|
||||
[4, 28, 0],
|
||||
[5, 28, 0],
|
||||
[6, 28, 0],
|
||||
[7, 28, 0],
|
||||
])
|
||||
# Setting the display formula should add another display column.
|
||||
self.apply_user_action(['SetDisplayFormula', 'Favorites', 1, None, '$favorite.viewers'])
|
||||
@@ -216,9 +227,11 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 29],
|
||||
[2, 25, 0],
|
||||
[3, 28, 0],
|
||||
[3, 25, 0],
|
||||
[4, 28, 0],
|
||||
[5, 28, 0],
|
||||
[6, 28, 0],
|
||||
[7, 28, 0],
|
||||
])
|
||||
|
||||
# Change column display formula.
|
||||
@@ -235,9 +248,11 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "colRef", "displayCol"],
|
||||
[1, 25, 29],
|
||||
[2, 25, 0],
|
||||
[3, 28, 0],
|
||||
[3, 25, 0],
|
||||
[4, 28, 0],
|
||||
[5, 28, 0],
|
||||
[6, 28, 0],
|
||||
[7, 28, 0],
|
||||
])
|
||||
|
||||
# Remove column.
|
||||
@@ -249,9 +264,10 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
])
|
||||
self.assertTableData("_grist_Views_section_field", cols="subset", data=[
|
||||
["id", "colRef", "displayCol"],
|
||||
[3, 28, 0],
|
||||
[4, 28, 0],
|
||||
[5, 28, 0],
|
||||
[6, 28, 0],
|
||||
[7, 28, 0],
|
||||
])
|
||||
|
||||
|
||||
@@ -381,7 +397,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
# pylint:disable=line-too-long
|
||||
self.assertOutActions(out_actions, {
|
||||
"stored": [
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [2, 4]],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [2, 4, 6]],
|
||||
["BulkRemoveRecord", "_grist_Tables_column", [26, 27]],
|
||||
["RemoveColumn", "People", "favorite"],
|
||||
["RemoveColumn", "People", "gristHelper_Display"],
|
||||
@@ -392,7 +408,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
"undo": [
|
||||
["BulkUpdateRecord", "People", [1, 2, 3], {"gristHelper_Display2": ["Netflix", "HBO", "NBC"]}],
|
||||
["BulkUpdateRecord", "People", [1, 2, 3], {"gristHelper_Display": ["Narcos", "Game of Thrones", "Today"]}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [2, 4], {"colRef": [26, 26], "displayCol": [28, 0], "parentId": [1, 2], "parentPos": [2.0, 4.0]}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [2, 4, 6], {"colRef": [26, 26, 26], "displayCol": [28, 0, 0], "parentId": [1, 2, 3], "parentPos": [2.0, 4.0, 6.0]}],
|
||||
["BulkAddRecord", "_grist_Tables_column", [26, 27], {"colId": ["favorite", "gristHelper_Display"], "displayCol": [27, 0], "formula": ["", "$favorite.show"], "isFormula": [False, True], "label": ["favorite", "gristHelper_Display"], "parentId": [2, 2], "parentPos": [6.0, 7.0], "type": ["Ref:Television", "Any"], "widgetOptions": ["\"{\"alignment\":\"center\",\"visibleCol\":\"show\"}\"", ""]}],
|
||||
["BulkUpdateRecord", "People", [1, 2, 3], {"favorite": [12, 11, 13]}],
|
||||
["AddColumn", "People", "favorite", {"formula": "", "isFormula": False, "type": "Ref:Television"}],
|
||||
|
||||
@@ -141,35 +141,42 @@ class TestDocModel(test_engine.EngineTestCase):
|
||||
self.assertPartialData('_grist_Views_section', ["id", "parentId", "tableRef"], [
|
||||
[1, 1, 4],
|
||||
[2, 0, 4],
|
||||
[3, 2, 5],
|
||||
[4, 0, 5],
|
||||
[5, 1, 4],
|
||||
[6, 1, 5],
|
||||
[3, 0, 4],
|
||||
[4, 2, 5],
|
||||
[5, 0, 5],
|
||||
[6, 0, 5],
|
||||
[7, 1, 4],
|
||||
[8, 1, 5],
|
||||
])
|
||||
self.assertPartialData('_grist_Views_section_field', ["id", "parentId", "parentPos"], [
|
||||
[1, 1, 1.0],
|
||||
[2, 1, 2.0],
|
||||
[3, 2, 3.0],
|
||||
[4, 2, 4.0],
|
||||
[5, 3, 5.0],
|
||||
[6, 3, 6.0],
|
||||
[7, 4, 7.0],
|
||||
[8, 4, 8.0],
|
||||
[9, 5, 9.0],
|
||||
[1, 1, 1.0],
|
||||
[2, 1, 2.0],
|
||||
[3, 2, 3.0],
|
||||
[4, 2, 4.0],
|
||||
[5, 3, 5.0],
|
||||
[6, 3, 6.0],
|
||||
[7, 4, 7.0],
|
||||
[8, 4, 8.0],
|
||||
[9, 5, 9.0],
|
||||
[10, 5, 10.0],
|
||||
[11, 6, 11.0],
|
||||
[12, 6, 12.0],
|
||||
[13, 7, 13.0],
|
||||
[14, 7, 14.0],
|
||||
[15, 8, 15.0],
|
||||
[16, 8, 16.0],
|
||||
])
|
||||
|
||||
table = self.engine.docmodel.tables.lookupOne(tableId='Test2')
|
||||
self.assertRecordSet(table.viewSections, [1, 2, 5])
|
||||
self.assertRecordSet(table.viewSections, [1, 2, 3, 7])
|
||||
self.assertRecordSet(list(table.viewSections)[0].fields, [1, 2])
|
||||
self.assertRecordSet(list(table.viewSections)[2].fields, [9, 10])
|
||||
self.assertRecordSet(list(table.viewSections)[3].fields, [13, 14])
|
||||
view = self.engine.docmodel.views.lookupOne(id=1)
|
||||
self.assertRecordSet(view.viewSections, [1, 5, 6])
|
||||
self.assertRecordSet(view.viewSections, [1, 7, 8])
|
||||
|
||||
self.engine.docmodel.remove(set(table.viewSections) - {table.rawViewSectionRef})
|
||||
self.assertRecordSet(view.viewSections, [6])
|
||||
self.engine.docmodel.remove(set(table.viewSections) -
|
||||
{table.rawViewSectionRef, table.recordCardViewSectionRef})
|
||||
self.assertRecordSet(view.viewSections, [8])
|
||||
|
||||
|
||||
def test_modifications(self):
|
||||
|
||||
@@ -54,10 +54,13 @@ class TestImportActions(test_engine.EngineTestCase):
|
||||
self.assertPartialData("_grist_Views_section", ["id", "tableRef", 'fields'], [
|
||||
[1, 1, [1, 2, 3]], # section for "Source" table
|
||||
[2, 1, [4, 5, 6]], # section for "Source" table
|
||||
[3, 2, [7, 8]], # section for "Destination1" table
|
||||
[4, 2, [9, 10]], # section for "Destination1" table
|
||||
[5, 3, [11]], # section for "Destination2" table
|
||||
[6, 3, [12]], # section for "Destination2" table
|
||||
[3, 1, [7, 8, 9]], # section for "Source" table
|
||||
[4, 2, [10, 11]], # section for "Destination1" table
|
||||
[5, 2, [12, 13]], # section for "Destination1" table
|
||||
[6, 2, [14, 15]], # section for "Destination1" table
|
||||
[7, 3, [16]], # section for "Destination2" table
|
||||
[8, 3, [17]], # section for "Destination2" table
|
||||
[9, 3, [18]], # section for "Destination2" table
|
||||
])
|
||||
|
||||
def test_transform(self):
|
||||
@@ -89,11 +92,14 @@ class TestImportActions(test_engine.EngineTestCase):
|
||||
self.assertPartialData("_grist_Views_section", ["id", "tableRef", 'fields'], [
|
||||
[1, 1, [1, 2, 3]],
|
||||
[2, 1, [4, 5, 6]],
|
||||
[3, 2, [7, 8]],
|
||||
[4, 2, [9, 10]],
|
||||
[5, 3, [11]],
|
||||
[6, 3, [12]],
|
||||
[7, 1, [13, 14]], # new section for transform preview
|
||||
[3, 1, [7, 8, 9]],
|
||||
[4, 2, [10, 11]],
|
||||
[5, 2, [12, 13]],
|
||||
[6, 2, [14, 15]],
|
||||
[7, 3, [16]],
|
||||
[8, 3, [17]],
|
||||
[9, 3, [18]],
|
||||
[10, 1, [19, 20]], # new section for transform preview
|
||||
])
|
||||
|
||||
# Apply useraction again to verify that old columns and sections are removing
|
||||
@@ -117,17 +123,20 @@ class TestImportActions(test_engine.EngineTestCase):
|
||||
[2, "Alison", "Boston", 7003, "", 2.0],
|
||||
])
|
||||
self.assertPartialData("_grist_Views_section", ["id", "tableRef", 'fields'], [
|
||||
[1, 1, [1, 2, 3]],
|
||||
[2, 1, [4, 5, 6]],
|
||||
[3, 2, [7, 8]],
|
||||
[4, 2, [9, 10]],
|
||||
[5, 3, [11]],
|
||||
[6, 3, [12]],
|
||||
[7, 1, [13]], # new section for transform preview
|
||||
[1, 1, [1, 2, 3]],
|
||||
[2, 1, [4, 5, 6]],
|
||||
[3, 1, [7, 8, 9]],
|
||||
[4, 2, [10, 11]],
|
||||
[5, 2, [12, 13]],
|
||||
[6, 2, [14, 15]],
|
||||
[7, 3, [16]],
|
||||
[8, 3, [17]],
|
||||
[9, 3, [18]],
|
||||
[10, 1, [19]], # new section for transform preview
|
||||
])
|
||||
|
||||
|
||||
def test_regenereate_importer_view(self):
|
||||
def test_regenerate_importer_view(self):
|
||||
# Generate without a destination table, and then with one. Ensure that we don't omit the
|
||||
# actions needed to populate the table in the second call.
|
||||
self.init_state()
|
||||
@@ -135,8 +144,8 @@ class TestImportActions(test_engine.EngineTestCase):
|
||||
out_actions = self.apply_user_action(['GenImporterView', 'Source', 'Destination1', None, {}])
|
||||
self.assertPartialOutActions(out_actions, {
|
||||
"stored": [
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [13, 14, 15]],
|
||||
["RemoveRecord", "_grist_Views_section", 7],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [19, 20, 21]],
|
||||
["RemoveRecord", "_grist_Views_section", 10],
|
||||
["BulkRemoveRecord", "_grist_Tables_column", [10, 11, 12]],
|
||||
["RemoveColumn", "Source", "gristHelper_Import_Name"],
|
||||
["RemoveColumn", "Source", "gristHelper_Import_City"],
|
||||
@@ -145,8 +154,8 @@ class TestImportActions(test_engine.EngineTestCase):
|
||||
["AddRecord", "_grist_Tables_column", 10, {"colId": "gristHelper_Import_Name", "formula": "$Name", "isFormula": True, "label": "Name", "parentId": 1, "parentPos": 10.0, "type": "Text", "widgetOptions": ""}],
|
||||
["AddColumn", "Source", "gristHelper_Import_City", {"formula": "$City", "isFormula": True, "type": "Text"}],
|
||||
["AddRecord", "_grist_Tables_column", 11, {"colId": "gristHelper_Import_City", "formula": "$City", "isFormula": True, "label": "City", "parentId": 1, "parentPos": 11.0, "type": "Text", "widgetOptions": ""}],
|
||||
["AddRecord", "_grist_Views_section", 7, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "sortColRefs": "[]", "tableRef": 1}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [13, 14], {"colRef": [10, 11], "parentId": [7, 7], "parentPos": [13.0, 14.0]}],
|
||||
["AddRecord", "_grist_Views_section", 10, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "sortColRefs": "[]", "tableRef": 1}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [19, 20], {"colRef": [10, 11], "parentId": [10, 10], "parentPos": [19.0, 20.0]}],
|
||||
# The actions to populate the removed and re-added columns should be there.
|
||||
["BulkUpdateRecord", "Source", [1, 2], {"gristHelper_Import_City": ["New York", "Boston"]}],
|
||||
["BulkUpdateRecord", "Source", [1, 2], {"gristHelper_Import_Name": ["John", "Alison"]}],
|
||||
@@ -181,11 +190,14 @@ class TestImportActions(test_engine.EngineTestCase):
|
||||
[2, "Alison", "Boston", 7003, "Alison", "Boston", 7003, 2.0],
|
||||
])
|
||||
self.assertPartialData("_grist_Views_section", ["id", "tableRef", 'fields'], [
|
||||
[1, 1, [1, 2, 3]],
|
||||
[2, 1, [4, 5, 6]],
|
||||
[3, 2, [7, 8]],
|
||||
[4, 2, [9, 10]],
|
||||
[5, 3, [11]],
|
||||
[6, 3, [12]],
|
||||
[7, 1, [13, 14, 15]], # new section for transform preview
|
||||
[1, 1, [1, 2, 3]],
|
||||
[2, 1, [4, 5, 6]],
|
||||
[3, 1, [7, 8, 9]],
|
||||
[4, 2, [10, 11]],
|
||||
[5, 2, [12, 13]],
|
||||
[6, 2, [14, 15]],
|
||||
[7, 3, [16]],
|
||||
[8, 3, [17]],
|
||||
[9, 3, [18]],
|
||||
[10, 1, [19, 20, 21]], # new section for transform preview
|
||||
])
|
||||
|
||||
@@ -88,27 +88,27 @@ class TestTableActions(test_engine.EngineTestCase):
|
||||
]),
|
||||
]),
|
||||
View(2, sections=[
|
||||
Section(3, parentKey="record", tableRef=2, fields=[
|
||||
Field(7, colRef=6),
|
||||
Field(8, colRef=7),
|
||||
Field(9, colRef=8),
|
||||
Section(4, parentKey="record", tableRef=2, fields=[
|
||||
Field(10, colRef=6),
|
||||
Field(11, colRef=7),
|
||||
Field(12, colRef=8),
|
||||
]),
|
||||
]),
|
||||
View(3, sections=[
|
||||
Section(5, parentKey="record", tableRef=1, fields=[
|
||||
Field(13, colRef=2),
|
||||
Field(14, colRef=3),
|
||||
Field(15, colRef=4),
|
||||
Section(7, parentKey="record", tableRef=1, fields=[
|
||||
Field(19, colRef=2),
|
||||
Field(20, colRef=3),
|
||||
Field(21, colRef=4),
|
||||
]),
|
||||
Section(7, parentKey="record", tableRef=3, fields=[
|
||||
Field(19, colRef=9),
|
||||
Field(20, colRef=11),
|
||||
Field(21, colRef=12),
|
||||
Section(9, parentKey="record", tableRef=3, fields=[
|
||||
Field(25, colRef=9),
|
||||
Field(26, colRef=11),
|
||||
Field(27, colRef=12),
|
||||
]),
|
||||
Section(8, parentKey="record", tableRef=2, fields=[
|
||||
Field(22, colRef=6),
|
||||
Field(23, colRef=7),
|
||||
Field(24, colRef=8),
|
||||
Section(10, parentKey="record", tableRef=2, fields=[
|
||||
Field(28, colRef=6),
|
||||
Field(29, colRef=7),
|
||||
Field(30, colRef=8),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
@@ -295,17 +295,17 @@ class TestTableActions(test_engine.EngineTestCase):
|
||||
])
|
||||
self.assertViews([
|
||||
View(2, sections=[
|
||||
Section(3, parentKey="record", tableRef=2, fields=[
|
||||
Field(7, colRef=6),
|
||||
Field(8, colRef=7),
|
||||
Field(9, colRef=8),
|
||||
Section(4, parentKey="record", tableRef=2, fields=[
|
||||
Field(10, colRef=6),
|
||||
Field(11, colRef=7),
|
||||
Field(12, colRef=8),
|
||||
]),
|
||||
]),
|
||||
View(3, sections=[
|
||||
Section(8, parentKey="record", tableRef=2, fields=[
|
||||
Field(22, colRef=6),
|
||||
Field(23, colRef=7),
|
||||
Field(24, colRef=8),
|
||||
Section(10, parentKey="record", tableRef=2, fields=[
|
||||
Field(28, colRef=6),
|
||||
Field(29, colRef=7),
|
||||
Field(30, colRef=8),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
|
||||
@@ -58,6 +58,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
self.assertPartialData("_grist_Views_section_field", ["id", "colRef", "widgetOptions"], [
|
||||
[1, 23, ""],
|
||||
[2, 23, ""],
|
||||
[3, 23, ""],
|
||||
])
|
||||
self.assertPartialData("Schools", ["id", "city"], [
|
||||
[1, "New York" ],
|
||||
@@ -78,8 +79,11 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
'grist_Transform', 'formula': 'return $city', 'label': 'grist_Transform',
|
||||
'type': 'Text'
|
||||
}],
|
||||
["AddRecord", "_grist_Views_section_field", 3, {
|
||||
"colRef": 24, "parentId": 2, "parentPos": 3.0
|
||||
["AddRecord", "_grist_Views_section_field", 4, {
|
||||
"colRef": 24, "parentId": 2, "parentPos": 4.0
|
||||
}],
|
||||
["AddRecord", "_grist_Views_section_field", 5, {
|
||||
"colRef": 24, "parentId": 3, "parentPos": 5.0
|
||||
}],
|
||||
["BulkUpdateRecord", "Schools", [1, 2, 3],
|
||||
{"grist_Transform": ["New York", "Colombia", "New York"]}],
|
||||
@@ -122,7 +126,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
|
||||
out_actions = self.remove_column('Schools', 'grist_Transform')
|
||||
self.assertPartialOutActions(out_actions, { "stored": [
|
||||
["RemoveRecord", "_grist_Views_section_field", 3],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [4, 5]],
|
||||
['RemoveRecord', '_grist_Tables_column', 24],
|
||||
['RemoveColumn', 'Schools', 'grist_Transform'],
|
||||
]})
|
||||
@@ -205,10 +209,10 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
Column(25, "C", "Any", isFormula=True, formula="", summarySourceCol=0),
|
||||
])
|
||||
new_view = View(1, sections=[
|
||||
Section(2, parentKey="record", tableRef=2, fields=[
|
||||
Field(4, colRef=23),
|
||||
Field(5, colRef=24),
|
||||
Field(6, colRef=25),
|
||||
Section(3, parentKey="record", tableRef=2, fields=[
|
||||
Field(7, colRef=23),
|
||||
Field(8, colRef=24),
|
||||
Field(9, colRef=25),
|
||||
])
|
||||
])
|
||||
self.assertTables([self.starting_table, new_table])
|
||||
@@ -223,10 +227,10 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
Column(29, "C", "Any", isFormula=True, formula="", summarySourceCol=0),
|
||||
])
|
||||
new_view.sections.append(
|
||||
Section(4, parentKey="record", tableRef=3, fields=[
|
||||
Field(10, colRef=27),
|
||||
Field(11, colRef=28),
|
||||
Field(12, colRef=29),
|
||||
Section(6, parentKey="record", tableRef=3, fields=[
|
||||
Field(16, colRef=27),
|
||||
Field(17, colRef=28),
|
||||
Field(18, colRef=29),
|
||||
])
|
||||
)
|
||||
# Check that we have a new table, only the new view; and a new section.
|
||||
@@ -256,8 +260,8 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
Column(35, "count", "Int", isFormula=True, formula="len($group)", summarySourceCol=0),
|
||||
])
|
||||
self.assertTables([self.starting_table, new_table, new_table2, new_table3, summary_table])
|
||||
new_view.sections.append(Section(7, parentKey="record", tableRef=5, fields=[
|
||||
Field(17, colRef=35)
|
||||
new_view.sections.append(Section(10, parentKey="record", tableRef=5, fields=[
|
||||
Field(26, colRef=35)
|
||||
]))
|
||||
self.assertViews([new_view])
|
||||
|
||||
@@ -311,26 +315,26 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
]),
|
||||
]),
|
||||
View(2, sections=[
|
||||
Section(3, parentKey="detail", tableRef=1, fields=[
|
||||
Field(7, colRef=2),
|
||||
Field(8, colRef=3),
|
||||
Field(9, colRef=4),
|
||||
Section(4, parentKey="detail", tableRef=1, fields=[
|
||||
Field(10, colRef=2),
|
||||
Field(11, colRef=3),
|
||||
Field(12, colRef=4),
|
||||
]),
|
||||
Section(5, parentKey="record", tableRef=2, fields=[
|
||||
Field(13, colRef=5),
|
||||
Field(14, colRef=7),
|
||||
Field(15, colRef=8),
|
||||
Section(6, parentKey="record", tableRef=2, fields=[
|
||||
Field(16, colRef=5),
|
||||
Field(17, colRef=7),
|
||||
Field(18, colRef=8),
|
||||
]),
|
||||
Section(8, parentKey='record', tableRef=3, fields=[
|
||||
Field(21, colRef=10),
|
||||
Field(22, colRef=11),
|
||||
Field(23, colRef=12),
|
||||
Section(10, parentKey='record', tableRef=3, fields=[
|
||||
Field(27, colRef=10),
|
||||
Field(28, colRef=11),
|
||||
Field(29, colRef=12),
|
||||
]),
|
||||
]),
|
||||
View(3, sections=[
|
||||
Section(6, parentKey="chart", tableRef=1, fields=[
|
||||
Field(16, colRef=2),
|
||||
Field(17, colRef=3),
|
||||
Section(7, parentKey="chart", tableRef=1, fields=[
|
||||
Field(19, colRef=2),
|
||||
Field(20, colRef=3),
|
||||
]),
|
||||
])
|
||||
])
|
||||
@@ -468,10 +472,10 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
{'title': 'Z'}])
|
||||
|
||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
||||
[1, 'Z', 1, 2],
|
||||
[2, 'Z_summary_state', 0, 4],
|
||||
[3, 'Table1', 0, 7],
|
||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef', 'recordCardViewSectionRef'],
|
||||
[1, 'Z', 1, 2, 3],
|
||||
[2, 'Z_summary_state', 0, 5, 0],
|
||||
[3, 'Table1', 0, 8, 9],
|
||||
])
|
||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||
['id', 'name'],
|
||||
@@ -485,11 +489,11 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
{'id': 'city', 'type': 'Text'},
|
||||
]])
|
||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef'],
|
||||
[1, 'Z', 1, 2],
|
||||
[2, 'Z_summary_state', 0, 4],
|
||||
[3, 'Table1', 0, 7],
|
||||
[4, 'Stations', 4, 10],
|
||||
['id', 'tableId', 'primaryViewId', 'rawViewSectionRef', 'recordCardViewSectionRef'],
|
||||
[1, 'Z', 1, 2, 3],
|
||||
[2, 'Z_summary_state', 0, 5, 0],
|
||||
[3, 'Table1', 0, 8, 9],
|
||||
[4, 'Stations', 4, 12, 13],
|
||||
])
|
||||
self.assertTableData('_grist_Views', cols="subset", data=[
|
||||
['id', 'name'],
|
||||
@@ -542,32 +546,32 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
]),
|
||||
]),
|
||||
View(2, sections=[
|
||||
Section(3, parentKey="detail", tableRef=1, fields=[
|
||||
Field(7, colRef=2),
|
||||
Field(8, colRef=3),
|
||||
Field(9, colRef=4),
|
||||
Section(4, parentKey="detail", tableRef=1, fields=[
|
||||
Field(10, colRef=2),
|
||||
Field(11, colRef=3),
|
||||
Field(12, colRef=4),
|
||||
]),
|
||||
Section(5, parentKey="record", tableRef=2, fields=[
|
||||
Field(13, colRef=5),
|
||||
Field(14, colRef=7),
|
||||
Field(15, colRef=8),
|
||||
Section(6, parentKey="record", tableRef=2, fields=[
|
||||
Field(16, colRef=5),
|
||||
Field(17, colRef=7),
|
||||
Field(18, colRef=8),
|
||||
]),
|
||||
Section(8, parentKey='record', tableRef=3, fields=[
|
||||
Field(21, colRef=10),
|
||||
Field(22, colRef=11),
|
||||
Field(23, colRef=12),
|
||||
Section(10, parentKey='record', tableRef=3, fields=[
|
||||
Field(27, colRef=10),
|
||||
Field(28, colRef=11),
|
||||
Field(29, colRef=12),
|
||||
]),
|
||||
]),
|
||||
View(3, sections=[
|
||||
Section(6, parentKey="chart", tableRef=1, fields=[
|
||||
Field(16, colRef=2),
|
||||
Field(17, colRef=3),
|
||||
Section(7, parentKey="chart", tableRef=1, fields=[
|
||||
Field(19, colRef=2),
|
||||
Field(20, colRef=3),
|
||||
]),
|
||||
])
|
||||
])
|
||||
|
||||
# Remove a couple of sections. Ensure their fields get removed.
|
||||
self.apply_user_action(['BulkRemoveRecord', '_grist_Views_section', [5, 8]])
|
||||
self.apply_user_action(['BulkRemoveRecord', '_grist_Views_section', [6, 10]])
|
||||
|
||||
self.assertViews([
|
||||
View(1, sections=[
|
||||
@@ -578,16 +582,16 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
]),
|
||||
]),
|
||||
View(2, sections=[
|
||||
Section(3, parentKey="detail", tableRef=1, fields=[
|
||||
Field(7, colRef=2),
|
||||
Field(8, colRef=3),
|
||||
Field(9, colRef=4),
|
||||
Section(4, parentKey="detail", tableRef=1, fields=[
|
||||
Field(10, colRef=2),
|
||||
Field(11, colRef=3),
|
||||
Field(12, colRef=4),
|
||||
])
|
||||
]),
|
||||
View(3, sections=[
|
||||
Section(6, parentKey="chart", tableRef=1, fields=[
|
||||
Field(16, colRef=2),
|
||||
Field(17, colRef=3),
|
||||
Section(7, parentKey="chart", tableRef=1, fields=[
|
||||
Field(19, colRef=2),
|
||||
Field(20, colRef=3),
|
||||
]),
|
||||
])
|
||||
])
|
||||
@@ -613,8 +617,8 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
self.assertEqual(count_calls[0], 0)
|
||||
|
||||
# Do a schema action to ensure it gets called: this causes a table rename.
|
||||
# 7 is id of raw view section for the Tabl1 table
|
||||
self.apply_user_action(['UpdateRecord', '_grist_Views_section', 7, {'title': 'C'}])
|
||||
# 8 is id of raw view section for the Table1 table
|
||||
self.apply_user_action(['UpdateRecord', '_grist_Views_section', 8, {'title': 'C'}])
|
||||
self.assertEqual(count_calls[0], 1)
|
||||
|
||||
self.assertTableData('_grist_Tables', cols="subset", data=[
|
||||
@@ -1403,6 +1407,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "parentId", "tableRef"],
|
||||
[1, 1, 2],
|
||||
[2, 0, 2], # the raw view section
|
||||
[3, 0, 2], # the record card view section
|
||||
])
|
||||
self.assertTableData('_grist_Views_section_field', cols="subset", data=[
|
||||
["id", "parentId"],
|
||||
@@ -1414,6 +1419,11 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
[4, 2],
|
||||
[5, 2],
|
||||
[6, 2],
|
||||
|
||||
# the record card view section
|
||||
[7, 3],
|
||||
[8, 3],
|
||||
[9, 3],
|
||||
])
|
||||
|
||||
# Test that the records cannot be removed by normal user actions
|
||||
@@ -1433,6 +1443,7 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
["id", "parentId", "tableRef"],
|
||||
[1, 1, 2],
|
||||
[2, 0, 2], # the raw view section
|
||||
[3, 0, 2], # the record card view section
|
||||
])
|
||||
self.assertTableData('_grist_Views_section_field', cols="subset", data=[
|
||||
["id", "parentId"],
|
||||
@@ -1444,6 +1455,45 @@ class TestUserActions(test_engine.EngineTestCase):
|
||||
[4, 2],
|
||||
[5, 2],
|
||||
[6, 2],
|
||||
|
||||
# the record card view section
|
||||
[7, 3],
|
||||
[8, 3],
|
||||
[9, 3],
|
||||
])
|
||||
|
||||
def test_record_card_view_section_restrictions(self):
|
||||
self.load_sample(self.sample)
|
||||
self.apply_user_action(["AddEmptyTable", None])
|
||||
|
||||
# Check that record card view sections cannot be removed by normal user actions.
|
||||
with self.assertRaisesRegex(ValueError, "Cannot remove record card view section$"):
|
||||
self.apply_user_action(["RemoveRecord", '_grist_Views_section', 3])
|
||||
|
||||
# Check that most of their column values can't be changed.
|
||||
with self.assertRaisesRegex(ValueError, "Cannot modify record card view section$"):
|
||||
self.apply_user_action(["UpdateRecord", '_grist_Views_section', 3, {"parentId": 1}])
|
||||
with self.assertRaisesRegex(ValueError, "Cannot modify record card view section fields$"):
|
||||
self.apply_user_action(["UpdateRecord", '_grist_Views_section_field', 9, {"parentId": 1}])
|
||||
|
||||
# Make sure nothing got removed or updated.
|
||||
self.assertTableData('_grist_Views_section', cols="subset", data=[
|
||||
["id", "parentId", "tableRef"],
|
||||
[1, 1, 2],
|
||||
[2, 0, 2],
|
||||
[3, 0, 2],
|
||||
])
|
||||
self.assertTableData('_grist_Views_section_field', cols="subset", data=[
|
||||
["id", "parentId"],
|
||||
[1, 1],
|
||||
[2, 1],
|
||||
[3, 1],
|
||||
[4, 2],
|
||||
[5, 2],
|
||||
[6, 2],
|
||||
[7, 3],
|
||||
[8, 3],
|
||||
[9, 3],
|
||||
])
|
||||
|
||||
def test_update_current_time(self):
|
||||
|
||||
@@ -918,7 +918,12 @@
|
||||
// Raw data widget
|
||||
["AddRecord", "_grist_Views_section", 2, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "tableRef": 4, "title": ""}],
|
||||
["AddRecord", "_grist_Views_section_field", 2, {"colRef": 34, "parentId": 2, "parentPos": 2.0}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2}],
|
||||
|
||||
// Record card widget
|
||||
["AddRecord", "_grist_Views_section", 3, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "single", "tableRef": 4, "title": ""}],
|
||||
["AddRecord", "_grist_Views_section_field", 3, {"colRef": 34, "parentId": 3, "parentPos": 3.0}],
|
||||
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2, "recordCardViewSectionRef": 3}],
|
||||
|
||||
// Actions generated from AddColumn.
|
||||
["AddColumn", "Bar", "world",
|
||||
@@ -927,9 +932,10 @@
|
||||
{"colId": "world", "parentPos": 13.0,
|
||||
"formula": "rec.hello.upper()", "parentId": 4, "type": "Text",
|
||||
"isFormula": true, "label": "world", "widgetOptions": ""}],
|
||||
["AddRecord", "_grist_Views_section_field", 3, {"colRef": 35, "parentId": 2, "parentPos": 3.0}]
|
||||
["AddRecord", "_grist_Views_section_field", 4, {"colRef": 35, "parentId": 2, "parentPos": 4.0}],
|
||||
["AddRecord", "_grist_Views_section_field", 5, {"colRef": 35, "parentId": 3, "parentPos": 5.0}]
|
||||
],
|
||||
"direct": [true, true, true, true,
|
||||
"direct": [true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true,
|
||||
true, true, true],
|
||||
"undo": [
|
||||
@@ -943,10 +949,13 @@
|
||||
["RemoveRecord", "_grist_Views_section_field", 1],
|
||||
["RemoveRecord", "_grist_Views_section", 2],
|
||||
["RemoveRecord", "_grist_Views_section_field", 2],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0}],
|
||||
["RemoveRecord", "_grist_Views_section", 3],
|
||||
["RemoveRecord", "_grist_Views_section_field", 3],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0, "recordCardViewSectionRef": 0}],
|
||||
["RemoveColumn", "Bar", "world"],
|
||||
["RemoveRecord", "_grist_Tables_column", 35],
|
||||
["RemoveRecord", "_grist_Views_section_field", 3]
|
||||
["RemoveRecord", "_grist_Views_section_field", 4],
|
||||
["RemoveRecord", "_grist_Views_section_field", 5]
|
||||
],
|
||||
"retValue": [
|
||||
{
|
||||
@@ -1257,15 +1266,16 @@
|
||||
{"parentId": [1,1], "colRef": [31,32], "parentPos": [1.0,2.0]}],
|
||||
["AddRecord", "_grist_Views_section", 2, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "tableRef": 4, "title": ""}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [3, 4], {"colRef": [31, 32], "parentId": [2, 2], "parentPos": [3.0, 4.0]}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2}],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [1, 3]],
|
||||
["AddRecord", "_grist_Views_section", 3, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "single", "tableRef": 4, "title": ""}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [5, 6], {"colRef": [31, 32], "parentId": [3, 3], "parentPos": [5.0, 6.0]}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2, "recordCardViewSectionRef": 3}],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [1, 3, 5]],
|
||||
["RemoveRecord", "_grist_Tables_column", 31],
|
||||
["RemoveColumn", "ViewTest", "hello"]
|
||||
|
||||
],
|
||||
"direct": [true, true, true, true, true, true, true, true, true,
|
||||
true, true,
|
||||
true, true, true],
|
||||
true, true, true, true, true, true, true],
|
||||
"undo": [
|
||||
["RemoveTable", "ViewTest"],
|
||||
["RemoveRecord", "_grist_Tables", 4],
|
||||
@@ -1277,8 +1287,11 @@
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [1,2]],
|
||||
["RemoveRecord", "_grist_Views_section", 2],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [3, 4]],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [1, 3], {"colRef": [31, 31], "parentId": [1, 2], "parentPos": [1.0, 3.0]}],
|
||||
["RemoveRecord", "_grist_Views_section", 3],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [5, 6]],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0, "recordCardViewSectionRef": 0}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [1, 3, 5],
|
||||
{"colRef": [31, 31, 31], "parentId": [1, 2, 3], "parentPos": [1.0, 3.0, 5.0]}],
|
||||
["AddRecord", "_grist_Tables_column", 31,
|
||||
{"colId": "hello", "parentPos": 9.0,
|
||||
"parentId": 4, "type": "Text"
|
||||
@@ -2199,7 +2212,8 @@
|
||||
{"tableRef": 4, "defaultWidth": 100, "borderWidth": 1,
|
||||
"parentId": 1, "parentKey": "record", "sortColRefs": "[]", "title": ""}],
|
||||
["AddRecord", "_grist_Views_section", 2, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "tableRef": 4, "title": ""}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2}],
|
||||
["AddRecord", "_grist_Views_section", 3, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "single", "tableRef": 4, "title": ""}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2, "recordCardViewSectionRef": 3}],
|
||||
["AddTable", "Bar", [
|
||||
{"id": "manualSort", "formula": "", "isFormula": false, "type": "ManualSortPos"},
|
||||
{"isFormula": false, "formula": "", "type": "Text", "id": "hello"},
|
||||
@@ -2223,21 +2237,23 @@
|
||||
{"type": "raw_data", "name": "Bar"}],
|
||||
["AddRecord", "_grist_TabBar", 2, {"tabPos": 2.0, "viewRef": 2}],
|
||||
["AddRecord", "_grist_Pages", 2, {"pagePos": 2.0, "viewRef": 2, "indentation": 0}],
|
||||
["AddRecord", "_grist_Views_section", 3,
|
||||
["AddRecord", "_grist_Views_section", 4,
|
||||
{"tableRef": 5, "defaultWidth": 100, "borderWidth": 1,
|
||||
"parentId": 2, "parentKey": "record", "sortColRefs": "[]", "title": ""}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [1,2,3],
|
||||
{"parentId": [3,3,3], "colRef": [32,33,34], "parentPos": [1.0,2.0,3.0]}],
|
||||
["AddRecord", "_grist_Views_section", 4, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "tableRef": 5, "title": ""}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [4, 5, 6], {"colRef": [32, 33, 34], "parentId": [4, 4, 4], "parentPos": [4.0, 5.0, 6.0]}],
|
||||
["UpdateRecord", "_grist_Tables", 5, {"primaryViewId": 2, "rawViewSectionRef": 4}],
|
||||
{"parentId": [4,4,4], "colRef": [32,33,34], "parentPos": [1.0,2.0,3.0]}],
|
||||
["AddRecord", "_grist_Views_section", 5, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "tableRef": 5, "title": ""}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [4, 5, 6], {"colRef": [32, 33, 34], "parentId": [5, 5, 5], "parentPos": [4.0, 5.0, 6.0]}],
|
||||
["AddRecord", "_grist_Views_section", 6, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "single", "tableRef": 5, "title": ""}],
|
||||
["BulkAddRecord", "_grist_Views_section_field", [7, 8, 9], {"colRef": [32, 33, 34], "parentId": [6, 6, 6], "parentPos": [7.0, 8.0, 9.0]}],
|
||||
["UpdateRecord", "_grist_Tables", 5, {"primaryViewId": 2, "rawViewSectionRef": 5, "recordCardViewSectionRef": 6}],
|
||||
["AddRecord", "Bar", 1, {"foo": 0, "hello": "a", "manualSort": 1.0}],
|
||||
["AddRecord", "Bar", 2, {"foo": 1, "hello": "b", "manualSort": 2.0}],
|
||||
["AddRecord", "Bar", 3, {"foo": 1, "hello": "c", "manualSort": 3.0}],
|
||||
["BulkUpdateRecord", "Bar", [1, 2, 3], {"world": ["A", "B", "C"]}]
|
||||
],
|
||||
"direct": [true, true, true, true, true, true, true, true,
|
||||
true, true, true,
|
||||
true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, false],
|
||||
"undo": [
|
||||
@@ -2249,18 +2265,21 @@
|
||||
["RemoveRecord", "_grist_Pages", 1],
|
||||
["RemoveRecord", "_grist_Views_section", 1],
|
||||
["RemoveRecord", "_grist_Views_section", 2],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0}],
|
||||
["RemoveRecord", "_grist_Views_section", 3],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0, "recordCardViewSectionRef": 0}],
|
||||
["RemoveTable", "Bar"],
|
||||
["RemoveRecord", "_grist_Tables", 5],
|
||||
["BulkRemoveRecord", "_grist_Tables_column", [31,32,33,34]],
|
||||
["RemoveRecord", "_grist_Views", 2],
|
||||
["RemoveRecord", "_grist_TabBar", 2],
|
||||
["RemoveRecord", "_grist_Pages", 2],
|
||||
["RemoveRecord", "_grist_Views_section", 3],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [1,2,3]],
|
||||
["RemoveRecord", "_grist_Views_section", 4],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [1,2,3]],
|
||||
["RemoveRecord", "_grist_Views_section", 5],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [4, 5, 6]],
|
||||
["UpdateRecord", "_grist_Tables", 5, {"primaryViewId": 0, "rawViewSectionRef": 0}],
|
||||
["RemoveRecord", "_grist_Views_section", 6],
|
||||
["BulkRemoveRecord", "_grist_Views_section_field", [7, 8, 9]],
|
||||
["UpdateRecord", "_grist_Tables", 5, {"primaryViewId": 0, "rawViewSectionRef": 0, "recordCardViewSectionRef": 0}],
|
||||
["RemoveRecord", "Bar", 1],
|
||||
["RemoveRecord", "Bar", 2],
|
||||
["RemoveRecord", "Bar", 3]
|
||||
@@ -2281,7 +2300,7 @@
|
||||
"id": 5,
|
||||
"columns": ["hello", "world", "foo"],
|
||||
"views": [
|
||||
{ "sections": [ 3 ], "id": 2 }
|
||||
{ "sections": [ 4 ], "id": 2 }
|
||||
]
|
||||
},
|
||||
// AddRecord retValues
|
||||
@@ -2333,10 +2352,12 @@
|
||||
"parentId": 1, "parentKey": "record", "sortColRefs": "[]", "title": ""}],
|
||||
// Raw data widget
|
||||
["AddRecord", "_grist_Views_section", 2, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "record", "tableRef": 4, "title": ""}],
|
||||
// Record card widget
|
||||
["AddRecord", "_grist_Views_section", 3, {"borderWidth": 1, "defaultWidth": 100, "parentKey": "single", "tableRef": 4, "title": ""}],
|
||||
// As part of adding a table, we also set the primaryViewId.
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2}]
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 1, "rawViewSectionRef": 2, "recordCardViewSectionRef": 3}]
|
||||
],
|
||||
"direct": [true, true, true, true, true, true, true, true, true],
|
||||
"direct": [true, true, true, true, true, true, true, true, true, true],
|
||||
"undo": [
|
||||
["RemoveTable", "Foo"],
|
||||
["RemoveRecord", "_grist_Tables", 4],
|
||||
@@ -2346,7 +2367,8 @@
|
||||
["RemoveRecord", "_grist_Pages", 1],
|
||||
["RemoveRecord", "_grist_Views_section", 1],
|
||||
["RemoveRecord", "_grist_Views_section", 2],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0}]
|
||||
["RemoveRecord", "_grist_Views_section", 3],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"primaryViewId": 0, "rawViewSectionRef": 0, "recordCardViewSectionRef": 0}]
|
||||
]
|
||||
}
|
||||
}],
|
||||
@@ -2359,7 +2381,8 @@
|
||||
"USER_ACTION": ["RemoveTable", "Foo"],
|
||||
"ACTIONS": {
|
||||
"stored": [
|
||||
["BulkRemoveRecord", "_grist_Views_section", [1, 2]],
|
||||
["BulkRemoveRecord", "_grist_Views_section", [1, 2, 3]],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"recordCardViewSectionRef": 0}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"rawViewSectionRef": 0}],
|
||||
["RemoveRecord", "_grist_TabBar", 1],
|
||||
["RemoveRecord", "_grist_Pages", 1],
|
||||
@@ -2369,11 +2392,12 @@
|
||||
["RemoveRecord", "_grist_Tables", 4],
|
||||
["RemoveTable", "Foo"]
|
||||
],
|
||||
"direct": [true, true, true, true, true, true, true, true, true],
|
||||
"direct": [true, true, true, true, true, true, true, true, true, true],
|
||||
"undo": [
|
||||
["BulkAddRecord", "_grist_Views_section", [1, 2],
|
||||
{"borderWidth": [1, 1], "defaultWidth": [100, 100], "parentId": [1, 0],
|
||||
"parentKey": ["record", "record"], "sortColRefs": ["[]", ""], "tableRef": [4, 4]}],
|
||||
["BulkAddRecord", "_grist_Views_section", [1, 2, 3],
|
||||
{"borderWidth": [1, 1, 1], "defaultWidth": [100, 100, 100], "parentId": [1, 0, 0],
|
||||
"parentKey": ["record", "record", "single"], "sortColRefs": ["[]", "", ""], "tableRef": [4, 4, 4]}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"recordCardViewSectionRef": 3}],
|
||||
["UpdateRecord", "_grist_Tables", 4, {"rawViewSectionRef": 2}],
|
||||
["AddRecord", "_grist_TabBar", 1, {"tabPos": 1.0, "viewRef": 1}],
|
||||
["AddRecord", "_grist_Pages", 1, {"pagePos": 1.0, "viewRef": 1}],
|
||||
|
||||
@@ -479,6 +479,24 @@ class UserActions(object):
|
||||
):
|
||||
raise ValueError("Cannot modify raw view section fields")
|
||||
|
||||
# Prevent modifying record card widgets and their fields.
|
||||
if (
|
||||
table_id == "_grist_Views_section"
|
||||
and any(rec.isRecordCard for i, rec in self._bulk_action_iter(table_id, row_ids))
|
||||
):
|
||||
allowed_fields = {"layoutSpec", "options", "theme"}
|
||||
if not set(column_values) <= allowed_fields:
|
||||
raise ValueError("Cannot modify record card view section")
|
||||
|
||||
if (
|
||||
table_id == "_grist_Views_section_field"
|
||||
and any(rec.parentId.isRecordCard for i, rec in self._bulk_action_iter(table_id, row_ids))
|
||||
and not set(column_values) <= {
|
||||
"displayCol", "parentPos", "rules", "visibleCol", "widgetOptions"
|
||||
}
|
||||
):
|
||||
raise ValueError("Cannot modify record card view section fields")
|
||||
|
||||
# If any extra actions were generated (e.g. to adjust positions), apply them.
|
||||
for a in extra_actions:
|
||||
self._do_doc_action(a)
|
||||
@@ -1300,13 +1318,15 @@ class UserActions(object):
|
||||
def _removeViewSectionRecords(self, table_id, row_ids):
|
||||
"""
|
||||
Remove view sections, including their fields.
|
||||
Raises an error if trying to remove a table's rawViewSectionRef.
|
||||
Raises an error if trying to remove a table's rawViewSectionRef or recordCardViewSectionRef.
|
||||
To bypass that check, call _doRemoveViewSectionRecords.
|
||||
"""
|
||||
recs = [rec for i, rec in self._bulk_action_iter(table_id, row_ids)]
|
||||
for rec in recs:
|
||||
if rec.isRaw:
|
||||
raise ValueError("Cannot remove raw view section")
|
||||
if rec.isRecordCard:
|
||||
raise ValueError("Cannot remove record card view section")
|
||||
self._doRemoveViewSectionRecords(recs)
|
||||
|
||||
def _doRemoveViewSectionRecords(self, recs):
|
||||
@@ -1355,16 +1375,35 @@ class UserActions(object):
|
||||
|
||||
ret = self.doAddColumn(table_id, col_id, col_info)
|
||||
|
||||
if not transform and table_rec.rawViewSectionRef:
|
||||
# Add a field for this column to the "raw_data" section for this table.
|
||||
# TODO: the position of the inserted field or of the inserted column will often be
|
||||
# bogus, since fields and columns are not the same. This requires better coordination
|
||||
# with the client-side.
|
||||
self._docmodel.insert(
|
||||
table_rec.rawViewSectionRef.fields,
|
||||
col_info.get('_position'),
|
||||
colRef=ret['colRef']
|
||||
)
|
||||
if not transform:
|
||||
if table_rec.rawViewSectionRef:
|
||||
# Add a field for this column to the "raw_data" section for this table.
|
||||
# TODO: the position of the inserted field or of the inserted column will often be
|
||||
# bogus, since fields and columns are not the same. This requires better coordination
|
||||
# with the client-side.
|
||||
self._docmodel.insert(
|
||||
table_rec.rawViewSectionRef.fields,
|
||||
col_info.get('_position'),
|
||||
colRef=ret['colRef']
|
||||
)
|
||||
|
||||
if table_rec.recordCardViewSectionRef:
|
||||
# If the record card section or one of its fields hasn't yet been modified,
|
||||
# add a field for this column.
|
||||
section = table_rec.recordCardViewSectionRef
|
||||
modified = (
|
||||
section.layoutSpec or
|
||||
section.options or
|
||||
section.rules or
|
||||
section.theme or
|
||||
any(f.widgetOptions for f in section.fields)
|
||||
)
|
||||
if not modified:
|
||||
self._docmodel.insert(
|
||||
table_rec.recordCardViewSectionRef.fields,
|
||||
col_info.get('_position'),
|
||||
colRef=ret['colRef']
|
||||
)
|
||||
|
||||
return ret
|
||||
|
||||
@@ -1807,7 +1846,8 @@ class UserActions(object):
|
||||
columns,
|
||||
manual_sort=True,
|
||||
primary_view=True,
|
||||
raw_section=True)
|
||||
raw_section=True,
|
||||
record_card_section=True)
|
||||
|
||||
|
||||
@useraction
|
||||
@@ -1821,12 +1861,14 @@ class UserActions(object):
|
||||
columns,
|
||||
manual_sort=True,
|
||||
primary_view=False,
|
||||
raw_section=True
|
||||
raw_section=True,
|
||||
record_card_section=True
|
||||
)
|
||||
|
||||
|
||||
def doAddTable(self, table_id, columns, manual_sort=False, primary_view=False,
|
||||
raw_section=False, summarySourceTableRef=0):
|
||||
raw_section=False, record_card_section=False,
|
||||
summarySourceTableRef=0):
|
||||
"""
|
||||
Add the given table with columns with or without additional views.
|
||||
"""
|
||||
@@ -1887,10 +1929,20 @@ class UserActions(object):
|
||||
table_title if not summarySourceTableRef else ""
|
||||
)
|
||||
|
||||
if primary_view or raw_section:
|
||||
if record_card_section:
|
||||
record_card_section = self.create_plain_view_section(
|
||||
result["id"],
|
||||
table_id,
|
||||
self._docmodel.view_sections,
|
||||
"single",
|
||||
""
|
||||
)
|
||||
|
||||
if primary_view or raw_section or record_card_section:
|
||||
self.UpdateRecord('_grist_Tables', result["id"], {
|
||||
'primaryViewId': primary_view["id"] if primary_view else 0,
|
||||
'rawViewSectionRef': raw_section.id if raw_section else 0,
|
||||
'recordCardViewSectionRef': record_card_section.id if record_card_section else 0,
|
||||
})
|
||||
|
||||
return result
|
||||
@@ -1924,6 +1976,7 @@ class UserActions(object):
|
||||
|
||||
# Copy the columns from the raw view section to a new table.
|
||||
raw_section = existing_table.rawViewSectionRef
|
||||
record_card_section = existing_table.recordCardViewSectionRef
|
||||
raw_section_cols = [f.colRef for f in raw_section.fields]
|
||||
col_info = [summary.make_col_info(col=c) for c in raw_section_cols]
|
||||
columns = [summary.get_colinfo_dict(ci, with_id=True) for ci in col_info]
|
||||
@@ -1933,13 +1986,19 @@ class UserActions(object):
|
||||
manual_sort=True,
|
||||
primary_view=False,
|
||||
raw_section=True,
|
||||
record_card_section=True,
|
||||
)
|
||||
|
||||
new_table_id = result['table_id']
|
||||
new_raw_section = self._docmodel.get_table_rec(new_table_id).rawViewSectionRef
|
||||
new_table = self._docmodel.get_table_rec(new_table_id)
|
||||
new_raw_section = new_table.rawViewSectionRef
|
||||
new_record_card_section = new_table.recordCardViewSectionRef
|
||||
|
||||
# Copy view section options to the new raw view section.
|
||||
self._docmodel.update([new_raw_section], options=raw_section.options)
|
||||
# Copy view section options to the new raw and record card view sections.
|
||||
self._docmodel.update(
|
||||
[new_raw_section, new_record_card_section],
|
||||
options=[raw_section.options, record_card_section.options]
|
||||
)
|
||||
|
||||
old_to_new_col_refs = {}
|
||||
for existing_field, new_field in zip(raw_section.fields, new_raw_section.fields):
|
||||
|
||||
Reference in New Issue
Block a user