* chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1
Bumps [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) from 0.14.2 to 0.22.1.
- [Release notes](https://github.com/oxc-project/tsgolint/releases)
- [Commits](https://github.com/oxc-project/tsgolint/compare/v0.14.2...v0.22.1)
---
updated-dependencies:
- dependency-name: oxlint-tsgolint
dependency-version: 0.22.1
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* chore: Switch tsconfig to bundler resolution for tsgolint 0.22.1
oxlint-tsgolint 0.22.1 removed support for moduleResolution=node10
(the alias for "node"). Switch to "bundler" with resolvePackageJsonExports
disabled so packages whose exports field omits a types condition still
resolve. Update markdown-it type imports to sub-paths since the package's
.d.mts entry only re-exports a subset of named types.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix: Resolve type-aware lint errors caught by tsgolint 0.22.1
oxlint-tsgolint 0.22.1 catches several await-thenable, no-floating-promises,
and no-meaningless-void-operator cases the prior 0.14.2 missed:
- Drop redundant inner `await` from Promise.all([await x, await y]) call sites
so the array entries are real Promises rather than already-resolved values.
- Replace Promise.all wrappers around synchronous presenters (presentEvent,
presentTemplate, presentPublicTeam) with plain map / direct calls.
- Wrap non-promise branches of ternaries inside Promise.all with
Promise.resolve so the array remains thenable across both arms.
- Add `void` to the unawaited provider.connect() in the auth-failed retry
chain, and remove `void` from the disconnect() call which returns void.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* 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>
* wip
* Remove obsolete snapshots
* simplify
* chore(test): Convert mocks to TypeScript and tighten fetch mock types
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Remove unneccessary patches
* Migrate to msw instead of custom fetch mock
* Address PR review comments
- Split chained vi.useFakeTimers().setSystemTime() into separate calls.
- Switch test setup to dynamic imports so EventEmitter.defaultMaxListeners
assignment runs before module init (static imports were hoisted above it).
- Drop redundant NODE_ENV guard in monkeyPatchSequelizeErrorsForJest; its
sole caller already gates on env.isTest.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* chore: Replace lodash with es-toolkit
Migrate all direct lodash imports to es-toolkit/compat for a smaller,
faster, lodash-compatible utility library. Transitive lodash usage from
other packages remains unchanged.
* fix: Restore isPlainObject semantics in CanCan policy
The lodash migration aliased `isObject` to `lodash/isPlainObject` and
the codemod incorrectly mapped the local name to es-toolkit's `isObject`,
which also returns true for arrays and functions. This caused condition
objects in policy definitions to be skipped, breaking authorization
checks across the codebase.
* fix: Restore unicode-aware length counting in validators
es-toolkit/compat's size() returns string.length, while lodash's _.size()
counts unicode code points. Switch to [...value].length to preserve the
previous behavior so multi-byte characters like emoji count as one.
- Use transient `$rtl` prop on Meta styled component so it isn't forwarded to the DOM
- Wrap ActionButton in observer so action visibility checks read MobX computed values inside a reactive context
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Plumbed `dictionary` props through editor components, menus, extensions,
and nodes. Replaces with `useTranslation()` in React contexts and direct
`t` imports from i18next elsewhere.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix: Open notifications in a bottom drawer on mobile
Match the mobile context menu pattern by rendering the notifications
panel as a Vaul bottom drawer below the tablet breakpoint, while
keeping the existing Radix popover on desktop.
* fix: Notification drawer opens at correct height on mobile
Skip the height animation while bounds is unmeasured to avoid a
feedback loop between framer-motion's animation toward 0 and the
ResizeObserver re-targeting it. Eagerly import Notifications so first
paint has real content for the initial measurement, and bump its
minHeight to 75vh on mobile to match other bottom drawers.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Increase emoji picker cell size on mobile
Mobile uses a 40px button with a 32px emoji glyph (vs. 32px / 24px on
desktop), so roughly 8 emojis fit across a typical phone screen for
easier touch targeting.
https://claude.ai/code/session_017Rrv75Rc6eZ7eb2iNpZxpu
* tweaks
---------
Co-authored-by: Claude <noreply@anthropic.com>
* chore: Update editor generics
* fix: Address PR review on editor generics
- Restore null-guard on Link click handler so anchors aren't inert when no onClickLink is provided
- Mark onClickLink optional in LinkOptions and openLink command to match runtime
- Remove dead `collapsed` option from HeadingOptions
- Make ToggleBlock dictionary optional and restore optional-chained access for server-side schema instantiation
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* chore: promote no-explicit-any from warn to error and resolve violations
Upgrades the oxlint rule severity and removes all 40 existing
`no-explicit-any` warnings across the codebase. Most call sites gained
proper types (SharedEditor refs, JSONNode/JSONMark for ProseMirror JSON
walking, DocumentsStore, dd-trace `Span` parameter inference, prosemirror
Fragment public API in place of internal `(fragment as any).content`).
A few load-bearing `any` uses were preserved with scoped disable
comments where changing the type would cascade widely (Sequelize JSONB
columns on `Event`, the `withTracing` higher-order function generic,
`Extension.options` consumed by many subclasses, dd-trace's `req`
patching).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: resolve no-explicit-any lint warnings in plugins
Replaces uses of `any` in the plugins directory with concrete types,
`unknown`, or structured type assertions, addressing the remaining
typescript-eslint(no-explicit-any) warnings flagged by oxlint.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: address review feedback in GitLabIssueProvider
Drop trailing semicolon from log string and add early return in
`destroyNamespace` when neither `user_id` nor `full_path` is present
to avoid an unnecessary full-scan transaction.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* fix: centralize sidebar expansion state to eliminate O(N²) tree traversals
Each DocumentLink previously traversed the full collection tree independently
to determine whether to auto-expand (pathToDocument / descendants), which is
O(N) per row and quadratic overall. With thousands of documents this makes
the sidebar unusable.
Replaces per-node expansion state with a single MobX-backed
SidebarExpansionState per tree root. The ObservableSet ensures only the
toggled node re-renders. Alt-click cascade, auto-expand on navigation,
and drag-to-reparent expansion all go through the same centralized state
instead of the per-node SidebarDisclosureContext relay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: move SidebarExpansionContext alongside other sidebar contexts
Rename hooks/useSidebarExpansion.ts to components/SidebarExpansionContext.ts
to match the convention of SidebarContext.ts and SidebarDisclosureContext.ts.
The context is now the default export with hooks as named exports.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: scope sidebar expansion to its own tree and restore alt-click cascade
`useSidebarExpansionState` was unconditionally adding the active document
id to every per-tree expansion set, which made `SharedWithMeLink` auto-
expand whenever the user navigated anywhere in the matching sidebar
context. `computeAncestorPath` now includes the target when found and
returns empty when absent, so the hook only expands ids that actually
belong to its tree.
Also restores alt-click cascade for `StarredDocumentLink` and
`SharedWithMeLink`: the parents still broadcast disclosure events but
`DocumentLink` no longer listens, so nested children weren't expanded.
`StarredDocumentLink` now subscribes via `useSidebarDisclosure` (mirroring
`CollectionLinkChildren`), and `SharedWithMeLink` calls
`expansion.expandAll`/`collapseAll` directly on alt-click.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix: collapse expanded nodes when children are removed and deduplicate shared expansion provider
Restores the effect that collapses a node in the expansion state when it
no longer has children, preventing the reorder drop logic from treating
leaf nodes as expanded containers. Also removes the redundant
SidebarExpansionContext.Provider from SharedCollectionLink since the
parent SharedSidebar already provides one.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: resolve no-redundant-type-constituents and test/mock no-explicit-any warnings
Clears 36 lint warnings: all 5 no-redundant-type-constituents, 6
no-misused-spread (via narrowing getPartitionWhereClause's return type
to WhereAttributeHash), and 25 no-explicit-any in test/mock files.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: resolve no-base-to-string warnings in tests
Convert userProvisioner try/catch error assertions to Jest's
.rejects.toThrow() idiom, and cast webhook test body to string.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: resolve no-explicit-any warnings in cancan and tracing
Tighten types in the cancan policy framework and tracing decorators.
Constructor / generic-function upper bounds keep `any` where TypeScript
variance requires it, scoped to single-line oxlint-disable comments.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Adds missing stable dependencies (e.g. `t`, prop callbacks, store refs,
`setFocusedCommentId`) and removes unnecessary ones across hooks where the
fix is straightforward. For the two MobX-observed `.orderedData` deps in
`History.tsx`, keeps the original deps and silences the false positive
with `eslint-disable-next-line` so the memos still recompute when the
underlying observable arrays change.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* chore: resolve remaining unbound-method lint warnings
Apply targeted fixes per call pattern: arrow wrappers when passing a
method as a callback, arrow-function class fields when the method
doesn't depend on `this`, and `.bind()` when capturing for later
invocation.
Also replaces the rfc6902 hasOwnProperty re-export with a small wrapper
function so callers don't reference an unbound prototype method.
* chore: memoize history.goBack callbacks
Stable identity prevents Button re-renders and avoids re-subscribing
the global keydown handler in RegisterKeyDown when the parent renders.
* chore: enable typescript/restrict-template-expressions lint rule
Coerce values of unknown type with explicit String() and tighten typing
for template literal expressions across the codebase.
* fix: restore --line-height on Card for fadeOut ::after gradient
* chore: clear mechanical lint warnings
Drops 44 oxlint warnings (559 → 515) by fixing easy mechanical rules
across the codebase: no-useless-escape, no-duplicate-type-constituents,
no-redundant-type-constituents, no-unused-expressions,
no-meaningless-void-operator, require-array-sort-compare, await-thenable.
* chore: drop callback parameter from useCallback deps
The `open` argument is a parameter of the callback, not a closed-over
variable, so it doesn't belong in the deps array.
* chore: promote cleared lint rules to errors
Promotes the rules cleared in this PR from warn to error so future
violations fail the lint:
- no-unused-expressions
- typescript/await-thenable
- typescript/no-duplicate-type-constituents
- typescript/no-meaningless-void-operator
- typescript/require-array-sort-compare
Removes the override that suppressed no-useless-escape on source
files (the global rule is already error) and fixes the 21 escape
violations that this exposed in regex character classes and template
literals.
* chore: address PR review feedback
- usePinnedDocuments: simplify UrlId to plain string instead of the
intersection trick.
- PlantUML embed: move - to end of character class so it's a literal
hyphen rather than a range operator.
- checkboxes: type token params as Token | undefined to match the
actual call sites that pass tokens[index - 2] etc.
* fix: Resolve no-floating-promises lint errors
Adds await or void to 10 unhandled promises. Notable fixes: a test
assertion using `.resolves` was never awaited, and a custom emoji
fetch with setState was running during render instead of in an effect.
* chore: Promote no-floating-promises to error
Now that all occurrences are fixed, prevent regressions.
* chore(deps-dev): bump oxlint-tsgolint from 0.1.6 to 0.21.1
Bumps [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) from 0.1.6 to 0.21.1.
- [Release notes](https://github.com/oxc-project/tsgolint/releases)
- [Commits](https://github.com/oxc-project/tsgolint/compare/v0.1.6...v0.21.1)
---
updated-dependencies:
- dependency-name: oxlint-tsgolint
dependency-version: 0.21.1
dependency-type: direct:development
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot] <support@github.com>
* chore: Adjust lint config for newer oxlint-tsgolint
Pin oxlint to 1.50.0 and oxlint-tsgolint to 0.14.2. Older oxlint
can't parse newer tsgolint diagnostic payloads, and tsgolint >=0.15
rejects moduleResolution: "node" — moving off it requires either
"bundler" (currently breaks @hocuspocus@1.1.3 typings, which lack a
types condition in their package.json exports) or "node16"/"nodenext"
(would require explicit .js extensions on every relative import).
Add per-package ignorePatterns since they no longer propagate from
the root config when nested configs are present.
Drop tsconfig baseUrl (typescript-go in tsgolint rejects it) and add
a plugins/* path alias so cross-plugin imports keep resolving. The
babel resolver is switched from babel-plugin-tsconfig-paths-module-
resolver (which required baseUrl) to babel-plugin-module-resolver
with explicit aliases.
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
* chore: Resolve minimatch ReDoS advisories via dep bumps and resolutions
Bump glob (8→11), rimraf (2→6), babel-jest, jest-environment-jsdom (29→30),
and lint-staged (13→16) to drop several vulnerable transitive chains. Pin
remaining minimatch and brace-expansion descriptors via resolutions so all
in-tree copies are on their latest patched release. Removes 9 ignored
advisory IDs from .yarnrc.yml.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix: Make routeHelpers.urlify origin testable for jsdom 26
jsdom 26 (jest-environment-jsdom@30) makes window.location and
location.origin non-configurable, breaking the previous test that
redefined them via Object.defineProperty.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: Align jest-cli to ^30.3.0 with other jest packages
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
- Modal: translate default title and bind Dialog.Title to visible text
- Document Header: regroup imports and rename isNew -> wasNew
- Redis adapter: surface error.message and guard pingTimeout cleanup
- urls: fix typo and correct JSDoc @param names
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* Add year headings to compare version select
* Address review feedback on heading options
Use stable keys for heading options and set explicit displayName.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>