Activity Search Phase 1#1875
Conversation
237d865 to
2a5f418
Compare
|
This feels very useful, so much potential here |
9e5e9c4 to
1849440
Compare
b91a810 to
34a44a1
Compare
425dfe5 to
032a64a
Compare
dandelany
left a comment
There was a problem hiding this comment.
Still working on testing, but I noticed one potential issue with IDs I wanted to call out early - see review comments.
| <BulkActionDataGrid | ||
| bind:dataGrid | ||
| bind:selectedItemIds | ||
| idKey="id" |
There was a problem hiding this comment.
If I'm following correctly, this is the id field of an activity_directive row used as primary ID key for the data grid. This may cause problems here because (confusingly) directive IDs are not unique on their own, they're only unique within a given plan - eg. a branch/duplicate plan will have activities with the same IDs as the original. See the postgres schema here, which uses a compound primary key (id, plan_id):
We have gotten away with using this ID in other places in UI because they are single-plan only, but since activity search is explicitly cross-plan this will likely cause subtle problems when results contain duplicate IDs from several plans - we should copy the backend and key by a compound (id, plan_id) string here if possible.
There was a problem hiding this comment.
Ah yes, good catch, can make a compound key here.
| return []; | ||
| } | ||
| const idSet = new Set(selectedItemIds); | ||
| return activities.filter(a => idSet.has(a.id)); |
There was a problem hiding this comment.
See comment below re: non-unique activity directive IDs, I believe it applies here too
|
|
||
| export function copyActivityDirectivesToClipboard(sourcePlan: Plan, activities: ActivityDirective[]) { | ||
| export function copyActivityDirectivesToClipboard(sourcePlan: Plan | null, activities: ActivityDirective[]) { | ||
| const copiedActivityIds = new Set(activities.map(a => a.id)); |
There was a problem hiding this comment.
Same comment from above re: activity directive IDs may apply in this function too, it seems to be assuming unique directive IDs
There was a problem hiding this comment.
Yep this does not support cross-plan activity copying. Will take a look.
There was a problem hiding this comment.
Resolved in latest commit, take a look.
- Server-side pagination (offset + aggregate count) with first/prev/next/last controls - Expanded filters: plan name/owner, created_by, last-modified date range, scheduling-goal origin - Argument name dropdown driven by the selected model's activity type parameter schemas; narrows further when an activity type is selected - Server-side sort: AG Grid column state translated to nested Hasura order_by - All filter state encoded in URL query params (bookmarkable / shareable searches), initialized on load with deferred model-id resolution while subscription primes - Result table: tag chips, JSON arguments column, formatted timestamps via getShortISOForDate, plus toggleable Created At / Plan ID / Activity ID columns - Column picker (ActivityTableMenu) with show/hide all + reset; column state persisted via localStorage. Forward columnVisible / columnsReset events through SingleActionDataGrid so the picker can react - Search button always enabled; auto-search-on-load still gated on a non-empty filter
Adds persistColumnStateKey + transformColumnState props on DataGrid (forwarded through BulkAction/SingleActionDataGrid). WorkspaceFileBrowser drops its duplicated save/clear logic and rides its name-column processing through transformColumnState.
Replace maxOptionChars*8 width estimate with canvas measureText, reading the font off a hidden DOM ref so it tracks CSS. Pass items through RowVirtualizerFixed as a slot prop (fixes stale content when array changes in place). Add loading prop. TimelineItemList + mock updated for new virtualizer API.
Mission Model uses SearchableDropdown. Collapse pending-model state into a single selectedModelId (selectedModel derived). Inline subscription-error banner. Per-dropdown loading. Start Offset min/max filters. Argument Value defaults tooltip. Search always enabled, above Clear, sticky footer. 500ms-delayed spinner overlay over results; no-op local sort comparators avoid the flash before server-sorted data lands. SearchResults adopts the new persistColumnStateKey for column-state persistence.
UI / UX - Multi-select Activity Type filter (`_in` clause); arg-name dropdown handles multi - New filters: Last Modified By, Created After/Before, Plan Tag, Scheduling Goal - New columns: Model, Model ID, Absolute Start Time, Scheduling Goal - Column order regrouped: action → identity → plan/model → tagging → timing → audit → provenance - Open-in-plan: Svelte component cell, full-cell click, pinned-left icon column - Right-click context menu: "Copy N Activit(ies)" and "Open in plan" (single-select) - Click-drag column resize (no shift-key required) - Open-in-plan exempt from column picker and the "hide all" sweep Behavior fixes - Cross-plan paste respects the right-click paste-at-time even when the source activities' absolute times fall outside the target plan window - Arg value matching: JSON.parse + singleton-array sugar so typing `5` finds `XYZ: 5` and `XYZ: [1, 2, 5]`; numeric/bool branch covers all four shapes - Drop the `directive_id: id` gql alias — fixes Hasura sort error on Activity ID - DataGrid: querySelectorAll so the selected-row class stays in sync between center and pinned-left containers (fixes the two-tone selected row bug) Types / internals - ActivityDirectiveSearchResult now extends ActivityDirectiveDB instead of redefining shared fields; corrects applied_preset shape along the way - SEARCH_ACTIVITIES extends plan with mission_model, adds source_scheduling_goal, anchor_id, anchored_to_start, metadata for the clipboard mapping - Use ColumnPinnedType / SortDirection imports for the two literal ColDef fields
Activity directive ids are unique per-plan but not globally; cross-plan search results can collide on the bare id. Key the search results grid and the clipboard/paste anchor remap by (plan_id, id) so row identity, selection, and anchor preservation stay scoped to the source plan.
8265694 to
c4a558e
Compare
|
@AaronPlave is working on testing this at larger scale (~100k-1M directives), will hold off on final approval until done |
@dandelany did some performance testing and found that with 500k activities search performance was usually under a few seconds with the exception of search with a sort on directives by plan name (requiring a join) with no other significant filters to reduce result set - in that case search was slower but maybe 5-10 seconds on my machine, which feels like acceptable performance. |
Summary
New
/searchpage for finding activity directives across all plans, plus shared-component improvements that came out of building it.Search page
Filters (all bookmarkable via URL query params):
5matchesXYZ: 5andXYZ: [1, 2, 5]; arrays/structs accepted as JSON)Results:
Columns (default-visible unless noted):
Selection & cross-plan copy:
Shared changes
DataGrid:
persistColumnStateKey+transformColumnStateprops centralize column-state localStorage save/clearBulkActionDataGridandSingleActionDataGridtransformColumnStateSearchableDropdown:
measureTextwith font read off a hidden DOM ref (replaces themaxOptionChars * 8heuristic that overshot for proportional fonts)RowVirtualizerFixedas a slot prop so menus refresh while openloadingproptype="button"so Enter inside a sibling input no longer toggles the menuRowVirtualizerFixed:
itemsprop replacescount; slot exposesitemBug fixes & polish
querySelectorAllso pinned-left and center containers stay in sync (fixes two-tone selected row with pinned columns — affects every table with pinned columns, not just search)Test plan
TODO
Future Work
Future directions for this work could involve:
/searchpage