Skip to content

feat(phase7): Bootstrap 5 completion, marshmallow 4.x fixes, vis split packages - #19

Merged
gru3zi merged 40 commits into
feat/phase3-ace-removalfrom
feat/phase5-bs5-tabler
Jul 2, 2026
Merged

gru3zi merged 40 commits into
feat/phase3-ace-removalfrom
feat/phase5-bs5-tabler

Conversation

@gru3zi

@gru3zi gru3zi commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • 7.1b — Bootstrap 5 interactive attribute renames across 80 HTML templates: data-toggle/dismiss/target/backdrop/keyboard/content/html → data-bs-*. Fixes all broken modals, dropdowns, collapses, and popovers. Adds data-bs-trigger="hover" to 6 datastore popover elements, type="button" to 11 dropdown buttons.
  • 7.1a — BS5 CSS utility renames: spacing (ml/mr/pl/pr → ms/me/ps/pe), float (float-left/right → float-start/end), badge classes (badge-* → bg-* text-{white|dark}). 193 float renames, 402 spacing renames, 20 badge renames.
  • 7.2 — marshmallow 4.x compatibility: 82 auto_field('col') positional args → auto_field(column_name='col') keyword form; 18 .dump(obj, many=True) call-sites moved to Schema(many=True).dump(obj).
  • 7.3a/b — Replace vis@4.21.0-EOL monolith with vis-network@9.1.13 + vis-timeline@7.7.4 split packages. No JS callers changed (same window.vis global). Fixes minHeight: '400px' → minHeight: 400 for vis-timeline 7.x API. Removes redundant timeline CSS from alerts page.
  • 7.4 — Explanatory comment above graphene-sqlalchemy==3.0.0rc2 pin in requirements.txt.

New test files: e2e/tests/administrator/bs5_interactions.spec.js (7 interaction tests) and e2e/tests/visual-baseline.spec.js (4-page screenshot baseline).

Review protocol

Every slice: Codex/DeepSeek implements → Claude diff gate → Kimi UX review → DeepSeek grep verification. Three issues caught and fixed by Kimi before commit: missing data-bs-trigger, missing text-white on badge, missing type="button" on dropdown buttons.

Test plan

  • e2e/tests/administrator/bs5_interactions.spec.js — all 7 interaction tests pass
  • Modals open and close correctly (data-bs-toggle/dismiss)
  • Static backdrop modal (case timeline add-event) does not close on outside click
  • Case review modal does not close on Escape key
  • Popovers in datastore show body on hover (not blank, not click-triggered)
  • Alerts network graph renders (vis-network CSS + JS)
  • Case timeline graph renders (vis-timeline CSS + JS)
  • cd ui && npm run build passes
  • GET /api/v2/cases returns valid JSON (marshmallow schema)

🤖 Generated with Claude Code

gru3zi and others added 3 commits June 24, 2026 08:23
…es (slices 7.1b + 7.1a)

Slice 7.1b: rename all BS4 data-* attributes to data-bs-* equivalents across 80
HTML templates so modals, dropdowns, collapses, and popovers work in BS5:
- data-toggle/dismiss/target/backdrop/keyboard/content/html → data-bs-* (all 0 remaining)
- 6 inline <script> popover init selectors updated in datastore/case modal files
- Critical modal attributes verified: case.html:296 (static + keyboard=false),
  case_timeline.html:123 (static backdrop), alerts.html:263/269 (backdrop=false)
- data-trigger="hover" → data-bs-trigger="hover" in 6 datastore popover elements
- type="button" added to 11 dropdown toggle <button> elements per BS5 spec
- 2 dead data-toggle="tooltip" on bootstrap-select <option> elements intentionally skipped

Slice 7.1a: rename BS4 CSS utility classes across 75 HTML templates + svelte:
- ml-/mr-/pl-/pr- spacing → ms-/me-/ps-/pe- (402 instances); ml-auto/mr-auto preserved
- float-left/float-right → float-start/float-end (193 instances)
- badge-pill → rounded-pill (15 instances)
- badge-* → bg-* with correct text color (text-dark for warning/info/light, text-white for others)

New Playwright test files:
- e2e/tests/administrator/bs5_interactions.spec.js: 7 interaction tests that were
  failing before this commit (proving the regression) and pass after (proving the fix)
- e2e/tests/visual-baseline.spec.js: 4-page screenshot baseline for layout regression detection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…notation (slices 7.2 + 7.4)

Slice 7.2 — marshmallow-sqlalchemy schema modernisation:
- marshables.py: convert all 82 auto_field('col', ...) positional args to
  auto_field(column_name='col', ...) keyword form (marshmallow-sqlalchemy 1.x deprecation)
- 18 call sites across 13 files: move many=True from .dump(obj, many=True) to
  schema instantiation Schema(many=True).dump(obj) per marshmallow 4.x requirement
- 45 schemas already have unknown = EXCLUDE; no changes needed there

Slice 7.4 — requirements annotation:
- Add explanatory comment above graphene-sqlalchemy==3.0.0rc2 pin explaining
  why RC2 is intentional (no 3.0.0 final exists on PyPI; RC is de-facto stable)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t packages (slices 7.3a + 7.3b)

Replace the vis 4 EOL monolith with actively maintained split packages.
No JS callers needed updating — both packages write into window.vis using
the same globalThis merge pattern as the old monolith.

Slice 7.3a (vis-network@9.1.13):
- vite.config.js: copy src updated from node_modules/vis/dist/vis-network.min.js
  to node_modules/vis-network/standalone/umd/vis-network.min.js (standalone
  bundle includes vis-data internally; no separate dep needed)
- ui/public/assets/css/vis.min.css replaced with vis-network styles

Slice 7.3b (vis-timeline@7.7.4):
- vite.config.js: copy src updated from node_modules/vis/dist/vis-timeline-graph2d.min.js
  to node_modules/vis-timeline/dist/vis-timeline-graph2d.min.js
- ui/public/assets/css/vis.graph.css replaced with vis-timeline styles
- case.timeline.visu.js: minHeight: '400px' → minHeight: 400 (vis-timeline 7.x
  requires HeightWidthType as number for pixel values, not CSS string)

Cleanup (Kimi review findings):
- Remove dead vis@4.21.0-EOL from package.json/package-lock.json
- alerts.html: remove redundant vis.graph.css link (alerts only uses vis-network,
  not vis-timeline; timeline CSS was unnecessarily loaded on every alert page)

Build: ✓ 3.50s, no errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: eb31bab6-4411-4255-b2b2-21c8ebdc4a89

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key: "tools"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​vis-network@​9.1.138810010090100
Addednpm/​vis-timeline@​7.7.410010010090100

View full report

@socket-security

socket-security Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm vis-network is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: ui/package-lock.json → npm/vis-network@9.1.13

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/vis-network@9.1.13. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

gru3zi and others added 24 commits June 24, 2026 08:47
- Replace class="placeholder" → class="form-label" on 80 <label> elements
  across 25 files (BS5 repurposed 'placeholder' as skeleton loader,
  causing all floating labels to render as gray shimmer boxes)

- Replace form-row → row in 25 templates (form-row removed in BS5)

- Remove input-group-prepend/append wrapper divs in 35 files (40 wrappers
  removed; BS5 input-groups no longer use wrapper divs — children go
  directly inside .input-group)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ressions

- Rename ml-md-auto→ms-md-auto, mr-sm-2→me-sm-2 across 10 templates (missed by
  Phase 7 sed which only caught numeric ml-N/mr-N patterns)
- Fix access control page buttons (Users + Groups sections): replace float-end inside
  .card-header flex context with w-100 row + ms-auto col so buttons reach right edge
- Fix dashboard card section headers: move d-flex justify-content-between from inner
  .card-title (too narrow) to .card-header directly, so title stays left and
  refresh/action buttons push to far right across all 4 sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nner padding

- Replace all 22 class="close" BS4 modal buttons with BS5 btn-close pattern
  across 17 template files (case/, manage/, manage/access_control/)
- Remove nested col-md-12 wrapper in manage_cases.html table card so
  DataTables responsive can use the full content width
- Add .page-inner { padding: 20px 30px } to iris-layout.css to restore
  the card breathing room that was lost when Tabler BS5 removed the
  Atlantis-era content-area padding (cards were flush edge-to-edge)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sub-nav

- case.html: replace inner div.row badge wrapper with d-flex justify-content-end
  so status/severity pill badges don't stretch to full column width (573px→86px);
  rename ml-auto→ms-auto and drop float-end (BS4 utilities removed in BS5)
- case-nav_landing.html: remove float-start from container-fluid so the
  case sub-navbar spans full content width (927px→1130px)
- index.html: restore 4th stat card (Assigned alerts); change col-md-4→col-md-3
  for all four cards so they fit in a single row
- manage_cases.html: remove px-2 from card-body (was collapsing horizontal
  padding to 8px; correct value is the default 20px)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…odal

Global layout (iter 1, prior commit 5a34869) fixed page heights and card
styles. This commit fixes the case-page-specific breakage, which is the heart
of IRIS and where the user saw "completely broken" UI.

Manage modal (modal_case_info_from_case.html) — was structurally broken:
- Header used invalid `col md-12` + nested rows inside BS5's flex
  .modal-header, so the title / Info-Access pills / close button collapsed.
  Rebuilt as d-flex with a proper .btn-close.
- Edit button used float-end inside an h4 and clipped past the modal edge;
  now a flex child of a d-flex justify-content-between header line.
- Access-tab action buttons used float-end (no-op in flex); now d-flex.
- Footer used mr-auto (removed in BS5); renamed to me-auto so Delete /
  Close-Reopen spread correctly. All onclick handlers preserved.

Case tabs — migrated BS4 float/col layouts to BS5 flex so each tab renders
at viewport height (was spreading ~1.6x too tall) matching REF:
- case_timeline.html: filter/action navbar rebuilt as d-flex (was nested
  ul/col-8 soup); timeline_filtering sized via flex-grow + min-width:0.
- case-nav_landing.html, case.html, case_assets/ioc/notes_v2: float-* and
  legacy col utilities converted to flex utilities; ml-auto -> ms-auto.

CSS (iris-layout.css, iris-visual.css): added split-pane .page-with-aside
layout for the Notes editor, timeline-nav containment, and tightened the
case stat/action strips to match REF proportions.

Verified independently (not via Codex self-report):
- All 8 case tabs now render 1440x900 (REF parity); dashboard 1647px->900px.
- Manage modal: X top-right, Info/Access pills in a row, Edit inline (no
  clip), footer buttons clean — confirmed via fresh screenshots.
- Notes/Timeline/Graph component probes render identically to REF (no
  regression; they need interaction/data to populate, same as REF).
- Computed-style diffs 302 -> 195; residual 195 are acceptable framework
  variance (radius/font-weight/hue/shadow), not functional breakage.
- No .js/.py touched; _escape_tooltip_content() untouched.

Local-only commit; not pushed.

Co-Authored-By: Claude <noreply@anthropic.com>
User reviewed the case page after ee bbbc8f and flagged two issues.

Timeline (case/timeline) rendered BLANK on MOD:
- Root cause: the BS5/Tabler build no longer loads atlantis.css, but IRIS's
  case timeline uses Atlantis-specific structural classes (.timeline,
  .timeline::before, .timeline > li > .timeline-panel, .timeline-badge) plus
  .btn-conditional overlay controls. Without that CSS the timeline area was
  empty even though the JS/data were working.
- Fix: restored the vertical-timeline structural CSS (iris-layout.css) and the
  panel/badge/selection/flagged visuals + .btn-conditional default-hidden
  behavior (iris-visual.css). No JS changes.
- Verified: MOD case 5 timeline now renders its event panel (1301x153, 1
  panel); case 1 (no events) shows the empty state cleanly.

Manage modal Info/General-info fields looked cramped:
- Root cause: BS5/Tabler dropped .form-group styling (it was a BS4 class), so
  the label/value pairs rendered inline instead of stacked; .modal-xl was
  capped at 1140px vs REF 1200px.
- Fix: in iris-visual.css, restore block .form-group behavior inside
  #case_gen_info_content (label block/muted/semibold, value below) and
  neutralize legacy mt--3 collisions; in iris-layout.css set
  #modal_case_detail .modal-dialog.modal-xl max-width to 1200px.
- Verified: modal now 1200px (REF parity), fields 551px columns stacked.

Local-only commit; not pushed.

Co-Authored-By: Claude <noreply@anthropic.com>
The top header (.main-header) was visually broken vs REF: the navigation icons
bunched on the left with empty space on the right, the bar read as a lighter
blue, and the logo looked off.

Root cause (measured via e2e/probe_header.cjs, REF vs MOD computed styles):
- .main-header is display:flex in the BS5 shim, but the inner .navbar had no
  flex-grow, so it shrank to its intrinsic ~257px instead of spanning the
  remaining header width (REF: 1190px). Nav icons (search, switch-case, tasks,
  datastore, add, quick-actions) crammed into that narrow strip.
- .main-header background used var(--tblr-primary) = #066fd1 (Tabler's blue),
  slightly lighter than REF's solid #0963d5.

Fix (iris-layout.css):
- .main-header background pinned to #0963d5 (REF parity).
- .main-header > .navbar { flex: 1 1 auto; min-width: 0 } so it fills the bar.

Verified: MOD now matches REF on all header metrics — .navbar 1190x62
(was 257x62), .main-header #0963d5 (was #066fd1), .logo-header #05316a
(unchanged, was already correct), logo-white.png visible in both.

Local-only commit; not pushed.

Co-Authored-By: Claude <noreply@anthropic.com>
On /case/notes the action icon buttons (Add folder, Fold/unfold, Refresh, and
the other notes-panel .btn-sm controls) rendered at ~22x18 in MOD vs ~39x33 in
REF, so they looked wrong vs the older UI.

Root cause (measured via e2e/probe_notes_btn.cjs): the buttons are plain
.btn.btn-light.btn-sm with a Font Awesome <i> icon. Tabler's .btn-sm padding is
2px 4px; Atlantis's was 7px 13px. Icon-only buttons have no text to give them
width, so they collapsed to the icon + the tight padding (~18px tall).

Fix (iris-visual.css): scope .page-with-aside (the notes split-layout) .btn-sm
back to Atlantis padding (7px 13px, line-height 1.5). No template changes.

Verified: Add-folder button now 40x28 with padding 7px 13px (REF 39x33, same
padding) — was 22x18 / 2px 4px.

Local-only commit; not pushed.

Co-Authored-By: Claude <noreply@anthropic.com>
The note action toolbar (Comments / Copy link / Copy MD / Download / Delete /
three-dot menu) was stacking vertically — one button per line — instead of a
horizontal row, when a note was open.

Root cause (measured via e2e/probe_notes_toolbar.cjs + probe_tb2.cjs): the
toolbar container was <div class="row float-end"> holding raw buttons/spans
(not .col children). Bootstrap 5 adds `.row > * { width: 100% }` (it assumes
.row children are columns), so every button was forced to the full 459px row
width and flex-wrap stacked them one per line. BS4's .row had no such rule, so
they laid out horizontally in the old UI. (REF on :8444 has no notes to open,
so this was compared against the original IRIS layout.)

Fix (case_notes_v2.html): replace the misused `.row float-end` with
`d-flex flex-wrap justify-content-end align-items-center` — a real flex box
whose children keep content width and align right in one row.

Verified: container is now the d-flex class; buttons horizontal (horizontal:true),
content-width ~56-60px each (was 459px), right-aligned.

NOTE for future template changes: the Flask app container serves templates, so
template edits need `docker restart iriswebapp_app` (not just nginx) to clear
Jinja2's cache. CSS edits (ui/dist) need npm run build + nginx restart.

Local-only commit; not pushed.

Co-Authored-By: Claude <noreply@anthropic.com>
Adds e2e/smoke_api.cjs: authenticates to MOD (:8443), establishes case context,
and hits a spread of read endpoints across every module (api, dashboard, manage
cases/users/attributes, alerts, case notes/timeline/assets/ioc/tasks/evidences/
graph), reporting status + payload shape, plus a CSP/CORS header audit.

Run result: 16/17 endpoints return 2xx with valid JSON (status=success); the
one non-200 is /case/notes/groups/list (410 Gone — pre-existing deprecated
endpoint, not a regression: zero .py changed on this branch). CSP only blocks
external Google Fonts (font-src 'self' data:); same-origin scripts/XHR are
allowed, so API calls are unaffected.

Local-only commit; not pushed.

Co-Authored-By: Claude <noreply@anthropic.com>
…l-only)

Adds e2e/smoke_api_writes.cjs (30 read + 10 write endpoints) and
e2e/probe_500.cjs (REF-vs-MOD 500 comparison). Findings: 30/30 reads pass;
8/10 writes return clean 400 validation; 2 writes (/manage/cases/add,
/case/notes/add) 500 on invalid input — pre-existing backend error-handling
bugs (raise-of-Response; uncaught BusinessProcessingError), NOT from this
frontend-only migration.

Co-Authored-By: Claude <noreply@anthropic.com>
Both /manage/cases/add and /case/notes/add returned HTTP 500 on invalid
input instead of a clean 400:
  - manage_cases_routes.api_add_case: `raise response_error(...)` raises a
    Flask Response object -> TypeError -> 500. response_error() returns a
    Response, so it must be `return`ed (matches the sibling except clause).
  - case_notes_routes.case_note_add: `raise BusinessProcessingError(...)`
    from inside an `except ValidationError` handler is NOT caught by the
    sibling `except BusinessProcessingError` (Python does not route a
    re-raise back to sibling handlers), and no global errorhandler is
    registered, so it escaped to 500. Mirror the sibling clause with
    `return response_error('Data error', e.messages)`.

Pre-existing on main (branch touches zero other backend files); surfaced
by the extended API smoke test. Verified post-fix: 30/30 reads GREEN,
10/10 writes clean 400 (RED 0). The valid create paths are unaffected.

Co-Authored-By: Claude <noreply@anthropic.com>
iris-visual.css opened with @import url('https://fonts.googleapis.com/css2?...Lato...'),
which the app Content-Security-Policy refuses on every page — console error on
load plus a silent fallback to the system font. Lato is already self-hosted via
fonts.css (@font-face, loaded on every layout), so the @import was redundant.
Removing it eliminates the CSP violation with no visual change; Lato still renders.

Verified: modal probe across Manage + 4 add-forms — all open with full form
controls, 0 console errors (was ERR(1) per modal/page before).

Co-Authored-By: Claude <noreply@anthropic.com>
The topbar action icons (search, switch-case, add-tasklog, datastore, user menu)
sat at the LEFT of the full-width navbar instead of the right edge. Atlantis
pushed them right with ml-auto, which was lost in the Tabler migration; once
#search-nav is collapsed/absent the icons fall to the start.

Restore via `.main-header ul.topbar-nav { margin-left: auto }`. Scoped to the
<ul> deliberately: on case pages there are two .topbar-nav elements — the action
<ul> (goes right) and #search-nav, a <div class="topbar-nav"> holding the
case-context indicator that must stay LEFT next to the logo.

Verified: iconsRight=1424/1440 (16px gap) on /dashboard, /case, /case/assets;
#search-nav stays left (ctxLeft=266) on case pages.

Co-Authored-By: Claude <noreply@anthropic.com>
…match REF

REF/Atlantis renders the entire top header as dark navy #05316a: the logo block is
#05316a and the navbar portion carries a -45deg gradient with identical #05316a
stops (effectively solid navy). The #0963d5 base is fully covered and never seen.

We had set .main-header .navbar to transparent to defeat Tabler's white navbar bg,
which let the #0963d5 base show through on the navbar portion — so the header read
as the lighter medium blue instead of dark navy. Set the navbar to #05316a to match.

Verified (computed styles): MOD navbar now rgb(5,49,106) == REF; logoHeader already
matched. Whole header is uniformly dark navy on dashboard + case pages.

Co-Authored-By: Claude <noreply@anthropic.com>
…(row>*)

Add/edit modals (asset, IOC, task, event, multi-asset, rfile, conversation, note
edit, global task, customer, customer-contact) wrap their header action buttons in
Atlantis's `<div class="row float-end">`. Under BS5, .row > * gets width:100%, so
every button took full width and stacked vertically — the oversized "close" buttons.
Same root cause as the notes toolbar (d46a713).

Scoped CSS shim in iris-layout.css: treat .row.float-end inside .modal-header as a
right-aligned flex button-group (width:auto, justify-end). Covers all 12 modal
instances at once; scoped to .modal-header so it leaves the overview.html instance
alone.

Verified: add-IOC modal header buttons now 47x34 + 43x40 side-by-side at top-right
(was 90px wide, stacked vertically); matches REF's 60/56px side-by-side.

Co-Authored-By: Claude <noreply@anthropic.com>
…reate

The reference (original IRIS) instance on :8444 was bound to 127.0.0.1 only, so it
was unreachable from other machines on the network. Rebind to 0.0.0.0:8444 so it is
LAN-accessible (consistent with MOD on 0.0.0.0:8443).

Also fix two latent problems that broke `docker compose up --force-recreate`:
  - image tags pinned :v2.5.0 (not pullable — manifest unknown; the running stack
    actually uses :latest) -> switch to :latest so a stack restart no longer fails.
  - ref_nginx defined none of the env vars its nginx.conf template is envsubst'd
    with (INTERFACE_HTTPS_PORT, SERVER_NAME, IRIS_UPSTREAM_*, cert filenames), so a
    recreated nginx crashed with "host not found in ssl of listen directive". Add
    the env block mirroring MOD's nginx.

Verified: 0.0.0.0:8444->443; localhost:8444 and 192.168.10.161:8444 both 200.

Co-Authored-By: Claude <noreply@anthropic.com>
…on reboot

Neither the running MOD stack (docker-compose.dev.yml extends docker-compose.base.yml)
nor the REF stack (docker-compose.ref.yml) had a restart policy, so neither survived a
host reboot. (bv.yml already had it, but the live stacks don't use bv.yml.)

Add `restart: unless-stopped` to:
  - docker-compose.base.yml: rabbitmq, db, app, worker, nginx (MOD core services)
  - docker-compose.dev.yml: collab, sveltekit_frontend (MOD dev-only services)
  - docker-compose.ref.yml: all 5 REF services

Also applied live to all 11 running containers via `docker update` (no recreate), so
they auto-start now without waiting for the next `up -d`.

Verified: `docker compose config` parses clean for both stacks; restart resolves on
all MOD services via the base extends.

Co-Authored-By: Claude <noreply@anthropic.com>
The .main-header base background was #0963d5 (a brighter blue) while its navbar and
logo children are #05316a (navy). Under Tabler the navbar left a sub-pixel gap at the
header's bottom edge, so the brighter #0963d5 base leaked through as a thin lighter
("white") line between the navy header and the dark .panel-header case-header panel
below it. (Atlantis's navbar covered the base fully, so REF didn't show it.)

Set the .main-header base to #05316a to match the navbar/logo, so the whole header is
uniformly navy and no brighter color can leak through any seam.

Co-Authored-By: Claude <noreply@anthropic.com>
Block-level pixel diff (e2e/probe_uidiff.cjs) of all 12 key pages against the
upstream reference instance surfaced 10 real UI divergences from the BS4->BS5/
Tabler migration; all fixed:

- sidenav: user menu was expanded by default (collapse show); REF keeps it
  collapsed. Avatar squashed to 35x23 -> round 40x40; restored Atlantis
  .user block padding/margins/caret.
- header: case-context indicator (#search-nav) was display:none — ported
  Atlantis's '#search-nav { display:block !important }' + hidden toggle.
- tables: killed Tabler's uppercase+letter-spacing on thead cells.
- DataTables Export/Copy: restored 'btn-border btn-round' classes dropped
  from 16 buttons across 8 JS pages; buttons were gray blobs overlapping
  the info line.
- ported Atlantis .btn-sm sizing (7px/13px), .btn-border, .btn-round.
- pagination: circular page buttons (border-radius 100px).
- column-filter clear icon: ported .has-feedback/.form-control-feedback
  absolute positioning (was rendering below the input).
- access-control: section carets now rotate when expanded (.rotate-icon).
- case-nav tabs: restored translucent white active/hover pill.
- dashboard assigned-alerts card: was gray with empty count — ported the
  missing style block + backend count/link (dashboard_routes.py) +
  initAssignedAlertsCard() wiring from upstream.
- fixed follow-up regression: btn-white.btn-border in gradient banners
  stays outline-style (Create new case pill was white-on-white).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- case title in top navbar: vertically centered (#search-nav display:flex +
  align-items:center instead of block; title sat at y=7 vs navbar center 31)
- case-nav tabs: centered between title and action icons — BS4 justified the
  navbar container with space-between; port that to .navbar > .container-fluid
  and drop the ml-auto on the icons <ul> that glued tabs left
- stray non-functional search magnifier in header: hidden (Atlantis hides
  .toggle-nav-search on desktop; selector now matches both header variants)
- case header background: open cases were falling back to the closed-case
  dark gradient because bg-info-gradient was never ported; added it
  (#05316a -> #05466d) plus bg-dark/success/warning-gradient and included
  info/dark variants in the white-text rules
- Customer/SOC ID block: hugs the right edge again — BS5's .row > *
  width:100% made the ms-auto wrapper full-width so margin:auto had nothing
  to push against; .panel-header .row > .ms-auto { width:auto }

Verified by DOM probe (e2e/probe_punchlist.cjs) at 1920x1080 against REF:
title center 31/31, tabs center 1128 vs REF 1049 (both ~viewport center),
magnifier none/none, customer right edge 1896 vs REF 1879. Non-case pages
(dashboard, manage, alerts) re-probed: icons right, context left, unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The notes aside-nav had only its structural rules ported (flex column, li
padding); Atlantis's link/icon/badge styling was missing, so tree entries
fell back to Tabler link-blue at 14px with the folder count digit rendered
inline against the label.

Ported from atlantis.css:
- .aside-nav .nav > li > a: dark #313131, 12px, flex + centered, no underline
- li > a i: 20px icons with 15px right margin (was 0 — icons touched labels)
- li hover/active background + active weight
- .notes-number: small gray pill (8px font, 17px round) riding the top-right
  of the folder icon instead of an inline digit

Verified by DOM probe + screenshot vs REF: link color rgb(49,49,49),
font 12px, icon margin 15px, badge styled and positioned.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ray pill

The .minimized_modal rule in iris-layout.css was a placeholder (fixed
bottom-right, white bg) instead of Atlantis's actual style. Combined with
the element's col-10/col-sm-4 grid classes it rendered as a viewport-wide
white bar with invisible white-on-white text.

Ported the Atlantis rule verbatim: fixed 200px pill at bottom-left (30,40),
gray 45deg gradient, 0.5rem radius, heavy shadow, white 13px bold title.
Affects every minimizable modal (Add asset, Add IOC, tasks, events, ...).

Verified by scripted minimize on both instances: REF 200x52 vs MOD 200x51
at identical position, same gradient/radius/color.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…vy toolbar

The column-visibility popup is a runtime-built div.dt-button-collection that
the BS5 Buttons integration doesn't give a dropdown-menu skin at our version
combo, and it mounts inside the navy assets toolbar where the gradient-header
'all text white' rule made the items invisible-on-navy. The library also
inline-shifts the popup (margin-top:-80px) up under the navbar.

Styled the bare container as a proper white menu (border, radius, shadow,
z-index 2001) with dark 13px items, hover + active states, and overrode the
inline fit-shift with margin-top:6px !important so it opens below the button.
Applies to every colvis dropdown (assets, IOC, tasks, evidence, ...).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gru3zi and others added 13 commits July 2, 2026 07:12
…vertically

Tabler makes .card-header display:flex, which shrinks the header's inner
.row to content width (432px instead of the card's 1596px). The title and
button columns then bunch up on the left, and in narrow collapsed cards
(manage/objects sections) the float-end buttons wrap into a vertical stack
next to the title.

Atlantis card-headers are display:block — the row spans the card and
float-end buttons reach the right edge. One-line restore on .card
.card-header.

Verified on all six advanced pages (customers, objects x5 sections, modules,
attributes, case-templates, report-templates): every header's buttons now on
one row, right edge 1868/1920 matching REF. Regression-checked dashboard,
access-control, alerts card headers — all still single-row right-aligned.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d Search

Refresh/'Create new case' sat flush against the DataTables Search box
(0px gap vs REF's 21px). Added mb-3 to both buttons; gap now 16px.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sidebar now shows 'IRIS v3.0-bv-test'. Left .bumpversion.cfg untouched —
its current_version (2.5.0-bv1) no longer matches, so bumpversion's search
string won't hit until the version is set back to the vX.Y.Z-bvN format.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lipse

Markup uses Atlantis avatar classes, but Tabler ships its own .avatar
component (inline-flex, gray bg, 4px radius) that boxed the picture, and
the img kept its intrinsic ratio (80x53) so the rounded-circle rendered as
an ellipse. Neutralized the Tabler skin: .avatar transparent inline-block,
.avatar-img fills 100% with object-fit:cover + 50% radius, .avatar-xl 80px.

Verified: settings avatar now 80x80 circle, no gray box; sidebar avatar
unchanged (40x40 circle).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…2nd line

Same BS5 '.row > * { width:100% }' root cause: the title link (a.nav-link
me-auto) spanned the full header row, pushing the status/Edit/Refresh
cluster onto a second line at the left. And the h4 lost Atlantis's heading
scale (14px/600 instead of 1.0375rem/700 navy) — font-weight-bold is a
BS4-only class.

Fixed in iris-visual.css: title link and .float-end cluster shrink to
content on one row (me-auto pushes cluster right, flex-centered), and the
card-header nav-link h4 gets Atlantis sizing back.

Verified vs REF: h4 16.6px/700/navy at same position, controls right edge
1888 == REF, single row. No other page uses this header pattern (checked
dashboard, access-control, timeline).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…p for blue

Verified against upstream first: temporarily closed REF's case 1 and the
header rendered the same brown wash — the brown comes from upstream's own
bg-close-gradient second stop rgba(43,12,0,.72), not from our port.

Deliberate divergence from upstream: hue-rotate that stop to rgba(0,12,43,
.72) (same lightness/alpha, blue family). Closed cases stay visibly darker
than the open-case blue but no longer read as dirty brown next to the navy
chrome.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
User confirmed the brown wash on closed cases matches the original;
restore upstream's exact rgba(43,12,0,.72) stop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…er tints

Systematic 30-point computed-style + rendered-pixel audit vs REF
(e2e/probe_colors.cjs). Fixed every real mismatch:

- global link color: Atlantis navy #05316a (+#005fdb hover); Tabler had
  #066fd1 link-blue everywhere (table row links, etc.)
- btn-dark / btn-outline-dark: BS4 #343a40 (Tabler retints to #182433)
- btn-primary: Atlantis navy #05316a (kept off btn-border variants)
- pagination: active #007bff (BS4 primary), disabled #6c757d (Tabler
  washed it to #b8c4d4)
- badges: full Atlantis palette incl. the darker body-scoped tints
  (#9D2F35 danger, #056F08DB success, #DF7D03A3 warning), mapped across
  all three class families in the codebase (badge-*, text-bg-*, bg-*)
- text-success/danger/warning/info: Atlantis values (#31CE36, #F25961,
  #FFAD46, #48ABF7)
- header links/icons + gradient-panel text: full #fff (was 0.9 alpha)
- table th: #212529 (BS4) not #343a40

Verified: 26/30 computed checks now byte-identical; the 4 remaining are
false positives (transparent-vs-explicit same rendered color, and probe
grabbing different first <a>). Pixel sampling confirms header, badges,
pagination render identical; content bg deltas are 1-3 RGB units from
shadows at sample points (both bodies are #f9fbfd).

Also reverted the closed-case gradient experiment fully (3568e99) —
brown IS upstream.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…et ring

Two leftovers from the avatar fix: the .profile-picture wrapper lost
Atlantis's text-align:center (avatar sat at the left edge), and Tabler's
.avatar carries a 1px inset box-shadow ring that showed as a faint square
around the circle. Centered the wrapper and zeroed the shadow.

Verified: avatar centerX 1085 == REF, wrapper shadow none.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
'Build docker app' has been red for the last 3 pushes: the Dockerfile runs
plain 'npm ci', but the lockfile is generated with legacy peer resolution
(@tabler/core declares peerOptional dropzone@^6.0.0-beta.2 vs IRIS's pinned
dropzone@^5.7.0), so strict mode errors with EUSAGE/missing-from-lock.
Reproduced locally from HEAD's package{,-lock}.json in a clean dir: strict
fails, --legacy-peer-deps installs clean.

Aligned the Dockerfile with the flags ci.yml already uses (npm ci
--legacy-peer-deps).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Customer

Two issues on the severity/outcome pills (Unknown, Low, ...):
- readability: the gradient-header 'all text white' rule painted the
  btn-light pill's text white on its light-gray bg. Added a btn-light
  exception inside gradient panels (#ebecec bg, black text — Atlantis
  values verified against REF's computed rgb(235,236,236)/rgb(0,0,0)).
- placement: pills sat flush right; moved them inside the ms-auto column
  above Customer/SOC ID and center them over it (pill center 1810 vs
  Customer center 1806 at 1920w).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gru3zi
gru3zi merged commit 38c9331 into feat/phase3-ace-removal Jul 2, 2026
12 checks passed
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.

1 participant