Commit graph

12927 commits

Author SHA1 Message Date
Cathie Integra
6e9b8ccabf Develop: Add install-doctl.sh and install-hcloud.sh scripts 2026-05-09 09:49:56 +02:00
Michael Mayer
346d56bdb0 Develop: Update Makefile and scripts/dist/install-codex.sh
The current version of Codex does not have a "general_analytics" flag.

Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-08 09:05:46 +02:00
Michael Mayer
a719f680a9 Frontend: Hide assigned items and sort Batch Edit dropdowns #4966
availableLabelOptions and availableAlbumOptions become computeds that
hide anything already in labelItems / albumItems (matched by
$util.normalizeTitle so case and punctuation variants collapse) and
sort the survivors via locale-aware localeCompare. Raw cache results
live on cachedLabelOptions / cachedAlbumOptions so resolveLabelFromText
can still find canonical matches for items already in the chip list.

Brings the Batch Edit dialog in line with the Edit Dialog labels tab
and the lightbox sidebar — every label/album typeahead now filters
already-assigned items out of the dropdown and sorts alphabetically.
2026-05-06 21:39:56 +00:00
Michael Mayer
89242a70eb Frontend: Sort sidebar label & album dropdowns alphabetically #4966
The shared typeahead cache returns the cap-bounded result in whatever
order the backend's search?order=name produced, which in practice is
not reliably alphabetical (and would mis-sort Hebrew or Cyrillic
strings under naive byte-order anyway). loadChipOptions now applies a
locale-aware localeCompare with sensitivity:base + numeric:true after
the cache resolves, so the dropdown reads naturally in any language.
2026-05-06 21:31:53 +00:00
Michael Mayer
178861b5ba Frontend: Hide assigned labels and skip re-add in Edit Dialog #4966
Two related dedup fixes for the Edit Dialog labels combobox:

addLabel now bails out without calling the backend when the typed
name resolves (via $util.normalizeTitle) to a label already on the
photo. The backend treats a re-add as an update and was emitting
"Label updated" + "added <name>" toast pairs whenever a user picked
an existing chip from the dropdown.

labelOptions becomes a computed that filters the cached label list by
the same normalized-name comparison and sorts the survivors via
locale-aware localeCompare. The dropdown now only surfaces actionable
suggestions, in alphabetical order — assigned labels disappear from
the list reactively the moment view.model.Labels updates.
2026-05-06 21:27:25 +00:00
Michael Mayer
93b0b1e3f5 Frontend: Align Edit Dialog labels menu with input column #4966
Anchors the v-combobox menu at "bottom start" with minWidth:0 so the
dropdown's start edge tracks the input's start edge in both LTR and
RTL — Vuetify's default "bottom" + wider min-width otherwise pushes
the menu leftward into the photo-thumbnail column under the table.
Also adds density="compact" on the combobox itself to match the
lightbox sidebar's typography. Verified in browser at sub-pixel
alignment for English (delta 0.16 px) and Hebrew (delta 0.16 px).
2026-05-06 20:45:26 +00:00
Michael Mayer
e538e96ba0 Frontend: Hide menu icon and stop re-pop on Edit Dialog labels #4966
Adds menu-icon="" to suppress the v-combobox dropdown chevron in
the Edit Dialog labels tab — the comfortable-density row positions
the chevron visibly below the input baseline, since the auto-open on
focus is the discovery affordance instead. Wires v-model:menu plus a
suppressMenuOpen debounce so committing a selection no longer re-pops
the dropdown via Vuetify's search-changed watcher when the bound
model is cleared. Mirrors the chip-selector pattern.
2026-05-06 20:25:25 +00:00
Michael Mayer
bd3bec9cd1 Frontend: Upgrade Edit Dialog labels tab to combobox #4966
Replaces the bare <v-text-field> for new-label entry with a
<v-combobox> mirroring the sidebar pattern. The combobox sources its
suggestions from the shared typeahead cache and applies the same
$util.normalizeTitle canonical-match dedup as the sidebar's
addLabelImmediate (typing 'Hello Cat' resolves to an existing
'hello-cat' label instead of creating a duplicate). autofocus is
explicitly omitted because v-combobox auto-opens its menu on focus
and would lay out the dropdown before the tab geometry settles.
2026-05-06 20:07:22 +00:00
Michael Mayer
6ca665e19e Frontend: Use shared typeahead cache in batch-edit dialog #4966
Replaces the per-mount Promise.all([Album.search, Label.search]) in
fetchAvailableOptions with typeaheadCache.getAlbums / getLabels.
Opening the batch-edit dialog while the lightbox sidebar is also
editable now costs zero extra round-trips, and a label or album
created elsewhere shows up next time the dialog opens via the cache's
WS-driven invalidation.
2026-05-06 20:07:15 +00:00
Michael Mayer
f0edfd933d Frontend: Always render sidebar label & album combobox #4966
Drops the pencil-to-edit gesture for the lightbox info sidebar's chip
sections. The combobox/autocomplete row now stays mounted whenever the
section is editable, chip × icons are visible whenever isEditable, and
the toolbar ✓ only appears when there are pending REMOVALS. Per-field
input/search/key/options state lives under chipState.<field> so the
two comboboxes don't share scratch refs anymore. cancelEditing is
scoped to inline-text rollback; chip state clears via resetInlineEdits
on discard-pending. The sidebar consumes typeahead suggestions through
the new typeahead-cache module and reloads on combobox @focus to pick
up post-eviction freshness.
2026-05-06 20:07:10 +00:00
Michael Mayer
b3a582a9fb Frontend: Add shared label & album typeahead cache #4966
Adds frontend/src/common/typeahead-cache.js as a module-scope cache
that dedupes Label.search and Album.search across the sidebar info
panel, the batch-edit dialog, and the edit-dialog labels tab. WS
events (labels.updated/deleted, albums.updated/deleted, config.updated
for album deletes) evict the cache; concurrent callers share the same
in-flight promise, and session.logout clears both lists. Cap warning
behavior moves out of the sidebar into the cache implementation.
2026-05-06 20:07:01 +00:00
Michael Mayer
cc93833e57 Frontend: Align sidebar combobox menus and chip focus #4966
Sidebar inline dropdowns (Add label, Add to album, marker name
combobox) now structurally match every other Vuetify v-select /
v-autocomplete menu in the app:

- Drops the custom 1px-solid border + opaque .v-overlay__content
  background that no other menu draws. Only the inner .v-list is
  given a background; the standard MD elevation shadow alone draws
  the edge.
- Lifts the inner .v-list to secondary-light (#1e1e1e) so it sits
  visibly above the combobox input's surface-bright (#141417) bg
  instead of merging into it.
- Forwards { density: "compact" } via :list-props on each
  combobox/autocomplete (the documented Vuetify API for sizing the
  menu items, separate from the input field's own density prop).
  Title font drops to 0.8125rem so the menu typography matches the
  sidebar's other inline-edit text.

Polishes related chip styling:

- The chip :focus-visible ring now uses rgba(--v-theme-on-surface,
  0.5) instead of bright --v-theme-primary (#ebebeb), so the ring
  is clearly more prominent than the chip's 12%-alpha resting
  border without reading as a near-white halo on the dark sidebar
  and without reusing a notification token.
- Removes the unreachable .meta-chip--pending-add rule (additions
  go through the instant-save path now and never enter chipState).
2026-05-06 16:44:00 +00:00
Michael Mayer
676b2677cf Frontend: Tone down bright lightbox theme tokens for sidebar UX #4966
The original lightbox theme was sized for a basic image viewer with
no editable controls. The info sidebar now embeds dialogs, inline
editors, autocomplete dropdowns, and chip selectors — surfaces that
bind theme tokens which were previously invisible. Three values
were too bright on the near-black lightbox surface:

- highlight: #9c9c9c -> #3d3f40  (PConfirmDialog confirm button —
  was a near-white block, now a credible dark-grey button)
- selected: #9c9c9c -> #3d3f40  (Vuetify-internal selection
  surfaces: active list item, autocomplete-active row, and the
  on-selected fallback in views.css — same fix as highlight)
- hover-opacity: 0.019 -> 0.06,
  focus-opacity: 0.022 -> 0.08
  (lightbox was inheriting the dark-base defaults, which over a
  near-white overlay color left dropdown hover and keyboard-focus
  states almost invisible)

Scoped to the lightbox theme — every other theme keeps its current
highlight/selected values. The lightbox primary, info, and on-
surface tokens were left alone since they show up in many places
(focus rings, button text, captions) and would cascade unexpectedly.
2026-05-06 17:40:28 +02:00
Michael Mayer
1292ae24bc Frontend: Align discard dialog with PConfirmDialog convention #4966
Drops the icon="" / confirm-color="info" overrides on the discard-
unsaved-changes dialog so it inherits the same icon-left-of-title
layout and bg-highlight confirm button that every other call site
of <p-confirm-dialog> uses (see album/toolbar.vue, photo/toolbar
.vue, settings/apps.vue, etc.). Picks mdi-alert-circle-outline for
the icon — neutral warning, fits the "you may lose unsaved input"
question without implying permanent deletion.
2026-05-06 17:40:28 +02:00
Michael Mayer
7146de4cdd Frontend: Save sidebar label and album additions instantly #4966
Replaces the staged "type -> green pending chip -> click toolbar
check" flow for label and album additions with an instant-save
path. Removals stay batched under the toolbar check icon so users
can still toggle a chip back into place without an Undo.

- onLabelEnter / onLabelSelected fire Photo.addLabel(name) right
  away. The model's setValues(r.data) chain repopulates this.photo
  .Labels with the backend-canonical name, so the chip appears as
  a real meta-chip--primary with no transient pending-add state.
- onAlbumSelected fires Photo.addToAlbum(albumUID) right away.
  onAlbumEnter for brand-new titles still runs Album.save() first
  and chains addToAlbum once a UID exists.
- onAlbumEnter now tries a normalized exact match against
  albumOptions (via $util.normalizeTitle) before falling back to
  the existing fuzzy startsWith / includes lookup, so typed
  variants like "hello-cat" resolve to an existing "Hello Cat"
  album instead of silently creating a near-duplicate.
- addLabelImmediate cross-checks labelOptions and uses the
  canonical existing-label name when normalized-equal, so typed
  "Hello Cat" reuses an existing "hello-cat" label and the user
  sees the saved name immediately.
- startChipEditing bumps the typeahead cap from 1000 to 5000 and
  emits a console.warn when the response equals the cap (a strong
  signal it was truncated; not surfaced via $notify because the
  typical user can't act on it).
- chipState drops the additions arrays - additions never enter
  chipState anymore - and confirmAlbums migrates from raw
  $api.delete/post to Photo.removeFromAlbum, so all album-
  membership writes share one model code path.

Failure paths surface $notify.error("Failed to save changes") and
do not leave a transient chip behind. Discard-pending dialog still
fires for typed-but-uncommitted text (chipSearch) and for batched
removals.
2026-05-06 17:40:27 +02:00
Michael Mayer
26e86ead3e Frontend: Rename normalizeLabelTitle to normalizeTitle #4966
The helper is reused for album titles in upcoming sidebar work, so
the label-only name no longer fits. Renames the static method on
$util plus the matching wrapper (normalizeLabelTitleForCompare ->
normalizeTitleForCompare) in batch-edit.vue, the component prop
contract stays the same. No behavior change.
2026-05-06 17:40:27 +02:00
Michael Mayer
9f34fcf09e Frontend: Add Photo.addToAlbum and Photo.removeFromAlbum #4966
Adds two model methods on Photo for album-membership writes that
mirror the backend album-photo endpoints:

- Photo.addToAlbum(albumUID): POST /albums/<uid>/photos with
  { photos: [this.UID] }, then evict the LRU cache and refetch the
  canonical photo so this.Albums reflects the saved state.
- Photo.removeFromAlbum(albumUID): DELETE /albums/<uid>/photos with
  the same evict + refind.

The explicit refind is necessary because the backend publishes
albums.updated (not photos.updated) for membership changes, so the
photos.updated WS subscriber doesn't auto-evict here.

The Photo-level method names overlap with Thumb.addToAlbum /
removeFromAlbum on purpose: those operate at the photo-grid layer
and flip a Removed flag for lightbox menu visibility (see
lightbox.vue onRemoveFromAlbum). Both contracts are pinned in
their respective tests so a future "consolidation" PR doesn't
collapse them.
2026-05-06 17:40:27 +02:00
Theresa Gresch
a836a49261 Tests: Use triggerPhotoViewerAction to close lightbox in sidebar-edit 2026-05-06 16:42:34 +02:00
Michael Mayer
10389c8b74 Frontend: Scope lightbox onTabKey to its container ref #4966
Replace the unconditional @keydown.tab.stop on the v-dialog with
@keydown.tab="onTabKey" plus a runtime guard: stopPropagation now
fires only when document.activeElement is inside this.$refs.container
(or .content as a fallback). PhotoSwipe's _focusRoot() Tab trap stays
suppressed for the typical case (focus inside the lightbox tree, user
tabbing through chips and pencils), and a Tab event that bubbles up
through the dialog from a teleported autocomplete menu or any other
DOM context outside the lightbox tree can still reach PhotoSwipe.

Adds five unit tests covering the inside / outside / fallback / no-ref
/ no-event branches.
2026-05-06 13:03:37 +00:00
Michael Mayer
d9b314eafb Frontend: Detect more sidebar pending edits before nav #4966
hasPendingEdit() was missing two signals, so swiping or pressing the
arrow keys silently dropped typed-but-uncommitted text in the labels
combobox / albums autocomplete and the open Add-name marker prompt.
Add both: typed text in chipSearch while editingField is 'labels' or
'albums', and addNameDialog.visible. resetInlineEdits() also dismisses
an open Add-name dialog so the Discard path leaves the sidebar fully
clean. Existing wrapPswpNavGuards / onChange post-facto rollback already
route through this method, so the discard confirmation now appears for
the missed cases without any new wiring.
2026-05-06 12:09:16 +00:00
Michael Mayer
b98a346cf9 Frontend: Stop sidebar inline keys from closing the lightbox #4966
Add .stop to every @keydown handler on sidebar editors and the three
nested dialogs (datetime, camera, location). The Vuetify v-dialog above
the lightbox listens for @keydown.esc.exact.stop=close, and PhotoSwipe's
document handler still consumes a few printable keys. Without .stop,
Esc on a textarea closed the editor AND the lightbox, Esc on a nested
dialog closed both modals at once, and Esc on the labels combobox /
albums autocomplete closed the lightbox without ever cancelling the
chip edit (Vuetify's default escape doesn't stop propagation).

Also: add @keydown.escape.stop.prevent=cancelEditing to the labels
combobox and albums autocomplete (their template had no escape
handler), and call clearChipInput() inside cancelEditing so typed-but-
uncommitted chip text doesn't survive a cancel.
2026-05-06 11:56:12 +00:00
Michael Mayer
7cc26e99bd Frontend: Stop sidebar Tab at v-dialog and inset chip focus ring #4966
Move Tab interception from the PhotoSwipe-event bridge (onPswpKeyDown)
to a generic v-dialog @keydown.tab.stop handler. PhotoSwipe's Tab path
only calls _focusRoot() — a focus trap that Vuetify's v-dialog and
PhotoPrism's $view trap (common/view.js) already provide more
generically — so stopping the bubble at the dialog root is enough,
no PhotoSwipe-specific hook required. onPswpKeyDown stays for the
"z" / printable-key case where we still need to defeat the
toggleZoom shortcut while a textarea or input is focused.

Also: shift the .meta-chip:focus outline to outline-offset: -2px so
the focus ring renders inside the chip area instead of being clipped
when chips wrap against the sidebar edge.
2026-05-06 13:04:44 +02:00
Michael Mayer
ebea14a170 Frontend: Let sidebar inputs and Tab through PhotoSwipe key trap #4966
PhotoSwipe's _onKeyDown listens on document and consumes "z" for
toggleZoom and Tab for _focusRoot, so plain typing into the info
sidebar's textareas dropped "z" and Tab snapped focus back to the
lightbox root, leaving sidebar chips and pencils unreachable by
keyboard. Add an onPswpKeyDown bridge that listens via the lightbox's
own keydown event and calls preventDefault on the dispatched event so
PhotoSwipe's switch returns early (per its own defaultPrevented gate).
Two cases: Tab while the sidebar is open (regardless of focus), and
any key when an INPUT, TEXTAREA, or contentEditable element inside
the sidebar is focused. Registered once via this.lightbox.on, which
PhotoSwipe Lightbox replays onto each pswp instance on open.
2026-05-06 13:04:44 +02:00
Michael Mayer
27bcb78470 Frontend: Add keyboard support for sidebar chips #4966
Make label and album chips focusable (tabindex=0) and bind Enter +
Delete/Backspace via two new helpers: onChipActivate covers click and
Enter (navigates outside edit mode, toggles pending removal inside),
onChipDelete covers Delete and Backspace (no-op outside edit mode,
toggles inside). Vue 3's .delete keydown modifier captures both Delete
and Backspace, so one binding handles both keys.

Also: tighten the cache-freshness comment in confirmLabels to name the
.then((r) => this.setValues(r.data)) chain on Photo.addLabel /
removeLabel, so the next reader can verify the local-patch contract
without grepping model/photo.js. Resolves the documentation half of
proposal item L5 (the asymmetry with confirmAlbums is intentional and
already justified).
2026-05-06 13:04:43 +02:00
Ömer Duran
4005aea4fe
Tests: Stabilize sidebar-edit-003 and add HEIF JPEG fallback coverage #5554 #4966 #4965 #5509
* Tests: Stabilize sidebar-edit-003 and add HEIF JPEG fallback coverage

* Tests: Stabilize lightbox sidebar-edit suite on fast systems
2026-05-06 12:41:51 +02:00
Michael Mayer
aa4d51bed1 Docs: Update license NOTICE file
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-06 10:33:28 +02:00
Michael Mayer
511f0cf793 Frontend: Update deps in package.json and package-lock.json #4966
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-06 10:30:16 +02:00
Michael Mayer
05cd8fab17 Go: Update "github.com/golang/geo" in go.mod and go.sum
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-06 10:28:26 +02:00
Michael Mayer
ccccd95f78 Commands: Improve video failure summaries 2026-05-06 08:01:33 +00:00
Michael Mayer
0192e55f32 Commands: Resolve low-risk golangci-lint findings 2026-05-06 07:50:37 +00:00
Michael Mayer
bd7066e0c3 Commands: Count file download failures & pluralize logs 2026-05-06 07:50:27 +00:00
Michael Mayer
d90bf1f5d5 Frontend: Consolidate sidebar chip-state for labels/albums #4966
Replace four flat arrays (pendingLabel{Additions,Removals},
pendingAlbum{Additions,Removals}) with one chipState object keyed by
field, plus four generic helpers (isChipPendingRemoval,
togglePendingChipRemoval, removePendingChipAdd, resetChipState) that
take field + key. addPendingLabel / addPendingAlbum stay specialized
because their validation differs (string vs object input).

Also: route the chip-section header check/pencil through the existing
PSidebarInlineToolbar; add meta-labels / meta-albums classes for
parity with the per-field hooks; surface a notify.error on
confirmLabels / confirmAlbums rejection (was silent); document the
local-patch vs evict-and-refind asymmetry between addLabel/removeLabel
and the raw album-membership API; suppress the empty .metadata__chips
container when entering edit mode with zero existing chips and zero
pending additions, and hide the redundant 'Add label/album' prompt
while editing. Tests updated to the new state shape and method
signatures (140 sidebar/info tests still pass).
2026-05-05 14:10:48 +00:00
Michael Mayer
f12109f12c Develop: Upgrade base image from 260504-questing to 260505-questing
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-05 15:44:40 +02:00
Michael Mayer
4cb160c07e Frontend: Consolidate sidebar metadata fields via registry #4966
Replace four near-identical Subject/Artist/Copyright/License blocks
and the parallel Keywords/Notes blocks with two v-for loops over a
shared fieldRegistry computed (key, label, icon, read/write, display
mode, optional sanitized-html computed pointer). The registry is also
the lookup table for getFieldValue/setFieldValue, so each field's
label, model path, and rendering rule live in exactly one place.

Also: extract the check/pencil icon pair into PSidebarInlineToolbar,
swap the shared template ref for a function ref so the focus path
keeps working when the editors live inside v-for, and add
showDetailsSection/shouldShowFieldRow computed to replace the 6-term
OR gating expression. Net diff: -272 / +181 lines, no behavior change.
2026-05-05 13:03:55 +00:00
Cathie Integra
b0d6f94416 Setup: List chromium-common explicitly in install-chrome.sh package set 2026-05-05 14:56:27 +02:00
Michael Mayer
7f1b6f80af Frontend: Fix inline-edit focus stealing in info sidebar #4966
startEditing() used querySelector(.meta-inline-edit input) which matched
the first such element in the DOM. The People combobox shares that class
and renders above subject/artist/copyright/license/keywords/notes, so
clicking any of those add-prompts focused a marker input instead of the
clicked field. Replace the DOM query with a shared template ref on the
mutually-exclusive inline editors and add meta-<field> / meta-inline-<field>
hooks to all rows for consistent styling and test selectors.
2026-05-05 14:21:50 +02:00
Cathie Integra
6609b709d6 Setup: Document chromium runtime dependencies in install-chrome.sh 2026-05-05 12:50:26 +02:00
Cathie Integra
369edd3556 Setup: Install chromium from PhotoPrism's internal mirror with XtraDeb fallback 2026-05-05 12:47:25 +02:00
Michael Mayer
c03aebe5e2 Docs: Align AGENTS and CODEMAP files with frontend/README
AGENTS.md: add frontend/ to package-doc paths and point at
frontend/README.md for pin/override/dep policy.

frontend/AGENTS.md: new "Dependencies & Pins" section briefs agents
on the pins-are-intentional rule, the workspace npm install location,
and the orphan-audit pattern.

frontend/CODEMAP.md: trim the duplicated Vuetify pin paragraph and
link to frontend/README.md as the canonical rationale; keep the
upstream-issue caveats since they relate to component bindings.

Refresh Last Updated dates on all four files.
2026-05-05 10:17:28 +00:00
Michael Mayer
70582c903b Rules: Capture session learnings on pins, deps, and specs/ links
frontend-rules.md: new "Frontend Dependencies & Pins" section
points at frontend/README.md as the canonical pin doc, restates
the pins-are-intentional rule, and documents the workspace npm
install location plus the orphan-audit pattern.

commit-and-docs-style.md: explicit no-specs/-in-public rule with
the AGENTS.md/CLAUDE.md exception; note that gh issue create lacks
a --type flag so issue type must be set via the web UI.

sources-of-truth.md: add frontend/README.md to the package-README
list and call out its pin/override/orphan content directly.
2026-05-05 10:14:44 +00:00
Michael Mayer
eb49c285d7 Frontend: Retire redundant minimatch override
The "minimatch@~3.0": "^3.1.3" override was added on 2026-04-27 to
force-patch the ReDoS chain when postcss-url's locked minimatch@3.0.8
was the active vulnerability. With postcss-url removed, no consumer
in the tree pins to ~3.0.x anymore — every remaining minimatch
request (^3.0.4 from babel-plugin-istanbul/test-exclude and
eslint-plugin-node, ^3.1.5 from the eslint family, ^9.0.4 / ^10.1.1
from modern tooling) resolves naturally to a patched version.

Verification: removing the override leaves the lockfile byte-identical
("up to date in 932ms"), npm audit reports zero vulnerabilities, and
all installed minimatch versions are 3.1.5 / 5.1.x / 9.0.9 / 10.2.5
(no <3.1.4 entry). Build and 1055 vitest tests pass.
2026-05-05 10:13:03 +00:00
Michael Mayer
4410269cc2 Frontend: Drop unused @testing-library/react and vite-tsconfig-paths
Both were added during the Vitest framework integration (#4990) but
never referenced in any source file or test config — npm ls confirms
zero transitive consumers. PhotoPrism is Vue, so the React testing
library is not applicable; @testing-library/jest-dom (the actually
used helper) stays. The TS-paths resolver was speculatively added
when the Vite config was first stubbed and was never wired up.

README's "Known Unused" table is replaced with a short "Auditing for
Orphaned Dependencies" section so the sweep pattern (rg + npm ls)
is documented for future cleanups.
2026-05-05 10:07:55 +00:00
Michael Mayer
8339ed1b26 Frontend: Drop orphaned cheerio dependency from package.json
Cheerio was originally pulled in alongside easygettext@2.17.0 in May
2022 (commit d600d5faf), where easygettext declared cheerio@^1.0.0-rc.3
as a runtime dep for HTML parsing in the gettext-extract flow. When
easygettext was replaced by vue3-gettext / vue-gettext-extract in
October 2025 (commit ab9a0a969 / #1152), cheerio was overlooked and
left as a top-level dep with no consumers.

The exact pin to 1.0.0-rc.12 was set in September 2024 (commit
ab9e156c9, bundled into an unrelated UX commit) after an August 2024
bump to ^1.0.0 broke easygettext's ^1.0.0-rc.3 peer constraint. That
rationale evaporated when easygettext was removed; the lockfile
reverse-search confirms zero current consumers.

npm ls cheerio --all returns only the direct top-level entry; no
source files import it. make audit, make build-js, make test-js
(1055 passed / 13 skipped) all stay clean after removal.
2026-05-05 09:59:09 +00:00
Michael Mayer
3f9ac173c4 Frontend: Shorten docs in README.md
Signed-off-by: Michael Mayer <michael@photoprism.app>
2026-05-05 11:47:25 +02:00
Michael Mayer
3012786d82 Docs: Drop private subrepo references from public files
Sweeps top-level CODEMAP/GLOSSARY, package READMEs under internal/,
and a handful of source-comment references that linked to the private
specs/ subrepo. AGENTS.md hints stay (agent-instruction document) and
the agent-skill linking targets in Makefile are guarded with
directory checks.
2026-05-05 09:40:18 +00:00
Michael Mayer
f95aec73a3 Frontend: Drop private subrepo references from README
Removes specs/ links from the public package README so external
readers don't hit 404s and the existence of the private specs
subrepo isn't leaked.
2026-05-05 09:35:19 +00:00
Michael Mayer
68f9088629 Frontend: Add README documenting deps, pin rationale, and ESM blockers
Captures why specific packages are pinned (vuetify, axios, cheerio),
which transitive overrides exist and why, and which major upgrades
are currently blocked by CJS config files. Includes add/remove/bump
checklists so future contributors can avoid duplicate research.
2026-05-05 09:31:54 +00:00
Michael Mayer
044af03a6d Frontend: Bump axios from 1.15.2 to 1.16.0 in package.json
The supply-chain compromise that drove the original 1.14.0 quarantine
(malicious 1.14.1/0.30.4 from a hijacked maintainer account) was fully
remediated upstream weeks ago, so 1.16.0 is safe. Keeps the exact-pin
style recommended for high-risk packages.
2026-05-05 09:29:31 +00:00
Michael Mayer
c3fb3d53ca Frontend: Bump routine deps in package.json and package-lock.json
Updates four low-risk packages within their existing major lines:
@vue/compiler-sfc 3.5.18 -> 3.5.33 (track vue runtime), webpack-bundle-analyzer
4.10.2 -> 5.3.0 (CJS-compatible, drops Node <20.9), babel-plugin-polyfill-corejs3
0.13.0 -> 0.14.2, vite-tsconfig-paths 5.1.4 -> 6.1.1.
2026-05-05 09:27:18 +00:00
Michael Mayer
a2dce2b06c Frontend: Drop unused postcss-url and @vitejs/plugin-react
Removes two stale dependencies that have no code references in any
frontend/, plus/frontend/, pro/frontend/, or portal/frontend/ tree.
postcss-url was a 2019 leftover and is the only consumer of the
unpatched minimatch <=3.1.3 ReDoS chain (GHSA-3ppc-4f35-3m26,
GHSA-7r86-cg39-jmmj, GHSA-23c5-xmqv-rm74); npm audit now reports
zero vulnerabilities.
2026-05-05 09:22:20 +00:00