Skip to content

feat(tracker): Gantt — #10 bar coloring + overlays + sub-issue progress#10873

Draft
MichaelUray wants to merge 389 commits into
hcengineering:developfrom
MichaelUray:feat/gantt-bar-colors
Draft

feat(tracker): Gantt — #10 bar coloring + overlays + sub-issue progress#10873
MichaelUray wants to merge 389 commits into
hcengineering:developfrom
MichaelUray:feat/gantt-bar-colors

Conversation

@MichaelUray

@MichaelUray MichaelUray commented May 21, 2026

Copy link
Copy Markdown
Contributor

Stack context

This PR sits on top of #10872 (PR9 — filter chips + advanced search + view-option toggles, currently Draft) which in turn sits on top of the #10851 PR1#10859 PR7 Gantt feature series.

The diff against develop therefore shows the full dependent stack (PR1-PR7 + PR9 + bar-colors). The actual marginal content of this PR is documented below. Once the dependent PRs merge, this branch will be rebased onto upstream develop and the diff collapses to bar-colors only.

This PR is opened as Draft to give visibility into the planned feature surface and let CI run early — same convention as PR2-PR7.

Marginal bar-colors content (what this PR actually adds)

13 commits introducing the bar-coloring feature on top of the read-only/edit/dependencies/polish/tier2 viewlet, plus 3 small polish commits after the Plan-2 merge:

Core bar-coloring (13 commits)

Commit Description
1e10fc40b8 Bump contrast on Todo + Cancelled status bars
04eb240601 Add GanttBarIssueLike type + isPastDue / isBlocked predicates
fa5da87709 Add optional color field to Component and Milestone schemas
459a3740d3 ColorsPopup swatch in EditComponent + EditMilestone
76bac88823 Pure bar-color resolver for 6 color modes (Status / Priority / Assignee / Component / Milestone / Uniform)
0ada4c51c0 Extend GanttSavedViewOptions with 4 new toolbar fields
04ac2090fa Wire bar-color resolver into GanttView + GanttBar
b722d66c47 Render past-due stripe + blocked hatch overlays
323e93fbba Sub-issue progress fill (Status mode only)
3c0543807d Toolbar Color by dropdown with 6 modes
6a54362064 Persist bar-color toolbar state in saved views
3a7be3d271 Expose overlay + progress toggles in ganttViewOptions (Customize-View popover)
0547f5dcb0 Lighten canvas background

Post-Plan-2-merge polish (3 commits)

Commit Description
c228d5f7f7 Compact Group-by + Color-by toolbar dropdowns
f71613c2d7 Shorten GanttColorByNone label + cap select intrinsic width

Filter/view regression fixes (5 commits)

Regressions found and fixed during the last live-testing session:

  • fix(view): filter mutators emit fresh arrays (L-VF1)
  • re-arm List queryReady (L-VF2)
  • highlight each query term (L-VF3)
  • aria-expanded on overflow badge (L-VF6)
  • intersect $lte/$gte date bounds (L-VF7)

Feature summary

  • 6 color modes selectable from the toolbar Color by dropdown:
    • Status (default) — issue lifecycle stage
    • Priority — Urgent / High / Medium / Low / No-priority
    • Assignee — distinct hue per person
    • Component — uses the new optional color field on Component (falls back to a generated hue if unset)
    • Milestone — same pattern with Milestone color
    • Uniform — single color for all bars (good for screenshots / printing)
  • Overlay layer rendered on top of any base color:
    • Past-due bars get a red left-stripe
    • Blocked bars (finish-to-start predecessor not Done) get a diagonal hatch
    • Sub-issue progress fill (Status mode only) shows how much of the parent's work is Done
  • All toolbar state persists in saved views via 4 new fields on GanttSavedViewOptions. The Customize-View popover (cog icon) exposes the same toggles through ganttViewOptions for users who prefer the popover surface.

Test coverage

  • plugins/tracker-resources jest: 686 tests pass including the new bar-color resolver suites
  • packages/ui jest: 62 tests pass (includes the encoder hardening + leading-hyphen escape from PR9)
  • plugins/view-resources jest: 19 tests pass
  • svelte-check: 0 errors across all three packages

Deployment

This branch (feat/gantt-bar-colors) is currently deployed live at https://huly.uray.io as hardcoreeng/front:plan4-pr9-pr10 for hands-on testing. The feature has been validated end-to-end in the browser including saved-view round-trips and dropdown UX.

Companion docs PR

huly-docs#70 — includes bar-coloring.mdx (the dedicated bar-colors reference) plus 8 screenshots of the feature in action.

DCO

All commits in this PR are Signed-off-by: Michael Uray.

Note on rebasing

When PR9 merges upstream, this branch will be rebased to:

  1. Drop the Plan-2 merge commit (its content arrives via upstream/develop)
  2. Drop the cherry-picked encoder-hardening + leading-hyphen + marker-scrub commits (also in upstream via PR9)
  3. Keep only the 16 bar-colors-specific commits listed above

At that point the PR diff will be a clean bar-colors-only delta.

@huly-github-staging

Copy link
Copy Markdown

Connected to Huly®: UBERF-16463

…view comments

The dependency-add cycle check in the issue-editor panel used only
incoming + outgoing slices of the current issue:

  wouldCreateCycle(sourceId, targetId, [...incoming, ...outgoing])

That catches direct A→A and direct duplicates but misses transitive
cycles. Example: with C→B and B→A already in place, adding A→C from
A's panel passes the check because C→B is not in A's local slice —
the DFS never sees the back-edge B→A→C from the C side, so the new
edge silently closes the loop. The Gantt view already does a
project-wide check; the issue panel must match.

Add a third live-query bound to { space: issue.space } that loads all
relations in the project, and pass the full list to wouldCreateCycle
on add. The visible Predecessors/Successors lists keep using the
existing incoming/outgoing slices.

gantt + dependency code. The substance of each note is preserved but
rephrased so the comments document the technical reason, not the
review thread that surfaced it.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
The optional-chained `getAttribute('content-type')?.includes(...)` yields
`boolean | undefined`; guard the nullish case explicitly with `?? false`
to satisfy @typescript-eslint/strict-boolean-expressions without changing
behaviour (absent/non-JSON content-type still marks recording unavailable).

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…cade tier

Apply the reviewer-approved fix patterns to the pre-existing eslint errors
surfaced by the CI formatting job in the PR3b feature code:
- no-confusing-void-expression: block-body arrows for void event handlers
  (GanttCanvas/GanttSidebar/ConfirmCascadePopup/GanttHelpPopup dblclick/click/
  cleanup handlers).
- no-misused-promises: single stable void-wrapper (onWindowPointerUp) shared by
  attach/detach so the listener reference stays paired.
- prefer-optional-chain: nested {#if} guards preserving TS narrowing
  (GanttCanvas connector overlay, GanttDependencyLayer) and loose == null form.
- no-invalid-void-type: dispatcher payload void -> undefined (matches the
  codebase convention).
- strict-boolean-expressions: explicit zero / nullish handling in
  dependency-router and exporter.
- test files: drop non-null assertions in favour of optional chaining, remove
  unused imports/vars, rename snake_case locals to camelCase.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…ter develop merge

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…useup wrapper

The cascade merge + eslint import consolidation left three type errors
svelte-check flags in the PR3b GanttView:
- the './lib/types' import got merged into an `import type { ... }` with
  redundant inner `type` modifiers (invalid syntax) — flatten to plain names;
- `getEventPositionElement` was dropped from the @hcengineering/ui import —
  restore it (used by openGanttMenu);
- an onWindowMouseUp wrapper carried over from the PR3a edit tier referenced
  handleCanvasMouseUp, which PR3b renamed to handleCanvasPointerUp (wrapped as
  onWindowPointerUp) — remove the now-dead, dangling wrapper.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Der Add-Sub-Issue-Button oeffnet seit bc2414a (unified hierarchy add
chooser) nicht mehr direkt das CreateIssue-Formular, sondern zuerst den
HierarchyAddPopup mit den Optionen 'Create new sub-issue' /
'Link existing as sub-issue'. Die Playwright-page-objects clicken den
Zwischenschritt jetzt mit, bevor das Formular gefuellt wird:

 - IssuesPage.clickOnSubIssues        (subissues.spec 'create sub-issue')
 - IssuesDetailsPage.clickButtonAddSubIssue
   (subissues.spec 'Edit a sub-issue' / 'Delete a sub-issue')

Keine Assertion abgeschwaecht, kein Timeout erhoeht — nur der neue
UI-Pfad wird durchlaufen (analog zur milestone-page-object-Anpassung in

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
hcengineering#10851).
…ional

The Gantt schema PR (ControlPanel) adds several unconditional rows between
Assignee and Estimation in the issue side panel (Start date, Due date,
Deadline, Scheduling mode). The prior positional locator
(//span[text()="Estimation"]/../div/button)[N] had to be re-indexed each
time a row was added and had drifted to [5], which no longer resolves to the
Estimation editor button — so editIssue's estimation step could never open
the EditBoxPopup and 'div.selectPopup input' never appeared, failing
issues.spec:49 'Edit an issue' and subissues.spec:52 'Edit a sub-issue'.

Switch buttonEstimation to the same following-sibling path already used by
textEstimation, which targets the Estimation label's own editor button
regardless of how many rows precede it.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Restore the ru.json dependency/cascade i18n keys and the final Gantt
component sources that were carried into this branch via a merge commit.
Linearizing the branch onto the new develop dropped that merge, so this
commit re-materializes the exact intended tip content (develop does not
touch these files).

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…tics

The Alt-bypass violation count was still computing FS with the old
'predDue + lag' (no +1-day) formula. Aligning it with the new fsAnchor
helpers keeps Alt-bypass agreeing with cascade decisions and the CP
overlay in both legacy and working-days modes.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…heduler/CP

GanttView now subscribes to the current Project document and reads its
optional workingDaysConfig. The config is forwarded to:
- computeCriticalPath via the new third argument (cfg)
- simulateCascade via options.workingDays

Reactive: a project-config change retriggers the debounced CP recompute
exactly as issue/relation mutations already do. Spaces without a Project
(or with no config set) keep legacy calendar-day behaviour.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…ix FS +1d off-by-one

simulateCascade now accepts an optional WorkingDaysConfig via
`options.workingDays`. Forward and backward FS/SS/FF/SF anchor math
routes through the new working-days helpers, which fall back to legacy
calendar-day arithmetic when no config is given.

The legacy branch also implements the +1-day FS rule that critical-path
already obeys. Previously scheduler.ts computed FS successor anchor as
`predDue + lag * DAY_MS`, while critical-path.ts used `predDue + DAY_MS
+ lag * DAY_MS`. This silent disagreement meant cascade and CPM could
disagree about whether a successor was satisfying the FS constraint by
exactly one day. The spec (§Datums-Semantik) makes the +1-day rule
verbindlich; this commit aligns scheduler.ts with that convention.

BREAKING CHANGE: three pre-existing test expectations encode the bug
and were recalibrated:
- Test 5 (pull-predecessor): A.newDue = May 1 (was May 2), newStart =
  Apr 27 (was Apr 28).
- Test 6 (FS lag=2): B.newStart = May 8 (was May 7).
- Test 7 (FS lag=-1): B.newStart = May 12 (was May 11).

New tests cover the working-days mode (Mo-Fr, holidays, pull-predecessor
across a weekend) plus the legacy +1-day FS rule.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Adds a new background layer in GanttCanvas that fills every weekend or
holiday day with a low-alpha theme-divider colour. The layer renders
between the SVG root and the gridlines so it sits under all bars and
overlays — pointer-events are disabled.

- viewport.ts: new pure helper nonWorkingDaysInRange(from, to, cfg, max)
  returning UTC-midnight timestamps of non-working days in the viewport.
  Returns [] in legacy mode so the canvas pays zero cost when the project
  has no working-days config.
- GanttCanvas.svelte: new workingDaysConfig prop + reactive
  nonWorkingDays array, threaded into a dedicated <g class='non-working-days'>
  group.
- GanttView.svelte: forwards the project's cfg to the canvas.
- 5 new viewport tests covering legacy mode, weekend listing, the
  maxDays cap, inverted ranges, and explicit holidays.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
- TProject gains an optional workingDaysConfig property stored as a JSON
  Record (TypeRecord). Optional + additive: every existing Project keeps
  workingDaysConfig=undefined, preserving legacy calendar-day behaviour.
- Migration registers the new state 'gantt-add-working-days-config' as a
  no-op upgrade entry so the tracker schema-version tracker advances.
- 14 new IntlString keys (WorkingDaysConfig, WorkingDaysTitle, ..., per-
  weekday short labels Mon..Sun) registered in plugins/tracker/src/index.ts.
- EN + DE translations added in plugins/tracker-assets/lang/{en,de}.json
  for all 14 new keys.

This commit only persists the type and surfaces the labels; the
project-settings UI to edit the config is intentionally deferred to a
follow-up so this PR stays focused on scheduler correctness.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
computeCriticalPath now accepts an optional WorkingDaysConfig and routes
forward/backward anchor math through the shared working-days helpers.
Slack stays in milliseconds (LS - ES) to keep the result shape stable
for existing UI consumers; conversion to a working-day count for display
purposes is the caller's responsibility.

The legacy +1-day FS rule that critical-path already used now lives in
fsAnchor itself — both critical-path and scheduler share that source of
truth, eliminating the prior off-by-one drift between them.

All pre-existing CP tests remain green; new tests cover:
- FS chain across a weekend (Fri → next Mon is tight, no slack)
- FS lag=2 violation when succ is pinned earlier than required wd
- Holiday in the dependency gap forces a violation
- Legacy-mode regression check

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…lpers

Introduces the data shape and pure helper functions for Phase 2 of the
Gantt UX polish — a per-project working-days calendar.

- WorkingDaysConfig interface on tracker.Project (optional). Weekday mask
  uses bit 0=Mon..bit 6=Sun; holidays as UTC-midnight timestamps. Absence
  of the property means 'every day is a working day' (legacy mode).
- plugins/tracker-resources/.../lib/working-days.ts: pure helpers
  isWorkingDay, nextWorkingDay, addWorkingDays, workingDaysBetween, plus
  the four anchor functions fs/ss/ff/sf and their reverse counterparts.
  All accept cfg | undefined so the same call-site serves legacy and
  working-days mode.
- 44 Jest cases covering weekday mask, holidays, midnight rounding,
  cross-weekend arithmetic, negative spans, anchor semantics in both
  legacy (with the +1d FS fix) and Mo-Fr modes.

Helpers are not yet wired into scheduler.ts or critical-path.ts; those
follow in the next two commits to keep the diff readable.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…nt index

GanttView's sortedRows post-sort reordering kept each row's buildLayout()
y, which then drove the absolute position when the sidebar virtualizes.
That made the sorted sidebar visually appear in pre-sort order. Now the
sidebar derives vy = i × rowHeight from the current iteration index so
the rendered order matches the iteration order regardless of any
upstream sort or filter.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Three additional assertions covering the LayoutRow shape produced for
group-header rows (collapsible=true, issue/milestone=null, groupKey/
Count/Label populated), the issue-row carry-through of groupKey for the
canvas tint, and the preservation of y / height from the source group
rows.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…ModeEditor

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
The mkIssue test fixture was using a Partial<Issue> spread + a literal
'string' for _id, which violates the branded Ref<Issue> shape under
strict svelte-check. Replace with an explicit IssueOverrides interface
that casts _id once and feeds the rest of the Issue fields through
fixed defaults — keeps the test surface readable while making
svelte-check happy.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…umn components

GanttSidebarHeaderCell handles the sortable header label and the column
resize handle on the right edge. Resize uses window-level mousemove/up
listeners with clean teardown on mouseup or component destroy.

GanttSidebarColumn dispatches per-column-key cell rendering: identifier
(IssuePresenter), title (clickable openIssue), status (StatusBadge),
priority/estimation/dates as read-only text, predecessors/slack reusing
the existing helpers. Inline-edit popups are reserved for Phase 3a.v2
when the undo-manager (Phase 3c) is in place.

EN+DE i18n added for the 16 column header labels, the extended-mode
toggle and the sort-breaks-hierarchy warning tooltip.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…wnstream consumers

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Introduce SidebarColumnKey union, DEFAULT_COLUMNS, DEFAULT_WIDTHS map,
MIN/MAX_WIDTH clamps and a defensive parseColumns coercer that always
yields at least one valid column. 16 unit tests cover the legal and
malformed input paths.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
GanttView.svelte:
- Read ganttGroupBy from viewOptions (safe fallback 'none')
- In-memory ganttFilter + collapsedGroups (per-mode reset on group switch)
- filteredIssues feeds buildLayout (legacy) OR buildGroupedRows
- onToggle routes 'group:*' ids to collapsedGroups
- sortedRows short-circuits when groupBy active (sort applied within lane)
- Toolbar-right gains: Filter button with badge + popup (priority chips),
  Group-By dropdown with overrides-hierarchy tooltip
- Ctrl+F/Cmd+F shortcut toggles the filter popup (was reserved in Phase 1)

GanttSidebar.svelte:
- Renders 'group-header' rows in both legacy and extended-grid layouts
  with chevron, label, count; spans full grid width

GanttCanvas.svelte:
- Paints lane-tint band behind 'group-header' rows (.group-header-bg)

lib/types.ts:
- LayoutRow.kind union extended with 'group-header'
- Optional groupKey/groupLabel/groupCount fields

lib/build-rows.ts:
- groupRowsToLayoutRows adapter so existing Sidebar/Canvas iterate the
  same LayoutRow[] for both legacy and grouped modes

Strings:
- 22 new EN+DE keys for GroupBy / Filter / sentinel labels

256 → 289 Jest tests (green); svelte-check passes.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Three pure modules and their Jest suites:
- group-by: resolveGroupKey/sortGroupKeys/getGroupLabel + sentinels
  (__unassigned__, __no_component__, __no_milestone__, __no_label__,
  __unknown__). 17 tests.
- build-rows: buildGroupedRows produces the flat row stream with
  discriminated 'group-header' | 'issue' rows and pre-computed y
  positions. Supports withinGroupCompare for the Phase-3a sort hook.
  7 tests.
- filter-predicate: applyFilter / countActiveFilters with AND-across-keys
  and OR-within-key semantics; unknown keys ignored for forward compat.
  9 tests.

256 → 289 Jest tests (all green).

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…adeToken helper

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…orator

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…senceInTabs

The my-issues tab check used expect('.hulyComponent').not.toContainText(name),
but the empty-state renders the search echo (No issues found for "<name>"),
so the negative text assertion matched the echo and failed. Switch to the
established linesFromList row-count locator (toHaveCount 0/1), which targets a
real issue row and ignores the search echo. Strengthens the assertion; last
tracker uitest fail.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…le split)

InlineFilterChipsOverflow receives hiddenStartIndex as a one-shot snapshot of
visibleCount while its {#each $filterStore} body stays live. When the filter
set changes with the popover open, the snapshot points at the wrong subset
(M-VF3). Subscribe to filterStore on open and close the popover on the first
real mutation; clean up the subscription on user-close and on destroy.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…-safe (M-VF5)

Verified that raw query_string field-targeting in FullTextAdapter.search cannot
leak cross-space or cross-workspace data: workspaceId is a hard bool.must term,
and the sole caller (fulltext /api/v1/search via FullTextMiddleware) sits below
SpaceSecurityMiddleware, which either bakes the space constraint into the DB
findAll or post-filters via clientFilterSpaces. The ES hits are only a candidate
id-set, re-filtered downstream. No whitelist gate needed; record the proof.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…y (M-G1)

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…ng (M-G4)

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…hing parents (M-G5)

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…ponses (M-G7)

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
… (M-G9)

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…y (L-G3)

detectCycle previously ran on the full unfiltered relation graph before the
scheduled filter, so a cycle among purely unscheduled issues wrongly disabled
the whole critical-path panel. Move the check after activeRels is derived so
only cycles among scheduled relations degrade the result.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…(L-G1/L-G2/L-G4/L-G9)

- L-G1: generation-guard the async editableIssueIds IIFE so an older,
  slower canEdit chain can no longer overwrite the Set with a stale value.
- L-G4: gate the Tab/Arrow/+/- shortcuts behind isTextInputFocused() and
  only trap Tab when a bar has focus, so text inputs inside the Gantt root
  keep native typing/caret behaviour and keyboard users are never stuck.
- L-G9: precompute a Set of issues touched by a violated relation once per
  change instead of rescanning all relations for every rendered row.
- L-G2: inject the Issue/IssueRelation class refs into UndoManager (defaults
  preserved for the unit mocks) and align the apply() JSDoc/adapter with the
  real TxOperations.apply(scope,...) — the marker is the apply scope.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…preserved (L-G5)

gotoAllIssues truncates the route to the allIssues special view and does not
carry the search text. The header comment claimed the opposite; align the
doc/comment with the actual behaviour instead of adding a dead query param.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
… (L-G6)

changeStartDate/changeTargetDate persisted a new bound without checking the
other, allowing startDate > targetDate. Pull the opposite bound along so an
inverted range is never written.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Precise the JSDoc: the function only strips edit affordances from guest roles;
space membership and the actual write authority are enforced upstream by the
space-security layer, not here.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…L-G10)

SEARCH_VIEW_OPTIONS is appended to issuesOptions() but builder.createDoc is
idempotent, so existing workspaces never received the new entries on the
stored IssueList/IssueKanban viewlet docs. Add addSearchViewOptions, mirroring
addGanttPhase1ViewOptions, to merge the missing keys by key. Idempotent.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…tion (L-VF1)

removeFilter/updateFilter mutated the stored array in place before set(),
so reference-memoised consumers and reduceCalls queue coalescing could miss
the change. Build a new array each time.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
queryNoLookup is rebuilt as a new object every cycle, but createQuery skips
the callback for a deep-equal query. Resetting queryReady on object identity
alone could strand it at false forever (callback never re-fires), leaving the
result count / SearchEmptyState stale. Compare a serialised signature instead.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
splitHighlightSegments stripped only the first leading prefix and highlighted
the whole trimmed query as one literal, so a multi-word search highlighted
nothing. Strip all stacked leading prefixes and highlight each term via
alternation, matching search semantics.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…(L-VF6)

aria-expanded was hardcoded false; bind it to the live popover handle so AT
users get the real disclosure state. Also drop the stale IconClose dead-code
comment (the icon is used by the clear-all button).

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Date filters emit $lte/$gte, but the key-merge only handled $lt/$gt, so two
date filters on one key fell through to Object.assign (last wins) instead of
tightening the range. Add $lte/$gte branches keeping the tighter bound.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
…olors

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>

# Conflicts:
#	plugins/view-resources/src/components/filter/FilterBar.svelte
… the Tracker save-row path

The develop merge brought in hcengineering#10969's canSaveFilteredView gate, but it only
guarded the legacy chip-row save button. The branch-new showSaveRow path
(Tracker IssuesView, hideChips=true) renders SaveAs/Save without the gate, so a
ReadOnlyGuest/DocGuest would still see them. Add canSaveFilteredView to
showSaveRow — in that path the row is save-buttons only, so hiding it for guests
matches upstream intent (chips render separately via InlineFilterChips).

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants