When ?page= param contains a full URL (e.g. https://domain/module/page.ui),
normalize it to relative path (/module/page.ui) before loading.
Applied in _restore, _loadInto, navigate, and _onReplace.
Replace add.svg and delete.svg with minimalist design:
- 1.5px stroke width for thin, elegant appearance
- Round line caps and joins for smooth edges
- Consistent style across both icons
- Uses currentColor for theme compatibility
Add requestAnimationFrame deferred handleInput() call in setValue()
to ensure textarea height recalculates after DOM render, fixing
single-line display when value is set during Form build phase.
Menu widget's menu_clicked() was bypassing the standard _buildWidget
path in bricks.js, so Router._onReplace was never called when navigating
via sidebar menu items. This caused:
- Browser URL not updating on menu clicks
- F5 refresh not restoring the current page
Added Router hook after t.add_widget(w) in menu_clicked(), matching
the same pattern used in bricks.js _buildWidget.
1. Default uitype to 'str' when no alter matches (text input)
2. Handle alter.uitype='select' by converting to code with inline data
3. Read browserfields from opts.row_options.browserfields (CRUD-generated
UIs nest it under row_options, not at opts top level)
When valueField/textField are not explicitly set in opts, the auto-select
logic (line 1140) and nullable empty-option creation (lines 1144-1145) used
data[0][undefined] which returned undefined, causing:
- Single-option selects to show blank (auto-select failed)
- nullable empty options to have undefined keys
Now extracts vf/tf local variables with ||'value'/||'text' fallback at the
top of build_options(), used consistently throughout.
- Remove unused event.target.bricks_widget assignment
- Add check to prevent clicks on interactive elements (A, BUTTON, INPUT, SELECT, TEXTAREA) from triggering row selection
- This ensures toolbar buttons and form inputs inside rows work correctly
Menu constructor hardcoded background to 'white' when no bgcolor option
was provided. This caused white background in sidebar menus regardless
of theme (dark/light). Changed default to 'transparent' so Menu inherits
parent container's themed background color.
- .menuitem: dark bg #334155 + light text #E2E8F0 (with !important to
override Menu widget's inline backgroundColor:white)
- .popup .vbox/.vcontainer/.vscroll: override inline white bg
- .popup h1-h6: light text color for headings
- .mini-window: dark card style for WindowsPanel dock items
- .toppopup: dark shadow variant
Sage shell defaults to dark theme but bricks.css had no dark rules,
causing light-gray text (#8a8a8a) on light backgrounds (#fafafa/#efefef)
in CRUD tables — unreadable against the dark shell.
Added comprehensive [data-theme=dark] overrides:
- body: #CBD5E1 text on #0F172A bg
- .card/.tabular/.tabular-row: dark slate backgrounds
- .inputbox/.popup/.modal/.toolbar: dark variants
- .accordion/.tabpanel/.message: dark variants
When CRUD JSON has data_filter in params:
- Toolbar shows a '搜索' button (name:'filter')
- Click opens PopupWindow with Form widget
- Form fields are dynamically generated from data_filter definition
- Extracts all {var, field, op} from AND/OR/NOT nested structure
- Supports dropdown (uitype:'code') via browserfields.alters config
- Customizable labels via filter_labels option
- Form submit collects values → stored in this.filter_values
- merge_search_params() sends data_filter (JSON string) + each var value
to backend API as URL parameters
- Backend .dspy uses sqlor.filter.DBFilter.gen(ns) for SQL WHERE clause
Deleted previous inline DataFilter widget approach; replaced with
popup Form pattern that matches existing CRUD edit/add form UX.
- New bricks.DataFilter widget (bricks/data_filter.js): parses data_filter
JSON definition, renders search input fields for each var parameter,
supports AND/OR/NOT nested structures, and UiCode dropdowns for fields
with browserfields.alters uitype=code configuration.
- Modified DataViewer (bricks/dataviewer.js): added build_datafilter_widget(),
filter_event_handle(), filter_clear_handle() methods; extended
merge_search_params() to send data_filter JSON + collected var values
to the backend API.
- Updated build.sh: added data_filter.js to the JS concatenation list.
Backend integration: DataViewer sends data_filter (JSON string) and
each var's user input value as URL params. Backend .dspy uses
sqlor.filter.DBFilter to convert to SQL WHERE clause.