From 5295a1ce8f3aa7b4375bd19376eab9ccd211aacd Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Mon, 22 Jun 2026 11:56:15 +0800 Subject: [PATCH] feat: auto-enrich data_filter code fields with valueField/textField/params/dataurl from model codes When data_filter declares uitype='code' for a search field, xls2crud now automatically looks up the matching code definition in models/*.json codes array and populates valueField, textField, params (dbname/table/tblvalue/ tbltext), and dataurl. This prevents UiCode crash (Cannot read properties of undefined reading 'length') in InlineForm search forms. --- xls2ddl/__pycache__/tmpls.cpython-312.pyc | Bin 14016 -> 14912 bytes xls2ddl/__pycache__/xls2crud.cpython-312.pyc | Bin 19761 -> 22249 bytes xls2ddl/__pycache__/xls2ui.cpython-312.pyc | Bin 0 -> 3059 bytes xls2ddl/tmpls.py | 8 +++- xls2ddl/xls2crud.py | 48 +++++++++++++++++++ 5 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 xls2ddl/__pycache__/xls2ui.cpython-312.pyc diff --git a/xls2ddl/__pycache__/tmpls.cpython-312.pyc b/xls2ddl/__pycache__/tmpls.cpython-312.pyc index 9b46479d98662e3b9484a060be2ccb8c9e03fca9..200496c6c7e6af393a04d7c329e6b3c383ff4910 100644 GIT binary patch delta 903 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 delta 2088 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 list: + """Build enriched filter field list for InlineForm search form. + When a data_filter field has uitype='code', auto-populate + valueField/textField/params/dataurl from the model's codes definition.""" + if not desc.data_filter or not desc.data_filter.get('fields'): + return [] + codes_map = {} + if desc.codes: + for c in desc.codes: + cfield = c.field if isinstance(c, dict) else getattr(c, 'field', None) + if cfield: + codes_map[cfield] = c + modulename = getattr(desc, 'modulename', '') + result = [] + for f in desc.data_filter.fields: + field_name = f.field if isinstance(f, dict) else getattr(f, 'field', '') + field_title = f.title if isinstance(f, dict) else getattr(f, 'title', '') + field_uitype = f.uitype if isinstance(f, dict) else getattr(f, 'uitype', 'str') + field_def = { + 'name': field_name, + 'uitype': field_uitype, + 'placeholder': field_title, + 'cwidth': 15 + } + if field_uitype == 'code' and field_name in codes_map: + c = codes_map[field_name] + ctable = c.table if isinstance(c, dict) else getattr(c, 'table', '') + cvaluefield = c.valuefield if isinstance(c, dict) else getattr(c, 'valuefield', '') + ctextfield = c.textfield if isinstance(c, dict) else getattr(c, 'textfield', '') + ccond = (c.cond if isinstance(c, dict) else getattr(c, 'cond', None)) + field_def['valueField'] = field_name + field_def['textField'] = field_name + '_text' + field_def['params'] = { + 'dbname': "{{get_module_dbname('" + modulename + "')}}", + 'table': ctable, + 'tblvalue': cvaluefield, + 'tbltext': ctextfield, + 'valueField': field_name, + 'textField': field_name + '_text' + } + if ccond: + field_def['params']['cond'] = ccond + field_def['dataurl'] = "{{entire_url('/appbase/get_code.dspy')}}" + result.append(field_def) + return result + def build_data_browser(pat: str, desc: dict): desc = desc.copy() desc.fieldliststr = json.dumps(field_list(desc), ensure_ascii=False, indent=4) + desc.filter_fields = build_filter_field_list(desc) + desc.filterfieldstr = json.dumps(desc.filter_fields, ensure_ascii=False, indent=4) e = MyTemplateEngine([]) s = e.renders(data_browser_tmpl, desc) with codecs.open(os.path.join(pat, f'index.ui'), 'w', "utf-8") as f: