Require explicit portal access request IDs

Drop the request-all shortcut so callers always name the
documents, reports, and files to request. TopBar Get Access
now only signs in; bulk selection is the multi-resource path.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-07-27 16:18:30 +02:00
parent baa5a3588a
commit d0c9327e99
10 changed files with 129 additions and 211 deletions

View File

@@ -27,7 +27,7 @@ import { useTranslation } from "react-i18next";
import { graphql, useFragment } from "react-relay";
import { Link as RouterLink, useLocation } from "react-router";
import { buildRequestAllContinueUrl, redirectToInitiate } from "#/lib/auth/continueUrl";
import { getSafeContinueUrl, redirectToInitiate } from "#/lib/auth/continueUrl";
import { useLocalizedPath } from "#/lib/i18n/useLocale";
import type { TopBar_query$key } from "./__generated__/TopBar_query.graphql";
@@ -121,7 +121,7 @@ export function TopBar({ queryKey }: TopBarProps) {
highContrast
iconStart={<LockSimpleIcon />}
onClick={() => {
redirectToInitiate(buildRequestAllContinueUrl());
redirectToInitiate(getSafeContinueUrl(window.location.href));
}}
>
{t("topBar.getAccess")}

View File

@@ -43,7 +43,7 @@ import { useTranslation } from "react-i18next";
import { graphql, useFragment } from "react-relay";
import { useLocation } from "react-router";
import { buildRequestAllContinueUrl, redirectToInitiate } from "#/lib/auth/continueUrl";
import { getSafeContinueUrl, redirectToInitiate } from "#/lib/auth/continueUrl";
import { useSignOut } from "#/lib/auth/useSignOut";
import { useLocalizedPath } from "#/lib/i18n/useLocale";
import { useSubscribeDialog } from "#/lib/mailingList/subscribeDialogContext";
@@ -164,7 +164,7 @@ export function TopBarMobileNav({ identityKey }: TopBarMobileNavProps) {
iconStart={<LockSimpleIcon />}
onClick={() => {
close();
redirectToInitiate(buildRequestAllContinueUrl());
redirectToInitiate(getSafeContinueUrl(window.location.href));
}}
>
{t("topBar.getAccess")}

View File

@@ -23,10 +23,9 @@ import { FullNameRequiredError, NDASignatureRequiredError } from "@probo/relay";
import { localizedPath, resolveUrlLocale, type UrlLocale } from "#/lib/i18n/locale";
// Markers appended to a post-auth `continue` URL so the portal fires the pending
// "request access" mutation once the user lands back authenticated. `request-all`
// covers the top-bar "Get Access"; the per-resource markers carry the id of a
// single document / report / file whose access was requested from a locked row.
export const REQUEST_ALL_PARAM = "request-all";
// "request access" mutation once the user lands back authenticated. The
// per-resource markers carry the id of a single document / report / file whose
// access was requested from a locked row.
export const REQUEST_DOCUMENT_PARAM = "request-document-id";
export const REQUEST_REPORT_PARAM = "request-report-id";
export const REQUEST_FILE_PARAM = "request-file-id";
@@ -59,14 +58,6 @@ export function getSafeContinueUrl(param: string | null | undefined): string {
return fallback;
}
// Absolute URL of the current page with the request-all marker set, used as the
// `continue` target so the access request resumes after sign-in.
export function buildRequestAllContinueUrl(): string {
const url = new URL(window.location.href);
url.searchParams.set(REQUEST_ALL_PARAM, "true");
return url.toString();
}
// Absolute URL of the current page with a per-resource marker set, so a single
// document / report / file access request resumes after sign-in.
export function buildRequestAccessContinueUrl(param: string, id: string): string {

View File

@@ -27,9 +27,7 @@ import { graphql } from "relay-runtime";
import {
buildRequestAccessContinueUrl,
buildRequestAllContinueUrl,
gateRedirectPath,
REQUEST_ALL_PARAM,
REQUEST_DOCUMENT_PARAM,
REQUEST_FILE_PARAM,
REQUEST_REPORT_PARAM,
@@ -40,17 +38,6 @@ import { useMutation } from "#/lib/relay/useMutation";
import type { useResumeAccessRequest_documentMutation } from "./__generated__/useResumeAccessRequest_documentMutation.graphql";
import type { useResumeAccessRequest_fileMutation } from "./__generated__/useResumeAccessRequest_fileMutation.graphql";
import type { useResumeAccessRequest_reportMutation } from "./__generated__/useResumeAccessRequest_reportMutation.graphql";
import type { useResumeAccessRequestMutation } from "./__generated__/useResumeAccessRequestMutation.graphql";
const requestAllAccessesMutation = graphql`
mutation useResumeAccessRequestMutation {
requestAllAccesses {
compliancePortalAccess {
id
}
}
}
`;
const requestDocumentMutation = graphql`
mutation useResumeAccessRequest_documentMutation($input: RequestDocumentAccessInput!) {
@@ -99,10 +86,9 @@ const requestFileMutation = graphql`
// After a user signs in through OAuth /initiate, they land back on the page that
// carried a deferred access marker. This hook fires the matching mutation once
// (when authenticated) — request-all from the top bar, or a single
// document / report / file requested from a locked row — routes to the
// full-name gate when the backend asks for it, and clears the marker so a
// refresh never re-triggers it.
// (when authenticated) — a single document / report / file requested from a
// locked row — routes to the full-name gate when the backend asks for it, and
// clears the marker so a refresh never re-triggers it.
export function useResumeAccessRequest(isAuthenticated: boolean) {
const [searchParams, setSearchParams] = useSearchParams();
const navigate = useNavigate();
@@ -111,10 +97,6 @@ export function useResumeAccessRequest(isAuthenticated: boolean) {
const { t } = useTranslation();
const firedRef = useRef(false);
const [requestAllAccesses] = useMutation<useResumeAccessRequestMutation>(
requestAllAccessesMutation,
{ errorToast: false },
);
const [requestDocumentAccess] = useMutation<useResumeAccessRequest_documentMutation>(
requestDocumentMutation,
{ errorToast: false },
@@ -136,9 +118,8 @@ export function useResumeAccessRequest(isAuthenticated: boolean) {
const documentId = searchParams.get(REQUEST_DOCUMENT_PARAM);
const reportId = searchParams.get(REQUEST_REPORT_PARAM);
const fileId = searchParams.get(REQUEST_FILE_PARAM);
const all = searchParams.get(REQUEST_ALL_PARAM) === "true";
if (!documentId && !reportId && !fileId && !all) {
if (!documentId && !reportId && !fileId) {
return;
}
@@ -199,20 +180,11 @@ export function useResumeAccessRequest(isAuthenticated: boolean) {
variables: { input: { compliancePortalFileId: fileId } },
...makeHandlers(continueUrl),
}).catch(() => {});
return;
}
const allContinueUrl = buildRequestAllContinueUrl();
clear(REQUEST_ALL_PARAM);
void requestAllAccesses({
variables: {},
...makeHandlers(allContinueUrl),
}).catch(() => {});
}, [
isAuthenticated,
locale,
navigate,
requestAllAccesses,
requestDocumentAccess,
requestReportAccess,
requestFileAccess,