derived-variables.cy.ts:97 expected dc-derived-first on the REGION header,
because the comment assumed REGION opens the computed block. The grid follows
MPE_DERIVED order, and that order is LINE_VALUE, REGION, REGION_LABEL - so the
marker was on LINE_VALUE and correct. The spec asserted the wrong column, and
the development pipeline has been red on it since.
Dumping the header row on a local mock estate (sasjs/server desktop mode,
RUN_TIMES=js) shows:
6 | LINE_VALUE | dc-derived-header dc-derived-first
7 | REGION | dc-derived-header
8 | REGION_LABEL | dc-derived-header beforeHiddenColumn htLastVisibleHeader
and the same dump against the unmodified release/7.19 client, so this was never
a client defect.
The assertion now states the invariant instead: at least one derived header, the
first of them opens the block, and no other one carries the marker. That holds
whatever order the control table returns the variables in.
The hover text on a derived column said only that the column cannot be edited,
which tells the user nothing about what it holds. It now carries the column
label - the configured VAR_LABEL, or the generated name=expression that
mp_derivedvars writes when the administrator left the label blank - and falls
back to the plain rule when the label merely repeats the column name.
The cypress case that marks derived columns apart now also checks the tooltip
for both shapes: REGION_LABEL carries a configured label, REGION falls back to
the generated one.
Derived variables are read-only, but they were rendered exactly like any other
read-only column: dimmed via readonlyCell, with no indication that the column is
computed at read time rather than locked by a rule or by column level security.
The grid could not tell the difference either - getdata holds a derived column
read-only with a READONLY DQ rule, which is also a rule type a table can be
configured with.
getdata now names the derived columns in sasparams.DERIVEDVARS (space separated,
upper case, from MPE_DERIVED's outvars). The EDIT screen holds that list, and
marks those columns with their own classes instead of the read-only dimming:
a tinted header with an 'fx' marker and a tooltip, tinted italic cells, and a
left edge on the first derived column so the computed block reads as a group.
Blue is the info family, leaving the primary key green and the warning ochre to
their existing meanings. Light and dark values are both set.
The SASjs mock getdata.js returns the same field, so the Cypress suite exercises
the styling; the existing derived-variables spec asserted readonlyCell on the
derived header, which is now the fallback for a plain read-only column, so that
assertion moves to dc-derived-header and a physical column stays the control.
Lint: prettier --check clean on the touched client files; sasjs lint reports no
new warnings for getdata.sas.
The case rested on an editor not appearing after a fixed wait, which passes for
any reason the editor did not open. The editor marks a read-only column with
readonlyCell on the header and on its cells, and STATE in the same grid is the
control, so the state is asserted directly and the sleep goes.
Mutating the mock to drop the READONLY rule fails the case on exactly that
assertion (expected '<th.darkTH>' to have class 'readonlyCell'); restoring it
passes 5/5 in about 50s.
should('not.exist') passes the moment the element is missing, so a timeout on
it does not widen the window: an editor that opens after the assertion has
already passed goes unnoticed. The wait gives it that window, which is what the
case needs to rule the cell's editability out.
The screen opens read-only until the edit button is pressed, so the case
asserted nothing about the column: no cell opened an editor. It now enters edit
mode first, asserts the editor's absence directly rather than typing at
whatever happens to be focused, and a sibling case proves a physical column in
the same grid does open one - so the silence is about the column, not the
screen.
Mutating the mock to drop the READONLY rule fails the derived case and passes
the physical one; restoring it passes both (5/5, ~48s).
COLS.CLS_RULE is the only thing that marks a column read-only in the grid,
and the client applies it only when CLS_FLAG is set - which column level
security drives. A table with no CLS rules therefore rendered its derived
columns as ordinary editable cells, although the values are computed at read
time and dropped from the submission.
getdata now unions a READONLY dq rule per derived variable, which the client
honours unconditionally, and the mock emits the same rule. The SAS test
asserts the rule; the cypress spec double-clicks a derived cell and asserts the
value is unchanged.
A derived variable may need to reference one defined before it (a label that
concatenates a derived region, for example), so the order has to be
configured rather than assumed.
- MPE_DERIVED: new VARIABLE_ORDER column (ddl, makedatamodel, migration).
- mpe_derived: statements are generated in VARIABLE_ORDER then name sequence.
VARIABLE_ORDER is required and must be a positive integer. A reference to a
derived variable with an equal or higher order is rejected, because SAS
would otherwise treat it as uninitialised and return a missing value with no
error; references to lower-order variables are allowed.
- mock: same ordering, each variable compiled against the physical columns
plus those defined earlier, so the frontend can exercise a chained variable.
- makedata: VARIABLE_ORDER on both demo rows plus a chained REGION_LABEL.
- cypress: asserts the chained value in the grid.
- tests: the getdata test seeds a second variable built on the first.
- docs: VARIABLE_ORDER documented, with the ordered rule replacing the
self-contained one.
So the EDIT screen can be exercised before a SAS server is available.
- dcMockUtils: mpeDerived() reads MPE_DERIVED for a table and mpeDeriveRows()
adds the computed columns to the rows and to the schema, before the filter
runs - the same order as the real service.
- compileSasExpression() covers the subset of SAS expression syntax the mock
configs use (ifc, cats, catx, upcase, lowcase, strip, trim, length, substr,
index, comparisons, AND/OR and IN). Anything else leaves the column missing,
as a failing SAS expression would. The real evaluation is done by SAS.
- getdata / getcolvals apply the derivation before filtering, so a filter on a
derived column works and dropdown values come from the derived data.
- makedata: MPE_DERIVED schema and rows, a new TESTDATA.DERIVED_DEMO table
(REGION, LINE_VALUE) and its MPE_TABLES registration.
- cypress: derived-variables.cy.ts covers display and filtering on a character
and a numeric derived column.
Also bumps @sasjs/core to 5.6.0, which provides the mp_filterstore targetds=
parameter the validatefilter change depends on.