Commit af6fa01
feat(committees): add file upload, folder hierarchy, drill-down nav (#625)
* feat(committees): add file upload, folder hierarchy, drill-down nav
End-to-end document management on the committee Documents tab:
File upload
- Upload File button (gated by canEdit) reuses the shared lfx-file-upload
component for drag-drop + picker
- POST /api/committees/:id/documents/upload streams raw binary, BFF
re-emits as multipart/form-data to the upstream committee service
using the form-data package (now declared explicitly)
- GET /api/committees/:id/documents/:documentId/download streams the
file binary back to the browser with Content-Disposition
Folder hierarchy + drill-down
- Switched the committee Documents tab from documentService.getMyDocuments
(which silently filtered out folders and never fetched files) to
committeeService.getCommitteeDocuments, which now also queries the
query-service for committee_document resources alongside folders + links
- Root view: folders alphabetically with (N) child counts, then orphans
- Click a folder name to drill in; breadcrumb returns to root
- Add Link from inside a folder pre-selects that folder as the parent
Toast wiring fix
- Removed local MessageService provider in committee-documents.component.
A local provider creates a fresh instance disconnected from the global
<p-toast /> in app.component.html, which is why every Add Link / Add
Folder / Upload File toast was silently dropped
Action button polish
- Links now render an Open button (was Download) — opens in a new tab
- Files render Download wired to the new BFF download endpoint via the
new MyDocumentItem.downloadUrl field (the existing /api/documents/
download proxy is for external URLs only)
Better error toasts
- Read err.error.error (the actual BFF response field) before falling
back to err.error.message and the generic string
- Translate 409 conflicts to "A document with this name already exists
in this committee. Please pick a different name."
Two upstream gaps remain (filed separately against
lfx-v2-committee-service, assigned to Prabodh Chaudhari):
1. GET /committees/{uid}/documents to list uploaded files — replaces
the BFF indexer fallback used here
2. folder_uid on POST /committees/{uid}/documents — uploaded files
currently always land at the root regardless of the active folder
Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(review): address PR #625 review feedback
Address review comments from @github-advanced-security, @copilot-pull-request-reviewer,
and @coderabbitai:
- committee.controller.ts: extracted contentDispositionAttachment() helper
emitting RFC 5987 (ASCII fallback + filename*=UTF-8'') so backslashes,
control chars, and Unicode filenames are handled safely
(per @github-advanced-security CodeQL alert and @copilot/@CodeRabbit nits)
- committee.controller.ts: validate file_size query param matches the actual
request body length in uploadCommitteeDocument — refuse mismatches rather
than forwarding inaccurate metadata upstream (per @copilot)
- committee.controller.ts + committee.service.ts: switched download from
buffering the entire file to streaming. Added api-client.streamRequest()
and microservice-proxy.proxyStreamRequest() that return the raw fetch
Response so the controller pipes upstream.body directly to res via
pipeline(). Avoids holding 100MB payloads in RAM under concurrent
downloads (per @copilot)
- committee.service.ts: split downloadCommitteeDocument into
getCommitteeDocumentMetadata (uses committee_uid:{id} tag matching the
documented indexer contract and finds the doc by uid in the response,
instead of the unverified committee_document_uid tag) and
getCommitteeDocumentStream (per @CodeRabbit)
- committee.interface.ts: reverted CreateCommitteeDocumentType to
'link' | 'folder' (matches the JSON create endpoint validation) and
introduced DocumentFormMode = CreateCommitteeDocumentType | 'file' for
the dialog-mode discriminator (per @copilot)
- documents-table.component.ts: omit the anchor's download attribute when
navigating to a BFF downloadUrl so the server's Content-Disposition
filename (the original file_name) is honored instead of being overridden
by the display name (per @copilot)
- committee-documents.component.ts: reset currentFolderUid to null after
a successful file upload so the just-uploaded file is visible — uploads
always land at the committee root (folder_uid is not yet supported on
the upload endpoint, filed separately) (per @CodeRabbit)
- document-form.component.html: added aria-label and title to the icon-only
clear-file button for keyboard/screen-reader users (per @CodeRabbit)
Resolves 9 review threads.
Pushing back on 2 remaining threads (no code change):
- @copilot suggested isChild=true for folder-view children — intentionally
false because drilled-in children are siblings and the breadcrumb already
conveys context; isChild indentation is for the root view's grouped layout
- @copilot suggested adding file_size to the multipart upload payload —
upstream UploadCommitteeDocumentRequestBody has no file_size field; the
upstream calculates size from the binary
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(security): replace req.query cast with getStringQueryParam in uploadCommitteeDocument
Use getStringQueryParam() from validation.helper for all upload query params
instead of `req.query as Record<string, string>`. Express req.query values
are typed string | string[] | ParsedQs | ParsedQs[]; the cast was TypeScript-
only and provided no runtime protection against array injection via repeated
query-string keys (e.g. ?file_size[]=100).
getStringQueryParam enforces `typeof value === 'string'` at runtime and
returns undefined for arrays/objects, which the existing fieldErrors guard
then rejects with a ServiceValidationError.
Fixes CodeQL alerts js/type-confusion-through-parameter-tampering on
committee.controller.ts:694 and :697.
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
Agent-Logs-Url: https://github.com/linuxfoundation/lfx-v2-ui/sessions/fa5314b8-b06b-4e9c-898b-b11c9dcf6b9e
Co-authored-by: manishdixitlfx <142783321+manishdixitlfx@users.noreply.github.com>
* fix(review): address PR #625 review iteration 2
Address follow-up review comments from @coderabbitai on commit 24b0405.
The CodeQL alert fix landed separately as 8954620 (Copilot autofix bot).
- api-client.service.ts: wrapped streamRequest's fetch() in try/catch and
classify transport errors as MicroserviceError (timeout → 408, network →
500 with cause code) — mirrors the executeRequest pattern so the download
path no longer degrades a timeout into a generic 500 (per @CodeRabbit)
- committee.service.ts: paginate the committee_document listing via
fetchAllQueryResources (matches the pattern used for committees, members,
etc.). A single-page fetch silently dropped older files once a committee
accumulated more than the upstream page size (per @CodeRabbit)
- committee.service.ts: switched single-document metadata lookup to query
by `committee_document_uid:{documentId}` tag — every committee_document is
indexed with this tag per upstream CommitteeDocument.Tags(), so the query
returns at most one resource. Avoids both the pagination concern (no need
to walk pages) and the previous wide-then-filter pattern. Expanded the
CommitteeDocumentQueryResult docstring to document all available indexer
tags so future callers pick the right one (per @CodeRabbit)
Resolves 3 review threads.
Deferred to follow-up (response posted, thread left unresolved):
- Multipart double-buffering on upload — concern is valid but the fix
requires a cross-cutting api-client refactor (stream form-data via pipe()
instead of getBuffer()) that affects every FormData caller. Belongs in
its own PR after a sweep of upload sites.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(review): address PR #625 review feedback
Substantive fixes (per @copilot-pull-request-reviewer and @manishdixitlfx):
- committee.controller.ts: server-side allowlist check on upload using
shared ALLOWED_FILE_TYPES + isFileTypeAllowed (frontend-side allowlist
was bypassable via direct API calls); added path-traversal guard on
file_name; replaced `as any` on Readable.fromWeb with typed
NodeReadableStream<Uint8Array> assertion
- committee.service.ts: switched two logger.warning catches to use the
`err` field instead of `error: err.message` so the Pino error
serializer captures the full stack trace per logging-patterns.md;
updated the get_committee_documents debug log to mention files;
dropped file_size from the upload FormData (upstream
UploadCommitteeDocumentRequestBody schema does not declare file_size,
so it was dead data — verified against committee-service openapi3.yaml)
- committee-documents.component.ts: dropped redundant inner catchError
in initCommitteeDocuments — the frontend committeeService already
wraps with catchError(() => of([])); fixed Source filter so folder
rows are excluded from source matching (folders previously fell
through to source='link' which polluted the Link filter)
Comment-style cleanup (per @MRashad26):
- Shortened or removed verbose explanatory comments across
committee.controller.ts, committee.service.ts, api-client.service.ts,
committee-documents.component.ts, document-form.component.ts, and
documents-table.component.ts to align with the project's "default to
no comments" guidance — kept comments only where the WHY is
non-obvious
Net: -20 lines.
Resolves the substantive Copilot threads on folder source mapping,
server-side MIME validation, and the stale debug log; resolves the
two err-vs-error logger threads from my own review pass; resolves
all 16 of @MRashad26's verbosity comments; corroborates the existing
file_size FormData pushback by removing the dead field.
Pushbacks left unresolved (no code change, prior explanations stand):
- isChild=false for folder-view children — drilled-in rows are
siblings, indentation conveys nothing the breadcrumb doesn't already
- Copilot's request to ADD file_size to FormData — upstream schema
does not declare it; this commit removes the existing append for
consistency
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* docs(committees): clarify file_size is BFF-only and add folder_uid TODOs
- Expand JSDoc on UploadCommitteeDocumentRequest.file_size to make it
explicit that the field is BFF-only (used for request body validation
only; not forwarded to upstream which has no file_size in its schema)
- Add optional folder_uid field to UploadCommitteeDocumentRequest with
a TODO comment for when upstream adds support (LFXV2-1632)
- Add matching TODO comment in committee.service.ts where the FormData
is assembled to append folder_uid once upstream accepts it
Signed-off-by: copilot <copilot@github.com>
Agent-Logs-Url: https://github.com/linuxfoundation/lfx-v2-ui/sessions/fb2bbf75-72bf-4ae7-99ce-81ae9471ea70
Co-authored-by: manishdixitlfx <142783321+manishdixitlfx@users.noreply.github.com>
* fix(review): trim upload names; classify all stream errors
Address review comments from @coderabbitai:
- committee.controller.ts: trim `name` and `file_name` query params
before required-field validation so whitespace-only strings
(e.g. `" "`) fail. Use the trimmed values for the MIME allowlist
check, the path-traversal guard, the uploadData payload, and the
success log so upstream receives the actual stored value.
- api-client.service.ts: add a final-fallback `MicroserviceError(500,
NETWORK_ERROR)` in `streamRequest`'s catch block. Previously, an
Error instance without `cause.code` was rethrown raw, bypassing typed
server-side error handling. Every transport failure on the streaming
path is now a typed MicroserviceError, matching `executeRequest`.
Resolves 2 review threads.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Manish Dixit <142783321+manishdixitlfx@users.noreply.github.com>
* perf(ssr): route SSR API calls over loopback (#632)
* perf(ssr): route SSR API calls over loopback (LFXV2-1634)
Add ssrBaseUrlInterceptor that rewrites relative /api/* and
/public/api/* URLs to http://127.0.0.1:$PORT when running on the
server platform, so SSR talks to the in-process Express server
directly instead of routing through Cloudflare/Traefik via the
public hostname. Browser behavior is unchanged.
Datadog trace b40ef136d08d7f7740c34d90b0ddf006 showed an SSR-emitted
POST /public/api/meetings/:id/join-url taking 160 seconds; the
actual upstream meeting service responded in <200ms. The remaining
time was Cloudflare/LB/connection-queueing on the SSR's call to
itself via app.lfx.dev. Loopback removes that round trip.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
* fix(review): address PR #632 review feedback
Address review comments from copilot-pull-request-reviewer, coderabbitai:
- app.config.ts: reorder interceptors so authenticationInterceptor runs
before ssrBaseUrlInterceptor. authentication only attaches cookies when
req.url starts with /api/ or /public/api/, so it must see the original
relative URL before the SSR rewrite to loopback (per copilot-pull-request-reviewer, coderabbitai)
- ssr-base-url.interceptor.ts: add JSDoc above the exported interceptor
to match the convention in authentication.interceptor.ts (per coderabbitai)
Resolves 3 review threads.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
---------
Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* perf(ssr): defer meeting join URL fetch to client (LFXV2-1634) (#634)
Skip the POST /public/api/meetings/:id/join-url call during SSR.
The Zoom join URL is only consumed by window.open in the browser,
so fetching it server-side adds upstream-call latency to TTFB
without producing any user-visible content.
Datadog trace b40ef136d08d7f7740c34d90b0ddf006 showed this fetch
blocking SSR until the upstream resolved. PR #632 fixed the
routing of the call (loopback); this change removes it from the
SSR critical path entirely.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(dashboard): add info-icon tooltip to ED metric cards (#633)
* fix(dashboard): add info-icon tooltip to ED metric cards
Methodology tooltips were only visible on full-card hover with no
visual indicator. Add an optional infoTooltip input to metric-card
that renders a small (i) icon next to the title. Wire it up for all
ED marketing overview cards so users can discover calculation details.
Addresses Mazin's feedback that Flywheel Conversion is "opaque, no
calc shown" (Confluence item #13).
LFXV2-1623
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
* fix(dashboard): make info tooltip keyboard-accessible
Use a button element instead of bare <i> for the info icon so it is
focusable and has an aria-label. Stop click propagation to prevent
triggering the card click handler.
LFXV2-1623
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
---------
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(dashboard): label health scores as "projects scored" (#631)
* fix(dashboard): label health scores as "projects scored"
Health score buckets (4) can differ from Total Projects (3) because
not all projects have a Crowd.dev health score. Add "N projects
scored" subtitle on the card and update the drawer badge to say
"projects scored" so users don't confuse it with total project count.
LFXV2-1618
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
* fix(dashboard): update badge comment to match new copy
LFXV2-1618
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
---------
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(dashboard): add past/upcoming tag to event growth drawer rows (#630)
* fix(dashboard): add past/upcoming tag to event growth drawer rows
Event rows in the Event Growth drawer mixed realized and forecast
revenue without visual distinction. Add a "Past" or "Upcoming" tag
next to each event name, computed from the event date. Helps users
understand whether revenue is realized or committed.
LFXV2-1622
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
* fix(dashboard): address review feedback on event past/upcoming tags
Guard isPast for empty event dates, update JSDoc to reflect isPast
field, and add min-w-0/truncate to prevent long event names from
breaking column alignment.
LFXV2-1622
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
---------
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(dashboard): clarify events change indicator with past/upcoming split (#629)
The change indicator showed "+10 vs prev period" without context,
misleading users when most events are upcoming. Now appends a
breakdown "(2 past · 8 upcoming)" when upcoming events exist so
the total is transparent.
LFXV2-1626
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(dashboard): cap sponsorship percentage label at 999% (#628)
The progress bar already caps at 100% visually, but the text label
displayed the raw uncapped value (e.g. "61365% of goal") when the
Snowflake goal target is misconfigured. Cap the label at ">999%"
to prevent misleading numbers while the upstream data is corrected.
LFXV2-1619
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(dashboard): align engaged community channel names with chart labels (#627)
The card description and tooltip listed "Slack, Discord, GitHub,
mailing lists" but the Community Breakdown chart shows "Community,
Working Groups, Newsletter, Certified". Update both strings to
match the actual data channels.
LFXV2-1623
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(meetings): match registrant by username for restricted join (#636)
* fix(meetings): match registrant by username for join (LFXV2-1634)
Public meeting join and "my RSVP" lookups now identify the user by
their registrant rather than just their auth email. Resolves the case
where an account has multiple emails (auth-provider primary differs
from invited registrant email), which previously caused a false "not
registered" denial on join and a missing RSVP on the meeting page.
- Restricted-meeting access check matches by username first, falling
back to email; the matched registrant's stored email is used for the
upstream join_link call so Zoom resolves to the correct invitee.
- Current-user RSVP lookup resolves the registrant via email-or-
username, then filters RSVPs by registrant_id — RSVP records carry
registrant_id reliably, while their username field is often null.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
* fix(review): address PR #636 review feedback
Address review comments from copilot[bot], coderabbitai:
- meeting.service.ts: switched RSVP lookup from getUsernameFromAuth to
getEffectiveUsername — the former returns the OIDC `sub` (e.g.
`auth0|<id>`) for non-Authelia sessions, the latter returns the LFID
nickname that matches `registrant.username` (per copilot[bot])
- meeting.service.ts: filter RSVPs by a Set of all matching registrant
UIDs rather than only registrants[0], so users with occurrence-
specific invites or multiple registrant rows for the same meeting
see all their RSVPs (per copilot[bot], coderabbitai)
- public-meeting.controller.ts: identity-neutral validation and
authorization error messages — failures via the username path no
longer claim the problem was a missing or unmatched email address
(per copilot[bot], coderabbitai)
Resolves 6 review threads.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
* fix(meetings): match restricted-join denial by error code, not message
The previous commit changed the restricted-meeting denial message to
identity-neutral wording, which broke the meeting-join UI's alternate-
email affordance — meeting-join.component.ts only showed the "Click
here to join using a different email address" link when the error
message contained the substring "email address is not registered for
this restricted meeting".
Replace the brittle substring match with a stable error code:
- AuthorizationError now accepts an optional `code` override so call
sites can emit a more specific code than the generic
AUTHORIZATION_REQUIRED.
- The restricted-meeting denial path now throws with
code: 'NOT_REGISTERED_FOR_MEETING'.
- meeting-join.component.ts captures `error.error.code` from the API
response into a new joinUrlErrorCode signal and matches the email-
fallback affordance on that code instead of the message text.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
---------
Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* perf(observability): tag APM spans with matched Express route (#635)
* perf(observability): tag APM spans with Express route (LFXV2-1637)
Add an applyCustomAttributesOnSpan hook on HttpInstrumentation that
sets http.route to req.baseUrl + req.route.path and updates the span
name to METHOD ROUTE. Datadog uses these to compute resource_name, so
spans now bucket by endpoint (e.g. GET /api/meetings/:id) instead of
bare HTTP method.
For SSR catch-all routes where req.route isn't set, fall back to
bucketing by first URL segment (e.g. /meetings/*) so SSR latency is
no longer lumped into a single GET bucket.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
* fix(observability): bucket root SSR requests under route '/'
Address PR #635 review feedback from coderabbitai, copilot[bot]:
- otel.mjs: handle root path in SSR fallback so http.route is set
to '/' when URL has no segments. Previously, requests to '/' left
http.route unset and landed in the bare GET resource bucket — the
exact problem this PR set out to fix. The root dashboard route
(app.routes.ts path: '') is real SSR traffic, so this matters.
Resolves 2 review threads.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
* fix(review): address PR #635 review feedback
Address review comments from copilot-pull-request-reviewer:
- otel.mjs: skip pure wildcard route paths ('**', '*', '/*', '/**')
so static-asset fallthrough does not collapse SSR spans into
GET ** (per copilot[bot])
- otel.mjs: strip trailing slash from concatenated routes so
router.get('/') mounts (e.g. /api/meetings/) bucket as their
canonical path (per copilot[bot])
- otel.mjs: bucket single-segment fallback URLs as exact paths
(e.g. /login) instead of /login/*, since they are concrete
endpoints not prefixes (per copilot[bot])
Resolves 4 review threads.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
---------
Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(dashboards): rename marketing metrics heading to marketing overview (#637)
* fix(dashboards): rename Marketing Metrics heading to Marketing Overview
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
* fix(dashboards): clarify interface name vs UI label in JSDoc comments
Address review feedback: add note that MarketingMetrics* interface
names are retained for backwards compatibility while the UI heading
has been renamed to Marketing Overview.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
---------
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* feat(sidebar): use best_match sort for project search (#638)
* feat(sidebar): use best_match sort for project search
LFXV2-1639
Switch sidebar lens-items query to upstream best_match sort whenever the
user supplies a name term. Default alphabetical ordering is preserved for
empty-search browsing.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
* fix(review): address PR #638 review feedback
Address review comments from copilot[bot], @dealako:
- apps/lfx-one/src/server/services/navigation.service.ts: trim `name`
once in buildQuery — whitespace-only values no longer flip sort to
best_match or forward a meaningless query upstream (per copilot[bot],
confirmed by @dealako)
Resolves 1 review thread.
Signed-off-by: Asitha de Silva <asithade@gmail.com>
---------
Signed-off-by: Asitha de Silva <asithade@gmail.com>
Co-authored-by: David Deal <ddeal@linuxfoundation.org>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* docs: add permission persona navigation preread
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* feat(observability): add UX readiness health check endpoint (#639)
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* docs: add markdown permission persona preread
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
* fix(review): address PR #625 review feedback
Address review comments from @copilot-pull-request-reviewer and self-flagged
nits:
- committee.service.ts:741: rewrite misleading pagination comment to describe
fetchAllQueryResources behavior accurately (per @copilot)
- committee.service.ts:960 (getCommitteeDocumentMetadata): scope query with
tags_all=[committee_document_uid, committee_uid] to prevent cross-committee
metadata leakage on a guessed/leaked document UID (per @copilot)
- microservice-proxy.service.ts: remove dead error-wrapping branch in
proxyStreamRequest — apiClient.streamRequest throws MicroserviceError with
statusCode (not status), so the wrapper was unreachable; bare rethrow is
correct (per @copilot)
- committee-documents.component.ts: drop unused projectUid arg from
toDisplayItem and leave foundationUid undefined for committee documents
(project_uid may be a sub-project, not a foundation) (per @copilot)
- documents-table.component.html: add aria-hidden=true to decorative
folder/file icons (per @copilot)
- committee.interface.ts:549: drop the @see LFXV2-1632 reference on the
folder_uid TODO — that ticket is the streaming-uploads refactor, not the
folder_uid upstream gap (self-flagged)
- docs/architecture/frontend/permission-persona-navigation-model-preread.md:
prettier formatting fix to unblock pre-commit format:check
Resolves 7 review threads. Two threads remain unresolved pending human
review (isChild=false in folder view, file_size removed from upstream
multipart) — pushback responses already posted.
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
---------
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
Signed-off-by: Manish Dixit <142783321+manishdixitlfx@users.noreply.github.com>
Signed-off-by: Asitha de Silva <asithade@gmail.com>
Signed-off-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Asitha de Silva <asithade@gmail.com>
Co-authored-by: Misha Rautela <mrautela@linuxfoundation.org>
Co-authored-by: David Deal <ddeal@linuxfoundation.org>1 parent 36d7493 commit af6fa01
18 files changed
Lines changed: 1174 additions & 56 deletions
File tree
- apps/lfx-one
- src
- app
- modules/committees/components
- committee-documents
- document-form
- server
- controllers
- routes
- services
- docs/architecture/frontend
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| 60 | + | |
60 | 61 | | |
61 | 62 | | |
62 | 63 | | |
| |||
Lines changed: 26 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
7 | 15 | | |
8 | 16 | | |
9 | 17 | | |
| |||
23 | 31 | | |
24 | 32 | | |
25 | 33 | | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
26 | 50 | | |
27 | 51 | | |
28 | 52 | | |
| |||
60 | 84 | | |
61 | 85 | | |
62 | 86 | | |
| 87 | + | |
63 | 88 | | |
64 | | - | |
| 89 | + | |
65 | 90 | | |
66 | 91 | | |
67 | 92 | | |
Lines changed: 150 additions & 23 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
16 | | - | |
17 | 15 | | |
18 | | - | |
| 16 | + | |
19 | 17 | | |
20 | 18 | | |
21 | 19 | | |
22 | 20 | | |
23 | 21 | | |
24 | 22 | | |
25 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
31 | | - | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
35 | 34 | | |
36 | 35 | | |
37 | 36 | | |
| |||
46 | 45 | | |
47 | 46 | | |
48 | 47 | | |
| 48 | + | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
54 | | - | |
55 | | - | |
| 55 | + | |
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
| 61 | + | |
61 | 62 | | |
62 | 63 | | |
63 | | - | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
65 | 67 | | |
66 | 68 | | |
67 | 69 | | |
| |||
74 | 76 | | |
75 | 77 | | |
76 | 78 | | |
| 79 | + | |
| 80 | + | |
77 | 81 | | |
78 | 82 | | |
79 | 83 | | |
| |||
86 | 90 | | |
87 | 91 | | |
88 | 92 | | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
89 | 106 | | |
90 | 107 | | |
91 | 108 | | |
| |||
107 | 124 | | |
108 | 125 | | |
109 | 126 | | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
110 | 150 | | |
111 | 151 | | |
112 | 152 | | |
| |||
124 | 164 | | |
125 | 165 | | |
126 | 166 | | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
127 | 179 | | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
140 | 225 | | |
141 | 226 | | |
142 | 227 | | |
| |||
148 | 233 | | |
149 | 234 | | |
150 | 235 | | |
151 | | - | |
| 236 | + | |
| 237 | + | |
152 | 238 | | |
153 | 239 | | |
154 | 240 | | |
| |||
160 | 246 | | |
161 | 247 | | |
162 | 248 | | |
163 | | - | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
164 | 253 | | |
165 | 254 | | |
166 | 255 | | |
167 | 256 | | |
168 | 257 | | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
169 | 288 | | |
170 | 289 | | |
171 | 290 | | |
172 | 291 | | |
173 | 292 | | |
174 | 293 | | |
175 | 294 | | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
176 | 303 | | |
0 commit comments