From 3609f44607a9c859996eb03fa9684cf80b443e7e Mon Sep 17 00:00:00 2001 From: Rephl3x Date: Sun, 8 Mar 2026 22:30:49 +1300 Subject: [PATCH] Process 1 build 0803262229 --- .build_number | 2 +- backend/app/build_info.py | 4 +- frontend/app/globals.css | 23 +- frontend/app/portal/page.tsx | 400 ++++++++++++++++++++--------------- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- 6 files changed, 259 insertions(+), 176 deletions(-) diff --git a/.build_number b/.build_number index 49f3e6b..1abf701 100644 --- a/.build_number +++ b/.build_number @@ -1 +1 @@ -0803262216 +0803262229 diff --git a/backend/app/build_info.py b/backend/app/build_info.py index 8affb41..d7c70d3 100644 --- a/backend/app/build_info.py +++ b/backend/app/build_info.py @@ -1,2 +1,2 @@ -BUILD_NUMBER = "0803262216" -CHANGELOG = '2026-03-08|Process 1 build 0803262038\n2026-03-07|Process 1 build 0703261729\n2026-03-04|Process 1 build 0403261902\n2026-03-04|Improve email deliverability headers and SMTP identity\n2026-03-04|Fix admin user email visibility\n2026-03-04|Harden auth flows and add backend quality gate\n2026-03-03|Fix email branding with inline logo and reliable MIME transport\n2026-03-03|Fix email template rendering for Outlook-safe branded content\n2026-03-03|Update all email templates with uniform branded graphics\n2026-03-03|Add branded HTML email templates\n2026-03-03|Add SMTP receipt logging for Exchange relay tracing\n2026-03-03|Fix shared request access and Jellyfin-ready pipeline status\n2026-03-03|Process 1 build 0303261507\n2026-03-03|Improve SQLite batching and diagnostics visibility\n2026-03-03|Add login page visibility controls\n2026-03-03|Hotfix: expand landing-page search to all requests\n2026-03-02|Hotfix: add logged-out password reset flow\n2026-03-02|Process 1 build 0203261953\n2026-03-02|Process 1 build 0203261610\n2026-03-02|Process 1 build 0203261608\n2026-03-02|Add dedicated profile invites page and fix mobile admin layout\n2026-03-01|Persist Seerr media failure suppression and reduce sync error noise\n2026-03-01|Add repository line ending policy\n2026-03-01|Finalize diagnostics, logging controls, and email test support\n2026-03-01|Add invite email templates and delivery workflow\n2026-02-28|Finalize dev-1.3 upgrades and Seerr updates\n2026-02-27|admin docs and layout refresh, build 2702261314\n2026-02-27|Build 2702261153: fix jellyfin sync user visibility\n2026-02-26|Build 2602262241: live request page updates\n2026-02-26|Build 2602262204\n2026-02-26|Build 2602262159: restore jellyfin-first user source\n2026-02-26|Build 2602262049: split magent settings and harden local login\n2026-02-26|Build 2602262030: add magent settings and hardening\n2026-02-26|Build 2602261731: fix user resync after nuclear wipe\n2026-02-26|Build 2602261717: master invite policy and self-service invite controls\n2026-02-26|Build 2602261636: self-service invites and count fixes\n2026-02-26|Build 2602261605: invite trace and cross-system user lifecycle\n2026-02-26|Build 2602261536: refine invite layouts and tighten UI\n2026-02-26|Build 2602261523: live updates, invite cleanup and nuclear resync\n2026-02-26|Build 2602261442: tidy users and invite layouts\n2026-02-26|Build 2602261409: unify invite management controls\n2026-02-26|Build 2602260214: invites profiles and expiry admin controls\n2026-02-26|Build 2602260022: enterprise UI refresh and users bulk auto-search\n2026-02-25|Build 2502262321: fix auto-search quality and per-user toggle\n2026-02-02|Build 0202261541: allow FQDN service URLs\n2026-01-30|Build 3001262148: single container\n2026-01-29|Build 2901262244: format changelog\n2026-01-29|Build 2901262240: cache users\n2026-01-29|Tidy full changelog\n2026-01-29|Update full changelog\n2026-01-29|Bake build number and changelog\n2026-01-29|Hardcode build number in backend\n2026-01-29|release: 2901262102\n2026-01-29|release: 2901262044\n2026-01-29|release: 2901262036\n2026-01-27|Hydrate missing artwork from Jellyseerr (build 271261539)\n2026-01-27|Fallback to TMDB when artwork cache fails (build 271261524)\n2026-01-27|Add service test buttons (build 271261335)\n2026-01-27|Bump build number (process 2) 271261322\n2026-01-27|Add cache load spinner (build 271261238)\n2026-01-27|Fix snapshot title fallback (build 271261228)\n2026-01-27|Fix request titles in snapshots (build 271261219)\n2026-01-27|Bump build number to 271261202\n2026-01-27|Clarify request sync settings (build 271261159)\n2026-01-27|Fix backend cache stats import (build 271261149)\n2026-01-27|Improve cache stats performance (build 271261145)\n2026-01-27|Add cache control artwork stats\n2026-01-26|Fix sync progress bar animation\n2026-01-26|Fix cache title hydration\n2026-01-25|Build 2501262041\n2026-01-25|Harden request cache titles and cache-only reads\n2026-01-25|Serve bundled branding assets by default\n2026-01-25|Seed branding logo from bundled assets\n2026-01-25|Tidy request sync controls\n2026-01-25|Add Jellyfin login cache and admin-only stats\n2026-01-25|Add user stats and activity tracking\n2026-01-25|Move account actions into avatar menu\n2026-01-25|Improve mobile header layout\n2026-01-25|Automate build number tagging and sync\n2026-01-25|Add site banner, build number, and changelog\n2026-01-24|Improve request handling and qBittorrent categories\n2026-01-24|Map Prowlarr releases to Arr indexers for manual grab\n2026-01-24|Clarify how-it-works steps and fixes\n2026-01-24|Document fix buttons in how-it-works\n2026-01-24|Route grabs through Sonarr/Radarr only\n2026-01-23|Use backend branding assets for logo and favicon\n2026-01-23|Copy public assets into frontend image\n2026-01-23|Fix backend Dockerfile paths for root context\n2026-01-23|Add Docker Hub compose override\n2026-01-23|Remove password fields from users page\n2026-01-23|Use bundled branding assets\n2026-01-23|Add default branding assets when missing\n2026-01-23|Show available status on landing when in Jellyfin\n2026-01-23|Fix cache titles and move feedback link\n2026-01-23|Add feedback form and webhook\n2026-01-23|Hide header actions when signed out\n2026-01-23|Fallback manual grab to qBittorrent\n2026-01-23|Split search actions and improve download options\n2026-01-23|Fix cache titles via Jellyseerr media lookup\n2026-01-22|Update README with Docker-first guide\n2026-01-22|Update README\n2026-01-22|Ignore build artifacts\n2026-01-22|Initial commit' +BUILD_NUMBER = "0803262229" +CHANGELOG = '2026-03-08|Process 1 build 0803262216\n2026-03-08|Process 1 build 0803262038\n2026-03-07|Process 1 build 0703261729\n2026-03-04|Process 1 build 0403261902\n2026-03-04|Improve email deliverability headers and SMTP identity\n2026-03-04|Fix admin user email visibility\n2026-03-04|Harden auth flows and add backend quality gate\n2026-03-03|Fix email branding with inline logo and reliable MIME transport\n2026-03-03|Fix email template rendering for Outlook-safe branded content\n2026-03-03|Update all email templates with uniform branded graphics\n2026-03-03|Add branded HTML email templates\n2026-03-03|Add SMTP receipt logging for Exchange relay tracing\n2026-03-03|Fix shared request access and Jellyfin-ready pipeline status\n2026-03-03|Process 1 build 0303261507\n2026-03-03|Improve SQLite batching and diagnostics visibility\n2026-03-03|Add login page visibility controls\n2026-03-03|Hotfix: expand landing-page search to all requests\n2026-03-02|Hotfix: add logged-out password reset flow\n2026-03-02|Process 1 build 0203261953\n2026-03-02|Process 1 build 0203261610\n2026-03-02|Process 1 build 0203261608\n2026-03-02|Add dedicated profile invites page and fix mobile admin layout\n2026-03-01|Persist Seerr media failure suppression and reduce sync error noise\n2026-03-01|Add repository line ending policy\n2026-03-01|Finalize diagnostics, logging controls, and email test support\n2026-03-01|Add invite email templates and delivery workflow\n2026-02-28|Finalize dev-1.3 upgrades and Seerr updates\n2026-02-27|admin docs and layout refresh, build 2702261314\n2026-02-27|Build 2702261153: fix jellyfin sync user visibility\n2026-02-26|Build 2602262241: live request page updates\n2026-02-26|Build 2602262204\n2026-02-26|Build 2602262159: restore jellyfin-first user source\n2026-02-26|Build 2602262049: split magent settings and harden local login\n2026-02-26|Build 2602262030: add magent settings and hardening\n2026-02-26|Build 2602261731: fix user resync after nuclear wipe\n2026-02-26|Build 2602261717: master invite policy and self-service invite controls\n2026-02-26|Build 2602261636: self-service invites and count fixes\n2026-02-26|Build 2602261605: invite trace and cross-system user lifecycle\n2026-02-26|Build 2602261536: refine invite layouts and tighten UI\n2026-02-26|Build 2602261523: live updates, invite cleanup and nuclear resync\n2026-02-26|Build 2602261442: tidy users and invite layouts\n2026-02-26|Build 2602261409: unify invite management controls\n2026-02-26|Build 2602260214: invites profiles and expiry admin controls\n2026-02-26|Build 2602260022: enterprise UI refresh and users bulk auto-search\n2026-02-25|Build 2502262321: fix auto-search quality and per-user toggle\n2026-02-02|Build 0202261541: allow FQDN service URLs\n2026-01-30|Build 3001262148: single container\n2026-01-29|Build 2901262244: format changelog\n2026-01-29|Build 2901262240: cache users\n2026-01-29|Tidy full changelog\n2026-01-29|Update full changelog\n2026-01-29|Bake build number and changelog\n2026-01-29|Hardcode build number in backend\n2026-01-29|release: 2901262102\n2026-01-29|release: 2901262044\n2026-01-29|release: 2901262036\n2026-01-27|Hydrate missing artwork from Jellyseerr (build 271261539)\n2026-01-27|Fallback to TMDB when artwork cache fails (build 271261524)\n2026-01-27|Add service test buttons (build 271261335)\n2026-01-27|Bump build number (process 2) 271261322\n2026-01-27|Add cache load spinner (build 271261238)\n2026-01-27|Fix snapshot title fallback (build 271261228)\n2026-01-27|Fix request titles in snapshots (build 271261219)\n2026-01-27|Bump build number to 271261202\n2026-01-27|Clarify request sync settings (build 271261159)\n2026-01-27|Fix backend cache stats import (build 271261149)\n2026-01-27|Improve cache stats performance (build 271261145)\n2026-01-27|Add cache control artwork stats\n2026-01-26|Fix sync progress bar animation\n2026-01-26|Fix cache title hydration\n2026-01-25|Build 2501262041\n2026-01-25|Harden request cache titles and cache-only reads\n2026-01-25|Serve bundled branding assets by default\n2026-01-25|Seed branding logo from bundled assets\n2026-01-25|Tidy request sync controls\n2026-01-25|Add Jellyfin login cache and admin-only stats\n2026-01-25|Add user stats and activity tracking\n2026-01-25|Move account actions into avatar menu\n2026-01-25|Improve mobile header layout\n2026-01-25|Automate build number tagging and sync\n2026-01-25|Add site banner, build number, and changelog\n2026-01-24|Improve request handling and qBittorrent categories\n2026-01-24|Map Prowlarr releases to Arr indexers for manual grab\n2026-01-24|Clarify how-it-works steps and fixes\n2026-01-24|Document fix buttons in how-it-works\n2026-01-24|Route grabs through Sonarr/Radarr only\n2026-01-23|Use backend branding assets for logo and favicon\n2026-01-23|Copy public assets into frontend image\n2026-01-23|Fix backend Dockerfile paths for root context\n2026-01-23|Add Docker Hub compose override\n2026-01-23|Remove password fields from users page\n2026-01-23|Use bundled branding assets\n2026-01-23|Add default branding assets when missing\n2026-01-23|Show available status on landing when in Jellyfin\n2026-01-23|Fix cache titles and move feedback link\n2026-01-23|Add feedback form and webhook\n2026-01-23|Hide header actions when signed out\n2026-01-23|Fallback manual grab to qBittorrent\n2026-01-23|Split search actions and improve download options\n2026-01-23|Fix cache titles via Jellyseerr media lookup\n2026-01-22|Update README with Docker-first guide\n2026-01-22|Update README\n2026-01-22|Ignore build artifacts\n2026-01-22|Initial commit' diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 0680cb9..2aa5a05 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -6565,6 +6565,27 @@ textarea { gap: 16px; } +.portal-workspace-switch { + display: inline-flex; + gap: 8px; + align-items: center; +} + +.portal-workspace-switch button { + border: 1px solid var(--line); + border-radius: 10px; + background: var(--panel-soft); + color: var(--text); + padding: 8px 12px; + font-weight: 600; +} + +.portal-workspace-switch button.is-active { + border-color: var(--accent); + box-shadow: 0 0 0 1px rgba(107, 146, 255, 0.25); + background: rgba(107, 146, 255, 0.12); +} + .portal-overview-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); @@ -6689,7 +6710,7 @@ textarea { .portal-toolbar { display: grid; - grid-template-columns: 160px 180px minmax(0, 1fr) auto; + grid-template-columns: 180px minmax(0, 1fr) auto; gap: 10px; align-items: end; } diff --git a/frontend/app/portal/page.tsx b/frontend/app/portal/page.tsx index fc02650..0df1dcd 100644 --- a/frontend/app/portal/page.tsx +++ b/frontend/app/portal/page.tsx @@ -80,12 +80,6 @@ type DiscoveryResult = { backdropPath?: string | null } -const KIND_OPTIONS = [ - { value: 'request', label: 'Request' }, - { value: 'issue', label: 'Issue' }, - { value: 'feature', label: 'Feature' }, -] as const - const STATUS_OPTIONS = [ { value: 'new', label: 'New' }, { value: 'triaging', label: 'Triaging' }, @@ -131,6 +125,31 @@ const MEDIA_TYPE_OPTIONS = [ { value: 'tv', label: 'TV' }, ] as const +const WORKSPACE_OPTIONS = [ + { value: 'request', label: 'Requests' }, + { value: 'issue', label: 'Issues' }, +] as const + +const REQUEST_FILTER_STATUS_OPTIONS = [ + { value: 'pending', label: 'Pending approval' }, + { value: 'approved', label: 'Approved' }, + { value: 'processing', label: 'Processing' }, + { value: 'partially_available', label: 'Partially available' }, + { value: 'available', label: 'Available' }, + { value: 'failed', label: 'Failed' }, + { value: 'declined', label: 'Declined' }, +] as const + +const ISSUE_FILTER_STATUS_OPTIONS = [ + { value: 'new', label: 'New' }, + { value: 'triaging', label: 'Triaging' }, + { value: 'planned', label: 'Planned' }, + { value: 'in_progress', label: 'In progress' }, + { value: 'blocked', label: 'Blocked' }, + { value: 'done', label: 'Done' }, + { value: 'closed', label: 'Closed' }, +] as const + const formatDate = (value?: string | null) => { if (!value) return 'Never' const parsed = new Date(value) @@ -161,13 +180,13 @@ export default function PortalPage() { const [status, setStatus] = useState(null) const [totalItems, setTotalItems] = useState(0) const [hasMore, setHasMore] = useState(false) + const [workspace, setWorkspace] = useState<'request' | 'issue'>('request') - const [filterKind, setFilterKind] = useState('') + const [filterKind, setFilterKind] = useState<'request' | 'issue'>('request') const [filterStatus, setFilterStatus] = useState('') const [filterMine, setFilterMine] = useState(false) const [filterSearch, setFilterSearch] = useState('') - const [createKind, setCreateKind] = useState<'request' | 'issue' | 'feature'>('request') const [createTitle, setCreateTitle] = useState('') const [createDescription, setCreateDescription] = useState('') const [createMediaType, setCreateMediaType] = useState('') @@ -196,6 +215,9 @@ export default function PortalPage() { const [requestingTmdbIds, setRequestingTmdbIds] = useState>({}) const isAdmin = me?.role === 'admin' + const visibleKindCount = Number(overview?.overview?.by_kind?.[workspace] ?? 0) + const workspaceLabel = workspace === 'request' ? 'request' : 'issue' + const workspaceLabelPlural = workspace === 'request' ? 'requests' : 'issues' useEffect(() => { if (typeof window === 'undefined') return @@ -285,7 +307,7 @@ export default function PortalPage() { limit: '60', offset: '0', }) - if (filterKind) params.set('kind', filterKind) + params.set('kind', filterKind) if (filterStatus) params.set('status', filterStatus) if (filterMine) params.set('mine', '1') const trimmedSearch = filterSearch.trim() @@ -468,6 +490,17 @@ export default function PortalPage() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [filterKind, filterStatus, filterMine, filterSearch]) + useEffect(() => { + setFilterKind(workspace) + setFilterStatus('') + setCreateMediaType('') + setCreateYear('') + setSelectedItemId(null) + setSelectedItem(null) + setComments([]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [workspace]) + useEffect(() => { if (selectedItemId == null) return void loadItem(selectedItemId) @@ -495,11 +528,11 @@ export default function PortalPage() { setStatus(null) try { const payload: Record = { - kind: createKind, + kind: workspace, title: createTitle, description: createDescription, - media_type: createMediaType || null, - year: createYear.trim() ? toPositiveInt(createYear) : null, + media_type: workspace === 'request' ? createMediaType || null : null, + year: workspace === 'request' && createYear.trim() ? toPositiveInt(createYear) : null, external_ref: createExternalRef || null, priority: createPriority, } @@ -520,7 +553,7 @@ export default function PortalPage() { } const data = await response.json() const item = data?.item as PortalItem | undefined - setStatus('Portal item created.') + setStatus(workspace === 'request' ? 'Request item created.' : 'Issue item created.') setCreateTitle('') setCreateDescription('') setCreateMediaType('') @@ -649,97 +682,118 @@ export default function PortalPage() {

Request portal

- Raise requests, issues, and feature ideas. Track progress and keep discussion in one place. + Manage requests and issues in separate workflows.

+
+ {WORKSPACE_OPTIONS.map((option) => ( + + ))} +
+ {error &&
{error}
} {status &&
{status}
} -
-
-
-

Search and request content

-

- Search Seerr content directly, then submit a request in one click. -

+ {workspace === 'request' ? ( +
+
+
+

Search and request content

+

+ Search Seerr content directly, then submit a request in one click. +

+
-
-
- setDiscoverQuery(event.target.value)} - placeholder="Search movies or TV shows" - /> - -
- {discoverError &&
{discoverError}
} -
- {discoverLoading ? ( -
Searching Seerr…
- ) : discoverResults.length === 0 ? ( -
No discovery results yet.
- ) : ( - discoverResults.map((item, index) => { - const key = `${item.type ?? 'unknown'}:${item.tmdbId ?? index}` - const requesting = Boolean(requestingTmdbIds[key]) - const poster = resolveTmdbArtworkUrl(item.posterPath, 'w185') - const hasRequest = typeof item.requestId === 'number' && item.requestId > 0 - return ( -
-
- {poster ? :
No artwork
} -
-
-
- {item.title || 'Untitled'} - {item.type ?? 'unknown'} - {item.year ? {item.year} : null} +
+ setDiscoverQuery(event.target.value)} + placeholder="Search movies or TV shows" + /> + +
+ {discoverError &&
{discoverError}
} +
+ {discoverLoading ? ( +
Searching Seerr…
+ ) : discoverResults.length === 0 ? ( +
No discovery results yet.
+ ) : ( + discoverResults.map((item, index) => { + const key = `${item.type ?? 'unknown'}:${item.tmdbId ?? index}` + const requesting = Boolean(requestingTmdbIds[key]) + const poster = resolveTmdbArtworkUrl(item.posterPath, 'w185') + const hasRequest = typeof item.requestId === 'number' && item.requestId > 0 + return ( +
+
+ {poster ? :
No artwork
}
-

+

+
+ {item.title || 'Untitled'} + {item.type ?? 'unknown'} + {item.year ? {item.year} : null} +
+

+ {hasRequest ? ( + <> + Already requested + {item.statusLabel ? ` · ${item.statusLabel}` : ''} + {item.requestId ? ` · #${item.requestId}` : ''} + + ) : ( + 'Not requested yet' + )} +

+
+
{hasRequest ? ( - <> - Already requested - {item.statusLabel ? ` · ${item.statusLabel}` : ''} - {item.requestId ? ` · #${item.requestId}` : ''} - + ) : ( - 'Not requested yet' + )} -

+
-
- {hasRequest ? ( - - ) : ( - - )} -
-
- ) - }) - )} -
-
+ ) + }) + )} + + + ) : ( +
+
+ Issue workspace is for reporting problems and tracking resolution separately from content requests. +
+
+ )}
- Total items - {Number(overview?.overview?.total_items ?? totalItems ?? 0)} + Total {workspace === 'request' ? 'requests' : 'issues'} + {visibleKindCount}
Total comments @@ -756,26 +810,13 @@ export default function PortalPage() {
-

Create item

+

{workspace === 'request' ? 'Create request item' : 'Create issue item'}

- Use Request for new content, Issue for broken behavior, and Feature for improvements. + {workspace === 'request' + ? 'Create and track request-related notes in a dedicated request workflow.' + : 'Create and track operational issues in a dedicated issue workflow.'}

- - + {workspace === 'request' && ( + <> + + + + )}
-