Commit Graph

1659 Commits

Author SHA1 Message Date
dependabot[bot] fc01deeefd chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1 (#12320)
* 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>
2026-05-12 07:59:13 -04:00
Tom Moor 7a75433bdc fix: Move OIDC redirect to useEffect (#12301) 2026-05-09 08:42:53 -04:00
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
Tom Moor 0139b91b5d chore: Replace lodash with es-toolkit (#12281)
* 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.
2026-05-06 21:03:47 -04:00
Tom Moor 4387f3ced7 fix: Resolve console warnings for rtl DOM attribute and untracked MobX read (#12284)
- 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>
2026-05-06 20:48:13 -04:00
Tom Moor e0bc08478d feat: Add system preference to open desktop app on startup (#12279)
* feat: Adds toggle to open desktop app on startup

* Remove name hardcoding

* refactor
2026-05-06 19:29:42 -04:00
Tom Moor 41031aa7e6 Optimize icon picker for mobile with responsive sizing (#12275)
* 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>
2026-05-05 23:37:15 -04:00
Tom Moor cc2427492b fix: Various small layout issues with mobile 2026-05-03 20:44:11 -04:00
Tom Moor 61709ea42e fix: Minor warnings on login screen (#12250) 2026-05-03 08:34:52 -04:00
Tom Moor fca10221b9 chore: promote no-explicit-any from warn to error (#12244)
* 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>
2026-05-02 12:14:23 -04:00
Hemachandar e2c28f4b9f fix: Autofocus inside lazy-loaded modal and popover (#12146)
* fix: Autofocus inside lazy-loaded modal/popover

* use wrapperRef

* remove unused import
2026-05-01 08:15:14 -04:00
Tom Moor 4c8a1c89b2 chore: resolve no-explicit-any and no-base-to-string lint warnings (#12217) 2026-04-29 17:45:02 -04:00
Tom Moor 57308c46af chore: resolve lint warnings (no-explicit-any, no-redundant-type-constituents, no-base-to-string) (#12209)
* 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>
2026-04-28 22:55:30 -04:00
Tom Moor f8e70c2c39 chore: resolve mechanical react-hooks/exhaustive-deps warnings (#12207)
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>
2026-04-28 22:06:09 -04:00
Tom Moor f9a2cbc1b3 chore: resolve remaining unbound-method lint warnings (#12206)
* 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.
2026-04-28 20:49:35 -04:00
Tom Moor adbffc0734 chore: clear mechanical lint warnings (Phase 1) (#12198)
* 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.
2026-04-28 20:00:03 -04:00
Tom Moor 9b7ccf8cb5 fix: Resolve no-floating-promises lint errors (#12196)
* 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.
2026-04-28 18:13:46 -04:00
Tom Moor f111c8875e Tweak TOC positioning on share (#12171) 2026-04-26 22:52:10 -04:00
Copilot 7ed41eadc6 Add per-share branding: title and logoUrl overrides (#12003)
* feat: add title and logoUrl to Share model

Agent-Logs-Url: https://github.com/outline/outline/sessions/9bc9d438-6892-4903-9d32-6b6868f4fd97

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* fix: use STRING(4096) for logoUrl column in migration

Agent-Logs-Url: https://github.com/outline/outline/sessions/9bc9d438-6892-4903-9d32-6b6868f4fd97

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* feat: use share title and logoUrl to override team branding on shared page

Agent-Logs-Url: https://github.com/outline/outline/sessions/854d6d22-e80b-4673-b3b2-0f9cf43a3246

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* refactor: use ShareValidation class constants for title/logoUrl max lengths

Agent-Logs-Url: https://github.com/outline/outline/sessions/ea462d6a-d4d3-4882-ab8e-88060bf64877

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* fix: use ShareValidation constants in @Length msg template literals

Agent-Logs-Url: https://github.com/outline/outline/sessions/694116c2-47e8-4001-a103-c8a62c7ac71e

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* feat: add display settings popover with custom title and icon for shares

Move share toggles (search indexing, email subscriptions, show last
modified, show TOC) into a popover triggered by a settings cog. The
popover also includes inputs for a custom site title and icon upload
to override team branding on shared pages. Rename logoUrl to iconUrl,
loosen URL validation to allow relative attachment paths, and surface
the popover in the shared page header for users with edit permission.

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

* styling

* Display branding on single shared pages

* Review comments

* refactor

* PR feedback

* Lose 'Remove icon' button

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 21:23:13 -04:00
Tom Moor 2e3ae72cd2 feat: Show toggle theme shortcut in keyboard shortcuts modal (#12168) 2026-04-26 13:54:56 -04:00
Tom Moor c4d764e243 feat: Show a chip in header with search term when highlighted in doc (#12165)
* feat: Show a chip in header with search term when highlighted in doc

* theme
2026-04-25 10:59:30 -04:00
Tom Moor e034a28242 chore: Address AI code quality findings (#12163)
- 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>
2026-04-25 08:25:55 -04:00
Tom Moor 1b0a5fb067 fix: TOC auto-closes, closes #12140 (#12143) 2026-04-23 05:02:55 -04:00
Tom Moor eefa8d4222 Add year headings to compare version select (#12138)
* 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>
2026-04-22 19:04:35 -04:00
Tom Moor 276ae71a91 Various fixes (#12121) 2026-04-20 19:34:16 -04:00
Tom Moor 321b232f17 Move "Webhook" settings to table (#12119)
* Move 'Webhook' settings to table

* Add tests
2026-04-19 19:27:32 -04:00
Tom Moor 69e8aac4f1 Move "Api Keys" listing to filterable table (#12117)
* Move 'Api Keys' listing to filterable table

* Add context menu
Allow copying new keys
2026-04-19 18:12:32 -04:00
Tom Moor 7b182f9038 More styling improvements to highlight control 2026-04-19 18:07:08 -04:00
Tom Moor 666b3879b3 feat: Document history design (#12112)
* refactor

* refactor

* design
2026-04-19 09:37:09 -04:00
Tom Moor 36f6cb9e01 fix: Do not clear local database on passive logout (#12109) 2026-04-18 20:26:32 -04:00
Robert Hawkins 182f7f38f6 feat: Allow comparing any two revisions in document history (#12001)
* feat: Allow comparing any two revisions in document history

* Copilot review feedback
Move MobX store lookup out of useMemo so it stays reactive, fix i18n key spacing to match existing translations, and map synthetic latest revision ID to "latest" in the dropdown so DataLoader can fetch it.

* fix: Force editor remount when comparison target changes

* fix: Don't show wrong diff while compareTo revision is loading
2026-04-18 15:13:57 -04:00
Tom Moor 49d5052a51 feat: RTL layout (#12107)
* First pass

* Remove prop drilling, fix comment layout

* Revert dev:watch to use dev:backend

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 15:12:57 -04:00
Tom Moor c02ac30eb0 refactor: Convert Document scene to functional component (#12033)
* refactor: Convert Document scene from class to functional component

Replace the @observer class component with a functional component using
hooks (useStores, useTranslation, useHistory, useLocation) instead of
HOC wrappers (withStores, withTranslation, withRouter). All @observable
state converted to useState with companion refs for stale closure
avoidance in debounced callbacks and unmount cleanup.

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

* refactor: Extract save/dirty tracking into useDocumentSave hook

Moves all save, autosave, dirty-tracking, template insertion, and
unmount cleanup logic from DocumentScene into a dedicated hook. This
reduces the component from ~790 to ~500 lines and isolates re-renders
from save state changes (isSaving, isPublishing, etc.) to a smaller
surface.

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

* docs: Add JSDoc to DocumentScene Props and function

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

* unused

* Remove withStores

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-18 11:33:59 -04:00
Tom Moor 267835ce6f Add missing controls to starred documents (#12100)
* Add missing controls to starred documents

* refactor

* refactor

* fix: Enter does not submit

* fix: Reordering child docs in starred section

* refactor: Rename editTitle to labelText, remove non-null assertion

* Refactor draggable for consistency

* refactor

* Remove star icon

* fix: Allow drag and drop importing into starred

* tsc
2026-04-18 11:04:05 -04:00
Tom Moor e49e3136b6 Increase MCP guidance limit (#12097)
* Increase MCP guidance limit
Add new controls for Input

* PR feedback
2026-04-17 23:22:50 -04:00
Tom Moor 15bd969cfa fix: Handle trailing space on code challenge method (#12068)
* fix: Handle trailing space on code challenge method

* Add tests for codeChallengeMethod whitespace trimming

Addresses review feedback: adds test coverage for the trim behavior
in saveAuthorizationCode, verifying trailing whitespace is stripped
and whitespace-only input is treated as absent.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 22:02:32 -04:00
Tom Moor 0d98754f5f fix: Draft border is not visible in dark mode (#12051)
Add draft badge to header
2026-04-15 08:05:19 -04:00
Tom Moor ff2e408c05 fix: Search input in keyboard shortcuts is not rounded (#12047) 2026-04-15 08:04:53 -04:00
Tom Moor b3042540c4 fix: Shared doc should respect 'Show last modified' option when logged in (#12032) 2026-04-13 21:39:09 -04:00
Tom Moor f4f2506d36 fix: Guard IndexeddbPersistence for environments without indexedDB (#12027)
* fix: Guard IndexeddbPersistence for environments without indexedDB

In environments where `indexedDB` is unavailable (e.g. certain mobile
browsers or privacy-restricted contexts), y-indexeddb throws a
ReferenceError. This guards the creation with a typeof check and skips
local persistence gracefully, falling back to remote-only sync.

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

* fix: Track local persistence availability separately from sync state

Address review feedback: instead of forcing isLocalSynced=true when
indexedDB is unavailable (which drops the cached read-only render),
track hasLocalPersistence separately and derive readiness as
(!hasLocalPersistence || isLocalSynced) for showCache and onSynced.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 18:18:09 -04:00
Tom Moor fc16d3100a fix: Auto-hide TOC when window shrinks below mobile breakpoint (#12014) 2026-04-13 18:04:27 -04:00
Tom Moor 6874b02cc7 Add max character count to inputs (#12006) 2026-04-12 11:44:28 -04:00
Tom Moor fb9f4bb991 feat: Allow replacing custom emoji image (#11998)
* feat: Allow replacing custom emoji image
2026-04-10 18:51:59 -04:00
Tom Moor 64e75dac76 fix: Address various a11y findings (#11977)
* A11y improvements

* fix: Accessibility improvements for sidebar, layout, and emoji icons

- Add role="main" to content area and role="contentinfo" to right sidebar
- Add aria-expanded to sidebar Disclosure toggle button
- Add nav landmark with aria-label to shared sidebar navigation
- Render SidebarLink as button instead of div when no link target
- Hide decorative emoji icons from screen readers (aria-hidden)
- Add aria-hidden to EmojiIcon SVG element

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

* fix: Restore PopoverTrigger in FindAndReplace, add role to span

PopoverAnchor broke the find/replace popover. Revert to PopoverTrigger
and instead add role="button" and aria-label to the span so ARIA
attributes from Radix are valid on the element.

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

* fix: Sidebar button styling

* fix: Use semantic list elements for References document list

Change the References list container from div to ul and wrap each
ReferenceListItem in an li element for proper screen reader semantics.

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

* fix: Address PR review feedback for accessibility changes

- Heading buttons: switch from mousedown to click for keyboard access
- Heading fold: add aria-expanded attribute
- FindAndReplace: use real button element instead of span with role
- SidebarLink: branch render to avoid passing NavLink props to button
- Right sidebar: use role=complementary instead of contentinfo

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

* fix: Use translation hook for FindAndReplace, revert anchor click handler

- Use t() for aria-label in FindAndReplace button
- Revert heading anchor from click back to mousedown to avoid side effects

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

* fix: Add ts-expect-error for styled NavLink overload mismatch

The spread props on the NavLink branch cause a TypeScript overload
mismatch that was previously suppressed. Re-add the suppression.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-06 18:59:53 -04:00
Tom Moor 30d00df1e3 fix: Sidebar auto-opens when draft comment is present (#11964) 2026-04-04 17:50:49 -04:00
Tom Moor a411e08f1f chore: Address code quality findings (#11960)
* chore: Address code quality findings

* Round 2, quality findings

* fix: Add fallback for MediaQueryList.addEventListener in test env

The jsdom test environment doesn't implement addEventListener on
MediaQueryList. Prefer addEventListener but fall back to the
deprecated addListener when unavailable.
2026-04-04 16:11:10 -04:00
Tom Moor a0c70cee62 fix: Email is removed from group members table (#11961) 2026-04-04 15:58:05 -04:00
Tom Moor a02793514c fix: Hide image controls and pointers in present mode (#11958) 2026-04-04 12:31:56 -04:00
Tom Moor 741f6c07d2 fix: Current user last active at (#11957)
* fix: Last active timestamp should always read as now for current user

* Shorten language on members table
2026-04-04 12:28:16 -04:00
Tom Moor f901435226 fix: Cannot navigate to document out of present mode (#11952) 2026-04-04 09:05:16 -04:00