Files
Salihu b4cbb39f17 feat: request document access (#10825)
* feat: Request document access

Allow users without permission to a document to request access. Notifies
document managers via in-app notification and email; managers can grant
or dismiss the request.

- Adds AccessRequest model, migration, policy, presenter
- Adds accessRequests.create/info/approve/dismiss endpoints
- Adds DocumentAccessRequestNotificationsTask + email
- Adds Error403 request flow with loading state and pending indicator
- Auto-opens notifications popover via ?notifications=true (used in email)
- Adds SplitButton primitive for permission selection in notifications
- Refactors useConsumeQueryParam hook

* refactor

* fix: Make approve/dismiss idempotent on access requests

Return success when the access request has already been dismissed, or
when the user already has document membership at approve time, instead
of throwing 400. Avoids racy double-clicks on notification actions
producing user-visible errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Minor fixes

---------

Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 08:42:47 -04:00

83 lines
2.3 KiB
TypeScript

export { default as ApiKey } from "./ApiKey";
export { default as Attachment } from "./Attachment";
export { default as AuthenticationProvider } from "./AuthenticationProvider";
export { default as Relationship } from "./Relationship";
export { default as Collection } from "./Collection";
export { default as GroupMembership } from "./GroupMembership";
export { default as UserMembership } from "./UserMembership";
export { default as Comment } from "./Comment";
export { default as Document } from "./Document";
export { default as DocumentInsight } from "./DocumentInsight";
export { default as Event } from "./Event";
export { default as ExternalGroup } from "./ExternalGroup";
export { default as FileOperation } from "./FileOperation";
export { default as Group } from "./Group";
export { default as GroupUser } from "./GroupUser";
export { default as Import } from "./Import";
export { default as ImportTask } from "./ImportTask";
export { default as Integration } from "./Integration";
export { default as IntegrationAuthentication } from "./IntegrationAuthentication";
export { default as Notification } from "./Notification";
export { default as OAuthAuthentication } from "./oauth/OAuthAuthentication";
export { default as OAuthAuthorizationCode } from "./oauth/OAuthAuthorizationCode";
export { default as OAuthClient } from "./oauth/OAuthClient";
export { default as Pin } from "./Pin";
export { default as Reaction } from "./Reaction";
export { default as Revision } from "./Revision";
export { default as SearchQuery } from "./SearchQuery";
export { default as Share } from "./Share";
export { default as ShareSubscription } from "./ShareSubscription";
export { default as Star } from "./Star";
export { default as Team } from "./Team";
export { default as TeamDomain } from "./TeamDomain";
export { default as Template } from "./Template";
export { default as User } from "./User";
export { default as UserAuthentication } from "./UserAuthentication";
export { default as View } from "./View";
export { default as WebhookSubscription } from "./WebhookSubscription";
export { default as WebhookDelivery } from "./WebhookDelivery";
export { default as Subscription } from "./Subscription";
export { default as Emoji } from "./Emoji";
export { default as UserPasskey } from "./UserPasskey";
export { default as AccessRequest } from "./AccessRequest";