Skip to content

ci-verify: gantt-bar-colors (#10873 develop-merge conflict resolution)#12

Closed
MichaelUray wants to merge 391 commits into
developfrom
ci-verify/gantt-bar-colors
Closed

ci-verify: gantt-bar-colors (#10873 develop-merge conflict resolution)#12
MichaelUray wants to merge 391 commits into
developfrom
ci-verify/gantt-bar-colors

Conversation

@MichaelUray

Copy link
Copy Markdown
Owner

Fork-interner CI-Runner. Verifiziert build+svelte-check+test nach der FilterBar.svelte-Konfliktauflösung (develop-Merge 0e7e800). Kein Upstream-PR.

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>
…tors

Translates the indicator-triangle tooltip via Huly's translate() store so
the hover message respects the user's locale instead of hard-coding
English. Four strings cover the source/target × above/below grid.

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>
GanttSidebar grows an opt-in extendedColumns mode: when on, it renders a
sortable header row + per-column cells via GanttSidebarColumn and emits
sortChange / widthChange events. When off (default), the legacy compact
4-cell layout is preserved bit-for-bit, so existing users see no surface
change on upgrade.

GanttView holds the sidebar columns / widths / sort state in-memory,
applies the comparator to the row feed when sort is active (breaks
hierarchy by design — spec warns via tooltip), and forwards events from
the new header cells back into the cycleSort reducer.

models/tracker/viewlets.ts registers the ganttSidebarColumnsExtended
toggle in the Customize-View drawer alongside the existing PR4a/PR5
display toggles. Default OFF.

Signed-off-by: Michael Uray <michaeluray@users.noreply.github.com>
MichaelUray and others added 28 commits July 9, 2026 07:58
…-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>
Signed-off-by: Artyom Savchenko <armisav@gmail.com>
* Fix export

Signed-off-by: Artyom Savchenko <armisav@gmail.com>

* Fix copyright error

Signed-off-by: Artyom Savchenko <armisav@gmail.com>

* Potential fix for pull request finding 'CodeQL / Uncontrolled data used in path expression'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: Artyom Savchenko <armisav@gmail.com>

* Format fixes

Signed-off-by: Artyom Savchenko <armisav@gmail.com>

* Sanitize names

Signed-off-by: Artyom Savchenko <armisav@gmail.com>

* Fix file format

Signed-off-by: Artyom Savchenko <armisav@gmail.com>

* Update copyright year

Signed-off-by: Artyom Savchenko <armisav@gmail.com>

---------

Signed-off-by: Artyom Savchenko <armisav@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@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>
@MichaelUray MichaelUray deleted the ci-verify/gantt-bar-colors branch July 10, 2026 22:12
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