Commit Graph

8 Commits

Author SHA1 Message Date
cproudlock
d572c913e5 geenforce: let the wide pages use the page
Two caps, one inside the other: the section shell at 1400px and the reports
view at 1100px. Fine for nine columns; the reports table now carries twelve,
including the asset a PC drives, its location and its backup state, so it
was being squeezed while empty page sat to the right. Both are gone, and
the manifests editor gets the width too.

The Asset column no longer falls back to the PC's own asset number. The
collector stores a PC's hostname AS its assetnumber, so for any PC that
drives nothing that column just repeated the Host column next to it. It now
shows a dash, and carries content only when it says something Host does
not: the machine a bay PC controls, the tool a measuring PC controls, or
the role of a display.
2026-08-12 16:56:45 -04:00
cproudlock
598c2c98bc geenforce: reports say what the PC is, where, and whether it is backed up
A report row carried a hostname and some counts. Everything an operator
wants next hangs off the asset behind that host, and none of it was there.

Host now links to its PC page. Beside it, what the PC IS or DRIVES: the
machine number for a bay or part-marker PC, the measuring tool for a tool
PC, the role for a display - each linking to that asset's own page. A map
pin appears only when the asset has coordinates and hovers to the same
floor-plan preview the asset pages use; an icon that opened an empty map
would be worse than no icon.

The backup column is LAST CONFIRMED, not last changed. Dedup means an
unchanged config writes no revision, so a machine stable for six months has
a six-month-old newest revision and is perfectly healthy - the one to worry
about is the machine whose backup stopped running. It reads lastseenat and
names the kind rather than assuming ntlars, since udc/file kinds on the
share are coming.

Resolution is bulk, never per row: this table shows the whole fleet, so a
lookup inside the loop would be one query per PC. It reads the collector's
existing 'controls' relationship rather than re-deriving which machine a PC
drives - that same resolution living in two places is what put a wrong
subtype filter on the map. Every plugin it touches is optional, so each
lookup is ImportError-guarded and a lean build renders the table without
those columns. A host ShopDB has no asset for still shows: the enforcement
result is real even when the inventory is behind.
2026-08-12 16:31:24 -04:00
cproudlock
523e3e4ecc geenforce: give the manifest entry rows room to breathe
Every column in the entries table was sized to its button text with nothing
spare, so with flex-wrap on the action cell the Edit and Delete buttons
wrapped out of their 128px column and sat on top of the entry description.
The order column was tighter still, and its Up/Down buttons carried almost
no padding, which made them hard to hit as well as hard to read.

Widened the order, type and action columns to fit their contents on one
line, stopped the action cell wrapping, gave the buttons real padding, and
added vertical cell padding with top alignment so a two-line entry no
longer runs into the row beneath it.
2026-08-12 15:47:36 -04:00
cproudlock
d8fe0a48b2 Stop a stray click outside a modal discarding what was typed
Some checks failed
CI / backend (push) Failing after 8s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 8s
CI / migrations-mysql (push) Failing after 7s
Operators reported losing a part-filled form by clicking slightly outside it.
Every data-entry modal closed on a backdrop click with no warning and no way
back - the worst possible response to a misplaced click, and it happens most to
someone adding their first records at a new site.

Close-on-overlay is removed from 35 modals across 30 files: anything containing
an input, textarea, select or v-model. They still close by Cancel or the X.

Confirmation dialogs keep it, because a delete prompt holds nothing to lose and
dismissing one by clicking away is the behaviour people expect. VendorsList
shows the distinction - its edit form no longer closes that way, its delete
confirmation still does.

The shared Modal component now defaults closeOnOverlay to FALSE. Every current
caller holds a form, a checkout, a stock adjustment or a map position being
picked, and not one passed the prop, so all of them had the same fault. A modal
that genuinely wants dismissing that way opts in explicitly.

Also regroups the operator console menu, which had grown to numbers 1-9 plus
three letters bolted on with no order to them. Actions are now grouped by what
they touch, keyed by their first letter, and the old numbers still work so
nobody who has used it for months is stopped by a rearrangement.

The menu also warns when the server is not fully provisioned and names the key
that fixes it, instead of reporting it as ordinary status lines that read as
normal unless you already knew what to look for. That check is cached for the
session because it shells out to flask twice and the answer does not change
while somebody reads the screen.
2026-08-05 13:42:20 -04:00
cproudlock
b9d0cfac6a ui: stop audit-log columns clipping + widen ge-enforce report modal
Some checks failed
CI / backend (push) Failing after 1m53s
CI / naming (push) Successful in 1s
CI / frontend (push) Successful in 8s
CI / migrations-mysql (push) Failing after 8s
AuditLogs: the scoped table-layout:fixed + width:100% forced the table to fit
the settings pane, so cells ellipsis-clipped (Timestamp/User/IP fell off) rather
than scrolling. Drop it so columns size to content and the container scrolls
horizontally (global .table-container is overflow-x:auto). Only the free-form
Name/ID cell stays bounded (320px + title tooltip) so one long value cannot blow
the table width out.

EnforcementReports: the per-entry detail modal capped at 640px, too narrow for
the 5-column table. Widen to min(1000px, 92vw) and let the Message column wrap
instead of forcing horizontal scroll inside the modal.
2026-07-29 08:55:47 -04:00
cproudlock
d9080a59ca geenforce: move settings into the Settings rail
The client IP allowlist config was a tab inside the GE-Enforce section; move
it to the Settings rail via get_settings_cards (matches printedparts / zabbix /
dell). Route relocated from /geenforce/settings to /settings/geenforce; the
in-section Settings tab is removed. Card: Settings > GE-Enforce.
2026-07-27 14:44:26 -04:00
cproudlock
0860aa85c5 geenforce: IP allowlist for client endpoints + admin Settings tab
Fleet PCs on a trusted (vaulted) network can now reach the GE-Enforce client
endpoints (manifest, payload, report) without a per-PC token: the auth path
accepts a valid geenforce.fetch/report token OR a source IP in the configured
allowlist (setting geenforce_allowed_cidrs). Fail-closed; an empty allowlist
means the token stays the only path, so existing deployments are unchanged.

Rationale: the client token lives in HKLM on every kiosk, so it does not
defend against a compromised kiosk anyway - network-perimeter trust is the
same practical strength with far less provisioning + no token-rotation churn
on a DB wipe. Documented in-UI that this is perimeter trust, not per-device
identity.

- _ip_allowlisted() (ipaddress, X-Forwarded-For-aware via _client_ip)
- /geenforce/config GET/PUT extended with allowedcidrs, server-validated +
  normalized (bad CIDR -> 400)
- new GE-Enforce > Settings tab (GeEnforceSettings.vue) to edit the allowlist
  in admin, no SQL
- 3 regression tests (allow by IP, reject outside list, empty = token required)
2026-07-27 14:06:40 -04:00
cproudlock
23dc9fa379 ADR-013 Phase 4: relocate 4 self-contained plugin frontends
Relocate applications, geenforce, knowledgebase, and machines - each owns only
its own views dir, so a clean move to plugins/<name>/frontend/ (views/ +
routes.js, core imports rewritten to @/). geenforce's entryForm.js helper + its
vitest spec move with it (ManifestEditor imports it as a sibling).

Machinery fixes this batch surfaced:
- routes.gen.js codegen uses namespace imports (import * as p_x). A route file
  without a `toplevel` export is undefined on the namespace instead of a strict-
  ESM missing-binding build error.
- vitest gains a `pretest` stage so plugin-frontend specs (now under
  plugins/<name>/frontend/) run from their staged copy in src/.plugins-staged/.

Verified live: GE-Enforce (the most complex, uses the entryForm sibling helper)
renders fully from its staged frontend. Build + 58 vitest + naming green.
2026-07-18 23:51:23 -04:00