MemberJunction / MemberJunction/MJ
Unify the entity and query grid stacks — let query results render through mj-entity-data-grid instead of a parallel mj-query-data-grid
- Dominant language
- TSQL
- Stars
- 29
- Forks
- 6
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 323
Description
## Summary
MJ ships **two parallel grid stacks** that do substantially the same job:
| | entity path | query path |
|---|---|---|
| viewer | `mj-entity-viewer` (`@memberjunction/ng-entity-viewer`) | `mj-query-viewer` (`@memberjunction/ng-query-viewer`) |
| grid | `mj-entity-data-grid` | `mj-query-data-grid` |
| source | `RunView` over an `EntityInfo` | `RunQuery` over a `MJ: Queries` record |
They are separate packages with separate implementations of the same concerns — columns, sorting,
paging, export, saved grid state, toolbar, selection. A feature or fix landed on one does not reach
the other.
This proposes letting **query results render through the entity grid path**, so there is one grid
implementation and the query path becomes a data source rather than a second stack.
## Why this is worth doing — the capability is already 90% there
`mj-entity-data-grid` **already accepts host-supplied rows and columns**, documented in its own
source as a first-class mode:
```ts
/**
* Pre-loaded data (bypass RunView, use provided data).
* When provided, the grid displays this data instead of loading via RunView.
* Parent component is responsible for data loading and passing results here.
*/
@Input() set Data(value: Record[])
/** Column definitions - if not provided, auto-generates from entity metadata */
@Input() set Columns(value: GridColumnConfig[])
```
So the grid can already render arbitrary rows. What does not exist is the **wrapper**: there is no
query-driven equivalent of `mj-entity-viewer` that would feed a query's results and column metadata
into it. The parallel `mj-query-data-grid` was built instead.
## The concrete cost, from a real app
Two symptoms we hit building a teaching app on v6.1.0-edge.4, both traceable to the split:
1. **The two grids diverge in behaviour for no reason a user can see.** A nav page backed by an
entity and a nav page backed by a query sit next to each other in the same left rail and simply
work differently — different toolbar, different state handling, different affordances. From the
user's side these are both "a table of rows"; the distinction is an implementation detail leaking
into the UI.
2. **Bugs must be found and fixed twice.** We hit a zero-column bug in `mj-entity-data-grid`'s
grid-state path — `buildAgColumnDefsFromGridState()` drops any column setting whose field the
current entity lacks, and `buildAgColumnDefs()` accepts the resulting empty array rather than
falling through to the freshly-built `_columns` (filed separately). Whatever the equivalent
handling is in `mj-query-data-grid`, it is a second implementation with its own bug surface, and
a fix to one is invisible to the other.
The general shape: every future improvement to grid presentation — a new view type, a column
feature, an export format, an accessibility fix — either gets written twice or silently only works
on one kind of page.
## Suggested direction (not prescriptive)
Roughly in increasing order of ambition:
1. **Minimum** — a thin `mj-query-viewer` mode (or a new component) that runs the query and feeds
`mj-entity-data-grid` via `[Data]` + `[Columns]`, mapping `QueryField` metadata to
`GridColumnConfig`. Existing `mj-query-data-grid` callers keep working.
2. **Better** — make "entity-backed" vs "query-backed" a **data source** behind one viewer, so the
view-type system (grid / card / timeline / …) applies to query results too. Card view already
works for entity data; there is no reason a query result set cannot be carded.
3. **Cleanup** — once (2) holds, `mj-query-data-grid` becomes a deprecation candidate.
The main design question is what stands in for `EntityInfo` on the query side. A query already has
field metadata (`MJ: Query Fields`), so much of what the grid reads from `EntityFieldInfo` — display
name, type, formatting — has a counterpart; the parts that genuinely do not (record links, PK-based
row identity, permissions) are exactly the parts a query result legitimately lacks and could degrade
gracefully on.
## Not in scope
The record-detail panel (`mj-query-row-detail`) is fine as-is and this is not a request to change or
remove it — if query results move to the entity grid, an equivalent affordance should come along.
## Context
Found while building MJ Academy (a MemberJunction teaching course) on v6.1.0-edge.4 (`43217fa139`).
The app has a left-rail category whose sub-pages are a mix of entity grids and one stored Query
("Housing Occupancy"); the inconsistency between them is what prompted looking into it.
Contributor guide
Research direction
Start by reading the mj-entity-data-grid source, especially its Data and Columns inputs, then compare the mj-query-data-grid and mj-query-viewer implementations and the QueryField metadata they consume. Define the shared data-source or wrapper design before implementing it. Done means query results use the entity grid path with equivalent columns, toolbar, state, and row-detail behavior, while existing callers remain supported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100