mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Improving experience when editing group-by column.
Summary: Improving experience when editing group-by column: - Disable column rename - Allow changing most widget properties: - Color/Background - Number format - Date/DateTime format (but not the timezone) - All toggle options (for toggle column) - Remove Edit button on Choice Edit - Changing the underlying column should reset all those options back to the original column. Test Plan: nbrowser Reviewers: alexmojaki Reviewed By: alexmojaki Subscribers: alexmojaki Differential Revision: https://phab.getgrist.com/D3216
This commit is contained in:
@@ -8,6 +8,7 @@ import logger
|
||||
import summary
|
||||
import testutil
|
||||
import test_engine
|
||||
from useractions import allowed_summary_change
|
||||
|
||||
from test_engine import Table, Column, View, Section, Field
|
||||
|
||||
@@ -839,3 +840,96 @@ class Address:
|
||||
[ 1, 1.0, [1,2], 2, 9 ],
|
||||
[ 2, 2.0, [3], 1, 6 ],
|
||||
])
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# pylint: disable=R0915
|
||||
def test_allow_select_by_change(self):
|
||||
def widgetOptions(n, o):
|
||||
return allowed_summary_change('widgetOptions', n, o)
|
||||
|
||||
# Can make no update on widgetOptions.
|
||||
new = None
|
||||
old = None
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
new = ''
|
||||
old = None
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
new = ''
|
||||
old = ''
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
new = None
|
||||
old = ''
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
# Can update when key was not present
|
||||
new = '{"widget":"TextBox","alignment":"center"}'
|
||||
old = ''
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
new = ''
|
||||
old = '{"widget":"TextBox","alignment":"center"}'
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
# Can update when key was present.
|
||||
new = '{"widget":"TextBox","alignment":"center"}'
|
||||
old = '{"widget":"Spinner","alignment":"center"}'
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
# Can update but must leave other options.
|
||||
new = '{"widget":"TextBox","cant":"center"}'
|
||||
old = '{"widget":"Spinner","cant":"center"}'
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
# Can't add protected property when old was empty.
|
||||
new = '{"widget":"TextBox","cant":"new"}'
|
||||
old = None
|
||||
self.assertFalse(widgetOptions(new, old))
|
||||
|
||||
# Can't remove when there was a protected property.
|
||||
new = None
|
||||
old = '{"widget":"TextBox","cant":"old"}'
|
||||
self.assertFalse(widgetOptions(new, old))
|
||||
|
||||
# Can't update by omitting.
|
||||
new = '{"widget":"TextBox"}'
|
||||
old = '{"widget":"TextBox","cant":"old"}'
|
||||
self.assertFalse(widgetOptions(new, old))
|
||||
|
||||
# Can't update by changing.
|
||||
new = '{"widget":"TextBox","cant":"new"}'
|
||||
old = '{"widget":"TextBox","cant":"old"}'
|
||||
self.assertFalse(widgetOptions(new, old))
|
||||
|
||||
# Can't update by adding.
|
||||
new = '{"widget":"TextBox","cant":"new"}'
|
||||
old = '{"widget":"TextBox"}'
|
||||
self.assertFalse(widgetOptions(new, old))
|
||||
|
||||
# Can update objects
|
||||
new = '{"widget":"TextBox","alignment":{"prop":1},"cant":{"prop":1}}'
|
||||
old = '{"widget":"TextBox","alignment":{"prop":2},"cant":{"prop":1}}'
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
# Can't update objects
|
||||
new = '{"widget":"TextBox","cant":{"prop":1}}'
|
||||
old = '{"widget":"TextBox","cant":{"prop":2}}'
|
||||
self.assertFalse(widgetOptions(new, old))
|
||||
|
||||
# Can't update lists
|
||||
new = '{"widget":"TextBox","cant":[1, 2]}'
|
||||
old = '{"widget":"TextBox","cant":[2, 1]}'
|
||||
self.assertFalse(widgetOptions(new, old))
|
||||
|
||||
# Can update lists
|
||||
new = '{"widget":"TextBox","alignment":[1, 2]}'
|
||||
old = '{"widget":"TextBox","alignment":[3, 2]}'
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
|
||||
# Can update without changing list.
|
||||
new = '{"widget":"TextBox","dontChange":[1, 2]}'
|
||||
old = '{"widget":"Spinner","dontChange":[1, 2]}'
|
||||
self.assertTrue(widgetOptions(new, old))
|
||||
# pylint: enable=R0915
|
||||
|
||||
@@ -146,6 +146,32 @@ def guess_type(values, convert=False):
|
||||
return "Numeric" if total and counter[True] >= total * 0.9 else "Text"
|
||||
|
||||
|
||||
def allowed_summary_change(key, updated, original):
|
||||
"""
|
||||
Checks if summary group by column can be modified.
|
||||
"""
|
||||
if updated == original:
|
||||
return True
|
||||
elif key == 'widgetOptions':
|
||||
try:
|
||||
updated_options = json.loads(updated or '{}')
|
||||
original_options = json.loads(original or '{}')
|
||||
except ValueError:
|
||||
return False
|
||||
# Unfortunately all widgetOptions are allowed to change, except choice items. But it is
|
||||
# better to list those that can be changed.
|
||||
# TODO: move choice items to separate column
|
||||
allowed_to_change = {'widget', 'dateFormat', 'timeFormat', 'isCustomDateFormat', 'alignment',
|
||||
'fillColor', 'textColor', 'isCustomTimeFormat', 'isCustomDateFormat',
|
||||
'numMode', 'numSign', 'decimals', 'maxDecimals', 'currency'}
|
||||
# Helper function to remove protected keys from dictionary.
|
||||
def trim(options):
|
||||
return {k: v for k, v in options.items() if k not in allowed_to_change}
|
||||
return trim(updated_options) == trim(original_options)
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class UserActions(object):
|
||||
def __init__(self, eng):
|
||||
self._engine = eng
|
||||
@@ -574,7 +600,7 @@ class UserActions(object):
|
||||
# Type sometimes must differ (e.g. ChoiceList -> Choice).
|
||||
expected = summary.summary_groupby_col_type(expected)
|
||||
|
||||
if value != expected:
|
||||
if not allowed_summary_change(key, value, expected):
|
||||
raise ValueError("Cannot modify summary group-by column '%s'" % col.colId)
|
||||
|
||||
make_acl_updates = acl.prepare_acl_col_renames(self._docmodel, self, renames)
|
||||
|
||||
Reference in New Issue
Block a user