- Replace old implementation of PROCESSOR_TYPES and CATALOG_TYPES with the new cached approach
- Add an ordered_list dynamic field type (to be refined) - Add tabulator javascript library to project
This commit is contained in:
@@ -49,6 +49,51 @@ class ChunkingPatternsField(TextAreaField):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class OrderedListField(TextAreaField):
|
||||
"""Field for ordered list data that will be rendered as a Tabulator table"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
list_type = kwargs.pop('list_type', '')
|
||||
|
||||
# Behoud bestaande render_kw attributen als die er zijn
|
||||
if 'render_kw' in kwargs:
|
||||
existing_render_kw = kwargs['render_kw']
|
||||
else:
|
||||
existing_render_kw = {}
|
||||
|
||||
current_app.logger.debug(f"incomming render_kw for ordered list field: {existing_render_kw}")
|
||||
|
||||
# Stel nieuwe render_kw samen
|
||||
new_render_kw = {
|
||||
'data-list-type': list_type,
|
||||
'data-handle-enter': 'true'
|
||||
}
|
||||
|
||||
# Voeg klasse toe en behoud bestaande klassen
|
||||
if 'class' in existing_render_kw:
|
||||
existing_classes = existing_render_kw['class']
|
||||
if isinstance(existing_classes, list):
|
||||
existing_classes += ' ordered-list-field'
|
||||
new_render_kw['class'] = existing_classes
|
||||
else:
|
||||
# String classes samenvoegen
|
||||
new_render_kw['class'] = f"{existing_classes} ordered-list-field"
|
||||
else:
|
||||
new_render_kw['class'] = 'ordered-list-field'
|
||||
|
||||
# Voeg alle bestaande attributen toe aan nieuwe render_kw
|
||||
for key, value in existing_render_kw.items():
|
||||
if key != 'class': # Klassen hebben we al verwerkt
|
||||
new_render_kw[key] = value
|
||||
|
||||
current_app.logger.debug(f"final render_kw for ordered list field: {new_render_kw}")
|
||||
|
||||
# Update kwargs met de nieuwe gecombineerde render_kw
|
||||
kwargs['render_kw'] = new_render_kw
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class DynamicFormBase(FlaskForm):
|
||||
def __init__(self, formdata=None, *args, **kwargs):
|
||||
super(DynamicFormBase, self).__init__(*args, **kwargs)
|
||||
@@ -89,6 +134,8 @@ class DynamicFormBase(FlaskForm):
|
||||
validators_list.append(self._validate_tagging_fields_filter)
|
||||
elif field_type == 'dynamic_arguments':
|
||||
validators_list.append(self._validate_dynamic_arguments)
|
||||
elif field_type == 'ordered_list':
|
||||
validators_list.append(self._validate_ordered_list)
|
||||
|
||||
return validators_list
|
||||
|
||||
@@ -227,10 +274,52 @@ class DynamicFormBase(FlaskForm):
|
||||
except Exception as e:
|
||||
raise ValidationError(f"Invalid argument definition: {str(e)}")
|
||||
|
||||
def _validate_ordered_list(self, form, field):
|
||||
"""Validate the ordered list structure"""
|
||||
if not field.data:
|
||||
return
|
||||
|
||||
try:
|
||||
# Parse JSON data
|
||||
list_data = json.loads(field.data)
|
||||
|
||||
# Validate it's a list
|
||||
if not isinstance(list_data, list):
|
||||
raise ValidationError("Ordered list must be a list")
|
||||
|
||||
# Validate each item in the list is a dictionary
|
||||
for i, item in enumerate(list_data):
|
||||
if not isinstance(item, dict):
|
||||
raise ValidationError(f"Item {i} in ordered list must be an object")
|
||||
|
||||
except json.JSONDecodeError:
|
||||
raise ValidationError("Invalid JSON format")
|
||||
except Exception as e:
|
||||
raise ValidationError(f"Invalid ordered list: {str(e)}")
|
||||
|
||||
def add_dynamic_fields(self, collection_name, config, initial_data=None):
|
||||
"""Add dynamic fields to the form based on the configuration."""
|
||||
"""Add dynamic fields to the form based on the configuration.
|
||||
|
||||
Args:
|
||||
collection_name: The name of the collection of fields to add
|
||||
config: The full configuration object, which should contain the field definitions
|
||||
for the collection_name and may also contain list_type definitions
|
||||
initial_data: Optional initial data for the fields
|
||||
"""
|
||||
current_app.logger.debug(f"Adding dynamic fields for collection {collection_name} with config: {config}")
|
||||
# Store the full configuration for later use in get_list_type_configs_js
|
||||
if not hasattr(self, '_full_configs'):
|
||||
self._full_configs = {}
|
||||
self._full_configs[collection_name] = config
|
||||
|
||||
# Get the specific field configuration for this collection
|
||||
field_config = config.get(collection_name, {})
|
||||
if not field_config:
|
||||
# Handle the case where config is already the specific field configuration
|
||||
return
|
||||
|
||||
self.dynamic_fields[collection_name] = []
|
||||
for field_name, field_def in config.items():
|
||||
for field_name, field_def in field_config.items():
|
||||
# Prefix the field name with the collection name
|
||||
full_field_name = f"{collection_name}_{field_name}"
|
||||
label = field_def.get('name', field_name)
|
||||
@@ -264,6 +353,12 @@ class DynamicFormBase(FlaskForm):
|
||||
field_class = ChunkingPatternsField
|
||||
extra_classes = ['monospace-text', 'pattern-input']
|
||||
field_kwargs = {}
|
||||
elif field_type == 'ordered_list':
|
||||
current_app.logger.debug(f"Adding ordered list field for {full_field_name}")
|
||||
field_class = OrderedListField
|
||||
extra_classes = ''
|
||||
list_type = field_def.get('list_type', '')
|
||||
field_kwargs = {'list_type': list_type}
|
||||
else:
|
||||
extra_classes = ''
|
||||
field_class = {
|
||||
@@ -289,6 +384,12 @@ class DynamicFormBase(FlaskForm):
|
||||
except (TypeError, ValueError) as e:
|
||||
current_app.logger.error(f"Error converting initial data to JSON: {e}")
|
||||
field_data = "{}"
|
||||
elif field_type == 'ordered_list' and isinstance(field_data, list):
|
||||
try:
|
||||
field_data = json.dumps(field_data)
|
||||
except (TypeError, ValueError) as e:
|
||||
current_app.logger.error(f"Error converting ordered list data to JSON: {e}")
|
||||
field_data = "[]"
|
||||
elif field_type == 'chunking_patterns':
|
||||
try:
|
||||
field_data = json_to_patterns(field_data)
|
||||
@@ -305,6 +406,9 @@ class DynamicFormBase(FlaskForm):
|
||||
render_kw['data-bs-toggle'] = 'tooltip'
|
||||
render_kw['data-bs-placement'] = 'right'
|
||||
|
||||
|
||||
current_app.logger.debug(f"render_kw for {full_field_name}: {render_kw}")
|
||||
|
||||
# Create the field
|
||||
field_kwargs.update({
|
||||
'label': label,
|
||||
@@ -340,6 +444,73 @@ class DynamicFormBase(FlaskForm):
|
||||
# Return all fields that are not dynamic
|
||||
return [field for name, field in self._fields.items() if name not in dynamic_field_names]
|
||||
|
||||
def get_list_type_configs_js(self):
|
||||
"""Generate JavaScript code for list type configurations used by ordered_list fields."""
|
||||
from common.extensions import cache_manager
|
||||
|
||||
list_types = {}
|
||||
|
||||
# First check if we have any full configurations stored
|
||||
if hasattr(self, '_full_configs'):
|
||||
# Look for list types in the stored full configurations
|
||||
for config_name, config in self._full_configs.items():
|
||||
for key, value in config.items():
|
||||
# Check if this is a list type definition (not a field definition)
|
||||
if isinstance(value, dict) and all(isinstance(v, dict) for v in value.values()):
|
||||
# This looks like a list type definition
|
||||
list_types[key] = value
|
||||
|
||||
# Collect all list types used in ordered_list fields
|
||||
for collection_name, field_names in self.dynamic_fields.items():
|
||||
for full_field_name in field_names:
|
||||
field = getattr(self, full_field_name)
|
||||
if isinstance(field, OrderedListField):
|
||||
list_type = field.render_kw.get('data-list-type')
|
||||
if list_type and list_type not in list_types:
|
||||
# First try to get from current_app.config
|
||||
list_type_config = current_app.config.get('LIST_TYPES', {}).get(list_type)
|
||||
if list_type_config:
|
||||
list_types[list_type] = list_type_config
|
||||
else:
|
||||
# Try to find the list type in specialist configurations using the cache
|
||||
try:
|
||||
# Get all specialist types
|
||||
specialist_types = cache_manager.specialists_types_cache.get_types()
|
||||
|
||||
# For each specialist type, check if it has the list type we're looking for
|
||||
for specialist_type in specialist_types:
|
||||
try:
|
||||
# Get the latest version for this specialist type
|
||||
latest_version = cache_manager.specialists_version_tree_cache.get_latest_version(specialist_type)
|
||||
|
||||
# Get the configuration for this specialist type and version
|
||||
specialist_config = cache_manager.specialists_config_cache.get_config(specialist_type, latest_version)
|
||||
|
||||
# Check if this specialist has the list type we're looking for
|
||||
if list_type in specialist_config:
|
||||
list_types[list_type] = specialist_config[list_type]
|
||||
break
|
||||
except Exception as e:
|
||||
current_app.logger.debug(f"Error checking specialist {specialist_type}: {e}")
|
||||
continue
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Error retrieving specialist configurations: {e}")
|
||||
|
||||
# If no list types found, return empty script
|
||||
if not list_types:
|
||||
return ""
|
||||
|
||||
# Generate JavaScript code
|
||||
js_code = "<script>\n"
|
||||
js_code += "window.listTypeConfigs = window.listTypeConfigs || {};\n"
|
||||
|
||||
for list_type, config in list_types.items():
|
||||
js_code += f"window.listTypeConfigs['{list_type}'] = {json.dumps(config, indent=2)};\n"
|
||||
|
||||
js_code += "</script>\n"
|
||||
|
||||
return js_code
|
||||
|
||||
def get_dynamic_fields(self):
|
||||
"""Return a dictionary of dynamic fields per collection."""
|
||||
result = {}
|
||||
@@ -361,7 +532,7 @@ class DynamicFormBase(FlaskForm):
|
||||
if field.type == 'BooleanField':
|
||||
data[original_field_name] = full_field_name in self.raw_formdata
|
||||
current_app.logger.debug(f"Value for {original_field_name} is {data[original_field_name]}")
|
||||
elif isinstance(field, (TaggingFieldsField, TaggingFieldsFilterField, DynamicArgumentsField)) and field.data:
|
||||
elif isinstance(field, (TaggingFieldsField, TaggingFieldsFilterField, DynamicArgumentsField, OrderedListField)) and field.data:
|
||||
try:
|
||||
data[original_field_name] = json.loads(field.data)
|
||||
except json.JSONDecodeError:
|
||||
@@ -443,4 +614,4 @@ def validate_tagging_fields(form, field):
|
||||
except json.JSONDecodeError:
|
||||
raise ValidationError("Invalid JSON format")
|
||||
except (TypeError, ValueError) as e:
|
||||
raise ValidationError(f"Invalid field definition: {str(e)}")
|
||||
raise ValidationError(f"Invalid field definition: {str(e)}")
|
||||
|
||||
Reference in New Issue
Block a user