Commit graph

59 commits

Author SHA1 Message Date
Roland
048fea07ca
ui: the last of Semantic UI, in name and in dead CSS
The library has been uninstalled for some time, but the codebase still read as
though it were there: identifiers named after it, rules written against its
class names, and about 180 comments explaining a rule in terms of a thing that
is no longer installed.

Renamed, keeping the vocabulary the app actually uses: semanticUIColorMap ->
navColorHexMap, semanticColorNames -> paletteColorNames, semanticNames ->
iconNameAliases, semanticSizes -> sizeAliases, and SemanticUIColors ->
NavColors in wrolpi/schema.py, which is what validates nav_color on the way in.
ColorToSemanticHexColor had no callers at all and is gone.

The baseline ratchet has done its job -- the list reached zero, so the JSON is
deleted and the guard keeps only the checks with teeth: no package, no import,
no `className="ui "`, no toast library.  Its Theme.tsx check went with the
wrappers it was watching for.  It also asserts its own walk found files, so a
clean result cannot mean it scanned nothing.

Deleted from App.css: every rule requiring `.ui`, `.inverted`, `.segment` or
`.modal`, none of which any component has set since the stylesheet stopped
loading, plus the form skeletons, ui-alerts and progress-text rules that
nothing renders.  Two of them were doing harm rather than nothing: the drag
tints had a dark-theme variant under `.inverted` that stopped applying, leaving
15% of a fixed blue over a dark row, and now mix a token instead.

Two selectors naming markup that no longer exists were live bugs.  The file
browser's filter had `.ui.input.file-browser-filter`, so it rendered at the
browser default width on a bar laid out to give it 34em -- now qualified by its
container, because `.wrolpi-action-input` sets `width: 100%` at the same
specificity and is loaded later.  And SearchBox takes named props rather than a
rest spread, so the `id` DestinationForm hands it was dropped in silence and
the label it renders pointed at nothing; the download forms' Destination field
has had no associated label since the migration.

"Semantic roles" survives in four places, where it means what it says.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 19:15:57 -06:00
Roland
8aa9725feb
ui: the corner triggers, the More button, and the search modal
Four faults, each measured in the running app before and after.

The search glyph carried Semantic's `item` class, which has had no rules at all
since Semantic was removed: no pointer cursor, no hover, and an 18.6px hit area
against a 54.4px bar.  It is the same kind of thing as Help and Admin and now
takes the same class.  The share glyph did compute `cursor: pointer` -- it is an
`<a href>` -- but its target was the 24px box the icon occupies, so the pointer
appeared only if you found it exactly.  Corner anchors now stretch and pad like
a link.

The More button rendered with NO class at all: a bare grey UA button while the
rest of the bar took the user's colour.  Menu.Target clones its child and hands
it a className of its own, and the trigger spread those cloned props after its
own `className` attribute, so the clone replaced ours.  It is merged now.  This
was mine, from extracting NavDropdownTrigger last commit -- and it also made the
previous commit's "measured and drawn are the same component" claim only half
true, because the hidden placeholder is not cloned and so kept its class.

The bar still wrapped, for a reason the padding fix could not reach: the corner
does not keep a constant width.  The Cmd-K hint renders only once
useKeyboardDetected has seen a keypress, so it appears at an arbitrary later
moment and widens the corner by ~30px; the load, memory, temperature and drive
warnings come and go with the machine's state.  None of that resizes the
container, which was the only thing observed -- so nothing recalculated.  That
is the other half of "at certain widths": the same viewport wrapped or not
depending on whether the user had touched a key.  The corner and the home link
are observed too now.

The search modal showed an input and the first line of the first group.  The
suggestion list is absolutely positioned, which is right everywhere else -- a
list that reflows the page while you type is unusable -- but in a modal it fails
twice: an absolute list adds no height, so the panel sized itself to the search
box alone at 114px, and the panel's own `overflow: auto` then clipped the list
at that edge.  In the modal the list sits in flow; the inverse is asserted so
the rule cannot leak to the pages where overlaying is correct.

Two of the new tests were wrong first and reverting the fix left them green:
they asserted hand-written markup carrying the classes I expected the components
to have, rather than the real SearchIconButton and ShareButton.  They use the
real components now.  Every fix was then planted against: 5 red for the More
class, 2 for the search class, 2 for the corner hit area, 1 for the observer,
2 for the modal.

1115 jest / 62 suites, 196 in ui-layout.cy.js, clean npm run build.
Confirmed live: share and search both pointer at 54.4px, More white on the bar
colour with a transparent face, and the modal's list in flow and unclipped.
2026-08-05 18:38:04 -06:00
Roland
826b37527b
ui: fix the cypress failures, and two real defects behind them
All 43 cypress specs pass now (was 36 of 43).  Five of the seven failures were
stale selectors, two were real.

Real, and both mine:

  The search modal stopped focusing its input.  Mantine mounts modal content on
  a later tick, so the effect that focused it ran while the ref was still null;
  Semantic's modal mounted synchronously, which is why focusing there had been
  enough.  Fixed declaratively -- the field asks for focus itself, and SearchBox
  also sets `data-autofocus`, which is what Mantine's focus trap honours when it
  takes focus away from a plain autoFocus.

  Escape closed the suggestion list and the enclosing modal at once, so a user
  correcting a mistyped query lost the whole modal.  Escape now dismisses the
  suggestions and stops there; a second Escape, with the list closed, still
  closes the modal.

Stale selectors, all in the specs: Semantic's icon font (`i.search.icon`) is
SVG now, its `.ui.modal`/`.ui.dimmer` are the library's modal and overlay, and
one test asserted a button carried the classes `ui button secondary`.  That last
one is rewritten to check what a user can actually perceive -- that Edit is a
real link pointing at the edit route -- because framework class names say
nothing and break on every library change.

Two accessibility gaps the tests walked into:

  The nav's search control was an anchor with an onClick, no name and no
  keyboard path.  It now has a name, a role and Enter/Space activation, which is
  also what let the spec stop matching on icon-font classes.

  The search dialog had no accessible name at all; it has one now.

One `{force: true}` remains, with its reason recorded: Cypress judges that
field covered because it sits in a fixed modal under a sticky header, and I
verified by hand at Cypress's own viewport that it is the topmost element at
its centre, unobscured, and focused on open.

Also closed a hole in the ratchet that this uncovered.  A file could drop its
`semantic-ui-react` imports, leave the baseline, and still render Semantic
through Theme.tsx's wrappers -- which is exactly how a Semantic modal survived
in the search shortcut long after that file looked migrated.  A test now
forbids it, and the three files doing it (Calculators, KeyboardShortcutsProvider,
and Common.js reaching for theme names) import from the library or from
themes/names instead.
2026-08-05 18:35:07 -06:00
Roland
929534e455
ui: thirty-five files off Semantic, leaving fifteen
Phase 2, part 4.  Baseline 50 -> 15.

Migrated: all eight calculators, the rest of inventory and collections, the
Map/Zim/Docs cluster, Videos, Files, Search, Archive, DashboardPage,
DatesSelector, HelpModal, Events, Tags, Flasher's neighbours, admin Settings
and Status, Download, and App.

Also the three shared modules everything imports: api.js and customHooks.js
swap the Semantic toast library for the library's shim (same call shape), and
useForm.js renders the library's Message.  useForm accepts both the old
`{content, header, positive|negative}` shape and the new `{kind, title}`,
because the pages building those objects migrate separately.

Two library gaps closed, both found by call sites needing them:

  ActionInput is a forwardRef now.  Its ref reaches the input rather than the
  wrapper, because callers use it to focus or select the field -- a ref to the
  surrounding div would do neither, which is why one call site had resorted to
  hand-copying the component's markup.

  Header takes a `color` token name.  Three separate call sites had reached for
  an inline style to colour a heading that carries meaning ("3 items to add"
  against "2 to remove"), which is how a hex ends up in markup.

Two files needed repair after being interrupted mid-edit: MapViewer had a
Segment left in its error branch, and VideoPlayer had lost the useContext
import its own code still used.  Neither jest nor tsc noticed; only
`npm run build` did, which is the whole reason that check exists.

Fifteen files remain: Archive, BulkTagModal, Channels, Docs, FileBrowser,
FilePreview, Flasher, Nav, Playlists, Theme.tsx, Upload, VideoPlayer, Zim,
ControllerPage, admin/Downloads.  Theme.tsx is deliberately last -- the
unmigrated files still import its Semantic-backed wrappers, so it can only go
once they have.
2026-08-05 18:34:58 -06:00
Roland
73fafcd645
Search: fast ABC mode by default, opt-in deep search
The file_group.textsearch tsvector indexes all four text columns;
d_text (captions, document text, zip contents) is ~90% of the data,
making ts_rank searches take seconds on large libraries.  Add a
textsearch_abc generated column (title/author/description only, ~8x
smaller) and default all searches to it, with deep=true opting into the
full column.

Database:
- Migration adds the generated column and a GIN index (rewrites the
  table; a few minutes on large libraries).

Backend:
- FilesSearchRequest, VideoSearchRequest, ArchiveSearchRequest, and
  DocSearchRequest accept `deep`; each search function picks the column.
- /api/search_file_estimates returns both counts in one index-bound
  query (COUNT FILTER on the abc subset): `file_groups` (fast) and
  `file_groups_deep`.

UI (one coherent story across the count surfaces):
- The typing dropdown always suggests the deep count (what is findable).
- The tab badge shows the active mode's count so it matches the result
  list.
- The gap is reconciled by a hint offering deep search: count-aware on
  the global search ("No results in fast search. N results available in
  deep search." / "N more results available..."), generic on the module
  pages (no deep estimate there).  The hint resets pagination.
- "Search Depth" toggle in the search filter modals, persisted as
  ?deep=true.

Tests that relied on d_text matches now pass deep=True, with fast-mode
assertions alongside.  Also skip flaky test_download_channel on
CircleCI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 10:32:16 -06:00
Roland
05bb65fc03
Moving OTP and Vin decoder to calculators to save Navbar space. Reworking calculators to purpose groups, and adding colors. 2026-07-01 18:48:06 -06:00
lrnselfreliance
264cc8cd58
Consolidate search options into a single Filter modal (#497)
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Controller Tests / controller-tests (push) Waiting to run
Jest Tests / jest-tests (push) Waiting to run
* Consolidate search options into a single Filter modal

Reworks the file-search UI on the Dashboard, Videos, Archives, and Docs
pages. The crowded row of controls (sort, tags, limit, file-type filter,
date selector) is replaced with a single "Filter" button that opens one
comprehensive modal.

- Add SearchFilterModal + SearchFilterButton (violet + count badge when
  active). Sections (Sort, File Type, Tags, Results Per Page, Published
  Date) are shown per-page via props; layout uses a Semantic Grid.
- Selections are drafted locally and applied in a single updateQuery only
  on close/Done, so the search isn't re-run on every field change.
- Results Per Page and Sort use buttons (fewer clicks, no clipped dropdown).
- Extract shared SearchControlBar (view toggle + input + Filter) for the
  three results pages; move the global-search view toggle onto the tab row.
- Rework the Dashboard search line into one adaptive flex row; clear button
  only shows when there's an active search.
- Remove now-dead FilesView limit/tag returns and SearchLimitDropdown.

* Address review: reset limit on Clear All; use replace over replaceAll

- handleClearAll now resets Results Per Page to the default page size
  (DEFAULT_SEARCH_LIMIT = 24) so "Clear All" actually clears every setting.
- Replace start-anchored replaceAll(/^-/g) with replace(/^-/) for the sort key.
- Add a test covering the Clear All limit reset.

* Remove now-unused Media import from Files.js

The FilesSearchView refactor dropped the last <Media> usage in this file,
leaving an unused import (a build warning). Remove it.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 19:49:25 -06:00
Roland
c63fece967 Add Water Storage calculator (people → duration → containers)
New offline prepper calculator under Calculators:
- Men/women/children/pregnant-nursing counts with editable per-person
  daily rates (drinking + hygiene/dish use).
- Minimum/Comfortable presets grounded in CDC/FEMA (1 gal/person/day
  floor, store 2 weeks) and National Academies adequate-intake figures;
  Pregnant/Nursing adds the CDC/Ready.gov +0.5/+1 gal. Sources cited in
  the Daily Use info popup.
- Duration slider on a clean ladder (days → weeks → months → years) so it
  never lands on awkward values like "68 days".
- Containers Needed table listing every container (IBC tote → 500 mL
  bottle) with capacity and count + spare for the total volume.
- Total water and total weight (8.345 lb/gal, 1 kg/L).
- Imperial/metric, preset, and people counts persist via local storage.

Pure functions (dailyDemand, totalWater, containersNeeded, waterWeight,
formatDuration) covered by 21 unit tests. Registered in the calculator
list and global app search.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 18:06:48 -06:00
Roland
4e25459d50 Add Drive Ratio calculator to global search apps
Add a SUGGESTED_APPS entry so the Drive Ratio calculator shows under "Apps"
in the global search, matching the other calculator entries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 15:17:50 -06:00
Roland
c726654de9
Map search added to global search. Preview cards are displayed for all results in new Map tab.
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Controller Tests / controller-tests (push) Waiting to run
Jest Tests / jest-tests (push) Waiting to run
Map viewer has simple search.

Map search databases can be downloaded from CDN, or built locally. Map searches can be built offline, but will not have enriched things like state names downloaded from Wikidata.
2026-04-13 12:17:08 -06:00
Roland
b8a532c8d9
Key changes:
- Add MapLibre GL JS viewer with light/dark themes, terrain layer,
  and embedded static map page for coordinate sharing
- Add map pin support with persistent map_pins.yaml config
- Add map region subscriptions and downloader with progress tracking,
  sourcing pre-extracted PMTiles from a cold CDN
- Add map export to PNG and GPS coordinate copy via context menu
- Add MapViewer React component alongside reworked Map page
- Add map catalog and region-building script (build_map_regions.py)
- Remove OSM import/render scripts, leaflet files, Apache configs,
  renderd service, and osm-map-dumper Docker container
- Update Caddyfile to serve PMTiles and map static assets
- Update build/install/repair scripts for Protomaps dependencies
- Drop map_file table, add/drop map_subscription table (alembic)
- Adding button to skip primary drive mounting during onboarding.
2026-04-04 13:48:19 -06:00
Roland
c67e3ff490
Fixing bug where searching zims did not show results. 2026-03-22 13:30:33 -06:00
Roland
66a891c759
Refactoring videos and archives UI paths for consistent scheme. 2026-03-20 15:38:32 -06:00
Roland
aefc7b1def
Add Docs module for searching and organizing PDFs and EPUBs
Create a new Docs module that consolidates PDF and eBook handling into a
unified system with subjects and authors support. This replaces the
separate PDF/eBook modelers with a single Doc model backed by an
alembic migration (rename ebook to doc).

Key changes:
- New modules/docs package with models, API, extractors, and lib
- Subject and author metadata extraction with case-insensitive
  normalization for cleaner PDF metadata
- Frontend Docs pages with AuthorsPage, SubjectsPage using
  CollectionTable, and doc card deletion
- Global search integration for subjects and authors
- Generic collection item count support
- Frontend file card metadata adjusted to match collection sort
- Bump yt-dlp version
2026-03-20 14:17:06 -06:00
Roland
21c96d9501
Displaying cmd+k/ctrl+k global search keyboard shortcut suggestion. 2026-02-23 16:07:22 -07:00
Roland
3f411679bd
Adding keyboard shortcuts to UI.
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Controller Tests / controller-tests (push) Has been cancelled
Jest Tests / jest-tests (push) Has been cancelled
2025-12-26 18:59:20 -07:00
Roland
a92104728d Converting Theme.js to typescript so we can use shorthands like Card.Icon.
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Jest Tests / jest-tests (push) Waiting to run
2025-12-07 12:41:10 -07:00
Roland
8ea3ea8a67
Updating code to use new version of react-router. 2025-12-07 11:54:20 -07:00
Roland
add6bfb1b3
Disabling search temporarily when suggestions are fetched to prevent accidental clicks.
Some checks are pending
CodeQL / Analyze (push) Waiting to run
2025-08-26 17:56:33 -06:00
Roland
fb187e1305
Initial alpha version of the Ratio Calculator. 2025-01-18 10:08:11 -07:00
Roland
a17d2a416a
Moving global search model out of button link to avoid keeping modal open when selecting results. 2024-12-19 13:17:25 -07:00
Roland
0f003a6dc1
Moving navbar search button down into the menu as an icon. 2024-12-18 17:27:51 -07:00
Roland
0f232fd533
Moving FileGroups instead of refreshing files after they have been moved. 2024-10-16 18:56:25 -06:00
Roland
35ec6d44fe
Creating setting for changing navbar color. 2024-10-16 18:56:04 -06:00
Roland
53d2402d32
Only files that have been tagged will be returned when new 'Any' tag button is used to filter file search results. 2024-10-16 18:55:56 -06:00
Roland
213b6fc132
Adding Power Loss Calculator. 2024-10-16 18:55:45 -06:00
Roland
9986ce8a1f
Created Dipole Antenna calculator. 2024-10-16 18:55:41 -06:00
Roland
ae61977f0b
Reformatting. 2024-06-12 16:47:31 -06:00
Roland
7432d1824d
Reloading estimates when filter changes. 2024-06-12 16:35:33 -06:00
Roland
e58e764b6b
Matching against description for App search. 2024-05-31 23:52:27 -06:00
Roland
dd13534a39
Modifying Dashboard search clear button to clear all search params. 2024-05-25 10:48:08 -06:00
Roland
a5fb634766
Only searching suggestions when searchStr has a value. 2024-04-16 10:10:16 -06:00
Roland
7669cfe361
Ordering suggested channel names by video count. 2024-04-16 10:04:06 -06:00
Roland
969a065a6c
Splitting FileGroups from search suggestions to speed up channel/domain response time. 2024-04-16 09:46:47 -06:00
Roland
1795fae1b0
Merging useSearchMonths and useSearchDateRange into useSearchDate to avoid setting query twice when closing DateSelectorModal. 2024-04-14 14:01:07 -06:00
Roland
00fe799b8f
User can select from/to years when searching files. Indexing doc and docx files. 2024-03-07 12:12:48 -07:00
Roland
1bb333e43b
Adding preview URL query which allows sharing of a specific file. 2024-02-17 14:53:39 -07:00
Roland
6409e0ffde
Do not need to encode query. Clearing search input when user navigates to dashboard. 2024-02-17 13:46:28 -07:00
Roland
407d60c074
Using searching files is at /search. 2024-02-12 12:12:07 -07:00
Roland
23d84ed107
Search suggestions can filter by mimetypes. 2024-02-05 16:04:19 -07:00
Roland
dc9441f1ad
Cannot filter with global modal search. 2024-01-01 18:25:56 -07:00
Roland
170e227bf9
Removing search suggestions context. Passing suggestions down to search table. 2024-01-01 17:11:09 -07:00
Roland
3ad7b8af00
Global search waits for selection before submitting. 2024-01-01 15:16:03 -07:00
Roland
377c69e8a7
Adding search icon button to navbar. 2024-01-01 11:31:17 -07:00
Roland
d87bc7b314
Fetching search estimate with tags separate from suggestions. 2023-11-29 21:09:39 -07:00
Roland
bbfe76890b
Converting Search Suggetions to a Context. Search estimates is removed and suggestions is used instead. 2023-11-22 12:19:49 -07:00
Roland
94a2c50531
Reworking useLatestRequest to actually debounce before fetching. Modifying search to display loading message when results are pending. 2023-11-22 10:35:01 -07:00
Roland
dd3fad963c
Moving result location up to normalizeSuggetions so data is in one place. 2023-11-21 21:21:59 -07:00
Roland
e59ec3e9ac
Search Suggestions are debounced and only the latest response is used to set the results. 2023-11-21 21:15:24 -07:00
Roland
2d16374421
Matching tag names in FE, rather than in BE. 2023-11-21 15:48:52 -07:00