Compare commits

...

1196 Commits

Author SHA1 Message Date
Tom Moor d1bad8dbf4 perf: Avoid unneccessary mapping 2025-01-21 23:02:20 -05:00
Tom Moor 58a70ab62e refactor 2025-01-21 22:49:18 -05:00
Tom Moor aff26aa809 Add multiplayer support 2025-01-21 22:31:20 -05:00
Tom Moor e1cc6395f5 fix: Menu is modified before it closes 2025-01-20 21:35:32 -05:00
Tom Moor 38186d64e5 Merge main 2025-01-20 21:06:36 -05:00
dependabot[bot] fa70735585 chore(deps): bump dotenv from 16.4.5 to 16.4.7 (#8258)
Bumps [dotenv](https://github.com/motdotla/dotenv) from 16.4.5 to 16.4.7.
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v16.4.5...v16.4.7)

---
updated-dependencies:
- dependency-name: dotenv
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 14:24:33 -08:00
dependabot[bot] 8d694e666c chore(deps): bump react-window from 1.8.10 to 1.8.11 (#8259)
Bumps [react-window](https://github.com/bvaughn/react-window) from 1.8.10 to 1.8.11.
- [Release notes](https://github.com/bvaughn/react-window/releases)
- [Changelog](https://github.com/bvaughn/react-window/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bvaughn/react-window/compare/1.8.10...1.8.11)

---
updated-dependencies:
- dependency-name: react-window
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 14:24:19 -08:00
dependabot[bot] 324ce96aaf chore(deps): bump umzug from 3.8.1 to 3.8.2 (#8260)
Bumps [umzug](https://github.com/sequelize/umzug) from 3.8.1 to 3.8.2.
- [Release notes](https://github.com/sequelize/umzug/releases)
- [Changelog](https://github.com/sequelize/umzug/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sequelize/umzug/compare/v3.8.1...v3.8.2)

---
updated-dependencies:
- dependency-name: umzug
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 14:24:07 -08:00
Tom Moor cc7f9d1a72 Improve canva share link support, closes #8140 2025-01-19 23:24:37 -05:00
Tom Moor 0116441a58 fix: findByQuery with no query 2025-01-19 22:33:03 -05:00
Tom Moor be93b4ffe9 fix: Various bugs in the suggestion menu logic (#8256) 2025-01-19 17:41:34 -08:00
Tom Moor 11cb90b4fa chore: Simplify Enter rule on mentions 2025-01-19 11:46:11 -05:00
Tom Moor d1b7d0ee45 findByQuery 2025-01-18 22:56:24 -05:00
Tom Moor 029161002b Move hover helper to shared 2025-01-18 21:14:00 -05:00
Tom Moor 1e10985626 Add hover states to mention 2025-01-18 20:58:54 -05:00
Tom Moor e5fdaae09a feat: Add prefetching to shared document sidebar items 2025-01-18 16:35:35 -05:00
Tom Moor cfdb213cc1 Ensure both people and documents are showin in mention menu with no search term 2025-01-18 14:51:40 -05:00
Tom Moor 64106979ba Merge branch 'main' of github.com:outline/outline 2025-01-18 10:49:33 -05:00
Tom Moor 6dffa023b1 fix: Empty title column on shares management 2025-01-17 22:56:30 -05:00
Translate-O-Tron 869b6e7394 New Crowdin updates (#8235) 2025-01-17 18:27:57 -08:00
Tom Moor 73086139d2 Document mentions (#8225) 2025-01-17 15:56:38 -08:00
dependabot[bot] 92b257381b chore(deps): bump katex from 0.16.11 to 0.16.21 (#8253)
Bumps [katex](https://github.com/KaTeX/KaTeX) from 0.16.11 to 0.16.21.
- [Release notes](https://github.com/KaTeX/KaTeX/releases)
- [Changelog](https://github.com/KaTeX/KaTeX/blob/main/CHANGELOG.md)
- [Commits](https://github.com/KaTeX/KaTeX/compare/v0.16.11...v0.16.21)

---
updated-dependencies:
- dependency-name: katex
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-17 15:15:48 -08:00
Tom Moor 28d5d0da5d Add supported embed detection 2025-01-16 23:18:03 -05:00
Tom Moor 79df75e09d chore: Update bug_report.yml 2025-01-16 17:26:28 -08:00
Tom Moor 4517cd6ab1 Move bug report to form format 2025-01-16 20:22:51 -05:00
Hemachandar 3c86b48533 Convert GroupMembership mutations (#8242)
* Convert 'GroupMembership' mutations

* cleanup collectionGroupMemberships

* remove duplicate data
2025-01-16 15:23:09 -08:00
Tom Moor bcba35550a fix: NodeView does not re-render when editable prop changes (#8237) 2025-01-16 14:28:50 -08:00
Tom Moor 4af3ac98d1 fix: Improve styling with mixed RTL content (#8247)
* fix: Improve styling with mixed RTL content

* fix
2025-01-16 13:35:04 -08:00
Tom Moor 7421a9fbdc fix: Mentions should not be able to contain node content (#8246)
closes #8238
2025-01-16 03:49:38 -08:00
Tom Moor 56b9c60388 Revert "Updated ImportJsonTask file mapDocuments method to use unshift instea…" (#8241)
This reverts commit 9cab404194.
2025-01-15 07:16:41 -08:00
Tom Moor 8fec6758b8 fix: Move compression middleware to cover all /api and /auth routes 2025-01-14 19:01:51 -05:00
Tom Moor 1aaabf113b fix: Incorrect plain text serialization in exportTable (#8234) 2025-01-14 06:35:43 -08:00
Ali 5eb95f7bd9 fix: for comment 2025-01-14 11:50:48 +08:00
Translate-O-Tron a0d78378d7 New Crowdin updates (#8204) 2025-01-13 19:35:08 -08:00
dependabot[bot] 78bf8fd641 chore(deps): bump @sentry/react from 7.119.0 to 7.120.3 (#8233)
Bumps [@sentry/react](https://github.com/getsentry/sentry-javascript) from 7.119.0 to 7.120.3.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/7.120.3/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.119.0...7.120.3)

---
updated-dependencies:
- dependency-name: "@sentry/react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 19:34:24 -08:00
dependabot[bot] 5374d32801 chore(deps): bump @sentry/node from 7.120.0 to 7.120.3 (#8232)
Bumps [@sentry/node](https://github.com/getsentry/sentry-javascript) from 7.120.0 to 7.120.3.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/7.120.3/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.120.0...7.120.3)

---
updated-dependencies:
- dependency-name: "@sentry/node"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 18:52:28 -08:00
dependabot[bot] 68de78ead8 chore(deps): bump sonner from 1.4.3 to 1.7.1 (#8231)
Bumps [sonner](https://github.com/emilkowalski/sonner) from 1.4.3 to 1.7.1.
- [Release notes](https://github.com/emilkowalski/sonner/releases)
- [Commits](https://github.com/emilkowalski/sonner/compare/v1.4.3...v1.7.1)

---
updated-dependencies:
- dependency-name: sonner
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-13 18:52:17 -08:00
Ali c3ba07cee4 feat: add paste menu 2025-01-13 11:45:32 +08:00
WEI-HUA CHIEN 3998a80ae9 fix: Handle nested collapsed headings in findCollapsedNodes (#8223) 2025-01-11 08:59:40 -08:00
Hemachandar e910ecf559 fix: Update counter cache when a user is deleted (or) suspended (#8222) 2025-01-10 19:36:39 -08:00
Hemachandar e42b533b07 Move group management to table (#8212)
* convert to table

* refactor edit group modal

* refactor delete group modal

* refactor add people modal

* refactor create group modal

* rebased changes

* filter works

* empty group message

* retain group title click

* fade

* cleanup

* pre-filtered for determining isEmpty

* remove fade, unnecessary role check

* StickyFilters component

* createdAt column

* Remove DelayedMount
Add 'External ID' in menu when present

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2025-01-09 20:06:09 -05:00
Hemachandar 81d7492e5e Convert Comment and Reaction mutations (#8181)
* handle create, update, delete

* handle resolve, unresolve

* handle add_reaction, remove_reaction

* cleanup

* fix type

* afterDestroy hook

* remove unnecessary 'hooks:false' added in this PR

* tests
2025-01-09 15:48:09 -08:00
Hemachandar 3c5ce8cb3d Publish event in withCtx flow only (#8188)
* api key

* attachment

* file operation

* group

* share

* star

* subscription

* publish events in withCtx flow only

* cleanup GroupUser hooks:false

* type and rename

* rename publish to create
2025-01-08 05:27:49 -08:00
Hemachandar cf3e29bbab Improve useTableRequest for better reactivity (#8206)
* use data from store directly

* load active users only when no filter is set

* return invited user email in users.invite response

* shares
2025-01-08 05:27:36 -08:00
Translate-O-Tron 92a5954ec7 New Crowdin updates (#8193) 2025-01-07 05:29:21 -08:00
Hemachandar 4afa225967 Simplify email references determination (#8189)
* Simplify email references determination

* individual thread for comments

* use toPlainText
2025-01-07 05:29:04 -08:00
dependabot[bot] 48feaf9bc0 chore(deps): bump nodemailer and @types/nodemailer (#8197)
Bumps [nodemailer](https://github.com/nodemailer/nodemailer) and [@types/nodemailer](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/nodemailer). These dependencies needed to be updated together.

Updates `nodemailer` from 6.9.14 to 6.9.16
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/nodemailer/compare/v6.9.14...v6.9.16)

Updates `@types/nodemailer` from 6.4.15 to 6.4.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/nodemailer)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: "@types/nodemailer"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 17:14:23 -08:00
dependabot[bot] 3f2ac2d23b chore(deps-dev): bump @babel/cli from 7.25.9 to 7.26.4 (#8198)
Bumps [@babel/cli](https://github.com/babel/babel/tree/HEAD/packages/babel-cli) from 7.25.9 to 7.26.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.4/packages/babel-cli)

---
updated-dependencies:
- dependency-name: "@babel/cli"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 17:14:06 -08:00
dependabot[bot] 38c12bd2a9 chore(deps-dev): bump @types/resolve-path from 1.4.2 to 1.4.3 (#8199)
Bumps [@types/resolve-path](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/resolve-path) from 1.4.2 to 1.4.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/resolve-path)

---
updated-dependencies:
- dependency-name: "@types/resolve-path"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-06 17:13:52 -08:00
Hemachandar fafaddf07f feat: Option to return anchor text for comments (#8196)
* feat: Option to return anchor text for comments

* cleanup anchorText presentation

* consolidated anchor text

* cleanup unused method
2025-01-06 17:13:37 -08:00
Hemachandar 25f264a763 fix: Notify previously mentioned users when new comment is added to a thread (#8194) 2025-01-05 18:23:16 -08:00
Tom Moor 085785a94c Remove yellow badge for guests 2025-01-05 19:40:30 -05:00
Tom Moor 9c71566d66 fix: Filter input divider in light theme 2025-01-05 19:40:30 -05:00
Hemachandar 4a64a767e1 Convert GroupUser mutations (#8187)
* Convert 'GroupUser' mutations

* cleanup commands
2025-01-05 16:33:51 -08:00
Hemachandar 9bc1788bc0 Upgrade and virtualize table component (#8157)
* Upgrade and virtualize table component

* width in column def

* container height

* share query options

* full page scroll

* change z-index and remove shrink

* non-modal menu
2025-01-05 04:55:05 -08:00
Tom Moor e93ef8b392 fix: shares.update written on every view, regressed in #8177 2025-01-04 21:10:18 -05:00
Tom Moor db30d080ae fix: Highlight matching mentions in find and replace (#8184) 2025-01-02 19:06:42 -08:00
Translate-O-Tron 63d70c2cd5 New Crowdin updates (#8144) 2025-01-02 12:06:20 -08:00
Hemachandar 98fef1bb1f Convert Share mutations (#8177)
* Convert 'Share' mutations

* createContext

* name override in share.revoke method
2025-01-02 12:06:02 -08:00
Prasad Bandaru 9cab404194 Updated ImportJsonTask file mapDocuments method to use unshift instead of push for sorting order (#8183) 2025-01-02 12:05:50 -08:00
Tom Moor d6459150fe feat: Allow resizing of embed height (#8154)
* stash

* tsc

* remove console log

* Restore bottom bar on embeds

* fix: Cannot see selected state

* fix layout issue
2025-01-02 05:49:51 -08:00
Hemachandar 4789ddd947 Skip unnecessary update of comment sort preference (#8182) 2025-01-02 05:49:33 -08:00
Tom Moor 1c179a3c6b Move Group to model event writing (#8179)
* Move Group to model event writing

* cleanup type
2025-01-02 07:45:09 -05:00
Tom Moor b8c07eb298 chore: Cleanup unused pinDestroyer (#8180) 2025-01-01 14:02:45 -08:00
Tom Moor adfca1e5ca fix: Attempting to split undefined 2024-12-31 17:33:47 -05:00
Tom Moor 6ca3c25d35 fix: Do not report errors due to unsupported file types 2024-12-31 08:26:34 -05:00
Tom Moor 05a2c6ae1e fix: Zoom cursor shown while drag-resizing image 2024-12-31 08:26:34 -05:00
Hemachandar 234915f4a0 Convert Subscription mutations (#8166)
* createContext accepts object

* handle subscriptions

* use createContext

* should've done this on the initial attempt...
2024-12-31 05:25:43 -08:00
Tom Moor 538a1274ab fix: Scale width of caption with image (#8174) 2024-12-31 03:36:14 -08:00
Hemachandar 63422373ac Add teamId index on attachments table (#8175) 2024-12-31 03:36:05 -08:00
dependabot[bot] 708bd8a544 chore(deps): bump prosemirror-view from 1.36.0 to 1.37.1 (#8172)
Bumps [prosemirror-view](https://github.com/prosemirror/prosemirror-view) from 1.36.0 to 1.37.1.
- [Changelog](https://github.com/ProseMirror/prosemirror-view/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-view/compare/1.36.0...1.37.1)

---
updated-dependencies:
- dependency-name: prosemirror-view
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 16:30:23 -08:00
dependabot[bot] 120191d4d7 chore(deps-dev): bump eslint-plugin-react from 7.35.0 to 7.37.3 (#8169)
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.35.0 to 7.37.3.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.35.0...v7.37.3)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 16:29:40 -08:00
dependabot[bot] 6a2ab299a8 chore(deps): bump @babel/preset-react from 7.25.9 to 7.26.3 (#8170)
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.25.9 to 7.26.3.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.3/packages/babel-preset-react)

---
updated-dependencies:
- dependency-name: "@babel/preset-react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 16:29:27 -08:00
dependabot[bot] 74dc7094e1 chore(deps): bump i18next-http-backend from 2.5.0 to 2.7.1 (#8171)
Bumps [i18next-http-backend](https://github.com/i18next/i18next-http-backend) from 2.5.0 to 2.7.1.
- [Changelog](https://github.com/i18next/i18next-http-backend/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next-http-backend/commits)

---
updated-dependencies:
- dependency-name: i18next-http-backend
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-30 16:29:09 -08:00
Hemachandar 5dd993adf5 Convert WebhookSubscription mutations (#8161)
* Convert 'WebhookSubscription' mutations

* add tests

* remove unnecessary assignment
2024-12-30 16:11:32 -08:00
Hemachandar 41832bbaf1 fix: Use parent transaction for findOrCreate after-commit hook (#8173) 2024-12-30 16:11:11 -08:00
Tom Moor f448be5830 feat: Allow querying groups by externalId 2024-12-27 16:48:19 +00:00
Tom Moor f0fcb26b50 fix: Cannot read properties of undefined (reading 'replace'), closes #8123 2024-12-27 10:41:45 +00:00
Tom Moor ad237a619c fix: Avoid document scrolling behavior when auto-scrolling sidebar 2024-12-26 21:41:25 +00:00
Tom Moor 5f49938267 chore: Fix react key warning 2024-12-26 17:40:22 +00:00
Tom Moor 68a469daa7 Add externalId property on groups (#8127)
* Add 'externalId' property on groups

* Remove clientside Field decorator

* Allow querying by externalId
2024-12-26 08:44:04 -08:00
Tom Moor 3d5a167f7f fix: textBetween line breaks (#8145)
* fix: textBetween line breaks

* test
2024-12-26 03:31:12 -08:00
Tom Moor b58671cbd1 Exclude state column by default in document queries (#8139)
* Exclude state column by default in document queries

* restore withoutState scope
2024-12-26 03:30:48 -08:00
Tom Moor b3a3b0763f fix: Exported HTML does not include table column sizes (#8128) 2024-12-26 03:06:03 -08:00
Tom Moor a4becd66bd feat: Add 'Protobuf' highlighting, closes #8141 2024-12-26 11:05:25 +00:00
Tom Moor 3437bd3a6c fix: Additional Canva embed format, closes #8140 2024-12-25 11:28:17 +00:00
Tom Moor 86cfd62afa feat: Allow users to change email in-app (#8119) 2024-12-25 02:58:26 -08:00
Translate-O-Tron 85b62d3146 New Crowdin updates (#8132)
* fix: New Dutch translations from Crowdin [ci skip]

* fix: New Korean translations from Crowdin [ci skip]
2024-12-24 09:38:02 -08:00
dependabot[bot] 1fa0a5ea98 chore(deps): bump i18next-fs-backend from 2.3.2 to 2.6.0 (#8136)
Bumps [i18next-fs-backend](https://github.com/i18next/i18next-fs-backend) from 2.3.2 to 2.6.0.
- [Changelog](https://github.com/i18next/i18next-fs-backend/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next-fs-backend/compare/v2.3.2...v2.6.0)

---
updated-dependencies:
- dependency-name: i18next-fs-backend
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-24 09:30:57 -08:00
dependabot[bot] 2b4c8d981c chore(deps-dev): bump nodemon from 3.1.7 to 3.1.9 (#8135)
Bumps [nodemon](https://github.com/remy/nodemon) from 3.1.7 to 3.1.9.
- [Release notes](https://github.com/remy/nodemon/releases)
- [Commits](https://github.com/remy/nodemon/compare/v3.1.7...v3.1.9)

---
updated-dependencies:
- dependency-name: nodemon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-24 09:30:23 -08:00
Tom Moor ce55719626 chore: Print emails to console when Ethereal unavailable (offline) 2024-12-19 17:07:10 +09:00
Tom Moor b9f0f67fb2 chore: Tidy mention menu, remove unneccessary component 2024-12-19 14:39:16 +09:00
Tom Moor 02aa4c2928 fix: Consider CDN urls to not be internal 2024-12-19 09:48:21 +09:00
Tom Moor 77e8dbefd6 fix: Ensure signed urls on shared documents are valid longer than 60s 2024-12-19 09:43:49 +09:00
Tom Moor 1e5d281870 chore: Improve warning for SMTP_FROM_EMAIL not set, closes #8125 2024-12-19 06:57:05 +09:00
Tom Moor 9b68e6835e fix: Reduce visual strength of collection in doc breadcrumb 2024-12-18 11:07:39 +09:00
Tom Moor f17926f912 fix: Update slate to WCAG AA compliant, closes #8113 2024-12-18 10:46:06 +09:00
Tom Moor 2397196be8 fix: Shared document header always in mobile styling, closes #8121 2024-12-18 10:27:26 +09:00
Tom Moor 133db9c22c Improve error message when database URI contains invalid characters, closes #8110 2024-12-18 10:18:09 +09:00
Translate-O-Tron 0dd14cdf1a New Crowdin updates (#8058) 2024-12-17 16:56:43 -08:00
dependabot[bot] cc8ec28a39 chore(deps-dev): bump typescript from 5.6.3 to 5.7.2 (#8118)
* chore(deps-dev): bump typescript from 5.6.3 to 5.7.2

Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.6.3 to 5.7.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.6.3...v5.7.2)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* tsc

---------

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.moor@gmail.com>
2024-12-18 09:56:31 +09:00
Tom Moor c8cbb9ef9c Add HEIC to supported mimes, closes #8122 2024-12-18 09:49:28 +09:00
dependabot[bot] 4af07ab6c4 chore(deps-dev): bump eslint-plugin-import from 2.29.1 to 2.31.0 (#8116)
Bumps [eslint-plugin-import](https://github.com/import-js/eslint-plugin-import) from 2.29.1 to 2.31.0.
- [Release notes](https://github.com/import-js/eslint-plugin-import/releases)
- [Changelog](https://github.com/import-js/eslint-plugin-import/blob/main/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-plugin-import/compare/v2.29.1...v2.31.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-import
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-17 16:22:49 -08:00
dependabot[bot] 742c138b3d chore(deps): bump mermaid from 11.4.0 to 11.4.1 (#8117)
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.4.0 to 11.4.1.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Changelog](https://github.com/mermaid-js/mermaid/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.4.0...mermaid@11.4.1)

---
updated-dependencies:
- dependency-name: mermaid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-16 20:36:59 -08:00
Tom Moor ec1eacaeea fix: Cannot leave overlapping comments (#8107) 2024-12-16 20:36:32 -08:00
Tom Moor 8b15cc45b0 fix: Permissions checks on notification emails do not take into account shares (#8109)
* fix: Comment notifications not sent on drafts outside collection, shared docs

* fix: DocumentPublishedOrUpdatedEmail not sent for drafts

* tsc
2024-12-15 20:53:06 -08:00
Tom Moor e89c32424f fix: Subscribe to document automatically on share (#8108) 2024-12-15 17:37:20 -08:00
Tom Moor a458690bfc fix: Non-unique key parameter, closes #8104 2024-12-12 11:39:19 -05:00
Tom Moor df03a6da8c fix: Markdown escape characters left in titles on import (#8102) 2024-12-12 05:15:45 -08:00
Tom Moor 6dfe7d707a fix: Token type not supported by Markdown parser, closes #8101 2024-12-11 21:07:15 -05:00
Tom Moor c063709f1c Allow resizing final table column 2024-12-11 20:39:02 -05:00
Tom Moor dd8f6a987c perf: Avoid iterating child documents in documents.info when direct descendant 2024-12-09 22:13:04 -05:00
Tom Moor fa117870a2 perf: One less query in documents.info 2024-12-09 21:52:32 -05:00
dependabot[bot] 40b1e3c8c6 chore(deps): bump prosemirror-model from 1.23.0 to 1.24.0 (#8092)
* chore(deps): bump prosemirror-model from 1.23.0 to 1.24.0

Bumps [prosemirror-model](https://github.com/prosemirror/prosemirror-model) from 1.23.0 to 1.24.0.
- [Changelog](https://github.com/ProseMirror/prosemirror-model/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-model/compare/1.23.0...1.24.0)

---
updated-dependencies:
- dependency-name: prosemirror-model
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* tsc

* tsc

---------

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.moor@gmail.com>
2024-12-09 17:43:04 -08:00
Tom Moor e3b0f7db86 fix: Parsing of grist links with utm parameters, closes #8082 2024-12-09 20:42:36 -05:00
dependabot[bot] 6fddb29ff6 chore(deps): bump nanoid from 3.3.7 to 3.3.8 (#8098)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.7 to 3.3.8.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.3.7...3.3.8)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 17:37:36 -08:00
dependabot[bot] 569a7876ae chore(deps): bump utility-types from 3.10.0 to 3.11.0 (#8093)
Bumps [utility-types](https://github.com/piotrwitek/utility-types) from 3.10.0 to 3.11.0.
- [Release notes](https://github.com/piotrwitek/utility-types/releases)
- [Commits](https://github.com/piotrwitek/utility-types/compare/v3.10.0...v3.11.0)

---
updated-dependencies:
- dependency-name: utility-types
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 17:31:03 -08:00
dependabot[bot] bea56159ec chore(deps-dev): bump eslint-import-resolver-typescript from 3.6.3 to 3.7.0 (#8096)
Bumps [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) from 3.6.3 to 3.7.0.
- [Release notes](https://github.com/import-js/eslint-import-resolver-typescript/releases)
- [Changelog](https://github.com/import-js/eslint-import-resolver-typescript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-import-resolver-typescript/compare/v3.6.3...v3.7.0)

---
updated-dependencies:
- dependency-name: eslint-import-resolver-typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-09 17:30:41 -08:00
Tom Moor 908f053920 Add UI element to images that are externally hosted 2024-12-08 12:51:55 -05:00
Tom Moor 033c298bff fix: Retrieve image dimensions for all types, not only PNG 2024-12-07 17:15:25 -05:00
Tom Moor 22f02ad713 feat: Add 'Neon' highlighter color, increase presence of highlights 2024-12-07 16:27:57 -05:00
Tom Moor 92b1c578f6 feat: Improve inline rule matching (#8085)
* stash

* fix: Allow inline mark matching to work with preceding brackets
Refactor markInputRule, add markInputRuleForPattern

* docs
2024-12-07 12:46:25 -08:00
Tom Moor a738ea97b5 feat: Dropping a remote image will now upload (#8086)
* feat: Dropping a remote image will now upload

* refactor,DRY

* guard

* Parse correct file name from url where possible
2024-12-07 12:46:14 -08:00
Tom Moor 7fbe442863 Show editor tooltip shortcuts on separate line 2024-12-07 14:10:36 -05:00
Tom Moor 2db7690e27 feat: Triple clicking in code mark should select entire mark, closes #8072 2024-12-07 12:58:15 -05:00
Tom Moor 06b89635be Improved tooltip context – separate for header,sidebar,editor. 2024-12-07 12:45:29 -05:00
Tom Moor 1ff23756ac fix: Make FindAndReplace popover dynamic, fixes button overflow.
closes #8079
2024-12-06 19:55:45 -05:00
Tom Moor a00b677076 fix: Use sidebarContext in header breadcrumbs (#8077) 2024-12-06 08:00:50 -05:00
Tom Moor 6c1e4a5b40 Add shortcuts to formatting menu tooltips (#8080)
* Add shortcuts to formatting menu tooltips

* Tooltip styling

* tsc
2024-12-05 20:50:16 -08:00
Tom Moor 59078704c8 fix: Embed toggle is unresponsive (#8078)
* fix: Embed toggle is unresponsive

* fix: View recorded when toggling embeds
2024-12-05 20:01:16 -08:00
Hemachandar f1a20b27fd fix: auto-scroll sidebar to show active document (#7956) 2024-12-05 17:23:13 -08:00
Tom Moor 313b046e4e fix: Use singleton for tooltips, ensures that only one is visible at a time. (#8069)
* fix: Use singleton for tooltips, ensures that only one is visible at a time and animations are shared

* fix: give toolbar menu its own context

* Remove duplicate props
2024-12-05 16:10:12 -08:00
Tom Moor 1154432924 Adds count of occurences and index to find and replace (#8070)
* Adds count of occurences and index to find and replace

* Disable replace buttons also
2024-12-05 15:58:24 -08:00
infinite-persistence e8bddbe104 Notification for resolved comment (#8045)
* fix: probably copy-pasted function description

* fix: userIdsMentioned was always empty

* add: NotificationEventType.ResolveComment

* move: split handler for "mentioned" vs. "resolved"

The recipients for "resolved" will include more people (creator, repliers, mentioned), so it's easier to just split the handler than trying to augment it.

* implement: handleResolvedComment

* clone: CommentMentionedEmail as CommentResolvedEmail

Changes coming up in next commit...

* implement: CommentResolvedEmail

* Fix "New Comment↓" incorrectly showing in Resolved

## Repro 1 (with production code)
1. In a list of long resolved comments, scroll up and select the first one.
2. From another account, resolve another comment. The hint appears.

## Repro 2 (with production code)
1. Select Most-Recent, then Resolved.
2. F5. It's scrolled all the way to the bottom.

## Repro 3 (after this PR)
1. Click on the notification when someone resolved a comment. The screen jumps to "Resolved" + showing hint unnecessarily.

## Fix
The scrolling and hint was meant for Most Recent only, but missed out this case since "Resolve" is not part of the enum.

* Better sentences

* Refactor "mentions + author" calculation

* Remove unnecessary check

The resolver is already added to `userIdsNotified` from the start, so no point checking it again here.
2024-12-04 15:10:03 -08:00
Tom Moor dddb12027c fix: Crash in header ref, regressed in 7a6f75c34f closes #8068 2024-12-04 08:35:55 -05:00
dependabot[bot] 5cb3da82bc chore(deps): bump socket.io from 4.7.5 to 4.8.1 (#8056)
Bumps [socket.io](https://github.com/socketio/socket.io) from 4.7.5 to 4.8.1.
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io@4.7.5...socket.io@4.8.1)

---
updated-dependencies:
- dependency-name: socket.io
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 19:15:07 -08:00
Tom Moor 7a6f75c34f fix: Improved responsiveness of document header elements (#8066)
* fix: Made the document header components more responsive to the available space

* doc
2024-12-03 19:11:36 -08:00
Tom Moor 5d09be4add More improvements to LaTeX fence detection 2024-12-02 22:28:59 -05:00
Tom Moor 48cae96a56 fix: Improve validation around emoji node serialization/deserialization 2024-12-02 21:58:22 -05:00
Tom Moor e8ab7a4885 chore: Add additional node validation 2024-12-02 21:22:58 -05:00
dependabot[bot] 183d02d5c6 chore(deps-dev): bump react-refresh from 0.14.0 to 0.14.2 (#8053)
Bumps [react-refresh](https://github.com/facebook/react/tree/HEAD/packages/react) from 0.14.0 to 0.14.2.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v0.14.2/packages/react)

---
updated-dependencies:
- dependency-name: react-refresh
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-02 18:10:54 -08:00
Tom Moor 4b833b3e2e Add screen for API key management (#8049)
* API keys

* Add api key list for admins

* permissions
2024-12-02 18:10:36 -08:00
Translate-O-Tron d1b75d44f6 New Crowdin updates (#8040) 2024-12-02 14:36:10 -08:00
Tom Moor 8de59f0a2f fix: 'Resolve' button appearing on resolved threads, closes #8047 2024-12-01 09:53:38 -05:00
Tom Moor d8fbe35455 fix: Template variables are not applied on client (#8044)
* fix: Template variables are not applied on client

* test
2024-11-30 07:13:44 -08:00
Tom Moor 514a724d9d fix: Add default value for attachment preset for easier API use 2024-11-29 23:05:30 -05:00
Tom Moor d66f41c854 fix: Improve behavior of LaTeX at small screensizes, closes #8032 2024-11-29 11:20:01 -05:00
Tom Moor b2d6c40ea8 chore: Add warning for problematic selfhosted config, closes #8025 2024-11-29 11:07:23 -05:00
infinite-persistence c98d6aa33a Allow user to select doc-copy destination (#8030)
* DocumentExplorer: make style extensible

* Allow user to select doc-copy dest

The change in `documentDuplicator` essentially alters the fallback from "parent" to "top of collection". But there is only 1 place that uses it so far, so I think it's fine to support this PR.

In the next commit, the caller side will restore the default to "parent".

* Auto select parent as initial target (to retain existing behavior)

Otherwise, user would need to always search/expand the tree. I have a feeling that people might want the last selection to be persistent, but ignoring that for now.

The 50ms timeout feels dirty, but 0 was too fast, at least on my machine. I couldn't find anything in react-window for a "ready" flag.

* Rename: DuplicateDialog -> DocumentCopy

This begins the switch to DocumentCopy's look in the next few commits

* Revert DocumentExplorer style override

No longer needed since we won't be using it under a ConfirmationDialog anymore in the next commit.

* Switch to DocumentMove's style

* initialSelectionId -> defaultValue

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-11-29 10:33:38 -05:00
Hemachandar 554c2a5cdb Simplify determining from email address (#8039)
* Simplify determining from email address

* override only for cloud-hosted
2024-11-29 06:41:48 -08:00
Hemachandar ee426de942 Cleanup random text (#8036) 2024-11-29 08:14:59 -05:00
Tom Moor 746e65e658 fix: Recursively filter source document from explorer, closes #8028 2024-11-27 23:04:37 -05:00
Tom Moor 8a3a3453e7 fix: The operation was unable to achieve a quorum during its retry window 2024-11-27 23:04:37 -05:00
Tom Moor c7d339ded5 Tracking of total uploaded attachments / team (#8031)
* Add column and task to calculate size

* Store in MB, rather than Bytes

* Add cron task to recalculate attachment sizes

* findAllInBatches

* Index createdAt

* fix: Index on incorrect table
2024-11-27 18:42:23 -08:00
Tom Moor ed25554607 fix: Hide TOC on templates 2024-11-27 18:20:49 -05:00
Tom Moor 29329daf15 chore: Record on users.signin event 2024-11-27 17:59:46 -05:00
Tom Moor 3f6390ff18 chore: Remove error on double reload 2024-11-27 17:56:02 -05:00
Translate-O-Tron 54b43c6e6f New Crowdin updates (#8029)
* fix: New Chinese Simplified translations from Crowdin [ci skip]

* fix: New Chinese Simplified translations from Crowdin [ci skip]
2024-11-27 08:38:31 -08:00
Tom Moor 8c9c83eb5a fix: Improve contrast on context menus in dark mode 2024-11-27 10:16:22 -05:00
Tom Moor 63171e5da2 fix: Incorrect cursor on sortable table headers 2024-11-27 09:33:52 -05:00
Tom Moor bfd84681d7 fix: Jank in domain management screen 2024-11-26 22:29:26 -05:00
Tom Moor 7d6a47ce86 chore: Remove unused undo/redo methods 2024-11-26 20:53:44 -05:00
Tom Moor 68f715b607 chore: Remove unused typing tracking logic 2024-11-26 20:50:57 -05:00
Tom Moor ea2e7a4d0f chore: Remove duplicate ID annotations 2024-11-26 20:43:01 -05:00
Translate-O-Tron 26948af1b8 New Crowdin updates (#7967) 2024-11-26 17:24:29 -08:00
Tom Moor 816a6715c5 chore: Simplify comment sidebar persistence to be per-user (#8022) 2024-11-26 17:24:07 -08:00
Tom Moor 4579594c63 fix: Relayout jank on document references 2024-11-26 09:05:14 -05:00
Tom Moor 88f7705fd4 fix: Starred documents do not expand when focusing, related #7956 2024-11-25 23:30:01 -05:00
Hemachandar 8393847910 Check flag emoji is supported (#8009) 2024-11-25 19:32:41 -08:00
dependabot[bot] b9adfa175d chore(deps-dev): bump @types/readable-stream from 4.0.15 to 4.0.18 (#8019)
Bumps [@types/readable-stream](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/readable-stream) from 4.0.15 to 4.0.18.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/readable-stream)

---
updated-dependencies:
- dependency-name: "@types/readable-stream"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 19:31:39 -08:00
dependabot[bot] 7fff8161ff chore(deps): bump vite from 5.4.10 to 5.4.11 (#8021)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.10 to 5.4.11.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.11/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 19:31:30 -08:00
Tom Moor 0ef9f1aea1 fix: Improve fast-click functionality in sidebar 2024-11-25 22:22:21 -05:00
Tom Moor fe63c5d706 fix: JS error in usePosition hook 2024-11-25 20:42:31 -05:00
Tom Moor 7749f0ab9f fix: Undo/redo regression 2024-11-25 20:36:23 -05:00
Tom Moor 763b911dfd fix: Named commands broken, regressed in 921e89d7b7 2024-11-24 23:34:48 -05:00
Tom Moor 99e541ede8 fix: Ensure logout OIDC never immediately relogin 2024-11-24 22:34:16 -05:00
Tom Moor 06f48ec79a Add active/hover state to collapsed thread 2024-11-24 19:59:31 -05:00
infinite-persistence 5566d995bd Comment: collapse long replies (#7941)
* Comment: collapse long replies

## Ticket
Closes 5079

## Review
- For the case of RTL, followed how "Reply" is implemented (assumed that is the desired). If it need to be re-aligned, it can be fixed together with "Reply" later.
- The threshold number can be moved to constants.ts if we don't want to pollute the props.

* Card-style + Facepile
2024-11-24 16:20:46 -08:00
Tom Moor 921e89d7b7 fix: Undo/redo behavior incorrect in multiplayer editor (#8015) 2024-11-24 16:19:52 -08:00
Tom Moor 32602f89dd fix: Flash of styles when printing dark mode (#8010) 2024-11-24 06:15:34 -08:00
Tom Moor 2cce95488c fix: S3 expiry not passed correctly (#8013) 2024-11-24 06:15:19 -08:00
Tom Moor 0663d191fc fix: Lists with negative margin are cut off when printing to PDF. This is a pragmatic fix for the issue closes #7958 2024-11-23 12:00:05 -05:00
Tom Moor 84eb1b801d fix: 'Replace all' functionality replacing offset incorrectly 2024-11-23 00:47:26 -05:00
Hemachandar 5102cfe8eb Persist theme after update (#7997) 2024-11-21 05:18:11 -05:00
Tom Moor 1d0617dbd6 fix: Edge case where heading in first table cell changes margin on focus 2024-11-20 20:52:11 -05:00
Tom Moor eedfd549b3 fix: Rare loop of storage events between tabs causing flickering UI (#7996)
* fix: Rare loop of storage events between tabs causing flickering UI

* Types cleanup
2024-11-20 16:17:28 -08:00
Hemachandar 28cb5aa379 Convert pin mutations to use auto event insertion (#7993) 2024-11-20 16:14:11 -08:00
Tom Moor fd5391cbb6 Cache diff generation for email notifications (#7987)
* Cache diff generation, closes #7982

* Handle cannot acquire lock

* Refactor to guard
2024-11-20 14:45:12 -08:00
Hemachandar 6e685ee8d9 store pin location on mount (#7994) 2024-11-20 14:27:16 -08:00
Tom Moor b595a0d427 fix: No-op sending emails in self-hosted if configuration is unavailable rather than retrying
towards #7982
2024-11-19 20:45:32 -05:00
Tom Moor 1c86119065 fix: Cannot sort by role on member settings, closes #7986 2024-11-19 19:22:53 -05:00
Tom Moor c629006642 Add inline resolve action on comment threads (#7977)
* Add inline resolve action on comment threads

* perf refactor
2024-11-18 18:36:44 -08:00
Tom Moor 326f733d4c fix: Further improvements to diacritics matching in CMD+F 2024-11-18 18:04:10 -05:00
Tom Moor d4d683c046 fix: Missing space character in invite modal, related #7968 2024-11-18 17:51:49 -05:00
Tom Moor 8204ac343f chore: Upgrade Sentry/AWS 2024-11-18 17:48:36 -05:00
dependabot[bot] cae8de7c7a chore(deps): bump @octokit/auth-app from 6.1.2 to 6.1.3 (#7974)
Bumps [@octokit/auth-app](https://github.com/octokit/auth-app.js) from 6.1.2 to 6.1.3.
- [Release notes](https://github.com/octokit/auth-app.js/releases)
- [Commits](https://github.com/octokit/auth-app.js/compare/v6.1.2...v6.1.3)

---
updated-dependencies:
- dependency-name: "@octokit/auth-app"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 14:41:05 -08:00
dependabot[bot] 8efa601967 chore(deps-dev): bump @relative-ci/agent from 4.2.12 to 4.2.13 (#7975)
Bumps [@relative-ci/agent](https://github.com/relative-ci/agent) from 4.2.12 to 4.2.13.
- [Release notes](https://github.com/relative-ci/agent/releases)
- [Commits](https://github.com/relative-ci/agent/compare/v4.2.12...v4.2.13)

---
updated-dependencies:
- dependency-name: "@relative-ci/agent"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-18 14:40:53 -08:00
Tom Moor 86c3ea8e9d fix: Copy toolbar positioning 2024-11-17 10:00:52 -05:00
Tom Moor c222782534 Upgrade Mermaid script in exported HTML, related #7964 2024-11-17 09:51:46 -05:00
Tom Moor 19ea7ee52b Remove sourcemap generation in bundle size calc (#7966) 2024-11-16 16:57:19 -08:00
Tom Moor d1de84a07e Reduce build time (#7965)
* Test using xlarge

* wip

* wip
2024-11-16 10:45:14 -08:00
Tom Moor d73b4c55bf Mermaid v11 (#7964)
* mermaid-v11

* fix: Various rendering incompatibilities
2024-11-16 08:10:55 -08:00
Hemachandar 9843c4c995 Improvements around templates (#7952)
* hide new-doc-from-template menu item

* change trash path for deleted templates

* conditional show templates in command bar
2024-11-16 07:48:58 -08:00
dependabot[bot] 685397b057 chore(deps): bump cross-spawn from 7.0.3 to 7.0.5 (#7963)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.5.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.5)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-16 06:43:06 -08:00
Tom Moor 13d37d4207 perf: Fix increase in initial bundle size, prosemirror-transform must be fixed at 1.10.0 until paragraph join is fixed 2024-11-16 09:14:27 -05:00
Tom Moor 7bedfab301 fix: Mermaid diagrams in collapsed headings do not render, closes #7960 2024-11-15 23:43:05 -05:00
Translate-O-Tron db5850ac0d New Crowdin updates (#7898) 2024-11-15 18:15:32 -08:00
Hemachandar a4c40ce25e show resolved view when a resolved comment is opened from notif email (#7959)
* show resolved view when a resolved comment is opened from notif email

* check and replace state
2024-11-15 18:14:30 -08:00
Tom Moor f5457e79cd fix: Mermaid diagram moves up and down when focused in read-only editor 2024-11-14 20:00:55 -05:00
Hemachandar 73eeeefb25 fix: restore workspace templates (#7951) 2024-11-14 16:32:02 -08:00
Hemachandar 54f82cac96 fix: show all templates in the menu (#7950)
* fetch all templates

* websocket events for workspace templates
2024-11-14 16:31:48 -08:00
Tom Moor bb43c24efe fix: Improve handling of unknown errors – closes #7933 2024-11-13 21:22:06 -05:00
Tom Moor acf3d7cd08 fix: Add latex fences as markdown signal 2024-11-13 21:03:44 -05:00
github-actions[bot] 5245f93642 chore: Compressed inefficient images automatically (#7946)
Co-authored-by: tommoor <tommoor@users.noreply.github.com>
2024-11-13 20:47:49 -05:00
Benjamin Kramser cfce55250e Add Pinterest embed (#7930)
* add pinterest embed

* improved profile detection
2024-11-13 17:46:07 -08:00
Tom Moor 6421995b29 fix: Do not override from address in self-hosted env, closes #7929 2024-11-13 20:19:17 -05:00
Tom Moor 8cfd8e25db fix: Event should not be written when API key is used 2024-11-13 09:10:30 -05:00
Tom Moor 1282e9653e fix: Excess padding on internal read-only docs, should only have applied to shares 2024-11-13 08:16:06 -05:00
Tom Moor f1edaecf49 perf: Fix observable changing on every keydown 2024-11-13 08:16:06 -05:00
Tom Moor f7d737ca45 fix: Missing 'Untitled' in reference list 2024-11-13 08:16:06 -05:00
Tom Moor 41c2c760d4 v0.81.0 2024-11-13 08:16:06 -05:00
dependabot[bot] f692d1bc3a chore(deps-dev): bump terser from 5.32.0 to 5.36.0 (#7928)
Bumps [terser](https://github.com/terser/terser) from 5.32.0 to 5.36.0.
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/compare/v5.32.0...v5.36.0)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 05:06:33 -08:00
dependabot[bot] 5197d6e18c chore(deps): bump prosemirror-view from 1.34.3 to 1.36.0 (#7925)
Bumps [prosemirror-view](https://github.com/prosemirror/prosemirror-view) from 1.34.3 to 1.36.0.
- [Changelog](https://github.com/ProseMirror/prosemirror-view/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-view/compare/1.34.3...1.36.0)

---
updated-dependencies:
- dependency-name: prosemirror-view
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 05:06:16 -08:00
dependabot[bot] b901ea7b30 chore(deps-dev): bump eslint-plugin-react-hooks from 4.6.0 to 4.6.2 (#7924)
Bumps [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/HEAD/packages/eslint-plugin-react-hooks) from 4.6.0 to 4.6.2.
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/facebook/react/blob/main/packages/eslint-plugin-react-hooks/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/HEAD/packages/eslint-plugin-react-hooks)

---
updated-dependencies:
- dependency-name: eslint-plugin-react-hooks
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 05:05:21 -08:00
dependabot[bot] 3820499856 chore(deps-dev): bump @types/jest from 29.5.13 to 29.5.14 (#7927)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.13 to 29.5.14.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 05:05:11 -08:00
dependabot[bot] 0cffde63ab chore(deps): bump zod from 3.22.4 to 3.23.8 (#7926)
Bumps [zod](https://github.com/colinhacks/zod) from 3.22.4 to 3.23.8.
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Changelog](https://github.com/colinhacks/zod/blob/main/CHANGELOG.md)
- [Commits](https://github.com/colinhacks/zod/compare/v3.22.4...v3.23.8)

---
updated-dependencies:
- dependency-name: zod
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-13 05:05:01 -08:00
Hemachandar 449ba6488e hide share option for templates (#7937) 2024-11-13 05:03:36 -08:00
Tom Moor 62f3e6921f Add changes property to client event model 2024-11-10 22:58:51 -05:00
Tom Moor bc259316f7 Include changes in event presenter 2024-11-10 22:35:11 -05:00
Tom Moor 98e03cc227 Convert stars, towards #7920 (#7921) 2024-11-10 19:26:27 -08:00
Tom Moor 633e547d3e Refactor of event insertion (#5909) 2024-11-10 16:26:20 -08:00
Tom Moor d5de69fd4b fix: Exception for Notion import of a single document 2024-11-09 19:26:44 -05:00
Hemachandar feec01f160 fix: don't show comment marks for other users' drafts (#7838)
* fix: don't show comment marks for other users' drafts

* remove unnecessary draft check
2024-11-09 10:43:59 -08:00
Tom Moor aa5813032e fix: Click image to focus 2024-11-09 13:02:55 -05:00
Tom Moor a6ba189180 Add menu item to leave document that has been shared with current user (#7918)
* Add menu item to leave document that has been shared with current user

* Only redirect if viewing doc
2024-11-09 06:45:59 -08:00
Tom Moor 4c65bbc57c fix: Improved toolbar behavior with partial link selection, closes #7890 2024-11-08 22:41:58 -05:00
Tom Moor c76b4f46aa Tweak sharing UI 2024-11-08 21:35:55 -05:00
infinite-persistence ca17b41c53 share: add allowIndexing (#7896)
* share: add `allowIndexing`

## Ticket
Closes 7486

* i18n: follow existing no-punctuation style
2024-11-08 17:28:30 -08:00
Tom Moor 9747c6ba5d fix: Document mentions can be incorrectly attributed during collab session (#7913) 2024-11-08 05:35:49 -08:00
Tom Moor 55ffd6d098 feat: Adds support for importing CSV files (#7912)
* feat: Adds support for importing CSV files

* test

* tsc
2024-11-07 19:09:02 -08:00
Tom Moor 9b26ccda19 fix: Switching edit mode scrolls to page top, closes #7910 2024-11-07 22:04:15 -05:00
Hemachandar 56b38b9dbd fix: restore documents from a deleted collection (#7909) 2024-11-07 18:03:30 -08:00
Hemachandar 0a3a684493 fix: collection archival post-process parity with deletion (#7906) 2024-11-07 18:02:51 -08:00
Tom Moor 24548dc7ee fix: Cannot pick the same file twice for import 2024-11-06 23:28:23 -05:00
Tom Moor 28cc83ad05 test 2024-11-06 21:49:18 -05:00
Tom Moor c57b845093 fix: Sentry.configureScope silently throwing error 2024-11-06 21:33:13 -05:00
Hemachandar 62ee075a6f feat: store user timezone (#7902)
* feat: store user timezone

* tz validation
2024-11-06 18:06:19 -08:00
Tom Moor 356b0916fd fix: Spacing below document editor should also be rendered in read-only 2024-11-06 20:56:16 -05:00
Tom Moor 03160c44d4 fix: Line numbers are not immediately visible when pasting code blocks 2024-11-06 20:31:44 -05:00
Tom Moor bf65d80fc8 Refactor SmartText disabling to use existing pattern (forgot this exists) 2024-11-06 20:18:08 -05:00
infinite-persistence 3d0df9c612 Jump to 'workspace' settings section if invoked from Org Menu (#7900)
## Issue
When clicking on the top-left "OrganizationMenu > Settings", I always get confused why it is showing me the Profiles page, given that the current context is workspace/org.

## Change
Switch the shortcut to point to "Workspace::details" instead.
For Profile, it's more natural to click the profile button from the bottom-left.
2024-11-06 05:57:50 -08:00
infinite-persistence 9de95ff658 Fix header key for react-table v7 (#7894)
`header.id` does not exist in v7 (it does in v8). `@types` lied.

The returned props actually includes a `key`..

```
      return utils.propGetter({
        key: headerGroup.id,
        role: 'row'
      }, userProps);
```

... so we could have just spread it in `tr`, but we still had to explicitly define a `key` to satisfy lint.

## Stashed v7 documentation:
https://github.com/TanStack/table/blob/v7/docs/src/pages/docs/api/useTable.md#headergroup-properties
2024-11-06 05:55:25 -08:00
Hemachandar 55bdd6fbc0 fix: heading disclosure transform (#7904) 2024-11-06 05:41:15 -08:00
Tom Moor fec91fb210 fix: Comment button appearing on mobile with no text selection 2024-11-05 19:59:44 -05:00
Tom Moor abb1d3a923 Restore fallback for storing IP address on revisions.create 2024-11-05 19:54:08 -05:00
infinite-persistence f5de2834d6 Add user preference to disable smart quotes (#7881) 2024-11-05 16:45:06 -08:00
Hemachandar 68377c3c46 fix: stop propagating click events outside EventBoundary (#7897) 2024-11-05 12:29:05 -08:00
dependabot[bot] 9661e18cbd chore(deps-dev): bump eslint-plugin-jsx-a11y from 6.7.1 to 6.10.2 (#7889)
Bumps [eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y) from 6.7.1 to 6.10.2.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/compare/v6.7.1...v6.10.2)

---
updated-dependencies:
- dependency-name: eslint-plugin-jsx-a11y
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-05 08:09:37 -08:00
Tom Moor 08d210e483 fix: Enter with image selected should insert new paragraph below 2024-11-04 21:36:43 -05:00
Tom Moor 5a0ce58fa0 fix: Error backwards joining paragraphs to lists 2024-11-04 21:02:37 -05:00
dependabot[bot] 08eeac2049 chore(deps): bump @babel/plugin-transform-regenerator from 7.25.7 to 7.25.9 (#7887)
Bumps [@babel/plugin-transform-regenerator](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-regenerator) from 7.25.7 to 7.25.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.9/packages/babel-plugin-transform-regenerator)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-regenerator"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 15:47:59 -08:00
dependabot[bot] 08a49378ea chore(deps): bump react-hook-form from 7.53.0 to 7.53.1 (#7886)
Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.53.0 to 7.53.1.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.53.0...v7.53.1)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 15:47:41 -08:00
dependabot[bot] a4a068a3ba chore(deps): bump @babel/preset-react from 7.24.7 to 7.25.9 (#7888)
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.24.7 to 7.25.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.9/packages/babel-preset-react)

---
updated-dependencies:
- dependency-name: "@babel/preset-react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 15:47:27 -08:00
Tom Moor 27cbf5a56a fix: Image zoom behavior, closes #7883 2024-11-04 09:04:18 -05:00
Translate-O-Tron f3daf45ccc New Crowdin updates (#7850) 2024-11-03 15:00:09 -08:00
Hemachandar c1c20f1ff9 feat: allow search without a search term (#7765)
* feat: allow search without a search term

* tests

* conditional filter visibility

* add icon to collection filter
2024-11-03 14:59:48 -08:00
Tom Moor e4d60382fd fix: Regression in 763dd28829 2024-11-03 14:00:07 -05:00
Tom Moor 763dd28829 documentUpdater 2024-11-03 12:29:48 -05:00
Tom Moor 93f7fa8c89 fix: notifications.pixel errors, regressed in 5780959e93 2024-11-03 11:46:11 -05:00
Tom Moor 24e50d9290 fix: Overlapping UI elements when resizing sidebar beyond minimum width 2024-11-03 10:12:15 -05:00
Tom Moor c1b19ef86c userDestroyer 2024-11-03 09:41:07 -05:00
Tom Moor 5780959e93 notificationUpdater 2024-11-03 09:32:45 -05:00
Tom Moor 74192040a2 Add new security preference (#7879)
* Add security preference to remove document content in email notifications

* Refactor, reduce chance of misuse
2024-11-03 05:59:11 -08:00
Tom Moor 7b3eba0f2f fix: More consistent dark mode colors 2024-11-02 21:50:36 -04:00
Tom Moor 9b03b529f8 fix: Adding reaction unfocuses comment thread
fix: Scrollable area of reaction picker larger than dialog
2024-11-02 21:23:38 -04:00
Tom Moor aa579412d0 Remove explicit passing of transaction to createWithContext 2024-11-02 19:27:17 -04:00
Tom Moor 774402560e fix: Remove marine from user color rotation as it clashes with comment marks, closes #7846 2024-11-02 18:46:20 -04:00
Tom Moor 0a875d4738 Tweak colors 2024-11-02 18:40:52 -04:00
Hemachandar de04d1c0c5 feat: Comment reactions (#7790)
Co-authored-by: Tom Moor <tom@getoutline.com>
2024-11-02 10:58:03 -07:00
Tom Moor d87e1f6264 fix: Cannot use Discord authentication if guild name looks like a URL, closes #7776 2024-11-02 13:40:11 -04:00
Tom Moor 0e249951ab chore: Event.createFromContext usage (#7877)
* revisions.create

* Automatically pass transaction in state to createFromContext
2024-11-02 10:16:15 -07:00
Tom Moor 398be02091 Add authType column to events (#7872)
* Add authType column to events

* Record authType with createFromContext
2024-11-02 06:21:43 -07:00
infinite-persistence 83f0d34430 Comments: scroll to most-recent during load and when switching sort setting (#7825)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-11-02 06:15:12 -07:00
Tom Moor 21723d3ca2 fix: Triple click of last line in code block on Firefox (#7876) 2024-11-01 05:36:50 -07:00
Tom Moor bc4f0b926d Set reply-to email address to actor when permissions allow (#7840)
* Set reply-to email address to actor when permissions allow

* tsc

* Add reply email for Invite too
2024-11-01 05:36:29 -07:00
Tom Moor 4d67d47795 fix: Do not consider hover activity when page/window is out of focus (#7871) 2024-10-31 19:19:08 -07:00
Tom Moor d372ccf5b6 fix: Decrease sensitivity of markdown detection, closes #7873 2024-10-31 22:14:45 -04:00
Tom Moor d78eeaba84 fix: Group membership addition UI shows incorrect options after pagination, closes #7875 2024-10-31 21:23:34 -04:00
Tom Moor fc333abb86 perf: Improve sidebar performance when collection has large amount of root documents 2024-10-31 20:35:13 -04:00
Tom Moor 73ef9f9a05 fix: Close collapsed sidebar when window loses focus, related #7857 2024-10-30 19:10:44 -05:00
Tom Moor 670ddda3a4 fix: Quick fix for toolbar behind header, closes #7826 2024-10-30 17:28:47 -05:00
Tom Moor 6e74ccf61f fix: Allow single character workspace names. 2024-10-30 17:03:40 -05:00
Tom Moor f3f7189c93 test 2024-10-30 15:27:08 -05:00
Tom Moor 50e680aaaf fix: Deprecated shares do not load 2024-10-30 14:03:20 -05:00
Tom Moor 373ffba384 fix: Search bar overlaid by menu on large documents 2024-10-30 13:46:44 -05:00
dependabot[bot] b0182dfc76 chore(deps): bump vite from 5.4.8 to 5.4.10 (#7852)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.8 to 5.4.10.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.10/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.10/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-29 20:50:07 -07:00
dependabot[bot] 2084c4ff8e chore(deps): bump i18next-fs-backend from 2.3.1 to 2.3.2 (#7851)
Bumps [i18next-fs-backend](https://github.com/i18next/i18next-fs-backend) from 2.3.1 to 2.3.2.
- [Commits](https://github.com/i18next/i18next-fs-backend/compare/v2.3.1...v2.3.2)

---
updated-dependencies:
- dependency-name: i18next-fs-backend
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-29 20:49:48 -07:00
dependabot[bot] 29fce45a6e chore(deps-dev): bump @types/dotenv from 8.2.0 to 8.2.3 (#7853)
Bumps [@types/dotenv](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/dotenv) from 8.2.0 to 8.2.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/dotenv)

---
updated-dependencies:
- dependency-name: "@types/dotenv"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-29 14:35:01 -07:00
dependabot[bot] e524699a8c chore(deps-dev): bump @babel/cli from 7.23.4 to 7.25.9 (#7854)
Bumps [@babel/cli](https://github.com/babel/babel/tree/HEAD/packages/babel-cli) from 7.23.4 to 7.25.9.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.9/packages/babel-cli)

---
updated-dependencies:
- dependency-name: "@babel/cli"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-29 14:34:51 -07:00
Hemachandar 5e74554f4b fix: check collection group membership for backlinks (#7856) 2024-10-28 21:07:19 -07:00
Tom Moor 2a3909f65a Make from address for authentication related emails unguessable (#7844)
* Make from address for authentication-related emails unguessable

* feedback
2024-10-27 13:25:01 -07:00
Translate-O-Tron b91c06d26a New Crowdin updates (#7764) 2024-10-27 07:42:06 -07:00
Hemachandar f8433bc65e fix: add sidebar toggle for public docs (#7842) 2024-10-27 07:40:15 -07:00
Tom Moor 7bdae0cbda Revert "fix: Remove overflow from floating toolbar in desktop, as it sometimes causes the content to be misplaced"
This reverts commit bb988b551d.

Closes #7836
2024-10-26 10:14:49 -04:00
Hemachandar 3692d9c930 fix: move editor init to dispatchTransaction (#7833) 2024-10-25 08:33:18 -07:00
Alexandr Zagorskiy 2e1a827157 Feat/installation info endpoint (#7744)
* feat: add installation.info endpoint using DockerHub API

* feat: UI use an server-side API to show version info

* fix: review fixes

* test: installation.info endpoint

* feat: filtering pre-releases in installation.info endpoint

* fix: change fetch to ApiClient usage for getting version info

* Undo translation change

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-10-25 06:39:47 -07:00
Hemachandar fe33871dfe fix: wait for shared document to load (#7830) 2024-10-25 05:37:59 -07:00
Tom Moor f22bd1d7c8 perf: Multitude of small perf wins around comment sidebar, closes #7823 2024-10-24 19:22:22 -04:00
Tom Moor 48ff0ad84b fix: Duplicate threads in sidebar when comment mark crosses boundary 2024-10-24 09:45:20 -04:00
Tom Moor 4f626c08c2 perf: Fix comments double rendering on mount (#7824) 2024-10-24 05:46:43 -07:00
Hemachandar 57e9abd77f feat: allow sort by position for comments (#7770)
* feat: allow sort by position for comments

* wait for prosemirror nodes to load

* Move to menu

* remove sort; rename enum

* asc sort for in-thread display

* revert sort

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-10-22 20:18:33 -07:00
Apoorv Mishra 0d7ce76c21 Allow querying by user emails in order to @mention them (#7807)
* fix: readEmail permission

* fix: allow querying over user email in users.list

* fix: allow searching by email in @mention

* fix: include email in mentioned user's hover card

* fix: put email on separate line in hover card
2024-10-22 20:24:11 +05:30
Tom Moor c8d307c2d4 fix: Improve safety around image toolbar, related #7815 2024-10-21 21:42:27 -04:00
Tom Moor 10c51ef08d fix: Add syntax highlighting for Mermaid diagrams 2024-10-21 21:22:48 -04:00
Tom Moor bb988b551d fix: Remove overflow from floating toolbar in desktop, as it sometimes causes the content to be misplaced 2024-10-21 21:03:29 -04:00
dependabot[bot] 0e75edf7e3 chore(deps): bump prosemirror-markdown from 1.13.0 to 1.13.1 (#7811)
* chore(deps): bump prosemirror-markdown from 1.13.0 to 1.13.1

Bumps [prosemirror-markdown](https://github.com/prosemirror/prosemirror-markdown) from 1.13.0 to 1.13.1.
- [Changelog](https://github.com/ProseMirror/prosemirror-markdown/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-markdown/compare/1.13.0...1.13.1)

---
updated-dependencies:
- dependency-name: prosemirror-markdown
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* tsc

---------

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.moor@gmail.com>
2024-10-21 17:50:32 -07:00
dependabot[bot] 3523ee4c35 chore(deps-dev): bump @relative-ci/agent from 4.2.9 to 4.2.12 (#7810)
Bumps [@relative-ci/agent](https://github.com/relative-ci/agent) from 4.2.9 to 4.2.12.
- [Release notes](https://github.com/relative-ci/agent/releases)
- [Commits](https://github.com/relative-ci/agent/compare/v4.2.9...v4.2.12)

---
updated-dependencies:
- dependency-name: "@relative-ci/agent"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 17:25:51 -07:00
dependabot[bot] c0fba3913c chore(deps-dev): bump @types/turndown from 5.0.4 to 5.0.5 (#7812)
Bumps [@types/turndown](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/turndown) from 5.0.4 to 5.0.5.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/turndown)

---
updated-dependencies:
- dependency-name: "@types/turndown"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 17:25:37 -07:00
dependabot[bot] 597106cb48 chore(deps): bump prosemirror-transform from 1.10.0 to 1.10.2 (#7813)
Bumps [prosemirror-transform](https://github.com/prosemirror/prosemirror-transform) from 1.10.0 to 1.10.2.
- [Changelog](https://github.com/ProseMirror/prosemirror-transform/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-transform/compare/1.10.0...1.10.2)

---
updated-dependencies:
- dependency-name: prosemirror-transform
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-21 17:25:27 -07:00
Tom Moor 02c29e06fb perf: filter -> find to reduce policies iterated through (#7816) 2024-10-21 17:24:49 -07:00
Tom Moor 7226109989 perf: Avoid expensive DocumentHelper.toMarkdown call in presenter 2024-10-21 19:23:01 -04:00
Tom Moor 85957c10b8 fix: Invalid regex error bubbles from FindAndReplace 2024-10-20 21:27:22 -04:00
Tom Moor 7250bd3bcb fix: Cannot scrub videos in Chrome when using local storage
closes #7517
2024-10-20 21:21:51 -04:00
Tom Moor 2ee7e0f832 Use view transition API to smoothly transition between light/dark theme 2024-10-20 20:02:46 -04:00
Tom Moor c5278a71de Increase ping/pong rate to increase Heroku compatibility 2024-10-20 09:56:59 -04:00
Tom Moor e41519575f tsc 2024-10-19 12:37:17 -04:00
Tom Moor 201ccf39a0 Update icon on disclosure buttons/selects 2024-10-19 12:25:54 -04:00
Tom Moor ac3285a29a tsc 2024-10-19 08:54:58 -04:00
Tom Moor fdaeb6602d fix: Support diacritics in cmd+f, closes #7801 2024-10-19 08:22:20 -04:00
Tom Moor da4cd4ebcd Improved error handling for Azure auth, add default value for AZURE_RESOURCE_ID 2024-10-19 08:05:43 -04:00
Tom Moor b6fc8fb4b1 fix: Guard unset in awareness data 2024-10-18 09:00:02 -04:00
Tom Moor 4e6572d686 fix: Mutate clipboard content when copying from a single table cell. (#7798)
* fix: Mutate clipboard content when copying from a single table cell.
closes #7794

* refactor
2024-10-18 05:35:21 -07:00
Tom Moor 9e378899ff Remove string filtering in logger 2024-10-17 22:50:11 -04:00
Tom Moor 31dafc4258 Hide remote users selections after a timeout (#7788) 2024-10-17 15:38:36 -07:00
Hemachandar 6614b23eae fix: assorted comment bugs (#7795)
* fix: assorted comment bugs

* remove policy instead of force fetch
2024-10-17 15:38:26 -07:00
Tom Moor 9e54fd1bfb fix: User exists should account for deleted workspaces, closes #7793 2024-10-17 18:14:15 -04:00
Tom Moor f0add849f9 fix: Ensure max filename length for stored attachments, closes #7785 2024-10-16 23:18:18 -04:00
Tom Moor b55915c257 fix: Include deleted workspaces when searching for available subdomains, closes #7787 2024-10-16 22:59:22 -04:00
Tom Moor bdac4360b4 chore: Remove usage of y-prosemirror fork, pull in latest fixes from upstream 2024-10-16 21:37:52 -04:00
Tom Moor 72bfbf2060 Allow returning team API keys for admins from apiKeys.list (#7766)
* Allow returning team apiKeys.list for admins from apiKeys.list

* Filter apikeys in store
2024-10-14 15:29:47 -07:00
dependabot[bot] db02b0ae6b chore(deps): bump @babel/preset-env from 7.25.7 to 7.25.8 (#7780)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.25.7 to 7.25.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.8/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 14:30:10 -07:00
dependabot[bot] bb40e4079a chore(deps-dev): bump nodemon from 3.1.4 to 3.1.7 (#7781)
Bumps [nodemon](https://github.com/remy/nodemon) from 3.1.4 to 3.1.7.
- [Release notes](https://github.com/remy/nodemon/releases)
- [Commits](https://github.com/remy/nodemon/compare/v3.1.4...v3.1.7)

---
updated-dependencies:
- dependency-name: nodemon
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 14:29:58 -07:00
dependabot[bot] 198a96c78f chore(deps): bump emoji-regex from 10.3.0 to 10.4.0 (#7783)
Bumps [emoji-regex](https://github.com/mathiasbynens/emoji-regex) from 10.3.0 to 10.4.0.
- [Commits](https://github.com/mathiasbynens/emoji-regex/compare/v10.3.0...v10.4.0)

---
updated-dependencies:
- dependency-name: emoji-regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 14:29:43 -07:00
dependabot[bot] 1dd835bb87 chore(deps-dev): bump discord-api-types from 0.37.101 to 0.37.102 (#7779)
Bumps [discord-api-types](https://github.com/discordjs/discord-api-types) from 0.37.101 to 0.37.102.
- [Release notes](https://github.com/discordjs/discord-api-types/releases)
- [Changelog](https://github.com/discordjs/discord-api-types/blob/main/CHANGELOG.md)
- [Commits](https://github.com/discordjs/discord-api-types/compare/0.37.101...0.37.102)

---
updated-dependencies:
- dependency-name: discord-api-types
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-14 14:29:15 -07:00
dependabot[bot] 25c504ceaf chore(deps-dev): bump typescript from 5.4.5 to 5.6.3 (#7767)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.4.5 to 5.6.3.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.4.5...v5.6.3)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-11 19:45:02 -07:00
Tom Moor 9680e57849 chore: Remove suppressImplicitAnyIndexErrors TS rule (#7760) 2024-10-11 12:46:46 -07:00
Hemachandar 0f8ac54bcb feat: include content in document mentioned email (#7756)
* feat: include content in document mentioned email

* handle doc publish flow

* add tests, doc

* including heading node

* Diff border
2024-10-11 12:30:08 -07:00
Hemachandar 936a8b2510 fix: show all document backlinks for a user (#7751)
* fix: show all document backlinks for a user

* add findByIds method to Document model

* default options param

* move filter to Document model

* docs

* fix: Backlinks from collections without direct membership not returned

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-10-11 08:38:24 -07:00
Luke Thomas b7b5e3edb9 fix: Remove docker version in compose file (#7762) 2024-10-11 06:26:38 -07:00
Translate-O-Tron 1cea59abe2 New Crowdin updates (#7730) 2024-10-10 18:22:12 -07:00
Tom Moor 8f0211057c fix: RTL headings are not considered separately for layout
closes #7757
2024-10-10 20:45:50 -04:00
Tom Moor 2bfef05137 fix: Mention with space in search is not inserted correctly, closes #7759 2024-10-10 19:59:20 -04:00
dependabot[bot] d2a99b6872 chore(deps): bump vite from 5.3.1 to 5.4.8 (#7704)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.3.1 to 5.4.8.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.8/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.8/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-10 04:47:20 -07:00
Hemachandar 6c9f265918 feat: Lossless JSON import (#7274)
* feat: Lossless JSON import

* transform node only when attachments are present in the zip
2024-10-09 19:04:04 -07:00
Tom Moor 7a8d40b9e7 feat: Add option to export table as CSV, closes #7743 2024-10-08 21:23:38 -04:00
Tom Moor 3ddffdda17 fix: Race condition rendering Mermaid diagrams in dark mode 2024-10-08 20:43:48 -04:00
Tom Moor 91396148ae fix: “Share to web” control is unresponsive when opening via “Permissions” menu item 2024-10-08 19:20:40 -04:00
Tom Moor 1c2ea2aa92 fix: Incorrect keyboard shortcut for TOC shown on macOS 2024-10-08 18:55:19 -04:00
Tom Moor ba5eb60825 fix: Remove slashes and literal newlines from markdown, closes #7691 2024-10-07 23:01:07 -04:00
Tom Moor a0e363799c fix: Add extra safety around search queries 2024-10-07 22:29:54 -04:00
Tom Moor 3d457890cd fix: Regression in e857d00e3d rendering embeds 2024-10-07 22:04:51 -04:00
Tom Moor e857d00e3d chore: Moves ProseMirror NodeView to render within main React context (#7736) 2024-10-07 17:58:00 -07:00
Tom Moor 98d8435b15 Allow search page to work with Firefox keywords, closes #7722 2024-10-07 19:55:19 -04:00
dependabot[bot] b80463665b chore(deps): bump @babel/preset-env from 7.24.7 to 7.25.7 (#7740)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.24.7 to 7.25.7.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.25.7/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 16:54:55 -07:00
dependabot[bot] b4ce4a2922 chore(deps): bump prosemirror-model from 1.22.3 to 1.23.0 (#7741)
Bumps [prosemirror-model](https://github.com/prosemirror/prosemirror-model) from 1.22.3 to 1.23.0.
- [Changelog](https://github.com/ProseMirror/prosemirror-model/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-model/compare/1.22.3...1.23.0)

---
updated-dependencies:
- dependency-name: prosemirror-model
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 16:54:45 -07:00
dependabot[bot] 9bee54b07e chore(deps-dev): bump @types/react-avatar-editor from 13.0.2 to 13.0.3 (#7739)
Bumps [@types/react-avatar-editor](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-avatar-editor) from 13.0.2 to 13.0.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-avatar-editor)

---
updated-dependencies:
- dependency-name: "@types/react-avatar-editor"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 16:54:35 -07:00
Tom Moor d3c8224839 fix: Error during import with long filenames (#7738)
* fix: Stream error during import causes worker restart

* refactor

* fix: Ensure we never write filenames longer than the system can handle
2024-10-07 05:36:18 -07:00
Tom Moor 0a1c614c55 fix: Addressed several React warnings in icon picker 2024-10-06 11:38:24 -04:00
Tom Moor db4dad5e37 fix: Enter key while renaming item in sidebar should persist
fix: Renaming item in sidebar should not navigate to collection
2024-10-06 11:17:39 -04:00
Apoorv Mishra 35ff70bf14 Archive collections (#7266)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-10-06 05:37:11 -07:00
Tom Moor 8b5fdba6f4 chore: Remove usage of deprecated docker build image 2024-10-05 12:51:38 -04:00
dependabot[bot] e0a3ad92e0 chore(deps): bump cookie from 0.6.0 to 0.7.0 (#7734)
Bumps [cookie](https://github.com/jshttp/cookie) from 0.6.0 to 0.7.0.
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.0)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-05 08:21:33 -07:00
Tom Moor 10f4889737 fix: Cloned response on network error can cause process to hang (remove) 2024-10-05 10:59:56 -04:00
Tom Moor 7f66393e63 spelling 2024-10-03 21:51:07 -04:00
Tom Moor 033b05f679 fix: User cannot update profile when MembersCanDeleteAccount setting is disabled, closes #7729 2024-10-03 20:25:35 -04:00
Tom Moor 8356d44cae Merge branch 'main' of github.com:outline/outline 2024-10-03 19:39:06 -04:00
Translate-O-Tron 030c0fd40e New Crowdin updates (#7641) 2024-10-03 16:32:38 -07:00
Tom Moor 1a02b0d9d7 Add script to backfill ApiKey hashes (#7717)
* Add hashed column for API keys

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2024-10-03 16:27:25 -07:00
Apoorv Mishra be5f092117 Show nested docs on Archive page (#7488)
* fix: nested docs should appear in archive

* fix(app): ArchivableModel

* fix(server): ArchivableModel

* fix: PartialWithArchivedAt not needed

* fix: new PartialExcept type

* fix: restore deletion

* fix: review
2024-10-02 10:10:41 +05:30
Tom Moor 0ba423feb4 fix: Improve empty state for command menu no results 2024-10-01 22:28:38 -04:00
Tom Moor a41e17f875 feat: Add 'Copy public link' option to document menu 2024-10-01 09:55:33 -04:00
Hemachandar db114fd966 perf: store document state in context (#7658)
* perf: store document state in context

* provide doc-context for shared routes
2024-10-01 05:16:32 -07:00
dependabot[bot] ce987d23ed chore(deps): bump socket.io-client from 4.7.5 to 4.8.0 (#7701)
Bumps [socket.io-client](https://github.com/socketio/socket.io) from 4.7.5 to 4.8.0.
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-client@4.7.5...socket.io-client@4.8.0)

---
updated-dependencies:
- dependency-name: socket.io-client
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-30 17:16:53 -07:00
Tom Moor 5e61fcd336 Add hashed column for API keys (#7699)
* Add hashed column for API keys

* test

* Add obfuscatedValue getter
2024-09-30 17:16:35 -07:00
dependabot[bot] 4f84daf558 chore(deps-dev): bump @types/body-scroll-lock from 3.1.0 to 3.1.2 (#7703)
Bumps [@types/body-scroll-lock](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/body-scroll-lock) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/body-scroll-lock)

---
updated-dependencies:
- dependency-name: "@types/body-scroll-lock"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-30 16:30:17 -07:00
dependabot[bot] f80842ca20 chore(deps-dev): bump @types/jest from 29.5.12 to 29.5.13 (#7702)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.12 to 29.5.13.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-30 16:30:07 -07:00
Tom Moor 53758b69fb fix: Another race condition with policy removal on startup 2024-09-30 18:57:39 -04:00
Tom Moor cd86877cb0 fix: Race condition with policies removed on app load 2024-09-30 17:51:01 -04:00
清纯的小黄瓜 ffae5d2f20 fix: sidebar cannot display correctly on mobile, when collapsed is true (#7694) 2024-09-30 05:21:44 -07:00
Hemachandar 21adfdd1bf perf: use findAll for querying document collaborators (#7697)
* perf: use findAll for querying document collaborators

* remove unnecessary compact
2024-09-29 09:43:07 -07:00
Hemachandar 91c2f60827 fix: align document and collection title (#7696) 2024-09-29 09:37:09 -07:00
Tom Moor a253d2921a Add reverse alphabetical sort for collections, closes #7692 2024-09-29 09:53:50 -04:00
Tom Moor b83d218fbe fix: Add icons to copy functionality in command menu 2024-09-29 09:37:15 -04:00
Tom Moor dce96955a1 Tweak command bar heading style 2024-09-29 09:33:09 -04:00
Tom Moor ba7c446f59 Add confirmation dialog when dragging 2024-09-29 09:31:00 -04:00
Tom Moor 7b9ec4c43a Show targeted collection/document in command bar, closes #7678 2024-09-28 22:46:41 -04:00
Tom Moor faaf0a6733 Add recently viewed documents to top of command menu (#7685)
* Add recent documents to command menu
Add priority key to actions and sections

* refactor

* Rename section

* refactor, remove more unused code
2024-09-28 17:30:40 -07:00
Hemachandar c58aafeb32 fix: check doc access before sending mention email (#7664)
* fix: check doc access before sending mention email

* refactor

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-09-28 14:29:34 -07:00
bLue 3f73c9d2bf fix: Adjust math delimiter to fix markdown import/export compatibility issue (#6727)
#6650)
2024-09-28 12:45:03 -07:00
Tom Moor b6e43e1990 Add Heading 4 to block menu 2024-09-28 13:13:25 -04:00
Tom Moor 0a2c066253 fix: Improve display of Mermaid pie charts 2024-09-28 12:31:46 -04:00
Tom Moor 840db4692e fix: Correctly decorate urlId as Unique (#7671) 2024-09-28 06:23:27 -07:00
Tom Moor fa961d7464 fix: Drop to reorder cursor appearing where move location is invalid 2024-09-28 09:21:26 -04:00
Tom Moor 3e75b24f7a fix: Table sorting does not take into account tables without a header 2024-09-27 22:12:01 -04:00
Tom Moor ce91071995 fix: post login redirect path not correctly spent, closes #7662 2024-09-26 17:35:13 -04:00
Tom Moor 9b807f7a9e v0.80.2 2024-09-25 22:50:22 -04:00
Tom Moor 17493ca0cf fix: Account for multiple existing OIDC authentication providers, closes #7638 2024-09-25 22:49:48 -04:00
Tom Moor 1d4b05c9f6 fix: Add check for paths in useLastVisitedPath, closes #7655 2024-09-25 22:00:52 -04:00
Tom Moor 8a5e42071f fix: Remove deprecated meta tag 2024-09-25 08:58:17 -04:00
Tom Moor 6b53755f5a fix: Maximum call stack size exceeded, closes #7642 2024-09-24 23:11:58 -04:00
Tom Moor 709e4f44fd fix: Allow team creation without SSO methods 2024-09-24 22:33:53 -04:00
dependabot[bot] c37646b5ad chore(deps): bump bull from 4.12.2 to 4.16.3 (#7649)
Bumps [bull](https://github.com/OptimalBits/bull) from 4.12.2 to 4.16.3.
- [Release notes](https://github.com/OptimalBits/bull/releases)
- [Changelog](https://github.com/OptimalBits/bull/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/OptimalBits/bull/compare/v4.12.2...v4.16.3)

---
updated-dependencies:
- dependency-name: bull
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-23 20:37:56 -07:00
dependabot[bot] 36ca667c50 chore(deps-dev): bump discord-api-types from 0.37.87 to 0.37.101 (#7646)
Bumps [discord-api-types](https://github.com/discordjs/discord-api-types) from 0.37.87 to 0.37.101.
- [Release notes](https://github.com/discordjs/discord-api-types/releases)
- [Changelog](https://github.com/discordjs/discord-api-types/blob/main/CHANGELOG.md)
- [Commits](https://github.com/discordjs/discord-api-types/compare/0.37.87...0.37.101)

---
updated-dependencies:
- dependency-name: discord-api-types
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-23 19:13:38 -07:00
uy/sun 009e66a466 fix: disable bilibili autoplay (#7639) 2024-09-23 04:50:52 -07:00
Tom Moor 7adda26c6d v0.80.1 2024-09-22 13:00:56 -04:00
Tom Moor 62860c593b fix: Version number not updated from previous release, #7635 2024-09-22 13:00:48 -04:00
Tom Moor bdc2357984 Merge branch 'main' of github.com:outline/outline 2024-09-22 12:59:16 -04:00
Tom Moor 4fc1ed0d7e Add release script (#7637) 2024-09-22 09:59:10 -07:00
Tom Moor 5d068361cc fix: Protect against dangerous characters in env 2024-09-22 12:58:49 -04:00
Tom Moor 176cfff7f8 fix: Document editors are sometimes not included in insights/collaboratorIds, closes #7613 2024-09-21 15:30:56 -04:00
Tom Moor 2fd18f7fdb fix: Add resilience for absolute attachment paths in Markdown importer, closes #7512 2024-09-21 14:34:28 -04:00
Tom Moor 34f951c511 fix: Pragmatic fix to drafts count in sidebar, closes #7219 2024-09-21 13:51:46 -04:00
Tom Moor f0c26cf8c8 refactor: Move hooks to correct folder 2024-09-21 13:27:10 -04:00
Translate-O-Tron d77ddbd7de New Crowdin updates (#7595) 2024-09-21 06:31:07 -07:00
Tom Moor 4e1038837b chore: Remove old feature flag
fix: Loading jank when creating new collection
Add italic prop to Text component
2024-09-21 09:03:20 -04:00
Tom Moor c54fcc3536 fix: Improve scroll to comment logic, closes #7435 2024-09-20 23:31:46 -04:00
Tom Moor c4fa63df3d Sticky public access toggle (#7617)
* Sticky public access toggle

* tweak
2024-09-20 18:42:50 -07:00
Tom Moor 2b42ce0c0f fix: document.content column not updated when sending text attribute through API (#7630) 2024-09-20 07:37:42 -07:00
Apoorv Mishra 3208156591 In documents.archived, allow sort: "index" in request (#7628)
* fix: allow sorting by index and filtering by collectionId

* fix: cleanup
2024-09-20 11:29:20 +05:30
Tom Moor e8577ef2a8 chore: Bump prosemirror-view 2024-09-19 20:01:22 -04:00
Tom Moor ca66dec22b Merge branch 'main' of github.com:outline/outline 2024-09-19 20:00:36 -04:00
Tom Moor 41ccad7cce Adds natural behavior of Tab, Shift-Tab in code blocks (#7622)
* Adds proper handling of Tab, Shift-Tab in code blocks

* refactor
2024-09-19 17:00:05 -07:00
Tom Moor bd52b364dd Increase collection rate limit to 50/hour 2024-09-19 09:01:05 -04:00
Tom Moor 5c56714bc8 test: Remove table truncation as it causes sporadic test failures 2024-09-18 20:13:52 -04:00
Tom Moor 895a88f934 fix: Incorrect filter input background in dark mode 2024-09-18 09:25:46 -04:00
Tom Moor f32db08ef3 Add 'Toggle task list item' to shortcut guide 2024-09-18 09:22:38 -04:00
Tom Moor 05a513b10c test 2024-09-18 08:59:35 -04:00
Tom Moor bf3c6333b0 Allow drag and drop into "Shared with me" as parent (#7619)
* wip

* Remove collections from documents.move response

* Remove parsing of collections in documents.move response
2024-09-18 05:41:36 -07:00
Tom Moor 544554f106 fix: Prevent mismatch of parentDocumentId and collectionId in documents.move request 2024-09-17 20:48:13 -04:00
Tom Moor 37c90e1592 fix: Add guard for empty actorId, closes #7614 2024-09-16 22:18:50 -04:00
Nam Vu 815abc8423 feat: group/groupuser commands (#7548) 2024-09-16 17:50:57 -07:00
Tom Moor b9ed7ddf58 feat: Add confirmation for document archive, closes #7605 2024-09-16 20:36:51 -04:00
Tom Moor bc0b73e7a7 fix: OIDC signin to prevent duplicate auth providers (#7598)
* Refactor OIDC signin to prevent duplicate auth providers

* refactor
2024-09-16 17:21:41 -07:00
dependabot[bot] 1218bc1f3c chore(deps): bump @babel/plugin-transform-destructuring from 7.24.7 to 7.24.8 (#7608)
Bumps [@babel/plugin-transform-destructuring](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-destructuring) from 7.24.7 to 7.24.8.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.8/packages/babel-plugin-transform-destructuring)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-destructuring"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 16:45:40 -07:00
dependabot[bot] ae3b05fdba chore(deps-dev): bump @types/validator from 13.12.0 to 13.12.1 (#7609)
Bumps [@types/validator](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/validator) from 13.12.0 to 13.12.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/validator)

---
updated-dependencies:
- dependency-name: "@types/validator"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 16:45:25 -07:00
Tom Moor 549c8d9ed8 feat: Add ability to tag users out of document (#7601)
* feat: Add ability to tag users out of document

* cleanup fetchDocumentUsers
2024-09-16 16:45:01 -07:00
Tom Moor 6bb798220b feat: Add userId filter to documents.users endpoint 2024-09-15 21:41:06 -04:00
Tom Moor e032bb5ab8 Check document access before creating @mention notification 2024-09-15 21:27:07 -04:00
Tom Moor 23b3b8aa54 fix: Archived documents can appear in shared with me sidebar 2024-09-14 22:04:13 -04:00
Tom Moor 738d943bd4 fix: CMD+K with link editor open should focus editor 2024-09-14 16:31:06 -04:00
Tom Moor ae5c737ed2 perf: Do not trigger list hover transactions in read-only editor 2024-09-14 11:57:09 -04:00
Tom Moor 5116147ace fix: Internal URL detection on client, closes #7245 2024-09-14 11:46:42 -04:00
Tom Moor e6ba84e434 fix: Disconnected icon is misaligned 2024-09-14 11:38:26 -04:00
Tom Moor 3b546a7935 fix: Negative days in deletion banner, closes #7485 2024-09-14 11:20:48 -04:00
Tom Moor 9373da0da6 Add filtering and async loading to search filters (#7597)
* Add input within search filters

* Query users on demand

* Enforce input on collection and user filters

* Improve filter matching, reduce flickering
2024-09-14 08:12:01 -07:00
Tom Moor 494ef2a6cd fix: Include results from users with accents in users.list query 2024-09-12 20:46:17 -04:00
Tom Moor c60703cc5a Merge branch 'main' of github.com:outline/outline 2024-09-12 19:44:10 -04:00
Translate-O-Tron f5b6d10a73 New Crowdin updates (#7551) 2024-09-12 16:42:47 -07:00
Tom Moor 3b17926023 fix: Include results from users with accents in @mention search (#7590)
* fix: Include results from users with accents in @mention search

* test
2024-09-12 16:42:31 -07:00
Tom Moor 0c080038d7 fix: Filter self from user suggestions, closes #7559 2024-09-12 19:26:23 -04:00
Tom Moor ae0bd5f59d fix: Add guards around sessionStorage use, closes #7583 2024-09-12 18:41:21 -04:00
Tom Moor 7c9a2bbcf6 fix: Team is required for user queries from slack hooks 2024-09-12 12:39:24 -04:00
Tom Moor b55a8ab54f fix: Restore individual tabs to correct page post-login, closes #7467 2024-09-10 22:40:02 -04:00
Tom Moor 1bc41b4d62 fix: Syncronized login state of tabs, related #7467 2024-09-10 22:02:55 -04:00
Tom Moor 43b9eb0ad7 Home and Search sticky in sidebar 2024-09-10 21:39:24 -04:00
Tom Moor 3f87912656 perf: Remove subscriptions.list request on document load, ref #7442 2024-09-10 21:11:16 -04:00
Tom Moor c960804bb8 fix: Warning of active prop passed to dom 2024-09-10 21:04:48 -04:00
Tom Moor 26fa70cbbd fix: JS error when user removed from membership relation, closes #7582 2024-09-10 20:58:37 -04:00
Tom Moor ba749cac71 Add missing keyboard shortcuts in guide 2024-09-10 20:45:23 -04:00
Tom Moor df08a0063c fix: Missing highlight color in floating toolbar 2024-09-10 20:41:38 -04:00
Tom Moor 6591bbebc9 feat: Add Cmd-Shift-c as shortcut for inline code 2024-09-10 20:29:26 -04:00
Tom Moor cb56941a17 fix: Issue in latest Chrome with Korean IME, closes #7574 2024-09-10 20:23:53 -04:00
dependabot[bot] 209e5e20d5 chore(deps-dev): bump terser from 5.31.6 to 5.32.0 (#7567)
Bumps [terser](https://github.com/terser/terser) from 5.31.6 to 5.32.0.
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/compare/v5.31.6...v5.32.0)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-09 20:39:47 -07:00
dependabot[bot] 2d0612a9d0 chore(deps): bump @octokit/auth-app from 6.1.1 to 6.1.2 (#7569)
Bumps [@octokit/auth-app](https://github.com/octokit/auth-app.js) from 6.1.1 to 6.1.2.
- [Release notes](https://github.com/octokit/auth-app.js/releases)
- [Commits](https://github.com/octokit/auth-app.js/compare/v6.1.1...v6.1.2)

---
updated-dependencies:
- dependency-name: "@octokit/auth-app"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-09 20:39:30 -07:00
Apoorv Mishra fca4467bda Delay loading of document policies until document menu is opened (#7442)
* fix: loading of doc policies should be delayed until menu is opened

* fix: fetch upon hover and display menu only when data is loaded

* fix: remove documents.isFetching

* fix: wait for policies to load

* fix: bifurcate

* fix: className is never used at any callsite of

* fix: MenuContext

* fix: collection is derived from document

* fix: mount MenuContent only when button is clicked

* fix: jsdoc

* fix: aria-label

* fix: review
2024-09-09 22:46:37 +05:30
Tom Moor b77af9bda3 fix: Remove manual revision deletion in document delete endpoint 2024-09-08 11:06:43 -04:00
Tom Moor f984ee0fcc fix: Cannot unset collection description, closes #7553 2024-09-07 18:42:39 -04:00
Meng Sen f3fe73057a feat: add Umami (#7366)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-09-07 15:15:35 -07:00
Tom Moor 4a009ed35b feat: Adds team preference to disable user account removal (#7556)
* feat: Adds team preference to disable user account removal

* Switch to using policy
2024-09-07 10:36:41 -07:00
Tom Moor cd419190ef chore: Remove from presenter payloads 2024-09-07 11:53:38 -04:00
Tom Moor 7c309c7986 fix: Use padlock icon for document permissions in menu, small refactor 2024-09-07 11:52:11 -04:00
Tom Moor 4a2707c74c Update LICENSE 2024-09-05 19:50:09 -07:00
Tom Moor a6b9672779 0.79.1 2024-09-05 20:03:45 -04:00
Tom Moor 3bce4853c3 fix: group_user primary key migration needs to cleanup duplicate rows before adding constraint.
closes #7546
2024-09-05 19:57:15 -04:00
Tom Moor 6859b0cf62 Add 'Permissions' option to document menu for those with, erm.. permission 2024-09-05 19:30:13 -04:00
Tom Moor d10668de54 feat: Add 'nginx' language, closes #7542 2024-09-05 19:22:03 -04:00
Tom Moor f8535ff047 fix: Error in non-Outline Electron browser, improved typings 2024-09-05 19:19:39 -04:00
Tom Moor e2355d63a2 fix: Usage of env.URL before environment validation 2024-09-05 18:59:41 -04:00
Tom Moor ed22891a69 feat: Adds 'Dockerfile' as language (#7549) 2024-09-05 15:59:30 -07:00
Tom Moor 363c416873 fix: Docker HEALTHCHECK does not work if PORT is not explicity defined in env
closes #7547
2024-09-05 18:46:34 -04:00
dependabot[bot] 967594686e chore(deps): bump vite-plugin-pwa from 0.17.4 to 0.20.3 (#7522)
* chore(deps): bump vite-plugin-pwa from 0.17.4 to 0.20.3

Bumps [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa) from 0.17.4 to 0.20.3.
- [Release notes](https://github.com/vite-pwa/vite-plugin-pwa/releases)
- [Commits](https://github.com/vite-pwa/vite-plugin-pwa/compare/v0.17.4...v0.20.3)

---
updated-dependencies:
- dependency-name: vite-plugin-pwa
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: build error

---------

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.moor@gmail.com>
2024-09-05 05:28:52 -07:00
Tom Moor ce85b8f94d 0.79.0 2024-09-04 23:18:47 -04:00
Tom Moor 81b7ac5776 0.79.0-0 2024-09-04 22:49:05 -04:00
Translate-O-Tron fe5d8b7158 New Crowdin updates (#7505) 2024-09-04 19:37:05 -07:00
Tom Moor 7013a87c6e fix: Move wget installation and HEALTHCHECK to correct stage.
closes #7279
2024-09-04 22:30:59 -04:00
Hemachandar 4ef7e95863 feat: Add background task for empty_trash action (#7531)
* feat: Add background task for empty_trash action

* review

* enqueue task only if docs are available
2024-09-04 19:04:15 -07:00
Tom Moor f81a836549 fix: Improve scrolling behavior
closes #7533
2024-09-04 22:03:03 -04:00
Tom Moor 97674471db fix: Publish child documents created through editor CMD+K 2024-09-04 21:34:08 -04:00
Tom Moor 5a3e97d6c5 fix: CTRL+E shortcut code block scroll behavior
closes #7535
2024-09-04 21:21:34 -04:00
Tom Moor 273d6550ca fix: In templates insert template string for times 2024-09-04 21:09:26 -04:00
Tom Moor 75a78cd1c7 chore: fix Vite chunk warning 2024-09-03 22:39:22 -04:00
Tom Moor ff11a3c667 fix: Include plugin tests on CI (#7528)
* fix: Include plugin tests on CI
2024-09-03 19:13:42 -07:00
Tom Moor 1236cc9c16 fix: Emoji in heading does not appear in TOC, closes #7525 2024-09-03 21:01:42 -04:00
Tom Moor 8da5afc394 fix: Consider port in isInternalUrl util (#7529) 2024-09-03 17:22:43 -07:00
Hemachandar 7f17a51e11 feat: Add email headers to enhance threading (#7477)
* feat: Add email headers to enhance threading

* tsc

* review

* change comment mentioned email subject

* paginated load

* rename util method

* add tests

* group events

* test for unsupported notification

* typo

* review
2024-09-03 17:20:56 -07:00
Tom Moor bf1580a459 fix: Missing error toast if file size is too large on import document
closes #7524
2024-09-03 19:37:49 -04:00
Tom Moor 3e991c71c4 fix: Markdown table with column alignment not detected as markdown 2024-09-03 19:31:33 -04:00
Tom Moor e90b4d8871 Improve error log when SECRET_KEY is incorrectly defined.
Related #7523
2024-09-03 19:23:38 -04:00
dependabot[bot] ac6b4fcb4f chore(deps-dev): bump @types/readable-stream from 4.0.14 to 4.0.15 (#7513)
Bumps [@types/readable-stream](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/readable-stream) from 4.0.14 to 4.0.15.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/readable-stream)

---
updated-dependencies:
- dependency-name: "@types/readable-stream"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 06:17:39 -07:00
dependabot[bot] 0ac5139730 chore(deps): bump @sentry/react from 7.118.0 to 7.119.0 (#7514)
Bumps [@sentry/react](https://github.com/getsentry/sentry-javascript) from 7.118.0 to 7.119.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/7.119.0/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.118.0...7.119.0)

---
updated-dependencies:
- dependency-name: "@sentry/react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 06:17:24 -07:00
dependabot[bot] 53d2d68a21 chore(deps-dev): bump eslint-import-resolver-typescript (#7515)
Bumps [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) from 3.6.1 to 3.6.3.
- [Release notes](https://github.com/import-js/eslint-import-resolver-typescript/releases)
- [Changelog](https://github.com/import-js/eslint-import-resolver-typescript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-import-resolver-typescript/compare/v3.6.1...v3.6.3)

---
updated-dependencies:
- dependency-name: eslint-import-resolver-typescript
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-03 06:17:15 -07:00
Tom Moor 783122186a fix: Protect against pasting invalid @mentions 2024-09-03 08:37:33 -04:00
Tom Moor 9b24482c46 fix: Prevent ISE when searched query contains colon, closes #7481 2024-09-03 08:24:33 -04:00
Tom Moor 29fdd7e566 fix: Migration script check, closes #7479 2024-09-02 22:39:05 -04:00
Tom Moor bb074fc8cf feat: Add 'R' language highlighting, closes #7473 2024-09-02 22:18:42 -04:00
Tom Moor 19b6ee832b Suppress 'Added to document' notifications when user has existing document membership and added through group 2024-09-02 22:07:26 -04:00
Tom Moor 63e667d6d3 fix: Uncaught URI malformed error 2024-09-02 21:42:27 -04:00
Tom Moor 2afec241a0 test 2024-09-02 09:40:42 -04:00
Tom Moor d65037d4e7 perf: Increase default concurrency on worker 2024-09-02 09:31:18 -04:00
Tom Moor 58eb55efb3 fix: limit parallel image downloads in document importer 2024-09-02 09:22:29 -04:00
Hemachandar d930824b27 fix: Set DB batch limit (#7511)
* fix: Set DB batch limit

* better assertion
2024-09-02 05:08:58 -07:00
Tom Moor 167cc1adbf fix: Store group name against group events 2024-09-01 17:19:54 -04:00
Tom Moor 1491fc2eb4 fix: Allow dragging shared documents to starred section (#7506)
* fix: Allow dragging shared documents to starred section

* fix: Allow read-only collection drag and drop
fix: Full screen delete modal from drag and drop
2024-09-01 14:19:40 -07:00
Tom Moor b95eb114f1 fix: Do not send notification to actor in group addition 2024-09-01 12:44:33 -04:00
Boris Bliznioukov 20799c941e logout for OIDC #6909 (#7446)
* logout for OIDC

* logout fix

* add some time
2024-09-01 07:11:45 -07:00
Translate-O-Tron 2290dff1f2 New Crowdin updates (#7489) 2024-09-01 06:52:52 -07:00
Tom Moor f61689abdc feat: Invite groups to documents (#7275) 2024-09-01 06:51:52 -07:00
Tom Moor fefb9200f1 fix: Assorted fixes from group memberships branch (tom/document-group-permissions) 2024-08-31 10:11:11 -04:00
Tom Moor 0a4d67d96f perf: Reduce rendering when editing title 2024-08-30 13:04:43 -04:00
Apoorv Mishra 5374784df6 New Replace type utility (#7476)
* fix: Replace type

* trigger ci
2024-08-30 10:02:38 +05:30
Translate-O-Tron d090316065 New Crowdin updates (#7438) 2024-08-29 13:32:55 -07:00
Tom Moor 0fc3099f75 Standardize websocket collection channel logic 2024-08-29 12:09:52 -04:00
Tom Moor 264dda25a5 fix: Filter trashed documents from 'Shared with me'
closes #7478
2024-08-29 11:27:08 -04:00
Tom Moor 8031b2906d fix: Assorted fixes from group memberships branch (tom/document-group-permissions) 2024-08-29 11:26:12 -04:00
Tom Moor 0642396264 perf: Policies refactor (#7460) 2024-08-28 06:10:38 -07:00
dependabot[bot] 88f405375c chore(deps): bump react-hook-form from 7.52.2 to 7.53.0 (#7462)
Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.52.2 to 7.53.0.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.52.2...v7.53.0)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-27 04:28:40 -07:00
Tom Moor 7bd8738ecd Client lifecycle hooks (#7407)
* Add example client lifecycle hooks

* AfterCreate, AfterDelete hooks
2024-08-27 04:28:21 -07:00
Hemachandar 043a8623b9 chore: Script to invalidate unfurls cache (#7459) 2024-08-26 19:14:25 -07:00
Apoorv Mishra 5d85a3a093 Specify time conversion unit (#7458)
* fix: specificity in time units

* fix: milliseconds -> ms
2024-08-25 18:57:45 +05:30
Tom Moor 2578a1f75f fix: Random icon color chosen when none set 2024-08-24 17:56:49 -04:00
Tom Moor 9578611d8f fix: Floating formatting toolbar on Android mobile, closes #7052 2024-08-24 15:13:29 -04:00
Tom Moor 65b1fd9a1f fix: Date/time commands operate differently when hitting space than other menu items 2024-08-24 11:10:25 -04:00
Tom Moor 282b0f486b Merge branch 'main' of github.com:outline/outline 2024-08-24 08:36:44 -04:00
Hemachandar e3cd9af6df fix: Set redis expiry in seconds (#7456)
* fix: Set redis expiry in seconds

* change expiry for github and iframely
2024-08-24 05:36:12 -07:00
Tom Moor a1373f8078 fix: MobX warning - attempted to use array index out of bounds 2024-08-23 11:25:01 -04:00
Tom Moor 6a85d7444d Add reserved space for pinned documents 2024-08-23 11:13:05 -04:00
Tom Moor 24222ddbb1 fix: Add small amount of empty space to the bottom of shared documents 2024-08-23 09:02:52 -04:00
Tom Moor a59215d27c Add video and audio as safe inline content-disposition 2024-08-23 08:53:18 -04:00
github-actions[bot] 23ad780672 chore: Auto Compress Images (#7455)
Co-authored-by: tommoor <tommoor@users.noreply.github.com>
2024-08-23 05:18:23 -07:00
Blendman974 ac26fd2be7 Feature: Add generic Iframe support (#7319)
* Added generic Iframes support

* Rename Iframe to Embed and more explicit matchOnPaste boolean

* Update icon, text

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-08-23 05:17:27 -07:00
Tom Moor 6a09af16a4 fix: Blue focus outline on browser edge when zooming images 2024-08-22 21:51:55 -04:00
Tom Moor ce2fc94289 fix: Do not replace smart quotes in code (#7450) 2024-08-22 18:40:36 -07:00
Tom Moor 3b01551e1a fix: Allow shift+enter soft break in comments, closes #7451 2024-08-22 21:06:24 -04:00
Tom Moor d2b3e50a48 Vendorize cancan with performance improvements (#7448)
* Vendorize CanCan with performance improvements

* docs
2024-08-22 17:10:58 -07:00
Tom Moor 5549676185 fix: Escape key with suggestion menu open should not unfocus editor 2024-08-22 09:21:47 -04:00
Tom Moor 976db13ea0 Allow space when searching for @mention 2024-08-22 09:21:23 -04:00
Tom Moor 510a756378 perf: Cache textSerializers on server 2024-08-21 23:15:06 -04:00
Tom Moor d399ffa9f8 Add clear option to remove highlight in formatting menu
closes #7436
2024-08-21 22:55:57 -04:00
Tom Moor 932e5bf121 fix: Error on search shows previous results instead of error state, closes #7437 2024-08-21 22:32:45 -04:00
Tom Moor 330ee819c5 fix: Error in documentDuplicate when content is not yet written, closes #7432 2024-08-21 22:15:32 -04:00
Tom Moor 61e29d91bf fix: Enable the 'e' shortcut to focus editor 2024-08-21 22:07:23 -04:00
Tom Moor 5e0c773826 fix: Incorrect response value from fetchAll (not used up until now)
Added warning when fetchAll is used with an endpoint without pagination info
2024-08-21 21:54:07 -04:00
Tom Moor 1f7e8c158d perf: Avoid multiple renders when adding search results to store 2024-08-21 16:59:25 -04:00
Translate-O-Tron eb6cc62630 New Crowdin updates (#7406) 2024-08-21 05:23:38 -07:00
Tom Moor 5380d8c7ac fix: Refactor postLoginRedirect logic for reliability (#7428) 2024-08-21 05:23:25 -07:00
Tom Moor fd379dddba perf: Remove old usage of dynamic require statement in policy serialization (#7427) 2024-08-21 05:22:59 -07:00
Tom Moor 5e825cef10 fix: Include actor as sender for document edited emails, related #7424 2024-08-21 08:18:56 -04:00
Tom Moor ad07f4b5f7 fix: 'Restore' option appears on documents when policy is not loaded 2024-08-21 00:03:03 -04:00
Tom Moor 2a502e43ef perf: Avoid count query in search where possible (#7426)
* Remove unused replacements

* perf: Avoid count query where possible

* logic
2024-08-20 18:59:32 -07:00
Tom Moor 18d4eaee07 perf: Add missing indexes (#7425)
* perf: Add missing indexes to notifications table

* Add two more missing indexes

* tests
2024-08-20 17:44:06 -07:00
Tom Moor 058e413a6e perf: Avoid unneccessary toMarkdown call in document presenter 2024-08-20 20:15:52 -04:00
Tom Moor 1c527c97a7 fix: Partial documents.update payload wipes existing document icon 2024-08-19 19:23:17 -04:00
Tom Moor 8ac3c17310 fix: Reduce unneccessary client fetches 2024-08-19 19:10:30 -04:00
Tom Moor 5687514fd5 fix: Set deletedAt rather than remove ParanoidModels
Related #7413
2024-08-19 16:55:09 -04:00
dependabot[bot] 27ea4332eb chore(deps): bump katex from 0.16.10 to 0.16.11 (#7416)
Bumps [katex](https://github.com/KaTeX/KaTeX) from 0.16.10 to 0.16.11.
- [Release notes](https://github.com/KaTeX/KaTeX/releases)
- [Changelog](https://github.com/KaTeX/KaTeX/blob/main/CHANGELOG.md)
- [Commits](https://github.com/KaTeX/KaTeX/compare/v0.16.10...v0.16.11)

---
updated-dependencies:
- dependency-name: katex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 11:48:52 -07:00
dependabot[bot] 382a0155a2 chore(deps-dev): bump @types/crypto-js from 4.2.1 to 4.2.2 (#7415)
Bumps [@types/crypto-js](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/crypto-js) from 4.2.1 to 4.2.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/crypto-js)

---
updated-dependencies:
- dependency-name: "@types/crypto-js"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 11:48:38 -07:00
Tom Moor 24b07698a7 Sidebar order 2024-08-19 09:16:56 -04:00
Tom Moor e9380f270e fix: Non-clickable items have cursor 2024-08-19 09:16:30 -04:00
Tom Moor 16badaea5d fix: Counter cache not correctly recalculated for missing keys 2024-08-19 08:45:19 -04:00
DiamondYuan b82a379c0e refactor: Improve search functionality in SuggestionsMenu (#7411) 2024-08-19 04:47:21 -07:00
Tom Moor 300d0c56ac chore: Restore createDatabaseInstance flexibility 2024-08-18 11:00:12 -04:00
Tom Moor f887a5b4f1 fix: Select inputs unactionable 2024-08-18 10:44:15 -04:00
Tom Moor 0ab8b52582 feat: Cache count of group members (#7377) 2024-08-17 14:34:12 -07:00
Translate-O-Tron c9d4f5038b New Crowdin updates (#7336) 2024-08-17 07:42:07 -07:00
Tom Moor 53cc2d8154 fix: Flash of highlighted menu item state as context menu opens 2024-08-17 10:02:04 -04:00
Tom Moor 82651737b8 Tweak initial avatar styling 2024-08-17 09:22:45 -04:00
Tom Moor 7a06d94548 fix: Visible horizontal scrollbars on EmojiPicker 2024-08-17 09:18:07 -04:00
Tom Moor 516c5082c8 fix: Reduce size of button to match visual area on Collaborators component 2024-08-17 09:11:18 -04:00
Tom Moor 7269201bca fix: 'Image failed to load' state not centered on large images 2024-08-17 09:09:59 -04:00
Tom Moor 86be197049 fix: Websocket event not required for each document in imported collection
fix: Newly imported collections do not appear in sidebar until reload
2024-08-17 09:03:05 -04:00
Tom Moor a65d126ccf fix: Empty IFRAMELY_URL environment variable triggers validation
Related #7401
2024-08-16 22:40:04 -04:00
Tom Moor eee14d98a7 fix: Flashing of document header with many live collaborators
closes #7400
2024-08-16 22:33:00 -04:00
Tom Moor d738081880 fix: Menu on document revisions not actionable 2024-08-16 22:15:58 -04:00
Tom Moor c3cefc40e5 fix: Improve sidebar loading state 2024-08-15 21:38:21 -04:00
Tom Moor 695476a038 fix: Hide 'duplicate child documents' option when there are none 2024-08-15 21:08:46 -04:00
Tom Moor 1a31cf562e fix: Comment marks should be removed from duplicated documents
closes #7390
2024-08-15 21:01:12 -04:00
Tom Moor d7c13bc8b0 chore: Ensure failed build step exits build 2024-08-15 20:49:25 -04:00
dependabot[bot] 36e8c4796d chore(deps): bump axios from 1.6.8 to 1.7.4 (#7395)
Bumps [axios](https://github.com/axios/axios) from 1.6.8 to 1.7.4.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.6.8...v1.7.4)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-15 17:07:09 -07:00
Tom Moor d3ddb25c76 fix: Issues viewing document comments past default pagination (#7397)
* fix: Default pagination always used for fetchAll

* fix: comments.list does not return total in pagination
2024-08-15 16:56:39 -07:00
Tom Moor 51839dd780 fix: Unable to scroll elements in latest chrome (#7394) 2024-08-15 07:10:51 -07:00
Tom Moor fc2967d080 chore: Bump prosemirror deps for fixes 2024-08-14 20:49:43 -04:00
Tom Moor aba0297bd5 chore: Add PK to group_users, remove deletedAt column (#7369) 2024-08-14 04:03:56 -07:00
Tom Moor dd1df68e74 chore: Refactor @Encrypted decorator (#7381)
* chore: Simplify encrypted decorator

* fix: Correctly handle and type nullable encrypted fields

* docs
2024-08-14 03:54:37 -07:00
Tom Moor d2f5ac3d53 fix: Canva links can contain an underscore 2024-08-14 06:48:10 -04:00
Tom Moor 5eae8734c1 fix: Unresponsive collection permissions, closes #7380 2024-08-13 22:28:23 -04:00
Tom Moor 542f01e36f fix: Disable unused markdown-it parser rules when associated node is not in schema
closes #7383
2024-08-13 21:33:23 -04:00
dependabot[bot] e0dfda6f7e chore(deps): bump prosemirror-tables from 1.3.7 to 1.4.0 (#7374)
Bumps [prosemirror-tables](https://github.com/prosemirror/prosemirror-tables) from 1.3.7 to 1.4.0.
- [Release notes](https://github.com/prosemirror/prosemirror-tables/releases)
- [Commits](https://github.com/prosemirror/prosemirror-tables/compare/v1.3.7...v1.4.0)

---
updated-dependencies:
- dependency-name: prosemirror-tables
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-12 14:31:16 -07:00
dependabot[bot] 6b7837a8d6 chore(deps): bump react-hook-form from 7.52.1 to 7.52.2 (#7375)
Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.52.1 to 7.52.2.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.52.1...v7.52.2)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-12 14:29:54 -07:00
dependabot[bot] b6c7a61243 chore(deps-dev): bump @types/sequelize from 4.28.19 to 4.28.20 (#7373)
Bumps [@types/sequelize](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/sequelize) from 4.28.19 to 4.28.20.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/sequelize)

---
updated-dependencies:
- dependency-name: "@types/sequelize"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-12 14:29:41 -07:00
Tom Moor a54218d9cc fix: Collections not fetched for viewers 2024-08-12 07:55:49 -04:00
Tom Moor a432a7caa3 fix: Show partial data in share popovers when loading 2024-08-11 09:39:35 -04:00
Tom Moor bb8aa3616a fix: Special case resizing image/video to editor width 2024-08-11 09:19:16 -04:00
Tom Moor 949d93bbfd fix: Do not touch updatedAt timestamp on Attachment access 2024-08-11 08:51:30 -04:00
Tom Moor d28e23dd8e fix: Public shared docs not correctly using cache 2024-08-10 20:59:33 -04:00
Tom Moor d8145ac370 fix: Image and video resize calculation 2024-08-10 19:38:00 -04:00
Tom Moor fbc4a7fcbd fix: Prevent attachment key modification 2024-08-10 18:27:30 -04:00
Tom Moor 04ecf14cc8 fix: Flash of scrolled document on nested shared links 2024-08-10 16:57:21 -04:00
Tom Moor 4eae1f1db3 fix: Copied internal links in shared documents are incorrect (#7368)
* Add internalUrlBase option for toJSON

* Return correct internal urls for shared data

* test
2024-08-10 09:36:03 -07:00
Tom Moor fd4ab0077d fix: Protect against 'position out of range' 2024-08-10 08:43:31 -04:00
Tom Moor d6c074102b Remove paranoid deletion from GroupUser (#7356) 2024-08-10 05:16:31 -07:00
Tom Moor 2beab0c274 fix: Mobile toolbar can display on printed docs depending on browser size
closes #7367
2024-08-10 08:02:40 -04:00
Tom Moor 4f35b8ea0d chore: 411 -> 387 lint warnings 2024-08-09 16:11:35 +01:00
Tom Moor e4cbf0a34a fix: Pasting into placeholder should replace placeholder
fix: Improved click behavior for placeholders

closes #7346
2024-08-08 21:56:30 +01:00
Tom Moor d79ce99629 fix: Enter in code block in list exits code block
closes #7363
2024-08-08 21:31:03 +01:00
Apoorv Mishra 8bf488de0b Fetch collections upon initial load (#7358)
* fix: don't hide sidebar if collections are not loaded, loading drafts should be enough

* fix: preload collections

* fix: remove duplicate API call
2024-08-08 12:52:20 -07:00
Tom Moor d420319b28 fix: readTemplate permission false if team unmutable 2024-08-06 22:05:22 +01:00
Tom Moor 413bcfa7de chore: Port zodIconType 2024-08-05 21:33:25 +01:00
dependabot[bot] 363f1fffca chore(deps): bump pg from 8.11.5 to 8.12.0 (#7351)
Bumps [pg](https://github.com/brianc/node-postgres/tree/HEAD/packages/pg) from 8.11.5 to 8.12.0.
- [Changelog](https://github.com/brianc/node-postgres/blob/master/CHANGELOG.md)
- [Commits](https://github.com/brianc/node-postgres/commits/pg@8.12.0/packages/pg)

---
updated-dependencies:
- dependency-name: pg
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 09:53:17 -07:00
dependabot[bot] 3e7b61c9d7 chore(deps-dev): bump eslint-plugin-react from 7.34.3 to 7.35.0 (#7349)
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.34.3 to 7.35.0.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.34.3...v7.35.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 09:47:22 -07:00
dependabot[bot] ac0488a4d6 chore(deps): bump prosemirror-view from 1.33.8 to 1.33.9 (#7347)
Bumps [prosemirror-view](https://github.com/prosemirror/prosemirror-view) from 1.33.8 to 1.33.9.
- [Changelog](https://github.com/ProseMirror/prosemirror-view/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-view/compare/1.33.8...1.33.9)

---
updated-dependencies:
- dependency-name: prosemirror-view
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 09:46:14 -07:00
Hemachandar 41af3a107e chore: Remove emoji column from documents and revisions (#7144)
* chore: Remove emoji column from documents and revisions

* fix: Incorrect icon color on collections in share menu

* Update types.ts

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
2024-08-05 01:08:20 -07:00
Tom Moor 964ba78d75 fix: Incorrect icon color on collections in share menu 2024-08-04 22:31:47 +01:00
Apoorv Mishra 340109d9a3 Make share dialog scrollable (#7344)
* fix: make share dialog scrollable

* fix: rename

* fix: mobile

* fix: useMaxHeight margin calculation

* cleanup

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-08-04 08:59:54 -07:00
Tom Moor 6c430dc747 fix: Do not parse response stream twice on 502 error 2024-08-02 20:03:33 +01:00
Tom Moor 93f12d8846 Shift-Ctrl-c added as editor shortcut for toggling code blocks 2024-08-02 17:39:37 +01:00
dependabot[bot] a93655bf6e chore(deps-dev): bump rollup-plugin-webpack-stats from 0.2.4 to 0.4.1 (#7322)
Bumps [rollup-plugin-webpack-stats](https://github.com/relative-ci/rollup-plugin-webpack-stats) from 0.2.4 to 0.4.1.
- [Release notes](https://github.com/relative-ci/rollup-plugin-webpack-stats/releases)
- [Commits](https://github.com/relative-ci/rollup-plugin-webpack-stats/compare/v0.2.4...v0.4.1)

---
updated-dependencies:
- dependency-name: rollup-plugin-webpack-stats
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-02 01:32:37 -07:00
Tom Moor e2b4fa456b chore: Improve debugging for BadGatewayError
closes #7307
2024-08-01 22:19:08 +01:00
Tom Moor cd04c4a8bf Improve buildAttachment construction in tests 2024-08-01 22:01:49 +01:00
Tom Moor bf7fb8aa68 fix: User avatar not correct cleaned up, closes #7337 2024-08-01 22:01:22 +01:00
Tom Moor 08a6376947 fix: Improve sanitization on file keys 2024-08-01 20:24:46 +01:00
Tom Moor a120427943 fix: Image download timeouts importing document should not exceed overall request timeout 2024-08-01 09:58:44 +01:00
Translate-O-Tron 59e97eba2b New Crowdin updates (#7284)
* fix: New Spanish translations from Crowdin [ci skip]

* fix: New Portuguese, Brazilian translations from Crowdin [ci skip]

* fix: New Hungarian translations from Crowdin [ci skip]

* fix: New Spanish translations from Crowdin [ci skip]

* fix: New Korean translations from Crowdin [ci skip]

* fix: New Ukrainian translations from Crowdin [ci skip]

* fix: New Chinese Simplified translations from Crowdin [ci skip]

* fix: New Portuguese, Brazilian translations from Crowdin [ci skip]

* fix: New Polish translations from Crowdin [ci skip]

* fix: New French translations from Crowdin [ci skip]

* fix: New Czech translations from Crowdin [ci skip]

* fix: New Danish translations from Crowdin [ci skip]

* fix: New German translations from Crowdin [ci skip]

* fix: New Hebrew translations from Crowdin [ci skip]

* fix: New Hungarian translations from Crowdin [ci skip]

* fix: New Italian translations from Crowdin [ci skip]

* fix: New Japanese translations from Crowdin [ci skip]

* fix: New Dutch translations from Crowdin [ci skip]

* fix: New Portuguese translations from Crowdin [ci skip]

* fix: New Swedish translations from Crowdin [ci skip]

* fix: New Turkish translations from Crowdin [ci skip]

* fix: New Chinese Traditional translations from Crowdin [ci skip]

* fix: New Vietnamese translations from Crowdin [ci skip]

* fix: New Indonesian translations from Crowdin [ci skip]

* fix: New Persian translations from Crowdin [ci skip]

* fix: New Thai translations from Crowdin [ci skip]

* fix: New Norwegian Bokmal translations from Crowdin [ci skip]

* fix: New Hungarian translations from Crowdin [ci skip]

* fix: New Hungarian translations from Crowdin [ci skip]

* fix: New Swedish translations from Crowdin [ci skip]

* fix: New Norwegian Bokmal translations from Crowdin [ci skip]

* fix: New Czech translations from Crowdin [ci skip]

* fix: New Czech translations from Crowdin [ci skip]

* fix: New Spanish translations from Crowdin [ci skip]

* fix: New Korean translations from Crowdin [ci skip]

* fix: New Ukrainian translations from Crowdin [ci skip]

* fix: New Chinese Simplified translations from Crowdin [ci skip]

* fix: New Portuguese, Brazilian translations from Crowdin [ci skip]

* fix: New Polish translations from Crowdin [ci skip]

* fix: New French translations from Crowdin [ci skip]

* fix: New Czech translations from Crowdin [ci skip]

* fix: New Danish translations from Crowdin [ci skip]

* fix: New German translations from Crowdin [ci skip]

* fix: New Hebrew translations from Crowdin [ci skip]

* fix: New Hungarian translations from Crowdin [ci skip]

* fix: New Italian translations from Crowdin [ci skip]

* fix: New Japanese translations from Crowdin [ci skip]

* fix: New Dutch translations from Crowdin [ci skip]

* fix: New Portuguese translations from Crowdin [ci skip]

* fix: New Swedish translations from Crowdin [ci skip]

* fix: New Turkish translations from Crowdin [ci skip]

* fix: New Chinese Traditional translations from Crowdin [ci skip]

* fix: New Vietnamese translations from Crowdin [ci skip]

* fix: New Indonesian translations from Crowdin [ci skip]

* fix: New Persian translations from Crowdin [ci skip]

* fix: New Thai translations from Crowdin [ci skip]

* fix: New Norwegian Bokmal translations from Crowdin [ci skip]

* fix: New Portuguese, Brazilian translations from Crowdin [ci skip]

* fix: New Portuguese, Brazilian translations from Crowdin [ci skip]

* fix: New Chinese Simplified translations from Crowdin [ci skip]

* fix: New Chinese Simplified translations from Crowdin [ci skip]

* fix: New Chinese Simplified translations from Crowdin [ci skip]

* fix: New German translations from Crowdin [ci skip]

* fix: New French translations from Crowdin [ci skip]

* fix: New French translations from Crowdin [ci skip]

* fix: New French translations from Crowdin [ci skip]
2024-08-01 01:52:23 -07:00
dependabot[bot] 80b59b1174 chore(deps): bump prosemirror-schema-list from 1.3.0 to 1.4.1 (#7324)
Bumps [prosemirror-schema-list](https://github.com/prosemirror/prosemirror-schema-list) from 1.3.0 to 1.4.1.
- [Changelog](https://github.com/ProseMirror/prosemirror-schema-list/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-schema-list/compare/1.3.0...1.4.1)

---
updated-dependencies:
- dependency-name: prosemirror-schema-list
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-31 06:49:17 -07:00
dependabot[bot] 6a17e8deec chore(deps): bump datadog-metrics from 0.11.1 to 0.11.2 (#7323)
Bumps [datadog-metrics](https://github.com/dbader/node-datadog-metrics) from 0.11.1 to 0.11.2.
- [Release notes](https://github.com/dbader/node-datadog-metrics/releases)
- [Commits](https://github.com/dbader/node-datadog-metrics/compare/v0.11.1...v0.11.2)

---
updated-dependencies:
- dependency-name: datadog-metrics
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-31 03:22:57 -07:00
dependabot[bot] cd0aba119b chore(deps): bump prosemirror-commands from 1.5.2 to 1.6.0 (#7325)
Bumps [prosemirror-commands](https://github.com/prosemirror/prosemirror-commands) from 1.5.2 to 1.6.0.
- [Changelog](https://github.com/ProseMirror/prosemirror-commands/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-commands/compare/1.5.2...1.6.0)

---
updated-dependencies:
- dependency-name: prosemirror-commands
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-31 03:22:45 -07:00
dependabot[bot] eca17ec63d chore(deps-dev): bump @types/react-color from 3.0.10 to 3.0.12 (#7326)
Bumps [@types/react-color](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-color) from 3.0.10 to 3.0.12.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-color)

---
updated-dependencies:
- dependency-name: "@types/react-color"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-31 03:22:23 -07:00
Brian Krausz e164c4e7ca Fix icon naming (#7327) 2024-07-30 02:38:15 -04:00
Tom Moor bead9ae79a fix: replaceImagesWithAttachments ran twice during documents.import 2024-07-29 23:50:37 +01:00
Tom Moor 336e424b8b docs 2024-07-27 16:10:09 -04:00
Tom Moor 0bb993634a fix: Allow starring drafts from document lists 2024-07-27 15:48:32 -04:00
Tom Moor 2f26e76b1e chore: Add transactions to stars mutations 2024-07-27 15:47:23 -04:00
Tom Moor 93a89eeef3 chore: Add transaction to integrations.update 2024-07-27 15:41:55 -04:00
Tom Moor 6e6a5014af chore: Add transactions to groups mutations 2024-07-27 15:37:45 -04:00
Tom Moor 3da1945bea perf: Optimize common path in presentDocument to not include JSON parsing 2024-07-27 15:12:11 -04:00
Hemachandar c2fbb31e77 Workspace templates (#7150)
* feat: Workspace templates

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-07-27 08:38:16 -07:00
Hemachandar 4c999d00d2 fix: use all properties from zip when importing a collection (#7318)
* fix: use all properties from zip when importing a collection

* use shared defaults
2024-07-27 08:31:00 -07:00
Tom Moor 738449a7d0 fix: Catch Iframely non-json response correctly in lib.
closes #7306
2024-07-27 09:49:56 -04:00
Tom Moor ae80128396 chore: aws-sdk upgrade 2024-07-27 09:47:59 -04:00
Tom Moor 1da5ac0bfe chore: Remove no longer required resolutions 2024-07-27 09:47:59 -04:00
Apoorv Mishra f56f240d9b Remove trailing spaces from search query (#7314)
* fix: tsquery err

* fix: test
2024-07-26 20:27:56 -07:00
github-actions[bot] 7de0ffb7f7 chore: Auto Compress Images (#7310)
Co-authored-by: tommoor <tommoor@users.noreply.github.com>
2024-07-26 05:49:18 -07:00
Baboon 0e667c5d3d add Dropbox embeddings support (#7299)
* add Dropbox embedder support

* Update embeds.ts

---------

Co-authored-by: Tom Moor <tom@getoutline.com>
2024-07-26 05:47:35 -07:00
Tom Moor 465c935879 fix: Remove .at usage, closes #7305 2024-07-26 08:47:09 -04:00
Tom Moor 9c628dfc54 fix: Ensure document changes are saved on unmount (#7293) 2024-07-24 17:16:43 -07:00
Apoorv Mishra 38b11b3f1e Ignore documents.empty_trash for DeliverWebhookTask (#7304) 2024-07-24 16:46:11 -07:00
Apoorv Mishra d7f53acfa2 Suppress document publish notification upon document creation (#7301)
* fix: do not trigger document publish event upon document creation
2024-07-24 06:44:07 -07:00
Tom Moor e033b20d6f fix: Query not taken into account when filtering groups, closes #7291 2024-07-23 22:49:57 -04:00
Tom Moor 87aacae479 Add back and forward shortcuts to shortcut guide 2024-07-23 22:28:25 -04:00
Tom Moor bbe6df19ea Add locking to collection.move mutation
Add removeIndexCollision tests
2024-07-23 22:13:56 -04:00
dependabot[bot] fd851dfbd1 chore(deps): bump react-hook-form from 7.41.5 to 7.52.1 (#7287)
Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.41.5 to 7.52.1.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.41.5...v7.52.1)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-23 04:20:44 -07:00
Tom Moor 1426c4e6ab fix: Index calculation does not take into account user scope (#7294)
* fix: Index calculation does not take into account user scope

* Standardize sort index maxlength to 256
2024-07-23 04:20:30 -07:00
dependabot[bot] 10b33ff91f chore(deps): bump outline-icons from 3.5.0 to 3.6.0 (#7288)
Bumps outline-icons from 3.5.0 to 3.6.0.

---
updated-dependencies:
- dependency-name: outline-icons
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 17:59:24 -07:00
dependabot[bot] 15f58d0e15 chore(deps): bump prosemirror-history from 1.4.0 to 1.4.1 (#7286)
Bumps [prosemirror-history](https://github.com/prosemirror/prosemirror-history) from 1.4.0 to 1.4.1.
- [Changelog](https://github.com/ProseMirror/prosemirror-history/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-history/compare/1.4.0...1.4.1)

---
updated-dependencies:
- dependency-name: prosemirror-history
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 17:59:01 -07:00
dependabot[bot] 6f5859a175 chore(deps): bump react-merge-refs from 2.0.2 to 2.1.1 (#7289)
Bumps [react-merge-refs](https://github.com/gregberge/react-merge-refs) from 2.0.2 to 2.1.1.
- [Release notes](https://github.com/gregberge/react-merge-refs/releases)
- [Changelog](https://github.com/gregberge/react-merge-refs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/gregberge/react-merge-refs/compare/v2.0.2...v2.1.1)

---
updated-dependencies:
- dependency-name: react-merge-refs
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 17:58:45 -07:00
Tom Moor 52776d5add fix: Empty emoji placeholder color 2024-07-22 20:13:42 -04:00
Tom Moor 474baf7b42 fix: Suppress notifications for changes that are not visible 2024-07-22 20:09:03 -04:00
Tom Moor 516ccce51d fix: Add support for new dbdiagram share links, closes #7281 2024-07-21 22:50:02 -04:00
Tom Moor 16c51c10fe docs 2024-07-21 21:24:55 -04:00
Tom Moor d312d00bca Allow function definition for onDelete behavior 2024-07-21 21:24:55 -04:00
Hemachandar e4c1281bf7 fix: replace document links when importing markdown (#7259) 2024-07-21 17:42:36 -07:00
Hemachandar bbbc00baaa fix: Set doc slug on importing collections (#7270)
* fix: Set doc slug on importing collections

* review
2024-07-21 17:42:22 -07:00
Translate-O-Tron 78d5992ad4 New Crowdin updates (#7272) 2024-07-21 17:42:09 -07:00
Brian Krausz f58ce49e3d fix: Error when passed too many user invites (#7282) 2024-07-21 17:41:46 -07:00
Tom Moor f0ba98e936 fix: Upon adding user to a group only the first collection in the group proactively joined 2024-07-21 08:14:51 -04:00
Tom Moor ff34a46361 0.78.0 2024-07-21 08:14:51 -04:00
Tom Moor 7849af6887 Update no-response.yml 2024-07-19 07:38:16 -07:00
Tom Moor 95a87878c3 fix: Groups added to collection are always added with read-only permission 2024-07-19 04:05:44 -07:00
Tom Moor 011ffc450c tsc 2024-07-18 20:18:55 -04:00
Tom Moor 51c5512902 fix: Templates menu not visible after creating document in collection
Regressed in e2213dbfa2
2024-07-18 19:30:50 -04:00
Alexis Lefebvre 76d64f90c1 chore: fix typo on “intitial” (#7273) 2024-07-18 08:00:39 -07:00
Tom Moor f48c05bef3 chore: CollectionGroupMembership -> GroupMembership (#7269)
* chore: CollectionGroupMembership -> GroupMembership

* Backwards compat

* docs
2024-07-17 18:39:13 -07:00
Tom Moor f675a04735 chore: Rename GroupPermission -> GroupMembership (#7214)
* GroupPermission -> GroupMembership

* Add group membership source

* wip
2024-07-17 16:31:20 -07:00
Tom Moor e52719c38e chore: Rename GroupMembership -> GroupUser (#7268)
* Rename GroupMembership -> GroupUserMembership

* GroupUser
2024-07-17 16:14:59 -07:00
Tom Moor cd854d4adb fix: Admins unable to see private shared docs, closes #7264 2024-07-17 07:42:47 -04:00
Tom Moor 7bb7f96008 Add optional logging of all server side requests for self-hosted debugging
related #7221
2024-07-15 21:44:08 -04:00
Translate-O-Tron 6d70b4b9c7 New Crowdin updates (#7240) 2024-07-15 17:53:54 -07:00
Hemachandar 78fd39a0fb fix: unset active collection id when navigating away from a document (#7241) 2024-07-15 17:53:33 -07:00
Tom Moor 8186e23d45 fix: Incorrect policies returned after unpublishing document
Related https://github.com/outline/outline/discussions/7258
2024-07-15 20:28:44 -04:00
Tom Moor e4492a32d2 fix: Table insert controls remain accessible in read-only mode
closes #7249
2024-07-15 20:20:16 -04:00
feingold-ant cb4f610bb4 doc editors can create child docs (#7257) 2024-07-15 16:57:06 -07:00
Ali Afsharzadeh 14a96e7262 Resolve buildx warnings during Docker image creation (#7246) 2024-07-15 16:56:56 -07:00
feingold-ant e2213dbfa2 If a document is created within a collection, publish it automatically. (#7243)
* If a document is created within a collection, publish it automatically.

* automatically publish from app, not server

* remove auto publish from server

* New draft -> New doc
2024-07-15 16:56:43 -07:00
dependabot[bot] e3d7fba239 chore(deps): bump validator from 13.11.0 to 13.12.0 (#7250)
Bumps [validator](https://github.com/validatorjs/validator.js) from 13.11.0 to 13.12.0.
- [Release notes](https://github.com/validatorjs/validator.js/releases)
- [Changelog](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/validatorjs/validator.js/compare/13.11.0...13.12.0)

---
updated-dependencies:
- dependency-name: validator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-15 14:42:51 -07:00
dependabot[bot] 33a43077d5 chore(deps-dev): bump @relative-ci/agent from 4.1.10 to 4.2.9 (#7252)
Bumps [@relative-ci/agent](https://github.com/relative-ci/agent) from 4.1.10 to 4.2.9.
- [Release notes](https://github.com/relative-ci/agent/releases)
- [Commits](https://github.com/relative-ci/agent/compare/v4.1.10...v4.2.9)

---
updated-dependencies:
- dependency-name: "@relative-ci/agent"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-15 14:42:09 -07:00
dependabot[bot] 4ced6c3b7f chore(deps): bump mailparser from 3.6.7 to 3.7.1 (#7251)
Bumps [mailparser](https://github.com/nodemailer/mailparser) from 3.6.7 to 3.7.1.
- [Release notes](https://github.com/nodemailer/mailparser/releases)
- [Changelog](https://github.com/nodemailer/mailparser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/mailparser/compare/v3.6.7...v3.7.1)

---
updated-dependencies:
- dependency-name: mailparser
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-15 14:41:09 -07:00
dependabot[bot] 06a40e8b7c chore(deps): bump prosemirror-view from 1.33.7 to 1.33.8 (#7254)
Bumps [prosemirror-view](https://github.com/prosemirror/prosemirror-view) from 1.33.7 to 1.33.8.
- [Changelog](https://github.com/ProseMirror/prosemirror-view/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-view/compare/1.33.7...1.33.8)

---
updated-dependencies:
- dependency-name: prosemirror-view
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-15 14:40:12 -07:00
Tom Moor 6a6c069e4e chore: Bump prosemirror-model 2024-07-14 15:50:13 -04:00
Tom Moor cf3ef2a839 fix: parseAttachmentIds error when node data contains empty href/src
closes #7230
2024-07-14 11:00:20 -04:00
Tom Moor a49f89bda6 Remove 'You saved' language 2024-07-14 09:58:12 -04:00
Tom Moor 82b2defac1 Cast node attrs to string 2024-07-14 09:33:29 -04:00
Vivian Erbenich c05a8cf73a Add AZURE_TENANT_ID enviroment variable for specific azure tenant. (#7028)
* Adds support for specific azure tenant via .env variables.

* remove AZURE_DISPLAY_NAME again

* lint

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-07-12 22:02:40 -04:00
Hemachandar 7f5e2cacd8 feat: show frequent languages in code block menu (#7222) 2024-07-12 18:51:48 -07:00
Tom Moor d8e97e0c1f Add POST handling for oidc callback (#7232) 2024-07-12 18:36:07 -07:00
Tom Moor 74bcf152f0 fix: Incorrect icon color on documents pinned to home cards 2024-07-12 08:53:23 -04:00
Tom Moor 57431720b2 Add document icons to editor search results 2024-07-12 08:48:45 -04:00
Tom Moor b8c6cc603b tsc 2024-07-11 08:09:26 -04:00
Tom Moor 71c48bcd47 More possible fixes for #7161 2024-07-11 08:01:40 -04:00
Tom Moor 4ad1148aa7 Make secondary login options non-primary. https://x.com/brian_lovin/status/1810895651217232135 2024-07-10 22:54:13 -04:00
Tom Moor 67c0335099 fix: Icon missing in ghost when dragging collection 2024-07-10 22:45:10 -04:00
Tom Moor c600148f4b fix: Inconsistencies with title icon positioning (#7224) 2024-07-10 19:05:05 -07:00
Tom Moor 299e49625b fix: Icon missing in ghost when dragging sidebar item 2024-07-10 22:04:37 -04:00
Translate-O-Tron 82d84e4859 New Crowdin updates (#7154) 2024-07-10 17:41:47 -07:00
Tom Moor e7d3dac36c fix: Outdated updatedBy returned in document mutations (#7223)
* fix: Outdated updatedBy information returned in document mutations

* tsc

* Update delete mutations to match
2024-07-10 17:41:30 -07:00
Tom Moor 0d0932a6f6 chore: Remove usage of deprecated parameter on client 2024-07-10 19:46:50 -04:00
Tom Moor 37e68413f0 fix: Groups do not appear in collection share UI unless previously loaded 2024-07-10 15:10:11 -04:00
Tom Moor 01bbc48c01 fix: Incorrect dialog padding 2024-07-10 08:27:43 -04:00
Tom Moor f02bbc3942 fix: Missing icons in document explorer, incorrect active styling 2024-07-10 07:57:39 -04:00
Tom Moor 9419e65837 Add OS icons to library, closes #6469 2024-07-08 22:20:14 -04:00
Tom Moor 28cfeba99a fix: Positioning of archived / trashed notices 2024-07-08 21:49:32 -04:00
Tom Moor 2c138687c7 fix: Increase contrast of search highlights in dark mode 2024-07-08 21:28:49 -04:00
Tom Moor f38c948573 Enable TOC by default on publicly shared docs 2024-07-08 21:26:45 -04:00
Tom Moor 1f5ccc3055 Add error state for broken images (#7200) 2024-07-08 17:55:17 -07:00
Max Mykhailenko 58008d84c4 Add support for TLDR viewer links (#7205) 2024-07-08 17:55:06 -07:00
dependabot[bot] ea678e40cc chore(deps): bump react-medium-image-zoom from 5.2.5 to 5.2.7 (#7209)
Bumps [react-medium-image-zoom](https://github.com/rpearce/react-medium-image-zoom) from 5.2.5 to 5.2.7.
- [Release notes](https://github.com/rpearce/react-medium-image-zoom/releases)
- [Changelog](https://github.com/rpearce/react-medium-image-zoom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rpearce/react-medium-image-zoom/compare/v5.2.5...v5.2.7)

---
updated-dependencies:
- dependency-name: react-medium-image-zoom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 17:54:43 -07:00
dependabot[bot] 53caddd930 chore(deps): bump prosemirror-inputrules from 1.3.0 to 1.4.0 (#7207)
Bumps [prosemirror-inputrules](https://github.com/prosemirror/prosemirror-inputrules) from 1.3.0 to 1.4.0.
- [Changelog](https://github.com/ProseMirror/prosemirror-inputrules/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-inputrules/compare/1.3.0...1.4.0)

---
updated-dependencies:
- dependency-name: prosemirror-inputrules
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 17:54:10 -07:00
dependabot[bot] 6ab182433b chore(deps): bump @fortawesome/react-fontawesome from 0.2.0 to 0.2.2 (#7206)
Bumps [@fortawesome/react-fontawesome](https://github.com/FortAwesome/react-fontawesome) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/FortAwesome/react-fontawesome/releases)
- [Changelog](https://github.com/FortAwesome/react-fontawesome/blob/0.2.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/react-fontawesome/compare/0.2.0...0.2.2)

---
updated-dependencies:
- dependency-name: "@fortawesome/react-fontawesome"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 17:53:46 -07:00
dependabot[bot] f01a45a80a chore(deps): bump string-replace-to-array from 2.1.0 to 2.1.1 (#7208)
Bumps [string-replace-to-array](https://github.com/appfigures/string-replace-to-array) from 2.1.0 to 2.1.1.
- [Changelog](https://github.com/appfigures/string-replace-to-array/blob/master/changelog.md)
- [Commits](https://github.com/appfigures/string-replace-to-array/compare/v2.1.0...v2.1.1)

---
updated-dependencies:
- dependency-name: string-replace-to-array
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 17:53:29 -07:00
dependabot[bot] 44366e1462 chore(deps): bump mammoth from 1.7.2 to 1.8.0 (#7210)
Bumps [mammoth](https://github.com/mwilliamson/mammoth.js) from 1.7.2 to 1.8.0.
- [Release notes](https://github.com/mwilliamson/mammoth.js/releases)
- [Changelog](https://github.com/mwilliamson/mammoth.js/blob/master/NEWS)
- [Commits](https://github.com/mwilliamson/mammoth.js/compare/1.7.2...1.8.0)

---
updated-dependencies:
- dependency-name: mammoth
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 17:53:11 -07:00
Hemachandar b3a24e4917 fix: TOC active indicator for last heading (#7204) 2024-07-08 17:51:26 -07:00
Tom Moor 43cf33fc0a fix: Light icons are not responsive to dark theme 2024-07-07 21:06:04 -04:00
Tom Moor 07b6441655 fix: Retain space for hidden TOC to prevent horizontal movement 2024-07-07 20:21:51 -04:00
Tom Moor 49198aafe9 Hide document TOC when empty 2024-07-07 20:15:26 -04:00
Tom Moor ddd103542a fix: Focusing shared document title on mobile causes it to move 2024-07-07 19:56:31 -04:00
Tom Moor 4654dfb658 test: Fix incorrect userProvisioner test 2024-07-07 11:00:10 -04:00
Tom Moor bdcde1aa53 centralize email parsing logic 2024-07-07 10:54:19 -04:00
Tom Moor c484d1defe fix: Error when accessing search from share logged in, 0067d1a58d 2024-07-06 11:49:51 -04:00
Tom Moor 1efd3b6f96 fix: Do not prompt for app install on public shares, closes #7198 2024-07-06 11:10:58 -04:00
Tom Moor e07be1ee5e chore: Remove long deprecated filter options 2024-07-06 10:53:00 -04:00
Tom Moor 0067d1a58d fix: Document data from documents.search with shareId does not include signed asset urls
closes #7196
2024-07-06 10:51:27 -04:00
Tom Moor 17451c180a fix: Header search input is on the wrong side on Drafts page 2024-07-03 21:14:56 -04:00
Tom Moor 4e989e5c44 fix: Resizing sidebars can also select text 2024-07-03 20:37:56 -04:00
Tom Moor 335957d914 fix: Alignment of keyboard help button 2024-07-03 20:31:51 -04:00
Tom Moor 1711d17e25 fix: newMentionIds no longer always in event data 2024-07-03 17:58:15 -04:00
Apoorv Mishra de90f879f1 Prevent modal top from shrinking (#7167)
* fix: prevent modal top from shrinking

* fix: scroll and max height for share modal and popover

* fix: review
2024-07-03 09:11:00 +05:30
Tom Moor 303125b682 chore: Upgrade nodemon 2024-07-02 21:50:32 -04:00
Tom Moor f33026f7b3 chore: Upgrade socket.io deps 2024-07-02 21:47:01 -04:00
Tom Moor 06b5efd18a chore: Update babel, aws-sdk deps 2024-07-02 21:38:21 -04:00
Tom Moor c8e67b969d fix: Gap between icon picker and title 2024-07-02 20:28:37 -04:00
Tom Moor b84851a4c3 tsc 2024-07-02 19:41:48 -04:00
Tom Moor c6408f7b3f fix: CJK content results in long context strings in search results
closes #7183
2024-07-02 19:34:49 -04:00
Tom Moor 18f729b970 Make selected icon in color picker 2px weight to match others 2024-07-02 18:31:41 -04:00
Tom Moor 2f9a7f9a21 Remove random color on document icons, closes #7181 2024-07-02 18:30:34 -04:00
Tom Moor c5b94e50df fix: RangeError when resolving or removing comment across marks, closes #7182 2024-07-02 18:24:23 -04:00
Tom Moor 8a8dad15ef fix: newMentionIds no longer always in event data, closes #7186 2024-07-02 18:03:22 -04:00
dependabot[bot] a8d4a5b587 chore(deps): bump koa from 2.15.0 to 2.15.3 (#7134)
Bumps [koa](https://github.com/koajs/koa) from 2.15.0 to 2.15.3.
- [Changelog](https://github.com/koajs/koa/blob/2.15.3/History.md)
- [Commits](https://github.com/koajs/koa/compare/2.15.0...2.15.3)

---
updated-dependencies:
- dependency-name: koa
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-02 14:58:03 -07:00
Liam Robinson a67c35257e fixed wrong discord callback url (#7184) 2024-07-02 13:35:55 -07:00
Tom Moor f9dadf5548 fix: Comment resolution control visible to non-editors 2024-07-02 07:52:21 -04:00
Tom Moor 117c4f5009 feat: Comment resolving (#7115) 2024-07-02 03:55:16 -07:00
dependabot[bot] f34557337d chore(deps): bump @octokit/auth-app from 6.0.4 to 6.1.1 (#7173)
Bumps [@octokit/auth-app](https://github.com/octokit/auth-app.js) from 6.0.4 to 6.1.1.
- [Release notes](https://github.com/octokit/auth-app.js/releases)
- [Commits](https://github.com/octokit/auth-app.js/compare/v6.0.4...v6.1.1)

---
updated-dependencies:
- dependency-name: "@octokit/auth-app"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 12:22:27 -07:00
dependabot[bot] 9b25e623b4 chore(deps-dev): bump @types/randomstring from 1.1.11 to 1.3.0 (#7172)
Bumps [@types/randomstring](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/randomstring) from 1.1.11 to 1.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/randomstring)

---
updated-dependencies:
- dependency-name: "@types/randomstring"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 12:21:28 -07:00
dependabot[bot] fe41824ef2 chore(deps): bump sequelize-cli from 6.6.1 to 6.6.2 (#7174)
Bumps [sequelize-cli](https://github.com/sequelize/cli) from 6.6.1 to 6.6.2.
- [Release notes](https://github.com/sequelize/cli/releases)
- [Changelog](https://github.com/sequelize/cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sequelize/cli/compare/v6.6.1...v6.6.2)

---
updated-dependencies:
- dependency-name: sequelize-cli
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 12:21:19 -07:00
dependabot[bot] e9755faf9a chore(deps): bump @sentry/react from 7.99.0 to 7.118.0 (#7175)
Bumps [@sentry/react](https://github.com/getsentry/sentry-javascript) from 7.99.0 to 7.118.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/7.118.0/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.99.0...7.118.0)

---
updated-dependencies:
- dependency-name: "@sentry/react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 12:21:07 -07:00
Tom Moor 9dcb04b58a fix: Empty space where logo should be on shared docs with no branding
fix: Not using emoji fallback on shared links
2024-07-01 11:04:00 -04:00
Tom Moor d8e571d82d fix: Flickering of resize cursor on sidebar when dragging 2024-07-01 10:49:00 -04:00
Tom Moor 3f4027c6fa fix: Event listener memory leak 2024-07-01 10:42:15 -04:00
Apoorv Mishra e507f09ff9 fix: collection permission check (#7171) 2024-07-01 19:40:35 +05:30
Apoorv Mishra 63ddc31710 Disallow empty comments and comments with only whitespaces (#7156)
* fix: disallow empty comments

* fix: avoid full traversal to validate comment

* fix: text

* fix:review

* fix: review
2024-06-30 11:38:43 +05:30
Tom Moor 5aa5ba0aa1 fix: Possible fix for #7161 2024-06-29 14:47:26 -07:00
Tom Moor ed496bdf60 fix: Flash of mispositioned document loading placeholder 2024-06-29 10:12:06 -07:00
Tom Moor 7201bdb9d8 fix: Flickering suggestion menu selection in Safari 2024-06-28 13:56:37 -07:00
Tom Moor 53e3245b15 fix: Fallback to emoji attribute in document structure 2024-06-26 11:44:17 -04:00
Tom Moor 2c666ddde2 fix: Duplicated documents use text rather than content 2024-06-26 09:20:16 -04:00
Tom Moor 6bb2953e8d 0.78.0-0 2024-06-25 22:21:32 -04:00
Tom Moor 6a1a3eee91 fix: Crash rendering some document hover previews 2024-06-25 22:20:33 -04:00
Tom Moor d03c7b33d3 Cast values in error response, related outline/openapi#5 2024-06-25 21:33:51 -04:00
Translate-O-Tron 355bc33f7c New Crowdin updates (#7128) 2024-06-25 18:19:03 -07:00
Tom Moor bf2378ec81 fix: Iframely is not correctly disabled with no API_KEY in env
closes #7147
2024-06-25 21:10:21 -04:00
Tom Moor 5c999f5327 Add Swedish translations (#7146) 2024-06-25 05:28:42 -07:00
Tom Moor 29a653aaeb fix: Admins cannot query permissions on private collections (#7145)
* fix: Admins have permission to see existence of all collections (in settings)

* fix: Current user filtered from suggestions. As an admin managing other collections this is limiting

* test
2024-06-25 05:28:32 -07:00
Jack Woodgate beabd32e6a fix: Improve SmartText fraction regex pattern (#7141)
Modify fraction regex statements to not match if directly preceded by a character
2024-06-25 05:11:13 -07:00
Tom Moor 77d6797d85 fix: Error choosing 'No access' as bulk import permission 2024-06-24 21:24:43 -04:00
Tom Moor fbd8f5981b fix: Consistently default letter icon content to ? 2024-06-24 21:20:45 -04:00
Tom Moor 8336207c23 fix: Document title steals focus on mount 2024-06-24 21:20:02 -04:00
Tom Moor 3054f34a90 fix: 'Search in collection' appearing in collection menu user does not have access to read documents within 2024-06-24 18:13:01 -04:00
Tom Moor 07a805696d fix: Templatize spuriously appearing in collection menu 2024-06-24 18:08:30 -04:00
dependabot[bot] 142493ddcc chore(deps): bump vite from 5.2.11 to 5.3.1 (#7132)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.2.11 to 5.3.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.3.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 14:32:24 -07:00
dependabot[bot] bd18b33b9d chore(deps): bump class-validator from 0.14.0 to 0.14.1 (#7131)
Bumps [class-validator](https://github.com/typestack/class-validator) from 0.14.0 to 0.14.1.
- [Release notes](https://github.com/typestack/class-validator/releases)
- [Changelog](https://github.com/typestack/class-validator/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/typestack/class-validator/compare/v0.14.0...v0.14.1)

---
updated-dependencies:
- dependency-name: class-validator
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 14:32:05 -07:00
dependabot[bot] 03373804fa chore(deps-dev): bump eslint-plugin-react from 7.34.1 to 7.34.3 (#7133)
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.34.1 to 7.34.3.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.34.1...v7.34.3)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 14:31:48 -07:00
dependabot[bot] daba308440 chore(deps): bump nodemailer and @types/nodemailer (#7135)
Bumps [nodemailer](https://github.com/nodemailer/nodemailer) and [@types/nodemailer](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/nodemailer). These dependencies needed to be updated together.

Updates `nodemailer` from 6.9.9 to 6.9.14
- [Release notes](https://github.com/nodemailer/nodemailer/releases)
- [Changelog](https://github.com/nodemailer/nodemailer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodemailer/nodemailer/compare/v6.9.9...v6.9.14)

Updates `@types/nodemailer` from 6.4.14 to 6.4.15
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/nodemailer)

---
updated-dependencies:
- dependency-name: nodemailer
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: "@types/nodemailer"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 14:31:36 -07:00
Tom Moor 1451f70b9e Changes plugin interface from 'roles' to 'enabled' method for more flexibility 2024-06-24 08:33:48 -04:00
Translate-O-Tron 6bb8a3d935 New Crowdin updates (#7079) 2024-06-23 14:26:19 -07:00
Tom Moor 95c768f444 Allow direct editing of collection icon (#7120)
* Allow direct editing of collection icon

* feedback
2024-06-23 14:26:00 -07:00
Tom Moor 2cad16d6b3 fix: Disable hover background on non-interactive share list items 2024-06-23 17:25:36 -04:00
Hemachandar 36a2a4709c fix: allow user to remove document icon (#7124) 2024-06-23 15:47:25 -04:00
Hemachandar 6fd3a0fa8a feat: Unified icon picker (#7038) 2024-06-23 06:31:18 -07:00
Tom Moor 56d90e6bc3 Add HEALTHCHECK into docker image (#7085)
* Add wget into docker image

* Add healthcheck
2024-06-22 07:05:55 -07:00
Tom Moor eaab97dcbf fix: Unable to scroll until multiple comments (#7112)
* fix: Unable to scroll in comments
fix: Missing highlighted text on first comment while composing

* docs
2024-06-22 07:05:23 -07:00
Tom Moor d8f14377f8 fix: Scrollwheel can cause image zoom to get stuck, closes #7083 2024-06-21 23:39:25 -04:00
Apoorv Mishra 0f1f0e82c2 Enable keyboard navigation in member invite list (#7102)
* feat: keyboard nav in share popover

* fix: memoize
2024-06-21 17:35:05 -07:00
Tom Moor 5ddc36555d fix: Remove breaking requirement to not pass collectionId with parentDocumentId.
This was regressed as part of 95b9453269 and unfortunately is a breaking change for API consumers
2024-06-21 20:34:31 -04:00
Tom Moor f17ce9d50b fix: collectionId and parentDocumentId now mutually exclusive in payload
closes #7110
2024-06-21 19:38:05 -04:00
Tom Moor 9e5d5c0347 fix: Incorrect policies returned from documents.update (#7111)
* fix: Incorrect policies returned from documents.update

* Regression test
2024-06-21 16:37:39 -07:00
Hemachandar 4897f001e4 Add icon column to document (#7066)
* Add icon column to document

* Backfill columns

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-06-21 06:26:20 -07:00
Hemachandar b6d178943a fix: Include drafts when loading templates (#7100)
* fix: Include drafts when loading templates

* fetch drafts when mounting templates settings
2024-06-21 04:36:22 -07:00
Hemachandar 1bf9012992 feat: Add lastUsedAt to API keys (#7082)
* feat: Add lastUsedAt to API keys

* rename column to lastActiveAt

* switch order
2024-06-20 06:18:35 -07:00
Tom Moor a19fb25bea fix: Open permissions for guests that have collection manage permission (#7075)
* fix: Opens up permissions for guests that have collection manage permission

* tsc

* tests
2024-06-20 06:18:18 -07:00
Brian Krausz 95b9453269 feat: docs managers can action docs & create subdocs (#7077)
* feat: docs managers can action docs & create subdocs

* tests

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-06-19 19:22:33 -07:00
Hemachandar 2333602f25 fix: Allow user to remove team logo (#7095) 2024-06-19 17:11:54 -07:00
Tom Moor a825925a31 fix: Layout issue with full-width documents and left TOC 2024-06-19 09:04:01 -04:00
Tom Moor 711b8acebc Add Norweigan translations (#7086) 2024-06-19 05:19:16 -07:00
Tom Moor d7ee63217b fix: Improve translation strings for api key management 2024-06-18 22:32:04 -04:00
Tom Moor 6dae1c2a5c Tweak language on API key list 2024-06-18 21:51:32 -04:00
Hemachandar 3af9861c4a feat: add API key expiry options (#7064)
* feat: add API key expiry options

* review
2024-06-18 18:34:45 -07:00
Hemachandar c04bedef4c fix: remove attachment signing for document export (#7081) 2024-06-18 18:34:05 -07:00
Translate-O-Tron aad709eca4 New Crowdin updates (#7073) 2024-06-17 18:48:45 -07:00
dependabot[bot] 044f5256db chore(deps): bump @sentry/node from 7.99.0 to 7.117.0 (#7069)
Bumps [@sentry/node](https://github.com/getsentry/sentry-javascript) from 7.99.0 to 7.117.0.
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/7.117.0/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/7.99.0...7.117.0)

---
updated-dependencies:
- dependency-name: "@sentry/node"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 14:03:08 -07:00
dependabot[bot] 5a6bb85f65 chore(deps-dev): bump @types/readable-stream from 4.0.12 to 4.0.14 (#7067)
Bumps [@types/readable-stream](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/readable-stream) from 4.0.12 to 4.0.14.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/readable-stream)

---
updated-dependencies:
- dependency-name: "@types/readable-stream"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 14:02:56 -07:00
dependabot[bot] ef45788a0b chore(deps): bump ws from 7.5.9 to 7.5.10 (#7068)
Bumps [ws](https://github.com/websockets/ws) from 7.5.9 to 7.5.10.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.5.9...7.5.10)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 14:02:46 -07:00
dependabot[bot] 4b4e593e83 chore(deps): bump umzug from 3.2.1 to 3.8.1 (#7071)
Bumps [umzug](https://github.com/sequelize/umzug) from 3.2.1 to 3.8.1.
- [Release notes](https://github.com/sequelize/umzug/releases)
- [Changelog](https://github.com/sequelize/umzug/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sequelize/umzug/compare/v3.2.1...v3.8.1)

---
updated-dependencies:
- dependency-name: umzug
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 14:02:30 -07:00
Translate-O-Tron 15a9bd225f New Crowdin updates (#7019) 2024-06-17 04:25:14 -07:00
Michael Fowler 77579bb4f1 fix: Use the default credential strategy in S3Client construction (#7061)
By omitting this option, we fall back to the hierarchy used by S3Client by
default.  When defined, the provider chain will use the values of
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY (and AWS_SESSION_TOKEN); in their
absence, the provider chain can retrieve credentials from a range of other
sources, including e.g. ECS credentials.

Although there are no longer any application reads from `env.AWS_ACCESS_KEY_ID`
and `env.AWS_SECRET_ACCESS_KEY`, they continue to serve a useful documentary
role.
2024-06-17 03:15:15 -07:00
Tom Moor 92301791f6 fix: Styling of disabled accent buttons 2024-06-16 20:49:46 -04:00
Tom Moor 9b542c451b fix: Unreadable tertiary text on InputSelect 2024-06-16 20:41:51 -04:00
Hemachandar 3edaf4f8ea feat: TOC position for publicly shared docs (#7057)
* feat: TOC position for publicly shared docs

* remove preferences object

* comment

* fix: Allow sidebar position preference without public branding switch

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-06-16 17:26:29 -04:00
Tom Moor 1290aecbc9 Add after option to setting plugin (#7056) 2024-06-16 09:43:32 -07:00
Hemachandar 05c1bee412 feat: allow user to set TOC display preference (#6943)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-06-16 09:21:08 -07:00
Tom Moor 3d0160463c chore: Refactor client plugin management (#7053)
* Update clientside plugin management to work as server

* docs

* tsc

* Rebase main
2024-06-16 08:11:26 -07:00
Sebastian Pietschner a9f1086422 Enhanced Discord Support (#7005)
* Add Discord Provider Prototype

* Add Discord Logo

* Add Plugin to Plugin Manager

* fixed discord auth support and added icon

* add csv role verification

* grab discord server icon and test server id and roles

* subdomain derived from server name

* use discord server specific nickname if available

* Cleanup and comment

* move discord api types to dev deps

* cleanup of server vs default params

* remove commented out lines

* revert envv.development

* revert in vscode

* update yarn lock

* add gif support for discord server icon

* add comment with docs link

* add env section for discord

* fix errors and clarify env

* add new cannot use without

* fix suggestions
2024-06-16 07:04:25 -07:00
Tom Moor 379d2cb788 fix: Attributes lost creating template on server (#7049) 2024-06-15 19:06:37 -07:00
Tom Moor eb1882eb96 fix: Signed file urls not returning inline content disposition 2024-06-15 12:29:58 -04:00
Tom Moor 6318714aee fix: Escape does not close CMD+K when viewing a document or collection 2024-06-14 22:56:39 -04:00
Tom Moor 9415a35795 chore: Add eslint rule to prevent app imports in shared (see: bf130f9915) 2024-06-14 22:22:55 -04:00
Tom Moor da9ea9f82c fix: Tweak top padding on TOC to always align with metadata 2024-06-14 21:30:52 -04:00
Tom Moor e733fd27e4 0.77.1 2024-06-14 20:32:13 -04:00
Tom Moor 63cfa6e25a fix: Restore field in document webhooks for backwards compat (#7044)
closes #7042
2024-06-14 16:36:54 -07:00
Tom Moor f8a9c18650 fix: Scroll does not reset when navigating shared docs on mobile (#7037)
closes #6968
2024-06-14 16:36:36 -07:00
Tom Moor f35676f347 Switch from Alpine -> Debian-slim (#7040)
* Switch from Alpine -> Debian-slim

* Drop arm/v6
2024-06-14 12:51:38 -07:00
Tom Moor bf130f9915 fix: EventBoundary import 2024-06-14 14:55:02 -04:00
Tom Moor dfe36fcbf5 fix: Add a plugin to fix the last column in a table (#7036) 2024-06-14 05:53:32 -07:00
Tom Moor e1c44ba1a8 fix: Exiting lightbox unfocuses image causing rerender part-way through transition, closes #7034 2024-06-13 20:57:50 -04:00
Tom Moor e69c0e62fa Merge branch 'main' of github.com:outline/outline 2024-06-13 18:19:46 -04:00
Tom Moor fd17364ebf 0.77.0 2024-06-13 15:31:33 -04:00
Apoorv Mishra 23c8adc5d1 Replace reakit/Composite with react-roving-tabindex (#6985)
* fix: replace reakit composite with react-roving-tabindex

* fix: touch points

* fix: focus stuck at first list item

* fix: document history navigation

* fix: remove ununsed ListItem components

* fix: keyboard navigation in recent search list

* fix: updated lib
2024-06-13 18:45:44 +05:30
Tom Moor 20b1766e8d Add link to guide in welcome email 2024-06-12 22:33:00 -04:00
Tom Moor 076d564aa3 fix: Sidebar hidden when viewing shared document logged-in 2024-06-12 22:30:39 -04:00
Tom Moor 5b866a7451 fix: isInternalUrl helper returns true for other cloud-hosted workspaces 2024-06-12 21:50:42 -04:00
Tom Moor 4ef3615516 fix: Reduce flashing of loaders in sidebar on first load 2024-06-12 21:30:10 -04:00
Brian Krausz b907d1887a [docs] Remove dead link for Node Security Project (#7022) 2024-06-12 18:13:09 -07:00
Tom Moor 8a4555f565 Allow using / anywhere on a line or table (#7026) 2024-06-12 05:50:54 -07:00
Tom Moor df3cd22aee Matomo integration (#7009) 2024-06-12 05:03:38 -07:00
dependabot[bot] 0bf66cc560 chore(deps): bump braces from 3.0.2 to 3.0.3 (#7018)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-11 20:09:10 -07:00
Tom Moor b769da2626 fix: Case where email platform will spend the email signin link (#7023) 2024-06-11 20:08:25 -07:00
Tom Moor 7bf5c4e533 Add manage permission to documents (#7003) 2024-06-10 17:38:23 -07:00
dependabot[bot] 1ad7c7409a chore(deps): bump @aws-sdk/s3-request-presigner from 3.577.0 to 3.592.0 (#7015)
Bumps [@aws-sdk/s3-request-presigner](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/s3-request-presigner) from 3.577.0 to 3.592.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/s3-request-presigner/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.592.0/packages/s3-request-presigner)

---
updated-dependencies:
- dependency-name: "@aws-sdk/s3-request-presigner"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-10 17:38:04 -07:00
Translate-O-Tron 428908b2df New Crowdin updates (#6915) 2024-06-10 17:37:23 -07:00
dependabot[bot] 1df1b0c110 chore(deps): bump turndown from 7.1.3 to 7.2.0 (#7013)
Bumps [turndown](https://github.com/mixmark-io/turndown) from 7.1.3 to 7.2.0.
- [Release notes](https://github.com/mixmark-io/turndown/releases)
- [Commits](https://github.com/mixmark-io/turndown/compare/v7.1.3...v7.2.0)

---
updated-dependencies:
- dependency-name: turndown
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-10 17:37:03 -07:00
dependabot[bot] 9d95c673d1 chore(deps): bump prosemirror-model from 1.21.0 to 1.21.1 (#7014)
Bumps [prosemirror-model](https://github.com/prosemirror/prosemirror-model) from 1.21.0 to 1.21.1.
- [Changelog](https://github.com/ProseMirror/prosemirror-model/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-model/compare/1.21.0...1.21.1)

---
updated-dependencies:
- dependency-name: prosemirror-model
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-10 17:35:06 -07:00
dependabot[bot] 203cd3c2a3 chore(deps-dev): bump terser from 5.19.2 to 5.31.1 (#7016)
Bumps [terser](https://github.com/terser/terser) from 5.19.2 to 5.31.1.
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/compare/v5.19.2...v5.31.1)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-10 17:34:48 -07:00
dependabot[bot] f663c5a7ef chore(deps-dev): bump @types/node from 20.10.0 to 20.14.2 (#7017)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.10.0 to 20.14.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-10 17:34:34 -07:00
Tom Moor be0a0f4e40 fix: Unexpected behavior when changing color of existing highlight 2024-06-09 21:19:37 -04:00
Tom Moor f439293a7b fix: Image placeholders incorrectly sized for uploading retina images 2024-06-09 14:28:54 -04:00
Tom Moor 2e466aefc3 fix: Missing delay before mounting loading skeleton 2024-06-09 14:23:48 -04:00
Tom Moor ed59b3e350 Add more highlighter color choices (#7012)
* Add more highlighter color choices, closes #7011

* docs
2024-06-09 10:54:31 -07:00
Tom Moor 808415b906 fix: Indent/outdent list controls, closes #6974 2024-06-08 21:51:52 -04:00
Tom Moor 2f495f0add chore: Extend use of Event.createFromContext (#7010) 2024-06-08 14:57:55 -07:00
Tom Moor 1bd37ad40b fix: Hide share button on templates 2024-06-08 13:59:57 -04:00
Tom Moor 562b03711f Add menu option to create template directly in collection 2024-06-08 13:42:59 -04:00
Tom Moor 30a5c8ea8b feat: Add ability to remove team logo/profile picture 2024-06-08 13:17:42 -04:00
Tom Moor c02f7c9c85 Remove gist.github.com, gitlab.com from default CSP (#7008) 2024-06-08 07:54:55 -07:00
Tom Moor 946cbce06e fix: Share filtering does not pass query to server, closes #7006 2024-06-07 21:36:27 -04:00
Tom Moor 8762adacbb fix: Gap after input prefix in web share settings 2024-06-06 23:38:18 -04:00
Tom Moor 2002c20bd3 fix: Cannot remove groups from collection 2024-06-06 21:47:21 -04:00
Tom Moor 1b60d7c946 fix: Remove delay on save after changing document emoji, closes #6999 2024-06-05 22:55:19 -04:00
Tom Moor 20d71391bb fix: Unneccessary height animation on share popover when reopening 2024-06-05 09:26:22 -04:00
Tom Moor 7bdafff235 Add ApiKeyCleanupProcessor 2024-06-05 08:30:56 -04:00
Tom Moor 025ee63f0b Add MembersCanCreateApiKey team preference 2024-06-05 08:30:30 -04:00
Tom Moor cf16d25a67 chore: Tidy API key settings page 2024-06-05 07:13:35 -04:00
Tom Moor 593f7a79b8 Remove ability to create additional API keys with an existing API key 2024-06-05 06:53:07 -04:00
Tom Moor c9d5ff7ca5 fix: Remove trust of state.host in auth error redirect 2024-06-05 06:45:23 -04:00
Tom Moor 1d97a6c10b chore: Remove old collection permissions UI (#6995) 2024-06-05 03:33:39 -07:00
Tom Moor 7eb6dcf00b fix: Prevent email login token reuse 2024-06-04 23:38:00 -04:00
Tom Moor 70bc8f1a5a fix: Shift-Enter in code block in table should behave correctly
closes #6994
2024-06-04 22:20:37 -04:00
Tom Moor 7a32271992 fix: Allow delete table row and column with mod+backspace 2024-06-04 21:59:22 -04:00
Tom Moor dd4c8c5546 fix: Add explicit error for missing auth token 2024-06-04 21:36:26 -04:00
dependabot[bot] 42f9971368 chore(deps): bump passport-oauth2 and @types/passport-oauth2 (#6988)
Bumps [passport-oauth2](https://github.com/jaredhanson/passport-oauth2) and [@types/passport-oauth2](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/passport-oauth2). These dependencies needed to be updated together.

Updates `passport-oauth2` from 1.7.0 to 1.8.0
- [Changelog](https://github.com/jaredhanson/passport-oauth2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jaredhanson/passport-oauth2/compare/v1.7.0...v1.8.0)

Updates `@types/passport-oauth2` from 1.4.15 to 1.4.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/passport-oauth2)

---
updated-dependencies:
- dependency-name: passport-oauth2
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: "@types/passport-oauth2"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-04 06:49:09 -07:00
Tom Moor e7602f8f1b fix: caption positioning 2024-06-03 21:42:50 -04:00
dependabot[bot] 20e275c0b9 chore(deps): bump octokit from 3.1.2 to 3.2.1 (#6989)
Bumps [octokit](https://github.com/octokit/octokit.js) from 3.1.2 to 3.2.1.
- [Release notes](https://github.com/octokit/octokit.js/releases)
- [Commits](https://github.com/octokit/octokit.js/compare/v3.1.2...v3.2.1)

---
updated-dependencies:
- dependency-name: octokit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 18:34:38 -07:00
Tom Moor 723c5c13f4 fix: Collapsed sidebar closes on far left hover in Arc/Edge redesign
closes #6982
2024-06-03 21:30:10 -04:00
Tom Moor c6423c47b3 fix: try/catch in correct location for regex find and replace
closes #6983
2024-06-03 20:54:07 -04:00
Tom Moor cfc7ae6d04 feat: Add support for Figam boards, add support for pasting Figma embed code
closes #6986
2024-06-03 20:40:20 -04:00
Tom Moor 23606dad1d Move image zooming back to unvendorized lib (#6980)
* Move image zooming back to unvendorized lib

* refactor

* perf: Avoid mounting zoom dialog until interacted

* Add captions to lightbox

* lightbox
2024-06-03 17:26:25 -07:00
dependabot[bot] 62ebba1c32 chore(deps): bump ioredis from 5.3.2 to 5.4.1 (#6987)
Bumps [ioredis](https://github.com/luin/ioredis) from 5.3.2 to 5.4.1.
- [Release notes](https://github.com/luin/ioredis/releases)
- [Changelog](https://github.com/redis/ioredis/blob/main/CHANGELOG.md)
- [Commits](https://github.com/luin/ioredis/compare/v5.3.2...v5.4.1)

---
updated-dependencies:
- dependency-name: ioredis
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 17:26:14 -07:00
dependabot[bot] 884a51e98b chore(deps): bump tmp from 0.2.1 to 0.2.3 (#6991)
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.1 to 0.2.3.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.1...v0.2.3)

---
updated-dependencies:
- dependency-name: tmp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 17:25:54 -07:00
dependabot[bot] 553057d4f9 chore(deps): bump @aws-sdk/s3-presigned-post from 3.577.0 to 3.588.0 (#6990)
Bumps [@aws-sdk/s3-presigned-post](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/packages/s3-presigned-post) from 3.577.0 to 3.588.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/packages/s3-presigned-post/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.588.0/packages/s3-presigned-post)

---
updated-dependencies:
- dependency-name: "@aws-sdk/s3-presigned-post"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-03 17:25:43 -07:00
Tom Moor 5ad6a63db8 tsc 2024-06-02 20:39:16 -04:00
Tom Moor 899a15afaf fix: Shift+click on table grip does not select rows/columns in between 2024-06-02 15:39:37 -04:00
Tom Moor 321f89effb chore: Bump prosemirror deps 2024-06-02 12:13:35 -04:00
Tom Moor 5bbe320c8c chore: Bump outline-icons 2024-06-02 12:09:11 -04:00
Tom Moor 5bd6c7b9c7 fix: Layout only changes not synced to content property 2024-06-02 10:29:26 -04:00
Tom Moor cb0f03d698 fix: Comment action not visible on mobile formatting toolbar 2024-06-01 16:39:32 -04:00
Tom Moor 938fd6ed2d feat: Enable block insertion in table cells from formatting menu
fix: Remove gutter controls from headers not at root
2024-06-01 12:21:33 -04:00
Tom Moor f2e9c0ab23 perf: Remove useComponentSize from image and video node render 2024-06-01 11:13:03 -04:00
Tom Moor 009458e435 fix: Finicky click target on share dialog permission action 2024-05-31 19:18:35 -04:00
Tom Moor 715b2b1b3f Hide collection header share button on mobile (no space, available in ...) 2024-05-31 18:21:55 -04:00
Tom Moor da19054555 Table improvements (#6958)
* Header toggling, resizable columns

* Allow all blocks in table cells, disable column resizing in read-only

* Fixed dynamic scroll shadows

* Refactor, scroll styling

* fix scrolling, tweaks

* fix: Table layout lost on sort

* fix: Caching of grip decorators

* refactor

* stash

* fix first render shadows

* stash

* First add column grip, styles

* Just add column/row click handlers left

* fix: isTableSelected for single cell table

* Refactor mousedown handlers

* fix: 'Add row before' command missing on first row

* fix overflow on rhs

* fix: Error clicking column grip when menu is open

* Hide table controls when printing

* Restore table header background

* fix: Header behavior when adding columns and rows at the edges

* Tweak header styling

* fix: Serialize and parsing of column attributes when copy/pasting
fix: Column width is lost when changing column alignment
2024-05-31 14:52:39 -07:00
Tom Moor 1db46f4aac fix: Change to 'No access' is not persisted in collection sharing dialog 2024-05-31 16:45:54 -04:00
François 9dda0da0e8 fix(app.json): add UTILS_SECRET env var (#6971) 2024-05-31 04:07:48 -07:00
Tom Moor 09782939d1 Update icon for drafts 2024-05-30 19:04:54 -04:00
Tom Moor 1f980050ca fix: Incorrect empty check for collection description results in large empty space below title 2024-05-30 18:57:40 -04:00
Tom Moor 6920f13ae4 fix: Missing space in new child document menu 2024-05-30 18:32:41 -04:00
Tom Moor a05beab3b6 Revert "Bump paragraph spacing"
This reverts commit 1c4817486b.
2024-05-30 18:28:15 -04:00
Tom Moor 3b9cbb08c8 fix: AggregateError thrown from ValidateSSOAccessTask 2024-05-30 00:02:37 -04:00
Tom Moor 30c43690c0 fix: Correctly replace urls with signed versions when display=link 2024-05-29 23:35:03 -04:00
Tom Moor 1ceb87515d fix: Default feature flag logic 2024-05-29 21:30:42 -04:00
Tom Moor 1c4817486b Bump paragraph spacing 2024-05-29 21:29:10 -04:00
Tom Moor 4b1b87abde fix: Cannot remove user from collection in beta sharing UI 2024-05-29 20:04:20 -04:00
Tom Moor 5e841f6b16 fix: Correctly replace urls with signed versions when fully qualified 2024-05-29 19:55:54 -04:00
dependabot[bot] 6fd7e755b0 chore(deps): bump semver and @types/semver (#6954)
Bumps [semver](https://github.com/npm/node-semver) and [@types/semver](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/semver). These dependencies needed to be updated together.

Updates `semver` from 7.6.0 to 7.6.2
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.6.0...v7.6.2)

Updates `@types/semver` from 7.5.6 to 7.5.8
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/semver)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: "@types/semver"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 15:50:33 -07:00
Tom Moor 14df74d776 fix: Broken external links on shared docs, closes #6962 2024-05-29 07:11:03 -04:00
Tom Moor d866d28c6e fix: Client side 'copy as markdown' does not work in doc with comments or mentions 2024-05-28 22:08:08 -04:00
Tom Moor 66c6c09e28 chore: Restrict import of passport package 2024-05-28 22:07:01 -04:00
Tom Moor 50bbe05334 Add range header support to files.get (#6950) 2024-05-28 05:12:25 -07:00
Tom Moor f58f309321 Simplify layout of full-width images 2024-05-27 14:12:38 -04:00
Tom Moor f9dac3cba1 fix: Missing key prop warning 2024-05-27 13:28:46 -04:00
Tom Moor 6f30972888 Merge branch 'main' of github.com:outline/outline 2024-05-27 13:27:47 -04:00
Tom Moor 24e4dd663b fix: Clarify functionality of personal Slack connection 2024-05-27 13:10:58 -04:00
dependabot[bot] 89ae3a5c6f chore(deps): bump prosemirror-view from 1.32.0 to 1.33.6 (#6956)
Bumps [prosemirror-view](https://github.com/prosemirror/prosemirror-view) from 1.32.0 to 1.33.6.
- [Changelog](https://github.com/ProseMirror/prosemirror-view/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-view/compare/1.32.0...1.33.6)

---
updated-dependencies:
- dependency-name: prosemirror-view
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 09:54:32 -07:00
dependabot[bot] 81e0ec0968 chore(deps): bump dd-trace from 3.51.0 to 3.58.0 (#6955)
Bumps [dd-trace](https://github.com/DataDog/dd-trace-js) from 3.51.0 to 3.58.0.
- [Release notes](https://github.com/DataDog/dd-trace-js/releases)
- [Commits](https://github.com/DataDog/dd-trace-js/compare/v3.51.0...v3.58.0)

---
updated-dependencies:
- dependency-name: dd-trace
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 09:54:11 -07:00
dependabot[bot] b5da5ce98c chore(deps): bump prosemirror-tables from 1.3.5 to 1.3.7 (#6953)
Bumps [prosemirror-tables](https://github.com/prosemirror/prosemirror-tables) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/prosemirror/prosemirror-tables/releases)
- [Commits](https://github.com/prosemirror/prosemirror-tables/compare/v1.3.5...v1.3.7)

---
updated-dependencies:
- dependency-name: prosemirror-tables
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 09:54:01 -07:00
Tom Moor 3d8daa1d8c fix: cmd+click on share links should redirect to shared url.
closes #6937
2024-05-27 11:38:38 -04:00
Tom Moor 1f097258f4 Enable new collection permissions UI 2024-05-27 09:34:53 -04:00
Tom Moor 7858133e71 DRY sharing interface 2024-05-27 09:34:53 -04:00
Pranav Joglekar 20642f4225 feat preview: add support for youtube clips (#6942) 2024-05-27 05:37:39 -07:00
Tom Moor e3837f6ad5 feat: Adds permission selector in document/collection invite flow (#6948)
* stash

* fix: Permissions cleared on collection addition
fix: Cannot remove user from document
Allow choosing permission in invite flow
2024-05-26 09:45:53 -07:00
RenderCoder 88eae87404 Fix: Adapt to Figma's New Link Structure for Embedding Design Previews (#6946)
Co-authored-by: RenderCoder <rendercoder@sot.app>
2024-05-26 08:05:08 -07:00
Tom Moor 3e083ce132 fix: Missing use of document.content 2024-05-26 10:24:21 -04:00
Tom Moor f103d73b48 Move collection description rendering to JSON (#6944)
* First pass, moving collection description rendering to JSON

* tsc

* docs

* refactor

* test
2024-05-25 15:17:19 -07:00
Tom Moor d51267b8bc JSON to client (#5553) 2024-05-24 05:29:00 -07:00
dependabot[bot] e1e8257df7 chore(deps): bump react-helmet-async from 2.0.1 to 2.0.5 (#6926)
Bumps [react-helmet-async](https://github.com/staylor/react-helmet-async) from 2.0.1 to 2.0.5.
- [Release notes](https://github.com/staylor/react-helmet-async/releases)
- [Commits](https://github.com/staylor/react-helmet-async/commits)

---
updated-dependencies:
- dependency-name: react-helmet-async
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 18:00:30 -07:00
dependabot[bot] 2d76dfee5a chore(deps-dev): bump eslint from 8.47.0 to 8.57.0 (#6927)
Bumps [eslint](https://github.com/eslint/eslint) from 8.47.0 to 8.57.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.47.0...v8.57.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 17:59:07 -07:00
dependabot[bot] 15bc9d36c9 chore(deps): bump prosemirror-transform from 1.8.0 to 1.9.0 (#6928)
Bumps [prosemirror-transform](https://github.com/prosemirror/prosemirror-transform) from 1.8.0 to 1.9.0.
- [Changelog](https://github.com/ProseMirror/prosemirror-transform/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prosemirror/prosemirror-transform/compare/1.8.0...1.9.0)

---
updated-dependencies:
- dependency-name: prosemirror-transform
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 17:58:52 -07:00
dependabot[bot] e5fd6a80d8 chore(deps-dev): bump typescript from 5.3.3 to 5.4.5 (#6929)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.3.3 to 5.4.5.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v5.3.3...v5.4.5)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-20 17:58:34 -07:00
Tom Moor 8c307e1db5 fix: The XML you provided was not well-formed with server-to-server S3 uploads larger than multi-part minimum 2024-05-20 20:45:28 -04:00
Tom Moor dd0bf64198 fix: AWS configuration with AWS_S3_ACCELERATE_URL specified 2024-05-19 09:53:36 -04:00
Nanguan Lin 3a7dd94e14 Migrate from s3 sdk v2 to v3 (#6731)
* chore: migrate from s3 sdk v2 to v3

* import signature-v4-crt

* downgrade minor version

* Add s3-presigned-post manually

* Change s3 mock

* Update server/storage/files/S3Storage.ts

* docs

* Upgrade aws-sdk

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-05-19 06:01:42 -07:00
Tom Moor cd4f3f9ff2 Use inline content disposition for common images and PDFs (#6924)
* Use inline content disposition for common images and PDFs

* Add double-click on widgets to download
2024-05-18 09:17:04 -07:00
Tom Moor c872f3e245 fix: Unneccessary network requests on shared documents 2024-05-18 11:29:35 -04:00
Tom Moor aa755ffc34 fix: Images in lists on shared documents sometimes render as code blocks 2024-05-18 10:54:36 -04:00
Tom Moor d36332273e fix: updateInsights policy missing 2024-05-17 17:04:10 -04:00
Tom Moor 2d510aaf4e Update link editor placeholder 2024-05-17 08:41:19 -04:00
Tom Moor 51ff1d865d tsc 2024-05-16 21:28:43 -04:00
Tom Moor 088138fb7a chore: Upgrade mammoth 2024-05-16 21:24:00 -04:00
Tom Moor 40a2c29c3f tsc 2024-05-16 21:23:02 -04:00
Tom Moor 3d87a03ca6 fix: Minor fixes to new collection sharing UI (behind flag) 2024-05-16 20:55:09 -04:00
Tom Moor cae013837b Update collection permissions UI (#6917) 2024-05-16 16:45:09 -07:00
Tom Moor 728c68be58 0.76.2-0 2024-05-16 19:02:04 -04:00
Tom Moor 64169ec414 fix: Cannot sign-in to invited account in self-hosted using email. closes #6902 2024-05-16 19:01:41 -04:00
Tom Moor c8d62c04cf fix: Do not require SMTP_USERNAME for email auth to be enabled
closes #6885
2024-05-16 18:22:10 -04:00
Tom Moor b9e7690a29 chore: Bump markdown-it 2024-05-16 08:37:48 -04:00
Tom Moor 9622452b5d fix: Infinite redirect loop on return from Slack auth without logged in session 2024-05-15 20:13:32 -04:00
dependabot[bot] bb69e891a4 chore(deps): bump vite from 5.0.13 to 5.2.11 (#6877)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.13 to 5.2.11.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.2.11/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-15 19:49:47 -04:00
Tom Moor 5ae0b03572 fix: Versions behind reads 'up to date' when github cannot be reached.
closes #6872
2024-05-14 22:07:01 -04:00
Tom Moor 73277ab8a2 Simplify publish shortcut, related #5794 2024-05-14 22:00:55 -04:00
Tom Moor 6cc0cde124 fix: Allow mixed ltr/rtl content in a document, closes #6836 2024-05-14 20:45:47 -04:00
Tom Moor bc7d6ac0d6 test 2024-05-14 20:05:32 -04:00
Translate-O-Tron 20c2c552da New Crowdin updates (#6851) 2024-05-14 16:42:15 -07:00
dependabot[bot] 582d4971b2 chore(deps): bump winston from 3.10.0 to 3.13.0 (#6905)
Bumps [winston](https://github.com/winstonjs/winston) from 3.10.0 to 3.13.0.
- [Release notes](https://github.com/winstonjs/winston/releases)
- [Changelog](https://github.com/winstonjs/winston/blob/master/CHANGELOG.md)
- [Commits](https://github.com/winstonjs/winston/compare/v3.10.0...v3.13.0)

---
updated-dependencies:
- dependency-name: winston
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 16:41:55 -07:00
dependabot[bot] 6f1bdf154d chore(deps-dev): bump eslint-plugin-react from 7.34.0 to 7.34.1 (#6904)
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.34.0 to 7.34.1.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.34.0...v7.34.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-14 16:41:41 -07:00
Tom Moor 2ecc9009f0 fix: Cannot mention users that have been explicitly added to document 2024-05-14 19:36:09 -04:00
Tom Moor 8120407bf3 Remove forced italic from block quotes 2024-05-12 22:12:24 -06:00
Tom Moor 936127de20 Add title prop to link editor results 2024-05-11 00:03:56 -06:00
Tom Moor 1a32405ee2 fix: Incorrect shortcut position 2024-05-11 00:02:39 -06:00
Tom Moor 7c3cd216bf fix: Long words in table of contents should wrap, closes #6883 2024-05-09 23:24:57 -06:00
dependabot[bot] dc8baff013 chore(deps): bump pg from 8.11.1 to 8.11.5 (#6875)
Bumps [pg](https://github.com/brianc/node-postgres/tree/HEAD/packages/pg) from 8.11.1 to 8.11.5.
- [Changelog](https://github.com/brianc/node-postgres/blob/master/CHANGELOG.md)
- [Commits](https://github.com/brianc/node-postgres/commits/pg@8.11.5/packages/pg)

---
updated-dependencies:
- dependency-name: pg
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-09 07:50:54 -07:00
dependabot[bot] 0ace8af892 chore(deps-dev): bump @types/readable-stream from 4.0.10 to 4.0.12 (#6876)
Bumps [@types/readable-stream](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/readable-stream) from 4.0.10 to 4.0.12.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/readable-stream)

---
updated-dependencies:
- dependency-name: "@types/readable-stream"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-09 07:50:41 -07:00
Tom Moor 86abd274b0 fix: Simplify redirect logic for self-hosted (#6867) 2024-05-04 07:45:31 -07:00
Tom Moor 4cb0f8bb94 0.76.1 2024-05-03 09:04:57 -04:00
Tom Moor 9204a8ab30 fix: Duplicate plugin registration logging in debug 2024-05-03 08:15:56 -04:00
Tom Moor adc4f2b544 fix: Enable import of tables from HTML that contain headings or lists 2024-05-02 21:19:44 -04:00
dependabot[bot] 760909b506 chore(deps): bump ejs from 3.1.8 to 3.1.10 (#6863)
Bumps [ejs](https://github.com/mde/ejs) from 3.1.8 to 3.1.10.
- [Release notes](https://github.com/mde/ejs/releases)
- [Commits](https://github.com/mde/ejs/compare/v3.1.8...v3.1.10)

---
updated-dependencies:
- dependency-name: ejs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-02 05:34:22 -07:00
Tom Moor 8dc530a50f fix: Policies on archived documents disallow unarchive (#6862) 2024-05-01 18:02:01 -07:00
Tom Moor 3298a1cd7d fix: Connecting Slack channel sometimes fails with 404 2024-04-30 08:54:23 -04:00
Tom Moor f7ea19cfcd 0.76.0 2024-04-29 20:30:46 -04:00
Tom Moor 40fecf13ad fix: Unneccessary API requests on deleted documents 2024-04-29 20:11:03 -04:00
Tom Moor 14c6251be4 fix: Icon misalignment in document restore menu 2024-04-29 20:11:03 -04:00
dependabot[bot] f76132f8d5 chore(deps): bump core-js from 3.36.0 to 3.37.0 (#6855)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.36.0 to 3.37.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.37.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 16:09:33 -07:00
dependabot[bot] 24e3cc880b chore(deps): bump sequelize from 6.35.2 to 6.37.3 (#6856)
Bumps [sequelize](https://github.com/sequelize/sequelize) from 6.35.2 to 6.37.3.
- [Release notes](https://github.com/sequelize/sequelize/releases)
- [Commits](https://github.com/sequelize/sequelize/compare/v6.35.2...v6.37.3)

---
updated-dependencies:
- dependency-name: sequelize
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 16:09:14 -07:00
Tom Moor 3953bbaa99 fix: 'pinToHome' policy should not be available for drafts, templates, deleted 2024-04-29 09:34:17 -04:00
Tom Moor 416cb0ceb9 fix: Missing options in document menu for trashed documents 2024-04-29 09:32:39 -04:00
Tom Moor 167467e8ea fix: 'Search in document' appears on deleted documents 2024-04-29 09:24:50 -04:00
Tom Moor 12f24a7cc1 chore: Remove date-fns resolution override 2024-04-29 09:22:36 -04:00
Tom Moor b7e19a0eb1 chore: Upgrade date-fns to v3 (#6849)
* chore: Upgrade date-fns

* fixes

* test
2024-04-26 16:34:06 -07:00
Tom Moor 958cf45d74 Support for filter by parent document (#6850)
* Backend support for filter by parent document

* parentDocumentId -> documentId
2024-04-25 19:44:15 -07:00
Tom Moor 3f4583ce72 fix: Invariant violation – team required after deleting workspace 2024-04-25 20:50:09 -04:00
Tom Moor 51611f8a86 fix: Correct invite placeholder now email invite is supported 2024-04-25 20:40:47 -04:00
Tom Moor 79899f3543 fix: 'Starred' section should open if collapsed and starred item is added 2024-04-25 20:27:12 -04:00
Tom Moor f0f6b729d4 Add animation to sidebar transition 2024-04-25 20:12:48 -04:00
Translate-O-Tron af8f4f0b5c New Crowdin updates (#6804) 2024-04-25 16:39:49 -07:00
Tom Moor bc64f1f2f7 Upgrade emoji-mart (#6848) 2024-04-25 16:39:32 -07:00
Tom Moor bf848f3a2f fix: Formatting toolbar clipped on first comment in sidebar, closes #6841 2024-04-24 22:55:33 -04:00
Tom Moor cffd0be0cf Add missing keyboard shortcuts to guide 2024-04-24 21:00:01 -04:00
Tom Moor 509a22a5b4 chore: Add more descriptive error for missing file system permission 2024-04-24 20:47:32 -04:00
Tom Moor 9b12d486f5 fix: Disable smart text replacements in code mark (#6839) 2024-04-23 19:30:52 -07:00
Tom Moor 3f8990520b fix: Squashed image in email diff #6612 2024-04-23 21:47:52 -04:00
Tom Moor c8a0343cf5 fix: Margin jumping on empty paragraph below heading 2024-04-23 19:48:09 -04:00
Tom Moor d5500540a4 fix: Incorrect icon color on completed issue unfurl 2024-04-23 08:50:57 -04:00
Tom Moor da29aa5fcb Add onFocus,onBlur callback props to InputSearch 2024-04-23 07:26:59 -04:00
Tom Moor a60e464f71 Document share dialog should allow inviting new users (#6827)
closes #6796
2024-04-23 04:23:09 -07:00
dependabot[bot] 3dbb7106a5 chore(deps-dev): bump @typescript-eslint/parser from 6.19.1 to 6.21.0 (#6830)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 6.19.1 to 6.21.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.21.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-23 04:20:32 -07:00
dependabot[bot] 67e98f4aff chore(deps): bump react-router-dom from 5.2.0 to 5.3.4 (#6832)
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 5.2.0 to 5.3.4.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/v5.3.4/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-23 04:20:20 -07:00
Tom Moor ac0fd2adbb Move event list to shared 2024-04-22 21:19:53 -04:00
Tom Moor 3825bc4181 Improve the quality of snippets for search results (#6828)
* Improve the quality of snippets for search results

* Prefer full match

* tweak highlight regex
2024-04-22 04:40:13 -07:00
Tom Moor 9855adcd3b fix: Clear IndexedDB cache command on FF, closes #6821 2024-04-21 20:48:01 -04:00
Tom Moor 0c997bfd8c Change behavior of Enter in tables, closes #6281 2024-04-21 20:13:48 -04:00
Tom Moor 3f7b377022 0.76.0-2 2024-04-21 12:39:38 -04:00
Tom Moor 6d3080e686 fix: Missing 'New doc' button on collection header for users without collection admin policy 2024-04-21 12:39:20 -04:00
Tom Moor e928c173d8 fix: '+' button appearing on collections in sidewith without document creation policy 2024-04-21 12:33:16 -04:00
Tom Moor 96758437fd fix: Only display collections for move/publish with permission 2024-04-21 12:26:41 -04:00
Tom Moor d80ef8329b fix: Only show scrollbars on settings table when neccessary 2024-04-21 11:54:50 -04:00
Tom Moor 21537b069b Special-case searching for urls as these are not indexed in whole by postgres.
closes OLN-276
2024-04-21 11:51:52 -04:00
Tom Moor e2bc4c277b Remove restriction on floated images being max 33% of document width
closes OLN-354
2024-04-21 11:14:18 -04:00
dependabot[bot] 1d01cb46e6 chore(deps): bump reflect-metadata from 0.1.14 to 0.2.2 (#6811)
Bumps [reflect-metadata](https://github.com/rbuckton/reflect-metadata) from 0.1.14 to 0.2.2.
- [Release notes](https://github.com/rbuckton/reflect-metadata/releases)
- [Changelog](https://github.com/rbuckton/reflect-metadata/blob/main/tsconfig-release.json)
- [Commits](https://github.com/rbuckton/reflect-metadata/commits)

---
updated-dependencies:
- dependency-name: reflect-metadata
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-21 07:21:01 -07:00
Dmitry Dygalo ea2c7cfcd4 chore: Replace css-inline with @css-inline/css-inline-wasm (#6336)
* chore: Replace `css-inline` with `@css-inline/css-inline-wasm`

Signed-off-by: Dmitry Dygalo <dmitry@dygalo.dev>

* Update yarn.lock

* Import order

* lint

---------

Signed-off-by: Dmitry Dygalo <dmitry@dygalo.dev>
Co-authored-by: Tom Moor <tom@getoutline.com>
2024-04-21 07:20:12 -07:00
Tom Moor 9f3dd51b48 fix: Infinite request loop when changing user preferences with window open twice 2024-04-20 17:04:24 -04:00
Tom Moor f543792640 Revert "fix: Only show scrollbars on settings table when neccessary"
This reverts commit 573c372f09.
2024-04-18 11:26:43 -04:00
Tom Moor 6b6156b032 fix: Reduce size of teamPermanentDeleter transactions for reliability 2024-04-18 09:32:13 -04:00
Tom Moor 18129a4bbb 0.76.0-1 2024-04-18 09:10:19 -04:00
Tom Moor e09826d1d1 fix: Race condition where inline comments could be removed, closes #6580 2024-04-17 22:39:32 -04:00
Tom Moor 573c372f09 fix: Only show scrollbars on settings table when neccessary 2024-04-17 19:55:42 -04:00
Tom Moor 2d947fb56b Realtime sync UI preferences between tabs 2024-04-17 19:50:42 -04:00
Tom Moor 30b7079508 fix: Clarify new doc insertion menu items 2024-04-17 19:40:38 -04:00
Tom Moor 9d3ff7f35f fix: Auto-focus name input on collection create/edit 2024-04-17 19:36:11 -04:00
Tom Moor e33ca19e64 fix: Compact invite dialog layout
closes #6819
2024-04-17 19:26:54 -04:00
一颗小土豆 2a5c13c2ba Handle several translation issues (#6820)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-04-17 07:11:54 -07:00
一颗小土豆 89e88c1afd Update Details.tsx (#6816) 2024-04-17 04:59:46 -07:00
Tom Moor dffb6604dd fix: Mermaid diagram styling in exported HTML/PDF
closes #6726
2024-04-16 22:21:28 -04:00
Tom Moor 1f6d8f8471 fix: Format view count correctly on shared links table 2024-04-16 21:06:18 -04:00
Tom Moor 780c3f8f04 fix: Settings table layout on mobile
closes #6807
2024-04-16 20:38:31 -04:00
Tom Moor c259c9617b Add color scheme setting to Settings -> Preferences 2024-04-16 20:19:07 -04:00
Tom Moor f6786945a0 fix: Missing scope on collection query 2024-04-16 20:02:11 -04:00
Tom Moor 38a65a0c59 0.76.0-0 2024-04-16 09:18:22 -04:00
Hemachandar ef0fb74308 feat: Add button to empty trash (#6772)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-04-16 06:04:56 -07:00
dependabot[bot] a5d2752122 chore(deps): bump i18next-http-backend from 2.2.2 to 2.5.0 (#6812)
Bumps [i18next-http-backend](https://github.com/i18next/i18next-http-backend) from 2.2.2 to 2.5.0.
- [Changelog](https://github.com/i18next/i18next-http-backend/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next-http-backend/compare/v2.2.2...v2.5.0)

---
updated-dependencies:
- dependency-name: i18next-http-backend
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-15 19:13:40 -07:00
dependabot[bot] f78e73a860 chore(deps-dev): bump jest-environment-jsdom from 29.6.4 to 29.7.0 (#6813)
Bumps [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom) from 29.6.4 to 29.7.0.
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v29.7.0/packages/jest-environment-jsdom)

---
updated-dependencies:
- dependency-name: jest-environment-jsdom
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-15 19:13:25 -07:00
Tom Moor 54c6abbba9 Allow setting permission of collections during import (#6799)
* Allow setting permission of collections during import

closes #6767

* Remove unused column
2024-04-15 19:13:12 -07:00
一颗小土豆 3315db449f Untranslated button: Notification settings (#6809)
* Update NotificationMenu.tsx

* Update translation.json
2024-04-15 06:02:13 -07:00
Tom Moor 34a8b8146d Shorten document filter labels 2024-04-13 22:39:54 -04:00
Tom Moor ca4d85cf19 fix: Allow duplicating a draft as a published doc 2024-04-13 22:32:52 -04:00
Tom Moor 9e8df4dd2d fix: Display @ infront of mentions 2024-04-13 22:30:29 -04:00
Tom Moor bc74f92999 fix: User mention hover previews not working 2024-04-13 22:18:17 -04:00
Tom Moor 1f50ce7d36 Highlight mentions of self in documents and comments 2024-04-13 22:15:01 -04:00
Tom Moor 2f7112eb42 fix: Improve display of original author information in document metadata 2024-04-13 15:54:45 -04:00
Translate-O-Tron f1bc71123c New Crowdin updates (#6692) 2024-04-13 11:33:25 -07:00
Tom Moor 765ae7b298 Add 80+ additional icons from FontAwesome (#6803)
* Add 80+ additional icons from FontAwesome

* fix: color switch transition, add 6 more icons to fill out grid

* Add strict validation for collection icon

* fix: Avoid import from app in server
2024-04-13 11:33:07 -07:00
Tom Moor 689886797c Add dialog to allow easy login to multiple workspaces in desktop app 2024-04-13 10:35:47 -04:00
Apoorv Mishra 90ed6a5366 Fixes hover preview going out of window bounds (#6776)
* fix: hover preview out of bounds

* fix: pop

* fix: check for both element and data

* fix: show loading indicator

* fix: width
2024-04-13 06:01:40 -07:00
Tom Moor 054bddb666 fix: Improved phrase matching in search (#6800)
* fix: Improved phrase matching in search

* test
2024-04-13 06:01:26 -07:00
Tom Moor 8490f5d558 Add security preference for workspace creation in cloud (#6801) 2024-04-13 06:01:15 -07:00
Tom Moor 1ee82e780e Update subheader on trash 2024-04-12 20:52:15 -04:00
Hemachandar 581944e754 feat: duplicate a document as draft (#6782)
* feat: duplicate a document as draft

* review

* Default `publish` toggle to match current document

Ensures duplicating a draft does not publish it.

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-04-12 17:47:59 -07:00
dependabot[bot] 0b99a88cd7 chore(deps): bump semver from 5.7.1 to 7.6.0 (#6769)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 7.6.0.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v7.6.0)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-12 06:10:25 -07:00
dependabot[bot] 6421d04ff7 chore(deps): bump react-avatar-editor from 13.0.0 to 13.0.2 (#6780)
Bumps [react-avatar-editor](https://github.com/mosch/react-avatar-editor) from 13.0.0 to 13.0.2.
- [Release notes](https://github.com/mosch/react-avatar-editor/releases)
- [Commits](https://github.com/mosch/react-avatar-editor/compare/v13.0.0...v13.0.2)

---
updated-dependencies:
- dependency-name: react-avatar-editor
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-12 06:10:09 -07:00
Tom Moor 65bbf0c455 fix: Mark editor content as unknown language to aid translation/screen readers 2024-04-12 07:53:45 -04:00
Hemachandar 5974e5635a add H3 to editor formatting toolbar (#6791) 2024-04-11 17:53:05 -07:00
Tom Moor 2e427a1e83 fix: Menus with accessory in-front of label cannot be navigated with keyboard letters
fix: Flash of outline state when focusing menu item with keyboard
2024-04-11 20:51:56 -04:00
Tom Moor 9c179fdd30 fix: Editor displayed as member in role menu 2024-04-10 23:06:30 -04:00
Tom Moor d883ba347b lint 2024-04-10 07:41:02 -04:00
Tom Moor c1b30b804c Add direct link to help docs 2024-04-10 07:38:32 -04:00
一颗小土豆 fe9a89c060 A sentence that is not properly translated under the member option in Settings (#6785)
* Update Members.tsx

* Update translation.json
2024-04-10 04:34:02 -07:00
Tom Moor 9b45feb9ee Improve user role management on members (#6775) 2024-04-09 19:02:40 -07:00
Tom Moor b458bb3af9 Refactor required route role 2024-04-06 21:43:15 -04:00
Tom Moor 79899d051c updateRole -> update_role 2024-04-06 21:16:44 -04:00
Tom Moor 3f209101e6 Add updateRole endpoint (#6771) 2024-04-06 06:32:15 -07:00
dependabot[bot] 52643c511c chore(deps): bump vite from 5.0.12 to 5.0.13 (#6758)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.12 to 5.0.13.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.0.13/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.0.13/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-05 08:31:22 -07:00
Apoorv Mishra 6a4628afef Refactor unfurling related types (#6730)
* wip

* fix: refactor unfurl types
2024-04-03 07:28:30 +05:30
Tom Moor e0ae044f4c fix: Await auth delete request before forwarding to OIDC 2024-04-02 21:57:20 -04:00
Tom Moor 40cf70d7ca Separate status and role filters in member management 2024-04-02 20:19:23 -04:00
Tom Moor 3f7d351aee Default collection and document permissions based on user role 2024-04-02 19:59:35 -04:00
Tom Moor 4311aac4ff fix: Incorrect role information in collection added email 2024-04-02 19:05:42 -04:00
Tom Moor 365f4c4b1f Add role parameter to users.list endpoint (#6754) 2024-04-02 05:00:12 -07:00
Tom Moor d2d3adefe6 Organize roles in order of access 2024-04-01 21:31:33 -04:00
Tom Moor ec30ef84af Improve InputSelect, Text components 2024-04-01 21:23:38 -04:00
Tom Moor 4b54686c76 Improve error message around port errors on server start 2024-04-01 21:06:22 -04:00
Tom Moor e9df3db1ef Remove comment for guests with read-only permissions 2024-04-01 20:51:13 -04:00
dependabot[bot] 1af25db60e chore(deps-dev): bump @babel/preset-typescript from 7.23.3 to 7.24.1 (#6752)
Bumps [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) from 7.23.3 to 7.24.1.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.1/packages/babel-preset-typescript)

---
updated-dependencies:
- dependency-name: "@babel/preset-typescript"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 17:25:11 -07:00
dependabot[bot] 8354fc6c61 chore(deps-dev): bump @types/validator from 13.11.7 to 13.11.9 (#6750)
Bumps [@types/validator](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/validator) from 13.11.7 to 13.11.9.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/validator)

---
updated-dependencies:
- dependency-name: "@types/validator"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 17:24:32 -07:00
Tom Moor c27cd945a7 Policies refactor, guest roles (#6732) 2024-03-31 17:28:35 -07:00
Tom Moor ceb7ae1514 Move invite dialog to centered design (#6740)
* wip

* Update invite dialog
2024-03-29 19:26:18 -07:00
Tom Moor 09c82bdf40 Remove isAdmin, isViewer from API response (#6738)
* Remove isAdmin,isViewer from API response

* snap
2024-03-29 06:29:59 -07:00
Tom Moor 7c083b4bfe chore: Remove isViewer and isAdmin columns (#6734) 2024-03-28 18:50:50 -07:00
Tom Moor 1c9b8c479e Remove sentence on s3-compatible storage being required (#6733) 2024-03-28 18:16:20 -07:00
Tom Moor 0dede0b56e Convert isViewer and isAdmin to getters (#6724) 2024-03-28 16:00:35 -07:00
Tom Moor 278b81a8fb fix: Handle github.com links that are not resources 2024-03-27 23:14:18 -04:00
Tom Moor 77716f3803 chore: Migrate user role to new column (#6721)
* Migration

* Double write

* Backfill script

* Simplify for self-hosted

* flip

* migration
2024-03-27 15:57:59 -07:00
Apoorv Mishra bea36f87a6 Refactor GitHub Integration (#6713)
* fix: refactor

* fix: tests

* fix: apply octokit plugin pattern
2024-03-27 17:22:06 +05:30
Viorel Cojocaru 6703ea801f build: Vite - set rollup output filenames (#6719) 2024-03-26 16:03:59 -07:00
Manuel Leduc f12b6fdf18 Fix spelling in README.md (#6717) 2024-03-26 09:33:21 -07:00
Tom Moor 34923d9b8d feat: Enable unfurling comments in Slack (#6716) 2024-03-26 06:09:41 -07:00
dependabot[bot] 462b643b7d chore(deps): bump turndown from 7.1.2 to 7.1.3 (#6707)
Bumps [turndown](https://github.com/mixmark-io/turndown) from 7.1.2 to 7.1.3.
- [Release notes](https://github.com/mixmark-io/turndown/releases)
- [Commits](https://github.com/mixmark-io/turndown/compare/v7.1.2...v7.1.3)

---
updated-dependencies:
- dependency-name: turndown
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-25 15:18:46 -07:00
dependabot[bot] 522a6cd7bd chore(deps): bump @babel/preset-react from 7.22.15 to 7.24.1 (#6708)
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.22.15 to 7.24.1.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.24.1/packages/babel-preset-react)

---
updated-dependencies:
- dependency-name: "@babel/preset-react"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-25 15:18:32 -07:00
dependabot[bot] a101a9af4a chore(deps-dev): bump eslint-config-prettier from 8.8.0 to 8.10.0 (#6710)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 8.8.0 to 8.10.0.
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v8.8.0...v8.10.0)

---
updated-dependencies:
- dependency-name: eslint-config-prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-25 15:18:23 -07:00
dependabot[bot] ceb7534daf chore(deps): bump katex from 0.16.9 to 0.16.10 (#6714)
Bumps [katex](https://github.com/KaTeX/KaTeX) from 0.16.9 to 0.16.10.
- [Release notes](https://github.com/KaTeX/KaTeX/releases)
- [Changelog](https://github.com/KaTeX/KaTeX/blob/main/CHANGELOG.md)
- [Commits](https://github.com/KaTeX/KaTeX/compare/v0.16.9...v0.16.10)

---
updated-dependencies:
- dependency-name: katex
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-25 15:18:14 -07:00
Tom Moor b6bfae0b2e fix: Merge broke slack connection 2024-03-24 21:32:48 -04:00
Tom Moor 26a1f57649 Remove use of useEventListener in shared directory 2024-03-24 21:16:19 -04:00
Tom Moor 8b6a760e02 Improve GitLab embed 2024-03-23 22:30:08 -04:00
Tom Moor d8d60814ce fix: Relative urls cannot be unfurled 2024-03-23 10:18:46 -04:00
Apoorv Mishra 450d0d9355 Github integration (#6414)
Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-03-23 07:09:28 -07:00
Tom Moor a648625700 fix: Trailing slash on exported markdown files
closes #6672
2024-03-21 20:40:36 -04:00
Tom Moor 1f7620c6f5 chore: Add warning if enabling debug logging while filtering it out, closes #6691 2024-03-21 20:11:15 -04:00
Tom Moor 1924c232fb fix: Enable use of self-hosted Iframely without API key
closes #6694
2024-03-21 19:58:12 -04:00
Apoorv Mishra bd2b32f9d5 Helper for cache related utilities (#6696)
Co-authored-by: Tom Moor <tom@getoutline.com>
2024-03-21 16:49:38 -07:00
Tom Moor 3b7010337c fix: Missing cascade prevents team permanant deletion 2024-03-19 19:06:30 -04:00
Tom Moor e2c8678855 chore: Move some tasks to background priority 2024-03-19 18:57:15 -04:00
Tom Moor 5248c95211 fix: Shared documents on suspended teams should be hidden 2024-03-18 23:10:58 -04:00
Tom Moor be211dbc5c fix: Table detection in isMarkdown, closes #6687 2024-03-18 22:54:27 -04:00
Tom Moor 6d81be2f13 fix: Only show close button when hovering toast 2024-03-18 21:40:34 -04:00
Translate-O-Tron ca0530bcb0 New Crowdin updates (#6624) 2024-03-18 18:22:13 -07:00
Tom Moor cbdacc7cfd Add ability to link Slack <-> Outline accounts (#6682) 2024-03-18 18:21:38 -07:00
dependabot[bot] e294fafd4f chore(deps): bump dd-trace from 3.33.0 to 3.51.0 (#6689)
Bumps [dd-trace](https://github.com/DataDog/dd-trace-js) from 3.33.0 to 3.51.0.
- [Release notes](https://github.com/DataDog/dd-trace-js/releases)
- [Commits](https://github.com/DataDog/dd-trace-js/compare/v3.33.0...v3.51.0)

---
updated-dependencies:
- dependency-name: dd-trace
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-18 17:54:17 -07:00
dependabot[bot] f1573d11e6 chore(deps): bump core-js from 3.33.3 to 3.36.0 (#6690)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.33.3 to 3.36.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.36.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-18 17:53:50 -07:00
Tom Moor 988a4c5ac1 Add refreshToken to IntegrationAuthentication 2024-03-17 13:23:20 -04:00
Tom Moor 64bcf40edd chore: Improve clarity of 'Shared links' page in settings 2024-03-17 13:17:03 -04:00
Tom Moor 4e47f4c1e2 chore: Remove params requirement on fetchPage 2024-03-17 13:13:23 -04:00
Tom Moor 8bd0aa43bc fix: Minor fix to table scroll styles 2024-03-16 15:19:51 -04:00
Tom Moor 2a30783e72 fix: no-op table sort should not modify document 2024-03-16 12:26:27 -04:00
Apoorv Mishra 85c8f83e33 PluginManager refactor (#6677)
* fix: refactor plugin manager

* fix: make id optional

* fix: allow add to accept single object

* fix: getHooks

* fix: tsc

* fix: remove id
2024-03-16 21:22:25 +05:30
Tom Moor 6775f25425 Automatically infer user language when signing in via Google (#6679) 2024-03-16 06:59:42 -07:00
Tom Moor f68c52e255 fix: Mobile media query not working correctly 2024-03-16 09:46:11 -04:00
Axel Rindle 34c2c5fd51 feat: support custom db schema (#6670)
* feat: db schema

* apply suggestion

Co-authored-by: Tom Moor <tom.moor@gmail.com>

* fix linter

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-03-15 06:08:12 -07:00
Tom Moor 1a386c9900 feat: Add table sorting controls (#6678)
* wip

* refactor

* fix: Missing shadow styling
2024-03-14 19:21:56 -07:00
Tom Moor 04c4d787ff Editor styling improvements 2024-03-14 22:21:01 -04:00
Tom Moor fb50b84400 fix: Plugin tasks not registered 2024-03-14 08:52:13 -04:00
Tom Moor 4c2a579d3f Include export format in filename 2024-03-13 23:00:07 -04:00
Tom Moor 69da25b216 Revert sonner – better styling 2024-03-13 21:06:20 -04:00
dependabot[bot] bb56796bdd chore(deps-dev): bump eslint-plugin-react from 7.33.2 to 7.34.0 (#6667)
Bumps [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) from 7.33.2 to 7.34.0.
- [Release notes](https://github.com/jsx-eslint/eslint-plugin-react/releases)
- [Changelog](https://github.com/jsx-eslint/eslint-plugin-react/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsx-eslint/eslint-plugin-react/compare/v7.33.2...v7.34.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-react
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 16:23:38 -07:00
dependabot[bot] 423039f2b3 chore(deps): bump diff and @types/diff (#6666)
Bumps [diff](https://github.com/kpdecker/jsdiff) and [@types/diff](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/diff). These dependencies needed to be updated together.

Updates `diff` from 5.1.0 to 5.2.0
- [Changelog](https://github.com/kpdecker/jsdiff/blob/master/release-notes.md)
- [Commits](https://github.com/kpdecker/jsdiff/compare/v5.1.0...v5.2.0)

Updates `@types/diff` from 5.0.4 to 5.0.9
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/diff)

---
updated-dependencies:
- dependency-name: diff
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: "@types/diff"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 16:00:16 -07:00
dependabot[bot] 04190f03e7 chore(deps): bump sonner from 1.0.3 to 1.4.3 (#6668)
Bumps [sonner](https://github.com/emilkowalski/sonner) from 1.0.3 to 1.4.3.
- [Release notes](https://github.com/emilkowalski/sonner/releases)
- [Commits](https://github.com/emilkowalski/sonner/commits/v1.4.3)

---
updated-dependencies:
- dependency-name: sonner
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 16:00:07 -07:00
Tom Moor ac4166da28 Add title emoji support in JSON import/export (#6660) 2024-03-10 20:09:44 -07:00
Tom Moor 9f55645655 fix: Backtick shortcut not applied correctly with composition (#6659)
* fix: Backtick shortcut not applied correctly with composition

* docs
2024-03-10 07:59:15 -07:00
Tom Moor fe4c2fb7d6 chore: Add eslint rule for no-shadow (#6658)
* chore: Add eslint rule for no-shadow

* fix
2024-03-09 13:04:27 -08:00
Tom Moor fc37070ac8 fix: variable shadowing in API router registration 2024-03-09 12:44:56 -05:00
Tom Moor 128f6cca77 chore: Remove unused link decoration logic 2024-03-09 10:44:10 -05:00
Apoorv Mishra 34e8a64b50 Share env vars client-side using @Public decorator (#6627)
* fix: public env vars using decorator

* fix: relocate

* fix: use env.public

* fix: register public env vars across plugins

* fix: test

* fix: tsc

* fix: mark remaining ones as public

* fix: move oidc ones to plugin

* fix: prevent overwrite

* fix: review
2024-03-09 14:48:59 +05:30
Tom Moor 0983dd91b6 fix: Backspace at the beginning of code block should convert to paragraph 2024-03-08 23:59:53 -05:00
Tom Moor efcad50970 Cleanup type on templates/index 2024-03-08 23:54:19 -05:00
Tom Moor f9a11a28d8 chore: Plugin registration (#6623)
* first pass

* test

* test

* priority

* Reduce boilerplate further

* Update server/utils/PluginManager.ts

Co-authored-by: Apoorv Mishra <apoorvmishra101092@gmail.com>

* fix: matchesNode error in destroyed editor transaction

* fix: Individual imported files do not display source correctly in 'Insights'

* chore: Add sleep before Slack notification

* docs

* fix: Error logged about missing plugin.json

* Remove email template glob

---------

Co-authored-by: Apoorv Mishra <apoorvmishra101092@gmail.com>
2024-03-08 20:32:05 -08:00
Tom Moor f3334cedb2 Reduce size of Insights display toggle 2024-03-08 23:03:06 -05:00
Tom Moor 1a454d6dbb chore: Add sleep before Slack notification 2024-03-08 22:02:20 -05:00
Tom Moor 8f996ca2f3 fix: Individual imported files do not display source correctly in 'Insights' 2024-03-08 21:29:34 -05:00
Tom Moor 193bde0bd5 fix: matchesNode error in destroyed editor transaction 2024-03-08 20:45:21 -05:00
Tom Moor df9f8cbabc Display import source data on documents (#6651)
* Display import source in Insights

* Ensure sourceMetadata is not returned on public requests

* Support createdByName

* Prefer display source name
2024-03-07 16:33:56 -08:00
Tom Moor 2d879d0939 fix: Restore env validation for plugins (#6649)
* fix: Restore env validation for plugins

* rever
2024-03-06 18:13:54 -08:00
Tom Moor 9bedc2f690 fix: Incorrect message on insights control, closes OLN-297 2024-03-06 08:11:55 -05:00
panos-- dce4fd6adc fix: HTML import escapes dollar signs in code (#6638) (#6645) 2024-03-06 05:00:50 -08:00
dependabot[bot] 98eba29cdd chore(deps-dev): bump @types/katex from 0.16.0 to 0.16.7 (#6633)
Bumps [@types/katex](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/katex) from 0.16.0 to 0.16.7.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/katex)

---
updated-dependencies:
- dependency-name: "@types/katex"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 20:27:12 -08:00
dependabot[bot] 1819ddfe63 chore(deps): bump cookie from 0.5.0 to 0.6.0 (#6631)
Bumps [cookie](https://github.com/jshttp/cookie) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Changelog](https://github.com/jshttp/cookie/blob/master/HISTORY.md)
- [Commits](https://github.com/jshttp/cookie/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: cookie
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 20:26:55 -08:00
dependabot[bot] 916eccfc38 chore(deps): bump socket.io from 4.7.3 to 4.7.4 (#6632)
Bumps [socket.io](https://github.com/socketio/socket.io) from 4.7.3 to 4.7.4.
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/4.7.3...4.7.4)

---
updated-dependencies:
- dependency-name: socket.io
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 20:26:40 -08:00
Pranav Joglekar a7aac2d8de fix: show complete page without scrollbar in print view (#6635) 2024-03-05 20:26:26 -08:00
Apoorv Mishra fd34a6d19c Refactor and regroup urlHelpers utils (#6462)
* fix: refactor urlHelpers

* fix: move to /plugins/slack/shared

* fix: remove .babelrc

* fix: remove Outline class

* fix: Slack -> SlackUtils

* fix: UrlHelper class
2024-02-29 11:41:03 +05:30
Tom Moor 021cd253af fix: Missing SET NULL on shares relationship. closes #6609 2024-02-28 22:49:34 -05:00
Translate-O-Tron 838b5d551e New Crowdin updates (#6473) 2024-02-28 17:46:47 -08:00
Tom Moor 6e1c38876a fix: Publicly shared pages redirect to login 2024-02-28 20:23:59 -05:00
Hemachandar 0f7bae13e2 feat: Archive all notifications (#6599)
* feat: Archive all notifications

* use non-modal notification menu

* don't show icons in context menu
2024-02-27 18:04:33 -08:00
Tom Moor 60e52d0423 Separate environment configs (#6597)
* Separate environment configs

* wip

* wip

* test

* plugins

* test

* test

* .sequelizerc, unfortunately can't go through /utils/environment due to not supporting TS

* docker-compose -> docker compose

* fix: .local wipes .development

* Add custom validation message for invalid SECRET_KEY (often confused)
2024-02-27 09:24:23 -08:00
dependabot[bot] 415383a1c9 chore(deps): bump es5-ext from 0.10.62 to 0.10.63 (#6607)
Bumps [es5-ext](https://github.com/medikoo/es5-ext) from 0.10.62 to 0.10.63.
- [Release notes](https://github.com/medikoo/es5-ext/releases)
- [Changelog](https://github.com/medikoo/es5-ext/blob/main/CHANGELOG.md)
- [Commits](https://github.com/medikoo/es5-ext/compare/v0.10.62...v0.10.63)

---
updated-dependencies:
- dependency-name: es5-ext
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 06:00:10 -08:00
dependabot[bot] e5a3ced1ba chore(deps-dev): bump @types/google.analytics from 0.0.42 to 0.0.46 (#6600)
Bumps [@types/google.analytics](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/google.analytics) from 0.0.42 to 0.0.46.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/google.analytics)

---
updated-dependencies:
- dependency-name: "@types/google.analytics"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 05:56:08 -08:00
dependabot[bot] 5663890c6c chore(deps-dev): bump @types/koa from 2.14.0 to 2.15.0 (#6601)
Bumps [@types/koa](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/koa) from 2.14.0 to 2.15.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/koa)

---
updated-dependencies:
- dependency-name: "@types/koa"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 05:55:57 -08:00
dependabot[bot] bf7ab58adf chore(deps): bump polished from 4.2.2 to 4.3.1 (#6602)
Bumps [polished](https://github.com/styled-components/polished) from 4.2.2 to 4.3.1.
- [Release notes](https://github.com/styled-components/polished/releases)
- [Commits](https://github.com/styled-components/polished/compare/v4.2.2...v4.3.1)

---
updated-dependencies:
- dependency-name: polished
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 05:55:45 -08:00
dependabot[bot] 6eb0f96c33 chore(deps): bump styled-normalize from 8.1.0 to 8.1.1 (#6604)
Bumps [styled-normalize](https://github.com/sergeysova/styled-normalize) from 8.1.0 to 8.1.1.
- [Release notes](https://github.com/sergeysova/styled-normalize/releases)
- [Commits](https://github.com/sergeysova/styled-normalize/compare/v8.1.0...v8.1.1)

---
updated-dependencies:
- dependency-name: styled-normalize
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 05:55:26 -08:00
Tom Moor edae1c6ee1 fix: Account for createdBy, updatedBy being undefined. closes #6578 2024-02-26 21:55:06 -05:00
Tom Moor 7e4b60df4d Spelling 2024-02-26 20:45:39 -05:00
Tom Moor 83c1c513bb chore: Ensure user is not connected to document when clearing cache 2024-02-25 11:41:50 -05:00
Tom Moor d42a493d8b chore: Suppress AWS deprecation message 2024-02-25 11:11:36 -05:00
Tom Moor 2ec4ff3cd0 chore: Add tags to queue processor traces 2024-02-25 11:07:28 -05:00
Tom Moor 9436c82ceb Alt fix 2024-02-24 17:02:51 -05:00
Tom Moor 0484941158 fix: Filter drafts by default, related #6537 2024-02-24 16:39:54 -05:00
Tom Moor 168643c084 chore: Move processing of documents.import to async worker (#6595) 2024-02-24 12:28:33 -08:00
Hemachandar 055f518409 fix: Conditionally show collections tooltip on invite screen (#6576)
* fix: Conditionally show collections tooltip on invite screen

* render collections tooltip only if non-empty
2024-02-24 11:02:59 -08:00
Pranav Joglekar 50b90b8878 improv: use statusFilter instead of includeArchive,includeDrafts for document search (#6537)
* improv: use statusFilter instead of includeArchive,includeDrafts for document search

* improv: update FilterComponent to add support for multiple selected items

* feat: update document type search ui

* fix test

* Restore support for old parameters to avoid breaking change

---------

Co-authored-by: Tom Moor <tom.moor@gmail.com>
2024-02-24 11:02:19 -08:00
Tom Moor b7f0af9b85 fix: Vendorized turndown-gfm-plugin and fixed performance issue with parsing tables
closes OLN-277
2024-02-24 13:01:04 -05:00
Tom Moor 4fe82f7df9 Add close button to toasts on hover 2024-02-24 09:57:35 -05:00
Tom Moor 49186fa4c6 fix: Make inline code easier to distinguish in dark mode, closes #6591 2024-02-24 00:06:55 -05:00
Tom Moor 80619ce516 fix: Do not attempt to fetch subscriptions for deleted document 2024-02-23 23:45:30 -05:00
Tom Moor 12d1c66473 Added user permission events to document history 2024-02-23 22:44:39 -05:00
Tom Moor 99cdef2ad4 fix: Document history is displayed in reverse order 2024-02-23 22:33:47 -05:00
Tom Moor bc3271b4ab fix: Passing publish=true in documents.update with published document errors 2024-02-23 21:02:52 -05:00
1231 changed files with 65230 additions and 33659 deletions
+2 -2
View File
@@ -12,7 +12,7 @@
"legacy": true
}
],
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-class-properties",
[
"transform-inline-environment-variables",
{
@@ -60,4 +60,4 @@
]
}
}
}
}
+14 -18
View File
@@ -4,22 +4,11 @@ defaults: &defaults
working_directory: ~/outline
docker:
- image: cimg/node:20.10
- image: cimg/redis:5.0
- image: cimg/postgres:14.2
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: circle_test
resource_class: large
environment:
NODE_ENV: test
SECRET_KEY: F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B
DATABASE_URL_TEST: postgres://postgres:password@localhost:5432/circle_test
DATABASE_URL: postgres://postgres:password@localhost:5432/circle_test
URL: http://localhost:3000
SMTP_FROM_EMAIL: hello@example.com
AWS_S3_UPLOAD_BUCKET_URL: https://s3.amazonaws.com
AWS_S3_UPLOAD_BUCKET_NAME: outline-circle
NODE_OPTIONS: --max-old-space-size=8000
executors:
@@ -83,17 +72,25 @@ jobs:
test-server:
<<: *defaults
parallelism: 3
docker:
- image: cimg/node:20.10
- image: cimg/redis:5.0
- image: cimg/postgres:14.2
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: circle_test
steps:
- checkout
- restore_cache:
key: dependency-cache-v1-{{ checksum "package.json" }}
- run:
name: migrate
command: ./node_modules/.bin/sequelize db:migrate --url $DATABASE_URL_TEST
command: ./node_modules/.bin/sequelize db:migrate
- run:
name: test
command: |
TESTFILES=$(circleci tests glob "server/**/*.test.ts" | circleci tests split)
TESTFILES=$(circleci tests glob "**/server/**/*.test.ts" | circleci tests split)
yarn test --maxWorkers=2 $TESTFILES
bundle-size:
<<: *defaults
@@ -113,8 +110,7 @@ jobs:
executor: docker-publisher
steps:
- checkout
- setup_remote_docker:
version: 20.10.6
- setup_remote_docker
- run:
name: Install Docker buildx
command: |
@@ -131,7 +127,7 @@ jobs:
docker buildx install
docker context create docker-multiarch
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
docker buildx create --name docker-multiarch --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x docker-multiarch
docker buildx create --name docker-multiarch --platform linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x docker-multiarch
docker buildx inspect --builder docker-multiarch --bootstrap
docker buildx use docker-multiarch
- run:
@@ -147,9 +143,9 @@ jobs:
name: Build and push Docker image
command: |
if [[ "$CIRCLE_TAG" == *"-"* ]]; then
docker buildx build -t $IMAGE_NAME:${CIRCLE_TAG/v/''} --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x --push .
docker buildx build -t $IMAGE_NAME:${CIRCLE_TAG/v/''} --platform linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x --push .
else
docker buildx build -t $IMAGE_NAME:latest -t $IMAGE_NAME:${CIRCLE_TAG/v/''} --platform linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x --push .
docker buildx build -t $IMAGE_NAME:latest -t $IMAGE_NAME:${CIRCLE_TAG/v/''} --platform linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x --push .
fi
workflows:
+10
View File
@@ -0,0 +1,10 @@
URL=https://local.outline.dev:3000
SMTP_FROM_EMAIL=hello@example.com
# Enable unsafe-inline in script-src CSP directive
# Setting it to true allows React dev tools add-on in Firefox to successfully detect the project
DEVELOPMENT_UNSAFE_INLINE_CSP=true
# Increase the log level to debug for development
LOG_LEVEL=debug
+49 -30
View File
@@ -13,7 +13,6 @@ UTILS_SECRET=generate_a_new_key
# For production point these at your databases, in development the default
# should work out of the box.
DATABASE_URL=postgres://user:pass@localhost:5432/outline
DATABASE_URL_TEST=postgres://user:pass@localhost:5432/outline-test
DATABASE_CONNECTION_POOL_MIN=
DATABASE_CONNECTION_POOL_MAX=
# Uncomment this to disable SSL for connecting to Postgres
@@ -30,30 +29,13 @@ REDIS_URL=redis://localhost:6379
# URL should point to the fully qualified, publicly accessible URL. If using a
# proxy the port in URL and PORT may be different.
URL=https://app.outline.dev:3000
URL=
PORT=3000
# See [documentation](docs/SERVICES.md) on running a separate collaboration
# server, for normal operation this does not need to be set.
COLLABORATION_URL=
# To support uploading of images for avatars and document attachments an
# s3-compatible storage must be provided. AWS S3 is recommended for redundancy
# however if you want to keep all file storage local an alternative such as
# minio (https://github.com/minio/minio) can be used.
# A more detailed guide on setting up S3 is available here:
# => https://wiki.generaloutline.com/share/125de1cc-9ff6-424b-8415-0d58c809a40f
#
AWS_ACCESS_KEY_ID=get_a_key_from_aws
AWS_SECRET_ACCESS_KEY=get_the_secret_of_above_key
AWS_REGION=xx-xxxx-x
AWS_S3_ACCELERATE_URL=
AWS_S3_UPLOAD_BUCKET_URL=http://s3:4569
AWS_S3_UPLOAD_BUCKET_NAME=bucket_name_here
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private
# Specify what storage system to use. Possible value is one of "s3" or "local".
# For "local", the avatar images and document attachments will be saved on local disk.
FILE_STORAGE=local
@@ -74,6 +56,17 @@ FILE_STORAGE_IMPORT_MAX_SIZE=
# and the files are temporary being automatically deleted after a period of time.
FILE_STORAGE_WORKSPACE_IMPORT_MAX_SIZE=
# To support uploading of images for avatars and document attachments in a distributed
# architecture an s3-compatible storage can be configured if FILE_STORAGE=s3 above.
AWS_ACCESS_KEY_ID=get_a_key_from_aws
AWS_SECRET_ACCESS_KEY=get_the_secret_of_above_key
AWS_REGION=xx-xxxx-x
AWS_S3_ACCELERATE_URL=
AWS_S3_UPLOAD_BUCKET_URL=http://s3:4569
AWS_S3_UPLOAD_BUCKET_NAME=bucket_name_here
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private
# –––––––––––––– AUTHENTICATION ––––––––––––––
# Third party signin credentials, at least ONE OF EITHER Google, Slack,
@@ -123,6 +116,36 @@ OIDC_DISPLAY_NAME=OpenID Connect
# Space separated auth scopes.
OIDC_SCOPES=openid profile email
# To configure the GitHub integration, you'll need to create a GitHub App at
# => https://github.com/settings/apps
#
# When configuring the Client ID, add a redirect URL under "Permissions & events":
# https://<URL>/api/github.callback
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_APP_NAME=
GITHUB_APP_ID=
GITHUB_APP_PRIVATE_KEY=
# To configure Discord auth, you'll need to create a Discord Application at
# => https://discord.com/developers/applications/
#
# When configuring the Client ID, add a redirect URL under "OAuth2":
# https://<URL>/auth/discord.callback
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
# DISCORD_SERVER_ID should be the ID of the Discord server that Outline is
# integrated with.
# Used to verify that the user is a member of the server as well as server
# metadata such as nicknames, server icon and name.
DISCORD_SERVER_ID=
# DISCORD_SERVER_ROLES should be a comma separated list of role IDs that are
# allowed to access Outline. If this is not set, all members of the server
# will be allowed to access Outline.
# DISCORD_SERVER_ID and DISCORD_SERVER_ROLES must be set together.
DISCORD_SERVER_ROLES=
# –––––––––––––––– OPTIONAL ––––––––––––––––
@@ -166,8 +189,9 @@ SLACK_VERIFICATION_TOKEN=your_token
SLACK_APP_ID=A0XXXXXXX
SLACK_MESSAGE_ACTIONS=true
# Optionally enable google analytics to track pageviews in the knowledge base
GOOGLE_ANALYTICS_ID=
# For Dropbox integration, follow these instructions to get the key https://www.dropbox.com/developers/embedder#setup
# and do not forget to whitelist your domain name in the app settings
DROPBOX_APP_KEY=
# Optionally enable Sentry (sentry.io) to track errors and performance,
# and optionally add a Sentry proxy tunnel for bypassing ad blockers in the UI:
@@ -181,8 +205,8 @@ SMTP_HOST=
SMTP_PORT=
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_FROM_EMAIL=hello@example.com
SMTP_REPLY_EMAIL=hello@example.com
SMTP_FROM_EMAIL=
SMTP_REPLY_EMAIL=
SMTP_TLS_CIPHERS=
SMTP_SECURE=true
@@ -198,10 +222,5 @@ RATE_LIMITER_REQUESTS=1000
RATE_LIMITER_DURATION_WINDOW=60
# Iframely API config
# IFRAMELY_URL=
# IFRAMELY_API_KEY=
# Enable unsafe-inline in script-src CSP directive
# Setting it to true allows React dev tools add-on in
# Firefox to successfully detect the project
DEVELOPMENT_UNSAFE_INLINE_CSP=false
IFRAMELY_URL=
IFRAMELY_API_KEY=
+31
View File
@@ -0,0 +1,31 @@
NODE_ENV=test
DATABASE_URL=postgres://user:pass@127.0.0.1:5432/outline-test
SECRET_KEY=F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B
SMTP_HOST=smtp.example.com
SMTP_USERNAME=test
SMTP_FROM_EMAIL=hello@example.com
SMTP_REPLY_EMAIL=hello@example.com
GOOGLE_CLIENT_ID=123
GOOGLE_CLIENT_SECRET=123
SLACK_CLIENT_ID=123
SLACK_CLIENT_SECRET=123
GITHUB_CLIENT_ID=123;
GITHUB_CLIENT_SECRET=123;
GITHUB_APP_NAME=outline-test;
OIDC_CLIENT_ID=client-id
OIDC_CLIENT_SECRET=client-secret
OIDC_AUTH_URI=http://localhost/authorize
OIDC_TOKEN_URI=http://localhost/token
OIDC_USERINFO_URI=http://localhost/userinfo
IFRAMELY_API_KEY=123
RATE_LIMITER_ENABLED=false
FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=/tmp
+10 -1
View File
@@ -32,11 +32,20 @@
"object-shorthand": "error",
"no-mixed-operators": "off",
"no-useless-escape": "off",
"no-shadow": "off",
"es/no-regexp-lookbehind-assertions": "error",
"react/self-closing-comp": ["error", {
"component": true,
"html": true
}],
"@typescript-eslint/no-shadow": [
"warn",
{
"allow": ["transaction"],
"hoist": "all",
"ignoreTypeValueShadow": true
}
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/await-thenable": "error",
@@ -131,4 +140,4 @@
"typescript": {}
}
}
}
}
-37
View File
@@ -1,37 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots or videos to help explain your problem.
**Outline (please complete the following information):**
- Install: [getoutline.com or self hosted]
- Version: [commit sha if self hosted]
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Mobile (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
+63
View File
@@ -0,0 +1,63 @@
name: Bug report
description: File a bug to help us improve
labels: ["bug"]
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: checkboxes
attributes:
label: This is not related to configuring Outline
description: I understand that questions related to configuring self-hosted Outline should be asked in the [community forum](https://github.com/outline/outline/discussions/categories/self-hosting).
options:
- label: The issue is not related to self-hosting config
required: true
- type: textarea
attributes:
label: Current Behavior
description: A concise description of what you're experiencing.
validations:
required: false
- type: textarea
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: false
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. In this environment...
1. With this config...
1. Run '...'
1. See error...
validations:
required: false
- type: textarea
attributes:
label: Environment
description: |
examples:
- **Outline**: Outline 0.80.0
- **Browser**: Safari
value: |
- Outline:
- Browser:
render: markdown
validations:
required: false
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
validations:
required: false
+1 -1
View File
@@ -1,7 +1,7 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 14
daysUntilClose: 7
# Label requiring a response
responseRequiredLabel: more information needed
+2
View File
@@ -2,6 +2,8 @@ dist
build
node_modules/*
.env
.env.local
.env.production
.log
.vscode/*
npm-debug.log
+9 -5
View File
@@ -7,9 +7,10 @@
"roots": ["<rootDir>/server", "<rootDir>/plugins"],
"moduleNameMapper": {
"^@server/(.*)$": "<rootDir>/server/$1",
"^@shared/(.*)$": "<rootDir>/shared/$1"
"^@shared/(.*)$": "<rootDir>/shared/$1",
"react-medium-image-zoom": "<rootDir>/__mocks__/react-medium-image-zoom.js"
},
"setupFiles": ["<rootDir>/__mocks__/console.js", "<rootDir>/server/test/env.ts"],
"setupFiles": ["<rootDir>/__mocks__/console.js"],
"setupFilesAfterEnv": ["<rootDir>/server/test/setup.ts"],
"globalSetup": "<rootDir>/server/test/globalSetup.js",
"globalTeardown": "<rootDir>/server/test/globalTeardown.js",
@@ -22,7 +23,8 @@
"^~/(.*)$": "<rootDir>/app/$1",
"^@shared/(.*)$": "<rootDir>/shared/$1",
"^.*[.](gif|ttf|eot|svg)$": "<rootDir>/__test__/fileMock.js",
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js"
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js",
"react-medium-image-zoom": "<rootDir>/__mocks__/react-medium-image-zoom.js"
},
"modulePaths": ["<rootDir>/app"],
"setupFiles": ["<rootDir>/__mocks__/window.js"],
@@ -37,7 +39,8 @@
"roots": ["<rootDir>/shared"],
"moduleNameMapper": {
"^@server/(.*)$": "<rootDir>/server/$1",
"^@shared/(.*)$": "<rootDir>/shared/$1"
"^@shared/(.*)$": "<rootDir>/shared/$1",
"react-medium-image-zoom": "<rootDir>/__mocks__/react-medium-image-zoom.js"
},
"setupFiles": ["<rootDir>/__mocks__/console.js"],
"setupFilesAfterEnv": ["<rootDir>/shared/test/setup.ts"],
@@ -50,7 +53,8 @@
"^~/(.*)$": "<rootDir>/app/$1",
"^@shared/(.*)$": "<rootDir>/shared/$1",
"^.*[.](gif|ttf|eot|svg)$": "<rootDir>/__test__/fileMock.js",
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js"
"^uuid$": "<rootDir>/node_modules/uuid/dist/index.js",
"react-medium-image-zoom": "<rootDir>/__mocks__/react-medium-image-zoom.js"
},
"setupFiles": ["<rootDir>/__mocks__/window.js"],
"testEnvironment": "jsdom",
+3 -2
View File
@@ -1,4 +1,6 @@
require('dotenv').config({ silent: true });
require("dotenv").config({
path: process.env.NODE_ENV === "test" ? ".env.test" : ".env",
});
var path = require('path');
@@ -6,5 +8,4 @@ module.exports = {
'config': path.resolve('server/config', 'database.json'),
'migrations-path': path.resolve('server', 'migrations'),
'models-path': path.resolve('server', 'models'),
'seeders-path': path.resolve('server/models', 'fixtures'),
}
+14 -8
View File
@@ -1,19 +1,17 @@
ARG APP_PATH=/opt/outline
FROM outlinewiki/outline-base as base
FROM outlinewiki/outline-base AS base
ARG APP_PATH
WORKDIR $APP_PATH
# ---
FROM node:20-alpine AS runner
RUN apk update && apk add --no-cache curl && apk add --no-cache ca-certificates
FROM node:20-slim AS runner
LABEL org.opencontainers.image.source="https://github.com/outline/outline"
ARG APP_PATH
WORKDIR $APP_PATH
ENV NODE_ENV production
ENV NODE_ENV=production
COPY --from=base $APP_PATH/build ./build
COPY --from=base $APP_PATH/server ./server
@@ -22,13 +20,19 @@ COPY --from=base $APP_PATH/.sequelizerc ./.sequelizerc
COPY --from=base $APP_PATH/node_modules ./node_modules
COPY --from=base $APP_PATH/package.json ./package.json
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001 && \
# Install wget to healthcheck the server
RUN apt-get update \
&& apt-get install -y wget \
&& rm -rf /var/lib/apt/lists/*
# Create a non-root user compatible with Debian and BusyBox based images
RUN addgroup --gid 1001 nodejs && \
adduser --uid 1001 --ingroup nodejs nodejs && \
chown -R nodejs:nodejs $APP_PATH/build && \
mkdir -p /var/lib/outline && \
chown -R nodejs:nodejs /var/lib/outline
ENV FILE_STORAGE_LOCAL_ROOT_DIR /var/lib/outline/data
ENV FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
RUN mkdir -p "$FILE_STORAGE_LOCAL_ROOT_DIR" && \
chown -R nodejs:nodejs "$FILE_STORAGE_LOCAL_ROOT_DIR" && \
chmod 1777 "$FILE_STORAGE_LOCAL_ROOT_DIR"
@@ -37,5 +41,7 @@ VOLUME /var/lib/outline/data
USER nodejs
HEALTHCHECK --interval=1m CMD wget -qO- "http://localhost:${PORT:-3000}/_health" | grep -q "OK" || exit 1
EXPOSE 3000
CMD ["yarn", "start"]
+3 -1
View File
@@ -1,5 +1,5 @@
ARG APP_PATH=/opt/outline
FROM node:20-alpine AS deps
FROM node:20-slim AS deps
ARG APP_PATH
WORKDIR $APP_PATH
@@ -17,3 +17,5 @@ RUN rm -rf node_modules
RUN yarn install --production=true --frozen-lockfile --network-timeout 1000000 && \
yarn cache clean
ENV PORT=3000
+3 -3
View File
@@ -3,8 +3,8 @@ Business Source License 1.1
Parameters
Licensor: General Outline, Inc.
Licensed Work: Outline 0.71.0
The Licensed Work is (c) 2020 General Outline, Inc.
Licensed Work: Outline 0.81.0
The Licensed Work is (c) 2024 General Outline, Inc.
Additional Use Grant: You may make use of the Licensed Work, provided that
you may not use the Licensed Work for a Document
Service.
@@ -15,7 +15,7 @@ Additional Use Grant: You may make use of the Licensed Work, provided that
Licensed Work by creating teams and documents
controlled by such third parties.
Change Date: 2027-08-18
Change Date: 2028-11-11
Change License: Apache License, Version 2.0
+12 -12
View File
@@ -1,28 +1,28 @@
up:
docker-compose up -d redis postgres
docker compose up -d redis postgres
yarn install-local-ssl
yarn install --pure-lockfile
yarn dev:watch
build:
docker-compose build --pull outline
docker compose build --pull outline
test:
docker-compose up -d redis postgres
yarn sequelize db:drop --env=test
yarn sequelize db:create --env=test
NODE_ENV=test yarn sequelize db:migrate --env=test
docker compose up -d redis postgres
NODE_ENV=test yarn sequelize db:drop
NODE_ENV=test yarn sequelize db:create
NODE_ENV=test yarn sequelize db:migrate
yarn test
watch:
docker-compose up -d redis postgres
yarn sequelize db:drop --env=test
yarn sequelize db:create --env=test
NODE_ENV=test yarn sequelize db:migrate --env=test
docker compose up -d redis postgres
NODE_ENV=test yarn sequelize db:drop
NODE_ENV=test yarn sequelize db:create
NODE_ENV=test yarn sequelize db:migrate
yarn test:watch
destroy:
docker-compose stop
docker-compose rm -f
docker compose stop
docker compose rm -f
.PHONY: up build destroy test watch # let's go to reserve rules names
+1 -1
View File
@@ -32,7 +32,7 @@ There is a short guide for [setting up a development environment](https://docs.g
Outline is built and maintained by a small team we'd love your help to fix bugs and add features!
Before submitting a pull request _please_ discuss with the core team by creating or commenting in an issue on [GitHub](https://www.github.com/outline/outline/issues) we'd also love to hear from you in the [discussions](https://www.github.com/outline/outline/discussions). This way we can ensure that an approach is agreed on before code is written. This will result in a much higher liklihood of your code being accepted.
Before submitting a pull request _please_ discuss with the core team by creating or commenting in an issue on [GitHub](https://www.github.com/outline/outline/issues) we'd also love to hear from you in the [discussions](https://www.github.com/outline/outline/discussions). This way we can ensure that an approach is agreed on before code is written. This will result in a much higher likelihood of your code being accepted.
If youre looking for ways to get started, here's a list of ways to help us improve Outline:
+1
View File
@@ -0,0 +1 @@
export default null;
+13 -2
View File
@@ -3,7 +3,13 @@
"description": "Open source wiki and knowledge base for growing teams",
"website": "https://www.getoutline.com/",
"repository": "https://github.com/outline/outline",
"keywords": ["wiki", "team", "node", "markdown", "slack"],
"keywords": [
"wiki",
"team",
"node",
"markdown",
"slack"
],
"success_url": "/",
"formation": {
"web": {
@@ -33,6 +39,11 @@
"generator": "secret",
"required": true
},
"UTILS_SECRET": {
"description": "A 32-character secret key, generate with openssl rand -hex 32",
"generator": "secret",
"required": true
},
"ENABLE_UPDATES": {
"value": "true",
"required": true
@@ -207,4 +218,4 @@
"required": false
}
}
}
}
+25
View File
@@ -0,0 +1,25 @@
import { PlusIcon } from "outline-icons";
import * as React from "react";
import stores from "~/stores";
import ApiKeyNew from "~/scenes/ApiKeyNew";
import { createAction } from "..";
import { SettingsSection } from "../sections";
export const createApiKey = createAction({
name: ({ t }) => t("New API key"),
analyticsName: "New API key",
section: SettingsSection,
icon: <PlusIcon />,
keywords: "create",
visible: () =>
stores.policies.abilities(stores.auth.team?.id || "").createApiKey,
perform: ({ t, event }) => {
event?.preventDefault();
event?.stopPropagation();
stores.dialogs.openModal({
title: t("New API key"),
content: <ApiKeyNew onSubmit={stores.dialogs.closeAllModals} />,
});
},
});
+149 -18
View File
@@ -1,23 +1,32 @@
import {
ArchiveIcon,
CollectionIcon,
EditIcon,
PadlockIcon,
PlusIcon,
RestoreIcon,
SearchIcon,
ShapesIcon,
StarredIcon,
TrashIcon,
UnstarredIcon,
} from "outline-icons";
import * as React from "react";
import { toast } from "sonner";
import stores from "~/stores";
import Collection from "~/models/Collection";
import CollectionPermissions from "~/scenes/CollectionPermissions";
import { CollectionEdit } from "~/components/Collection/CollectionEdit";
import { CollectionNew } from "~/components/Collection/CollectionNew";
import CollectionDeleteDialog from "~/components/CollectionDeleteDialog";
import ConfirmationDialog from "~/components/ConfirmationDialog";
import DynamicCollectionIcon from "~/components/Icons/CollectionIcon";
import SharePopover from "~/components/Sharing/Collection/SharePopover";
import { getHeaderExpandedKey } from "~/components/Sidebar/components/Header";
import { createAction } from "~/actions";
import { CollectionSection } from "~/actions/sections";
import { ActiveCollectionSection, CollectionSection } from "~/actions/sections";
import { setPersistedState } from "~/hooks/usePersistedState";
import history from "~/utils/history";
import { newTemplatePath, searchPath } from "~/utils/routeHelpers";
const ColorCollectionIcon = ({ collection }: { collection: Collection }) => (
<DynamicCollectionIcon collection={collection} />
@@ -65,9 +74,9 @@ export const editCollection = createAction({
name: ({ t, isContextMenu }) =>
isContextMenu ? `${t("Edit")}` : t("Edit collection"),
analyticsName: "Edit collection",
section: CollectionSection,
section: ActiveCollectionSection,
icon: <EditIcon />,
visible: ({ stores, activeCollectionId }) =>
visible: ({ activeCollectionId }) =>
!!activeCollectionId &&
stores.policies.abilities(activeCollectionId).update,
perform: ({ t, activeCollectionId }) => {
@@ -91,31 +100,65 @@ export const editCollectionPermissions = createAction({
name: ({ t, isContextMenu }) =>
isContextMenu ? `${t("Permissions")}` : t("Collection permissions"),
analyticsName: "Collection permissions",
section: CollectionSection,
section: ActiveCollectionSection,
icon: <PadlockIcon />,
visible: ({ stores, activeCollectionId }) =>
visible: ({ activeCollectionId }) =>
!!activeCollectionId &&
stores.policies.abilities(activeCollectionId).update,
perform: ({ t, activeCollectionId }) => {
if (!activeCollectionId) {
return;
}
const collection = stores.collections.get(activeCollectionId);
if (!collection) {
return;
}
stores.dialogs.openModal({
title: t("Collection permissions"),
fullscreen: true,
content: <CollectionPermissions collectionId={activeCollectionId} />,
title: t("Share this collection"),
style: { marginBottom: -12 },
content: (
<SharePopover
collection={collection}
onRequestClose={stores.dialogs.closeAllModals}
visible
/>
),
});
},
});
export const searchInCollection = createAction({
name: ({ t }) => t("Search in collection"),
analyticsName: "Search collection",
section: ActiveCollectionSection,
icon: <SearchIcon />,
visible: ({ activeCollectionId }) => {
if (!activeCollectionId) {
return false;
}
const collection = stores.collections.get(activeCollectionId);
if (!collection?.isActive) {
return false;
}
return stores.policies.abilities(activeCollectionId).readDocument;
},
perform: ({ activeCollectionId }) => {
history.push(searchPath(undefined, { collectionId: activeCollectionId }));
},
});
export const starCollection = createAction({
name: ({ t }) => t("Star"),
analyticsName: "Star collection",
section: CollectionSection,
section: ActiveCollectionSection,
icon: <StarredIcon />,
keywords: "favorite bookmark",
visible: ({ activeCollectionId, stores }) => {
visible: ({ activeCollectionId }) => {
if (!activeCollectionId) {
return false;
}
@@ -125,23 +168,24 @@ export const starCollection = createAction({
stores.policies.abilities(activeCollectionId).star
);
},
perform: async ({ activeCollectionId, stores }) => {
perform: async ({ activeCollectionId }) => {
if (!activeCollectionId) {
return;
}
const collection = stores.collections.get(activeCollectionId);
await collection?.star();
setPersistedState(getHeaderExpandedKey("starred"), true);
},
});
export const unstarCollection = createAction({
name: ({ t }) => t("Unstar"),
analyticsName: "Unstar collection",
section: CollectionSection,
section: ActiveCollectionSection,
icon: <UnstarredIcon />,
keywords: "unfavorite unbookmark",
visible: ({ activeCollectionId, stores }) => {
visible: ({ activeCollectionId }) => {
if (!activeCollectionId) {
return false;
}
@@ -151,7 +195,7 @@ export const unstarCollection = createAction({
stores.policies.abilities(activeCollectionId).unstar
);
},
perform: async ({ activeCollectionId, stores }) => {
perform: async ({ activeCollectionId }) => {
if (!activeCollectionId) {
return;
}
@@ -161,19 +205,85 @@ export const unstarCollection = createAction({
},
});
export const archiveCollection = createAction({
name: ({ t }) => `${t("Archive")}`,
analyticsName: "Archive collection",
section: CollectionSection,
icon: <ArchiveIcon />,
visible: ({ activeCollectionId, stores }) => {
if (!activeCollectionId) {
return false;
}
return !!stores.policies.abilities(activeCollectionId).archive;
},
perform: async ({ activeCollectionId, stores, t }) => {
const { dialogs, collections } = stores;
if (!activeCollectionId) {
return;
}
const collection = collections.get(activeCollectionId);
if (!collection) {
return;
}
dialogs.openModal({
title: t("Archive collection"),
content: (
<ConfirmationDialog
onSubmit={async () => {
await collection.archive();
toast.success(t("Collection archived"));
}}
submitText={t("Archive")}
savingText={`${t("Archiving")}`}
>
{t(
"Archiving this collection will also archive all documents within it. Documents from the collection will no longer be visible in search results."
)}
</ConfirmationDialog>
),
});
},
});
export const restoreCollection = createAction({
name: ({ t }) => t("Restore"),
analyticsName: "Restore collection",
section: CollectionSection,
icon: <RestoreIcon />,
visible: ({ activeCollectionId, stores }) => {
if (!activeCollectionId) {
return false;
}
return !!stores.policies.abilities(activeCollectionId).restore;
},
perform: async ({ activeCollectionId, stores, t }) => {
if (!activeCollectionId) {
return;
}
const collection = stores.collections.get(activeCollectionId);
if (!collection) {
return;
}
await collection.restore();
toast.success(t("Collection restored"));
},
});
export const deleteCollection = createAction({
name: ({ t }) => `${t("Delete")}`,
analyticsName: "Delete collection",
section: CollectionSection,
section: ActiveCollectionSection,
dangerous: true,
icon: <TrashIcon />,
visible: ({ activeCollectionId, stores }) => {
visible: ({ activeCollectionId }) => {
if (!activeCollectionId) {
return false;
}
return stores.policies.abilities(activeCollectionId).delete;
},
perform: ({ activeCollectionId, stores, t }) => {
perform: ({ activeCollectionId, t }) => {
if (!activeCollectionId) {
return;
}
@@ -195,6 +305,27 @@ export const deleteCollection = createAction({
},
});
export const createTemplate = createAction({
name: ({ t }) => t("New template"),
analyticsName: "New template",
section: ActiveCollectionSection,
icon: <ShapesIcon />,
keywords: "new create template",
visible: ({ activeCollectionId }) =>
!!(
!!activeCollectionId &&
stores.policies.abilities(activeCollectionId).createDocument
),
perform: ({ activeCollectionId, event }) => {
if (!activeCollectionId) {
return;
}
event?.preventDefault();
event?.stopPropagation();
history.push(newTemplatePath(activeCollectionId));
},
});
export const rootCollectionActions = [
openCollection,
createCollection,
+123
View File
@@ -0,0 +1,123 @@
import { DoneIcon, SmileyIcon, TrashIcon } from "outline-icons";
import * as React from "react";
import { toast } from "sonner";
import stores from "~/stores";
import Comment from "~/models/Comment";
import CommentDeleteDialog from "~/components/CommentDeleteDialog";
import ViewReactionsDialog from "~/components/Reactions/ViewReactionsDialog";
import history from "~/utils/history";
import { createAction } from "..";
import { DocumentSection } from "../sections";
export const deleteCommentFactory = ({
comment,
onDelete,
}: {
comment: Comment;
onDelete: () => void;
}) =>
createAction({
name: ({ t }) => `${t("Delete")}`,
analyticsName: "Delete comment",
section: DocumentSection,
icon: <TrashIcon />,
keywords: "trash",
dangerous: true,
visible: () => stores.policies.abilities(comment.id).delete,
perform: ({ t, event }) => {
event?.preventDefault();
event?.stopPropagation();
stores.dialogs.openModal({
title: t("Delete comment"),
content: <CommentDeleteDialog comment={comment} onSubmit={onDelete} />,
});
},
});
export const resolveCommentFactory = ({
comment,
onResolve,
}: {
comment: Comment;
onResolve: () => void;
}) =>
createAction({
name: ({ t }) => t("Mark as resolved"),
analyticsName: "Resolve thread",
section: DocumentSection,
icon: <DoneIcon outline />,
visible: () =>
stores.policies.abilities(comment.id).resolve &&
stores.policies.abilities(comment.documentId).update,
perform: async ({ t }) => {
await comment.resolve();
const locationState = history.location.state as Record<string, unknown>;
history.replace({
...history.location,
state: {
sidebarContext: locationState["sidebarContext"],
commentId: undefined,
},
});
onResolve();
toast.success(t("Thread resolved"));
},
});
export const unresolveCommentFactory = ({
comment,
onUnresolve,
}: {
comment: Comment;
onUnresolve: () => void;
}) =>
createAction({
name: ({ t }) => t("Mark as unresolved"),
analyticsName: "Unresolve thread",
section: DocumentSection,
icon: <DoneIcon outline />,
visible: () =>
stores.policies.abilities(comment.id).unresolve &&
stores.policies.abilities(comment.documentId).update,
perform: async () => {
await comment.unresolve();
const locationState = history.location.state as Record<string, unknown>;
history.replace({
...history.location,
state: {
sidebarContext: locationState["sidebarContext"],
commentId: undefined,
},
});
onUnresolve();
},
});
export const viewCommentReactionsFactory = ({
comment,
}: {
comment: Comment;
}) =>
createAction({
name: ({ t }) => `${t("View reactions")}`,
analyticsName: "View comment reactions",
section: DocumentSection,
icon: <SmileyIcon />,
visible: () =>
stores.policies.abilities(comment.id).read &&
comment.reactions.length > 0,
perform: ({ t, event }) => {
event?.preventDefault();
event?.stopPropagation();
stores.dialogs.openModal({
title: t("Reactions"),
content: <ViewReactionsDialog model={comment} />,
});
},
});
+43 -8
View File
@@ -1,13 +1,22 @@
import copy from "copy-to-clipboard";
import { CopyIcon, ToolsIcon, TrashIcon, UserIcon } from "outline-icons";
import {
BeakerIcon,
CopyIcon,
ToolsIcon,
TrashIcon,
UserIcon,
} from "outline-icons";
import * as React from "react";
import { toast } from "sonner";
import { createAction } from "~/actions";
import { DeveloperSection } from "~/actions/sections";
import env from "~/env";
import { client } from "~/utils/ApiClient";
import { Feature, FeatureFlags } from "~/utils/FeatureFlags";
import Logger from "~/utils/Logger";
import { deleteAllDatabases } from "~/utils/developer";
import history from "~/utils/history";
import { homePath } from "~/utils/routeHelpers";
export const copyId = createAction({
name: ({ t }) => t("Copy ID"),
@@ -67,21 +76,22 @@ export const copyId = createAction({
name: "Copy Release ID",
icon: <CopyIcon />,
section: DeveloperSection,
visible: () => !!env.RELEASE,
perform: () => copyAndToast(env.RELEASE),
visible: () => !!env.VERSION,
perform: () => copyAndToast(env.VERSION),
}),
];
},
});
export const clearIndexedDB = createAction({
name: ({ t }) => t("Delete IndexedDB cache"),
name: ({ t }) => t("Clear IndexedDB cache"),
icon: <TrashIcon />,
keywords: "cache clear database",
section: DeveloperSection,
perform: async ({ t }) => {
history.push(homePath());
await deleteAllDatabases();
toast.message(t("IndexedDB cache deleted"));
toast.success(t("IndexedDB cache cleared"));
},
});
@@ -101,7 +111,7 @@ export const createToast = createAction({
name: "Create toast",
section: DeveloperSection,
visible: () => env.ENVIRONMENT === "development",
perform: async () => {
perform: () => {
toast.message("Hello world", {
duration: 30000,
});
@@ -112,7 +122,7 @@ export const toggleDebugLogging = createAction({
name: ({ t }) => t("Toggle debug logging"),
icon: <ToolsIcon />,
section: DeveloperSection,
perform: async ({ t }) => {
perform: ({ t }) => {
Logger.debugLoggingEnabled = !Logger.debugLoggingEnabled;
toast.message(
Logger.debugLoggingEnabled
@@ -122,6 +132,30 @@ export const toggleDebugLogging = createAction({
},
});
export const toggleFeatureFlag = createAction({
name: "Toggle feature flag",
icon: <BeakerIcon />,
section: DeveloperSection,
visible: () => env.ENVIRONMENT === "development",
children: Object.values(Feature).map((flag) =>
createAction({
id: `flag-${flag}`,
name: flag,
selected: () => FeatureFlags.isEnabled(flag),
section: DeveloperSection,
perform: () => {
if (FeatureFlags.isEnabled(flag)) {
FeatureFlags.disable(flag);
toast.success(`Disabled feature flag: ${flag}`);
} else {
FeatureFlags.enable(flag);
toast.success(`Enabled feature flag: ${flag}`);
}
},
})
),
});
export const developer = createAction({
name: ({ t }) => t("Development"),
keywords: "debug",
@@ -130,10 +164,11 @@ export const developer = createAction({
section: DeveloperSection,
children: [
copyId,
clearIndexedDB,
toggleDebugLogging,
toggleFeatureFlag,
createToast,
createTestUsers,
clearIndexedDB,
],
});
+397 -117
View File
@@ -24,33 +24,52 @@ import {
UnpublishIcon,
PublishIcon,
CommentIcon,
GlobeIcon,
CopyIcon,
EyeIcon,
PadlockIcon,
GlobeIcon,
LogoutIcon,
} from "outline-icons";
import * as React from "react";
import { toast } from "sonner";
import { ExportContentType, TeamPreference } from "@shared/types";
import MarkdownHelper from "@shared/utils/MarkdownHelper";
import Icon from "@shared/components/Icon";
import {
ExportContentType,
TeamPreference,
NavigationNode,
} from "@shared/types";
import { getEventFiles } from "@shared/utils/files";
import UserMembership from "~/models/UserMembership";
import DocumentDelete from "~/scenes/DocumentDelete";
import DocumentMove from "~/scenes/DocumentMove";
import DocumentPermanentDelete from "~/scenes/DocumentPermanentDelete";
import DocumentPublish from "~/scenes/DocumentPublish";
import DocumentTemplatizeDialog from "~/components/DocumentTemplatizeDialog";
import DuplicateDialog from "~/components/DuplicateDialog";
import SharePopover from "~/components/Sharing";
import DeleteDocumentsInTrash from "~/scenes/Trash/components/DeleteDocumentsInTrash";
import ConfirmationDialog from "~/components/ConfirmationDialog";
import DocumentCopy from "~/components/DocumentCopy";
import MarkdownIcon from "~/components/Icons/MarkdownIcon";
import SharePopover from "~/components/Sharing/Document";
import { getHeaderExpandedKey } from "~/components/Sidebar/components/Header";
import DocumentTemplatizeDialog from "~/components/TemplatizeDialog";
import { createAction } from "~/actions";
import { DocumentSection } from "~/actions/sections";
import {
ActiveDocumentSection,
DocumentSection,
TrashSection,
} from "~/actions/sections";
import env from "~/env";
import { setPersistedState } from "~/hooks/usePersistedState";
import history from "~/utils/history";
import {
documentInsightsPath,
documentHistoryPath,
homePath,
newDocumentPath,
newNestedDocumentPath,
searchPath,
documentPath,
urlify,
trashPath,
} from "~/utils/routeHelpers";
export const openDocument = createAction({
@@ -61,23 +80,24 @@ export const openDocument = createAction({
keywords: "go to",
icon: <DocumentIcon />,
children: ({ stores }) => {
const paths = stores.collections.pathsToDocuments;
const nodes = stores.collections.navigationNodes.reduce(
(acc, node) => [...acc, ...node.children],
[] as NavigationNode[]
);
return paths
.filter((path) => path.type === "document")
.map((path) => ({
// Note: using url which includes the slug rather than id here to bust
// cache if the document is renamed
id: path.url,
name: path.title,
icon: function _Icon() {
return stores.documents.get(path.id)?.isStarred ? (
<StarredIcon />
) : null;
},
section: DocumentSection,
perform: () => history.push(path.url),
}));
return nodes.map((item) => ({
// Note: using url which includes the slug rather than id here to bust
// cache if the document is renamed
id: item.url,
name: item.title,
icon: item.icon ? (
<Icon value={item.icon} color={item.color ?? undefined} />
) : (
<DocumentIcon />
),
section: DocumentSection,
perform: () => history.push(item.url),
}));
},
});
@@ -87,11 +107,21 @@ export const createDocument = createAction({
section: DocumentSection,
icon: <NewDocumentIcon />,
keywords: "create",
visible: ({ currentTeamId, stores }) =>
!!currentTeamId && stores.policies.abilities(currentTeamId).createDocument,
perform: ({ activeCollectionId, inStarredSection }) =>
visible: ({ currentTeamId, activeCollectionId, stores }) => {
if (
activeCollectionId &&
!stores.policies.abilities(activeCollectionId).createDocument
) {
return false;
}
return (
!!currentTeamId && stores.policies.abilities(currentTeamId).createDocument
);
},
perform: ({ activeCollectionId, sidebarContext }) =>
history.push(newDocumentPath(activeCollectionId), {
starred: inStarredSection,
sidebarContext,
}),
});
@@ -101,16 +131,35 @@ export const createDocumentFromTemplate = createAction({
section: DocumentSection,
icon: <NewDocumentIcon />,
keywords: "create",
visible: ({ currentTeamId, activeDocumentId, stores }) =>
!!currentTeamId &&
!!activeDocumentId &&
!!stores.documents.get(activeDocumentId)?.template &&
stores.policies.abilities(currentTeamId).createDocument,
perform: ({ activeCollectionId, activeDocumentId, inStarredSection }) =>
visible: ({
currentTeamId,
activeCollectionId,
activeDocumentId,
stores,
}) => {
const document = activeDocumentId
? stores.documents.get(activeDocumentId)
: undefined;
if (
!currentTeamId ||
!document?.isTemplate ||
!!document?.isDraft ||
!!document?.isDeleted
) {
return false;
}
if (activeCollectionId) {
return stores.policies.abilities(activeCollectionId).createDocument;
}
return stores.policies.abilities(currentTeamId).createDocument;
},
perform: ({ activeCollectionId, activeDocumentId, sidebarContext }) =>
history.push(
newDocumentPath(activeCollectionId, { templateId: activeDocumentId }),
{
starred: inStarredSection,
sidebarContext,
}
),
});
@@ -118,7 +167,7 @@ export const createDocumentFromTemplate = createAction({
export const createNestedDocument = createAction({
name: ({ t }) => t("New nested document"),
analyticsName: "New document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <NewDocumentIcon />,
keywords: "create",
visible: ({ currentTeamId, activeDocumentId, stores }) =>
@@ -126,21 +175,16 @@ export const createNestedDocument = createAction({
!!activeDocumentId &&
stores.policies.abilities(currentTeamId).createDocument &&
stores.policies.abilities(activeDocumentId).createChildDocument,
perform: ({ activeCollectionId, activeDocumentId, inStarredSection }) =>
history.push(
newDocumentPath(activeCollectionId, {
parentDocumentId: activeDocumentId,
}),
{
starred: inStarredSection,
}
),
perform: ({ activeDocumentId, sidebarContext }) =>
history.push(newNestedDocumentPath(activeDocumentId), {
sidebarContext,
}),
});
export const starDocument = createAction({
name: ({ t }) => t("Star"),
analyticsName: "Star document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <StarredIcon />,
keywords: "favorite bookmark",
visible: ({ activeDocumentId, stores }) => {
@@ -159,13 +203,14 @@ export const starDocument = createAction({
const document = stores.documents.get(activeDocumentId);
await document?.star();
setPersistedState(getHeaderExpandedKey("starred"), true);
},
});
export const unstarDocument = createAction({
name: ({ t }) => t("Unstar"),
analyticsName: "Unstar document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <UnstarredIcon />,
keywords: "unfavorite unbookmark",
visible: ({ activeDocumentId, stores }) => {
@@ -191,7 +236,7 @@ export const unstarDocument = createAction({
export const publishDocument = createAction({
name: ({ t }) => t("Publish"),
analyticsName: "Publish document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <PublishIcon />,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
@@ -212,7 +257,7 @@ export const publishDocument = createAction({
return;
}
if (document?.collectionId) {
if (document?.collectionId || document?.template) {
await document.save(undefined, {
publish: true,
});
@@ -233,7 +278,7 @@ export const publishDocument = createAction({
export const unpublishDocument = createAction({
name: ({ t }) => t("Unpublish"),
analyticsName: "Unpublish document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <UnpublishIcon />,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
@@ -264,7 +309,7 @@ export const unpublishDocument = createAction({
export const subscribeDocument = createAction({
name: ({ t }) => t("Subscribe"),
analyticsName: "Subscribe to document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <SubscribeIcon />,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
@@ -292,7 +337,7 @@ export const subscribeDocument = createAction({
export const unsubscribeDocument = createAction({
name: ({ t }) => t("Unsubscribe"),
analyticsName: "Unsubscribe from document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <UnsubscribeIcon />,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
@@ -320,29 +365,30 @@ export const unsubscribeDocument = createAction({
});
export const shareDocument = createAction({
name: ({ t }) => t("Share"),
name: ({ t }) => `${t("Permissions")}`,
analyticsName: "Share document",
section: DocumentSection,
icon: <GlobeIcon />,
section: ActiveDocumentSection,
icon: <PadlockIcon />,
visible: ({ stores, activeDocumentId }) => {
const can = stores.policies.abilities(activeDocumentId!);
return can.manageUsers || can.share;
},
perform: async ({ activeDocumentId, stores, currentUserId, t }) => {
if (!activeDocumentId || !currentUserId) {
return;
}
const document = stores.documents.get(activeDocumentId);
const share = stores.shares.getByDocumentId(activeDocumentId);
const sharedParent = stores.shares.getByDocumentParents(activeDocumentId);
if (!document) {
return;
}
stores.dialogs.openModal({
style: { marginBottom: -12 },
title: t("Share this document"),
content: (
<SharePopover
document={document}
share={share}
sharedParent={sharedParent}
onRequestClose={stores.dialogs.closeAllModals}
visible
/>
@@ -354,7 +400,7 @@ export const shareDocument = createAction({
export const downloadDocumentAsHTML = createAction({
name: ({ t }) => t("HTML"),
analyticsName: "Download document as HTML",
section: DocumentSection,
section: ActiveDocumentSection,
keywords: "html export",
icon: <DownloadIcon />,
iconInContextMenu: false,
@@ -373,7 +419,7 @@ export const downloadDocumentAsHTML = createAction({
export const downloadDocumentAsPDF = createAction({
name: ({ t }) => t("PDF"),
analyticsName: "Download document as PDF",
section: DocumentSection,
section: ActiveDocumentSection,
keywords: "export",
icon: <DownloadIcon />,
iconInContextMenu: false,
@@ -397,7 +443,7 @@ export const downloadDocumentAsPDF = createAction({
export const downloadDocumentAsMarkdown = createAction({
name: ({ t }) => t("Markdown"),
analyticsName: "Download document as Markdown",
section: DocumentSection,
section: ActiveDocumentSection,
keywords: "md markdown export",
icon: <DownloadIcon />,
iconInContextMenu: false,
@@ -417,9 +463,11 @@ export const downloadDocument = createAction({
name: ({ t, isContextMenu }) =>
isContextMenu ? t("Download") : t("Download document"),
analyticsName: "Download document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <DownloadIcon />,
keywords: "export",
visible: ({ activeDocumentId, stores }) =>
!!activeDocumentId && stores.policies.abilities(activeDocumentId).download,
children: [
downloadDocumentAsHTML,
downloadDocumentAsPDF,
@@ -429,24 +477,50 @@ export const downloadDocument = createAction({
export const copyDocumentAsMarkdown = createAction({
name: ({ t }) => t("Copy as Markdown"),
section: DocumentSection,
section: ActiveDocumentSection,
keywords: "clipboard",
visible: ({ activeDocumentId }) => !!activeDocumentId,
icon: <MarkdownIcon />,
iconInContextMenu: false,
visible: ({ activeDocumentId, stores }) =>
!!activeDocumentId && stores.policies.abilities(activeDocumentId).download,
perform: ({ stores, activeDocumentId, t }) => {
const document = activeDocumentId
? stores.documents.get(activeDocumentId)
: undefined;
if (document) {
copy(MarkdownHelper.toMarkdown(document));
copy(document.toMarkdown());
toast.success(t("Markdown copied to clipboard"));
}
},
});
export const copyDocumentShareLink = createAction({
name: ({ t }) => t("Copy public link"),
section: ActiveDocumentSection,
keywords: "clipboard share",
icon: <GlobeIcon />,
iconInContextMenu: false,
visible: ({ activeDocumentId, stores }) =>
!!activeDocumentId &&
!!stores.shares.getByDocumentId(activeDocumentId)?.published,
perform: ({ stores, activeDocumentId, t }) => {
if (!activeDocumentId) {
return;
}
const share = stores.shares.getByDocumentId(activeDocumentId);
if (share) {
copy(share.url);
toast.success(t("Link copied to clipboard"));
}
},
});
export const copyDocumentLink = createAction({
name: ({ t }) => t("Copy link"),
section: DocumentSection,
section: ActiveDocumentSection,
keywords: "clipboard",
icon: <CopyIcon />,
iconInContextMenu: false,
visible: ({ activeDocumentId }) => !!activeDocumentId,
perform: ({ stores, activeDocumentId, t }) => {
const document = activeDocumentId
@@ -462,17 +536,17 @@ export const copyDocumentLink = createAction({
export const copyDocument = createAction({
name: ({ t }) => t("Copy"),
analyticsName: "Copy document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <CopyIcon />,
keywords: "clipboard",
children: [copyDocumentLink, copyDocumentAsMarkdown],
children: [copyDocumentLink, copyDocumentShareLink, copyDocumentAsMarkdown],
});
export const duplicateDocument = createAction({
name: ({ t, isContextMenu }) =>
isContextMenu ? t("Duplicate") : t("Duplicate document"),
analyticsName: "Duplicate document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <DuplicateIcon />,
keywords: "copy",
visible: ({ activeDocumentId, stores }) =>
@@ -488,7 +562,7 @@ export const duplicateDocument = createAction({
stores.dialogs.openModal({
title: t("Copy document"),
content: (
<DuplicateDialog
<DocumentCopy
document={document}
onSubmit={(response) => {
stores.dialogs.closeAllModals();
@@ -516,7 +590,7 @@ export const pinDocumentToCollection = createAction({
});
},
analyticsName: "Pin document to collection",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <PinIcon />,
iconInContextMenu: false,
visible: ({ activeCollectionId, activeDocumentId, stores }) => {
@@ -552,7 +626,7 @@ export const pinDocumentToCollection = createAction({
export const pinDocumentToHome = createAction({
name: ({ t }) => t("Pin to home"),
analyticsName: "Pin document to home",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <PinIcon />,
iconInContextMenu: false,
visible: ({ activeDocumentId, currentTeamId, stores }) => {
@@ -584,19 +658,36 @@ export const pinDocumentToHome = createAction({
export const pinDocument = createAction({
name: ({ t }) => t("Pin"),
analyticsName: "Pin document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <PinIcon />,
children: [pinDocumentToCollection, pinDocumentToHome],
});
export const searchInDocument = createAction({
name: ({ t }) => t("Search in document"),
analyticsName: "Search document",
section: ActiveDocumentSection,
icon: <SearchIcon />,
visible: ({ stores, activeDocumentId }) => {
if (!activeDocumentId) {
return false;
}
const document = stores.documents.get(activeDocumentId);
return !!document?.isActive;
},
perform: ({ activeDocumentId }) => {
history.push(searchPath(undefined, { documentId: activeDocumentId }));
},
});
export const printDocument = createAction({
name: ({ t, isContextMenu }) =>
isContextMenu ? t("Print") : t("Print document"),
analyticsName: "Print document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <PrintIcon />,
visible: ({ activeDocumentId }) => !!(activeDocumentId && window.print),
perform: async () => {
perform: () => {
queueMicrotask(window.print);
},
});
@@ -628,37 +719,42 @@ export const importDocument = createAction({
const files = getEventFiles(ev);
const file = files[0];
const document = await documents.import(
file,
activeDocumentId,
activeCollectionId,
{
publish: true,
}
);
history.push(document.url);
try {
const document = await documents.import(
file,
activeDocumentId,
activeCollectionId,
{
publish: true,
}
);
history.push(document.url);
} catch (err) {
toast.error(err.message);
}
};
input.click();
},
});
export const createTemplate = createAction({
export const createTemplateFromDocument = createAction({
name: ({ t }) => t("Templatize"),
analyticsName: "Templatize document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <ShapesIcon />,
keywords: "new create template",
visible: ({ activeCollectionId, activeDocumentId, stores }) => {
if (!activeDocumentId) {
const document = activeDocumentId
? stores.documents.get(activeDocumentId)
: undefined;
if (document?.isTemplate || !document?.isActive) {
return false;
}
const document = stores.documents.get(activeDocumentId);
return !!(
!!activeCollectionId &&
stores.policies.abilities(activeCollectionId).update &&
!document?.isTemplate &&
!document?.isDeleted
stores.policies.abilities(activeCollectionId).updateDocument
);
},
perform: ({ activeDocumentId, stores, t, event }) => {
@@ -667,7 +763,6 @@ export const createTemplate = createAction({
}
event?.preventDefault();
event?.stopPropagation();
stores.dialogs.openModal({
title: t("Create template"),
content: <DocumentTemplatizeDialog documentId={activeDocumentId} />,
@@ -682,14 +777,14 @@ export const openRandomDocument = createAction({
section: DocumentSection,
icon: <ShuffleIcon />,
perform: ({ stores, activeDocumentId }) => {
const documentPaths = stores.collections.pathsToDocuments.filter(
(path) => path.type === "document" && path.id !== activeDocumentId
);
const documentPath =
documentPaths[Math.round(Math.random() * documentPaths.length)];
const nodes = stores.collections.navigationNodes
.reduce((acc, node) => [...acc, ...node.children], [] as NavigationNode[])
.filter((node) => node.id !== activeDocumentId);
if (documentPath) {
history.push(documentPath.url);
const random = nodes[Math.round(Math.random() * nodes.length)];
if (random) {
history.push(random.url);
}
},
});
@@ -706,11 +801,50 @@ export const searchDocumentsForQuery = (searchQuery: string) =>
visible: ({ location }) => location.pathname !== searchPath(),
});
export const moveDocument = createAction({
name: ({ t }) => t("Move"),
analyticsName: "Move document",
export const moveTemplateToWorkspace = createAction({
name: ({ t }) => t("Move to workspace"),
analyticsName: "Move template to workspace",
section: DocumentSection,
icon: <MoveIcon />,
iconInContextMenu: false,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
return false;
}
const document = stores.documents.get(activeDocumentId);
if (!document || !document.template || document.isWorkspaceTemplate) {
return false;
}
return !!stores.policies.abilities(activeDocumentId).move;
},
perform: async ({ activeDocumentId, stores }) => {
if (activeDocumentId) {
const document = stores.documents.get(activeDocumentId);
if (!document) {
return;
}
await document.move({
collectionId: null,
});
}
},
});
export const moveDocumentToCollection = createAction({
name: ({ activeDocumentId, stores, t }) => {
if (!activeDocumentId) {
return t("Move");
}
const document = stores.documents.get(activeDocumentId);
return document?.template && document?.collectionId
? t("Move to collection")
: t("Move");
},
analyticsName: "Move document",
section: ActiveDocumentSection,
icon: <MoveIcon />,
iconInContextMenu: false,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
return false;
@@ -734,10 +868,48 @@ export const moveDocument = createAction({
},
});
export const moveDocument = createAction({
name: ({ t }) => t("Move"),
analyticsName: "Move document",
section: ActiveDocumentSection,
icon: <MoveIcon />,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
return false;
}
const document = stores.documents.get(activeDocumentId);
// Don't show the button if this is a non-workspace template.
if (!document || (document.template && !document.isWorkspaceTemplate)) {
return false;
}
return !!stores.policies.abilities(activeDocumentId).move;
},
perform: moveDocumentToCollection.perform,
});
export const moveTemplate = createAction({
name: ({ t }) => t("Move"),
analyticsName: "Move document",
section: ActiveDocumentSection,
icon: <MoveIcon />,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
return false;
}
const document = stores.documents.get(activeDocumentId);
// Don't show the menu if this is not a template (or) a workspace template.
if (!document || !document.template || document.isWorkspaceTemplate) {
return false;
}
return !!stores.policies.abilities(activeDocumentId).move;
},
children: [moveTemplateToWorkspace, moveDocumentToCollection],
});
export const archiveDocument = createAction({
name: ({ t }) => t("Archive"),
name: ({ t }) => `${t("Archive")}`,
analyticsName: "Archive document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <ArchiveIcon />,
visible: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
@@ -746,14 +918,30 @@ export const archiveDocument = createAction({
return !!stores.policies.abilities(activeDocumentId).archive;
},
perform: async ({ activeDocumentId, stores, t }) => {
const { dialogs, documents } = stores;
if (activeDocumentId) {
const document = stores.documents.get(activeDocumentId);
const document = documents.get(activeDocumentId);
if (!document) {
return;
}
await document.archive();
toast.success(t("Document archived"));
dialogs.openModal({
title: t("Are you sure you want to archive this document?"),
content: (
<ConfirmationDialog
onSubmit={async () => {
await document.archive();
toast.success(t("Document archived"));
}}
savingText={`${t("Archiving")}`}
>
{t(
"Archiving this document will remove it from the collection and search results."
)}
</ConfirmationDialog>
),
});
}
},
});
@@ -761,7 +949,7 @@ export const archiveDocument = createAction({
export const deleteDocument = createAction({
name: ({ t }) => `${t("Delete")}`,
analyticsName: "Delete document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <TrashIcon />,
dangerous: true,
visible: ({ activeDocumentId, stores }) => {
@@ -795,7 +983,7 @@ export const deleteDocument = createAction({
export const permanentlyDeleteDocument = createAction({
name: ({ t }) => t("Permanently delete"),
analyticsName: "Permanently delete document",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <CrossIcon />,
dangerous: true,
visible: ({ activeDocumentId, stores }) => {
@@ -826,10 +1014,31 @@ export const permanentlyDeleteDocument = createAction({
},
});
export const permanentlyDeleteDocumentsInTrash = createAction({
name: ({ t }) => t("Empty trash"),
analyticsName: "Empty trash",
section: TrashSection,
icon: <TrashIcon />,
dangerous: true,
visible: ({ stores }) =>
stores.documents.deleted.length > 0 && !!stores.auth.user?.isAdmin,
perform: ({ stores, t, location }) => {
stores.dialogs.openModal({
title: t("Permanently delete documents in trash"),
content: (
<DeleteDocumentsInTrash
onSubmit={stores.dialogs.closeAllModals}
shouldRedirect={location.pathname === trashPath()}
/>
),
});
},
});
export const openDocumentComments = createAction({
name: ({ t }) => t("Comments"),
analyticsName: "Open comments",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <CommentIcon />,
visible: ({ activeDocumentId, stores }) => {
const can = stores.policies.abilities(activeDocumentId ?? "");
@@ -844,18 +1053,18 @@ export const openDocumentComments = createAction({
return;
}
stores.ui.toggleComments(activeDocumentId);
stores.ui.toggleComments();
},
});
export const openDocumentHistory = createAction({
name: ({ t }) => t("History"),
analyticsName: "Open document history",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <HistoryIcon />,
visible: ({ activeDocumentId, stores }) => {
const can = stores.policies.abilities(activeDocumentId ?? "");
return !!activeDocumentId && can.read && !can.restore;
return !!activeDocumentId && can.listRevisions;
},
perform: ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
@@ -872,7 +1081,7 @@ export const openDocumentHistory = createAction({
export const openDocumentInsights = createAction({
name: ({ t }) => t("Insights"),
analyticsName: "Open document insights",
section: DocumentSection,
section: ActiveDocumentSection,
icon: <GraphIcon />,
visible: ({ activeDocumentId, stores }) => {
const can = stores.policies.abilities(activeDocumentId ?? "");
@@ -882,7 +1091,7 @@ export const openDocumentInsights = createAction({
return (
!!activeDocumentId &&
can.read &&
can.listViews &&
!document?.isTemplate &&
!document?.isDeleted
);
@@ -899,15 +1108,83 @@ export const openDocumentInsights = createAction({
},
});
export const toggleViewerInsights = createAction({
name: ({ t, stores, activeDocumentId }) => {
const document = activeDocumentId
? stores.documents.get(activeDocumentId)
: undefined;
return document?.insightsEnabled
? t("Disable viewer insights")
: t("Enable viewer insights");
},
analyticsName: "Toggle viewer insights",
section: ActiveDocumentSection,
icon: <EyeIcon />,
visible: ({ activeDocumentId, stores }) => {
const can = stores.policies.abilities(activeDocumentId ?? "");
return can.updateInsights;
},
perform: async ({ activeDocumentId, stores }) => {
if (!activeDocumentId) {
return;
}
const document = stores.documents.get(activeDocumentId);
if (!document) {
return;
}
await document.save({
insightsEnabled: !document.insightsEnabled,
});
},
});
export const leaveDocument = createAction({
name: ({ t }) => t("Leave document"),
analyticsName: "Leave document",
section: ActiveDocumentSection,
icon: <LogoutIcon />,
visible: ({ currentUserId, activeDocumentId, stores }) => {
const membership = stores.userMemberships.orderedData.find(
(m) => m.documentId === activeDocumentId && m.userId === currentUserId
);
return !!membership;
},
perform: async ({ t, location, currentUserId, activeDocumentId, stores }) => {
if (!activeDocumentId) {
return;
}
const document = stores.documents.get(activeDocumentId);
try {
if (document && location.pathname.startsWith(document.path)) {
history.push(homePath());
}
await stores.userMemberships.delete({
documentId: activeDocumentId,
userId: currentUserId,
} as UserMembership);
toast.success(t("You have left the shared document"));
} catch (err) {
toast.error(t("Could not leave document"));
}
},
});
export const rootDocumentActions = [
openDocument,
archiveDocument,
createDocument,
createTemplate,
createTemplateFromDocument,
deleteDocument,
importDocument,
downloadDocument,
copyDocumentLink,
copyDocumentShareLink,
copyDocumentAsMarkdown,
starDocument,
unstarDocument,
@@ -916,9 +1193,12 @@ export const rootDocumentActions = [
subscribeDocument,
unsubscribeDocument,
duplicateDocument,
moveDocument,
leaveDocument,
moveTemplateToWorkspace,
moveDocumentToCollection,
openRandomDocument,
permanentlyDeleteDocument,
permanentlyDeleteDocumentsInTrash,
printDocument,
pinDocumentToCollection,
pinDocumentToHome,
+33 -18
View File
@@ -3,7 +3,6 @@ import {
SearchIcon,
ArchiveIcon,
TrashIcon,
EditIcon,
OpenIcon,
SettingsIcon,
KeyboardIcon,
@@ -12,15 +11,11 @@ import {
ProfileIcon,
BrowserIcon,
ShapesIcon,
DraftsIcon,
} from "outline-icons";
import * as React from "react";
import { UrlHelper } from "@shared/utils/UrlHelper";
import { isMac } from "@shared/utils/browser";
import {
developersUrl,
changelogUrl,
feedbackUrl,
githubIssuesUrl,
} from "@shared/utils/urlHelpers";
import stores from "~/stores";
import SearchQuery from "~/models/SearchQuery";
import KeyboardShortcuts from "~/scenes/KeyboardShortcuts";
@@ -62,7 +57,7 @@ export const navigateToDrafts = createAction({
name: ({ t }) => t("Drafts"),
analyticsName: "Navigate to drafts",
section: NavigationSection,
icon: <EditIcon />,
icon: <DraftsIcon />,
perform: () => history.push(draftsPath()),
visible: ({ location }) => location.pathname !== draftsPath(),
});
@@ -92,11 +87,19 @@ export const navigateToSettings = createAction({
section: NavigationSection,
shortcut: ["g", "s"],
icon: <SettingsIcon />,
visible: ({ stores }) =>
stores.policies.abilities(stores.auth.team?.id || "").update,
visible: () => stores.policies.abilities(stores.auth.team?.id || "").update,
perform: () => history.push(settingsPath()),
});
export const navigateToWorkspaceSettings = createAction({
name: ({ t }) => t("Settings"),
analyticsName: "Navigate to workspace settings",
section: NavigationSection,
icon: <SettingsIcon />,
visible: () => stores.policies.abilities(stores.auth.team?.id || "").update,
perform: () => history.push(settingsPath("details")),
});
export const navigateToProfileSettings = createAction({
name: ({ t }) => t("Profile"),
analyticsName: "Navigate to profile settings",
@@ -133,13 +136,22 @@ export const navigateToAccountPreferences = createAction({
perform: () => history.push(settingsPath("preferences")),
});
export const openDocumentation = createAction({
name: ({ t }) => t("Documentation"),
analyticsName: "Open documentation",
section: NavigationSection,
iconInContextMenu: false,
icon: <OpenIcon />,
perform: () => window.open(UrlHelper.guide),
});
export const openAPIDocumentation = createAction({
name: ({ t }) => t("API documentation"),
analyticsName: "Open API documentation",
section: NavigationSection,
iconInContextMenu: false,
icon: <OpenIcon />,
perform: () => window.open(developersUrl()),
perform: () => window.open(UrlHelper.developers),
});
export const toggleSidebar = createAction({
@@ -147,7 +159,7 @@ export const toggleSidebar = createAction({
analyticsName: "Toggle sidebar",
keywords: "hide show navigation",
section: NavigationSection,
perform: ({ stores }) => stores.ui.toggleCollapsedSidebar(),
perform: () => stores.ui.toggleCollapsedSidebar(),
});
export const openFeedbackUrl = createAction({
@@ -156,14 +168,14 @@ export const openFeedbackUrl = createAction({
section: NavigationSection,
iconInContextMenu: false,
icon: <EmailIcon />,
perform: () => window.open(feedbackUrl()),
perform: () => window.open(UrlHelper.contact),
});
export const openBugReportUrl = createAction({
name: ({ t }) => t("Report a bug"),
analyticsName: "Open bug report",
section: NavigationSection,
perform: () => window.open(githubIssuesUrl()),
perform: () => window.open(UrlHelper.github),
});
export const openChangelog = createAction({
@@ -172,7 +184,7 @@ export const openChangelog = createAction({
section: NavigationSection,
iconInContextMenu: false,
icon: <OpenIcon />,
perform: () => window.open(changelogUrl()),
perform: () => window.open(UrlHelper.changelog),
});
export const openKeyboardShortcuts = createAction({
@@ -210,10 +222,12 @@ export const logout = createAction({
analyticsName: "Log out",
section: NavigationSection,
icon: <LogoutIcon />,
perform: () => {
void stores.auth.logout();
perform: async () => {
await stores.auth.logout();
if (env.OIDC_LOGOUT_URI) {
window.location.replace(env.OIDC_LOGOUT_URI);
setTimeout(() => {
window.location.replace(env.OIDC_LOGOUT_URI);
}, 200);
}
},
});
@@ -224,6 +238,7 @@ export const rootNavigationActions = [
navigateToArchive,
navigateToTrash,
downloadApp,
openDocumentation,
openAPIDocumentation,
openFeedbackUrl,
openBugReportUrl,
+15 -2
View File
@@ -1,4 +1,4 @@
import { MarkAsReadIcon } from "outline-icons";
import { ArchiveIcon, MarkAsReadIcon } from "outline-icons";
import * as React from "react";
import { createAction } from "..";
import { NotificationSection } from "../sections";
@@ -13,4 +13,17 @@ export const markNotificationsAsRead = createAction({
visible: ({ stores }) => stores.notifications.approximateUnreadCount > 0,
});
export const rootNotificationActions = [markNotificationsAsRead];
export const markNotificationsAsArchived = createAction({
name: ({ t }) => t("Archive all notifications"),
analyticsName: "Mark notifications as archived",
section: NotificationSection,
icon: <ArchiveIcon />,
iconInContextMenu: false,
perform: ({ stores }) => stores.notifications.markAllAsArchived(),
visible: ({ stores }) => stores.notifications.orderedData.length > 0,
});
export const rootNotificationActions = [
markNotificationsAsRead,
markNotificationsAsArchived,
];
+2 -2
View File
@@ -17,7 +17,7 @@ export const restoreRevision = createAction({
analyticsName: "Restore revision",
icon: <RestoreIcon />,
section: RevisionSection,
visible: ({ activeDocumentId, stores }) =>
visible: ({ activeDocumentId }) =>
!!activeDocumentId && stores.policies.abilities(activeDocumentId).update,
perform: async ({ event, location, activeDocumentId }) => {
event?.preventDefault();
@@ -47,7 +47,7 @@ export const copyLinkToRevision = createAction({
analyticsName: "Copy link to revision",
icon: <LinkIcon />,
section: RevisionSection,
perform: async ({ activeDocumentId, stores, t }) => {
perform: async ({ activeDocumentId, t }) => {
if (!activeDocumentId) {
return;
}
+22 -2
View File
@@ -1,12 +1,14 @@
import { PlusIcon } from "outline-icons";
import { ArrowIcon, PlusIcon } from "outline-icons";
import * as React from "react";
import styled from "styled-components";
import { stringToColor } from "@shared/utils/color";
import RootStore from "~/stores/RootStore";
import { LoginDialog } from "~/scenes/Login/components/LoginDialog";
import TeamNew from "~/scenes/TeamNew";
import TeamLogo from "~/components/TeamLogo";
import { createAction } from "~/actions";
import { ActionContext } from "~/types";
import Desktop from "~/utils/Desktop";
import { TeamSection } from "../sections";
export const createTeamsList = ({ stores }: { stores: RootStore }) =>
@@ -66,9 +68,27 @@ export const createTeam = createAction({
},
});
export const desktopLoginTeam = createAction({
name: ({ t }) => t("Login to workspace"),
analyticsName: "Login to workspace",
keywords: "change switch workspace organization team",
section: TeamSection,
icon: <ArrowIcon />,
visible: () => Desktop.isElectron(),
perform: ({ t, event, stores }) => {
event?.preventDefault();
event?.stopPropagation();
stores.dialogs.openModal({
title: t("Login to workspace"),
content: <LoginDialog />,
});
},
});
const StyledTeamLogo = styled(TeamLogo)`
border-radius: 2px;
border: 0;
`;
export const rootTeamActions = [switchTeam, createTeam];
export const rootTeamActions = [switchTeam, createTeam, desktopLoginTeam];
+45 -5
View File
@@ -1,8 +1,14 @@
import { PlusIcon } from "outline-icons";
import * as React from "react";
import { UserRole } from "@shared/types";
import { UserRoleHelper } from "@shared/utils/UserRoleHelper";
import stores from "~/stores";
import User from "~/models/User";
import Invite from "~/scenes/Invite";
import { UserDeleteDialog } from "~/components/UserDialogs";
import {
UserChangeRoleDialog,
UserDeleteDialog,
} from "~/components/UserDialogs";
import { createAction } from "~/actions";
import { UserSection } from "~/actions/sections";
@@ -12,17 +18,51 @@ export const inviteUser = createAction({
icon: <PlusIcon />,
keywords: "team member workspace user",
section: UserSection,
visible: ({ stores }) =>
visible: () =>
stores.policies.abilities(stores.auth.team?.id || "").inviteUser,
perform: ({ t }) => {
stores.dialogs.openModal({
title: t("Invite people"),
fullscreen: true,
title: t("Invite to workspace"),
content: <Invite onSubmit={stores.dialogs.closeAllModals} />,
});
},
});
export const updateUserRoleActionFactory = (user: User, role: UserRole) =>
createAction({
name: ({ t }) =>
UserRoleHelper.isRoleHigher(role, user!.role)
? `${t("Promote to {{ role }}", {
role: UserRoleHelper.displayName(role, t),
})}…`
: `${t("Demote to {{ role }}", {
role: UserRoleHelper.displayName(role, t),
})}…`,
analyticsName: "Update user role",
section: UserSection,
visible: () => {
const can = stores.policies.abilities(user.id);
return UserRoleHelper.isRoleHigher(role, user.role)
? can.promote
: UserRoleHelper.isRoleLower(role, user.role)
? can.demote
: false;
},
perform: ({ t }) => {
stores.dialogs.openModal({
title: t("Update role"),
content: (
<UserChangeRoleDialog
user={user}
role={role}
onSubmit={stores.dialogs.closeAllModals}
/>
),
});
},
});
export const deleteUserActionFactory = (userId: string) =>
createAction({
name: ({ t }) => `${t("Delete user")}`,
@@ -30,7 +70,7 @@ export const deleteUserActionFactory = (userId: string) =>
keywords: "leave",
dangerous: true,
section: UserSection,
visible: ({ stores }) => stores.policies.abilities(userId).delete,
visible: () => stores.policies.abilities(userId).delete,
perform: ({ t }) => {
const user = stores.users.get(userId);
if (!user) {
+6
View File
@@ -98,6 +98,11 @@ export function actionToKBar(
)
: [];
const sectionPriority =
typeof action.section !== "string" && "priority" in action.section
? (action.section.priority as number) ?? 0
: 0;
return [
{
id: action.id,
@@ -108,6 +113,7 @@ export function actionToKBar(
keywords: action.keywords ?? "",
shortcut: action.shortcut || [],
icon: resolvedIcon,
priority: (1 + (action.priority ?? 0)) * (1 + (sectionPriority ?? 0)),
perform: action.perform
? () => performAction(action, context)
: undefined,
+26
View File
@@ -2,10 +2,30 @@ import { ActionContext } from "~/types";
export const CollectionSection = ({ t }: ActionContext) => t("Collection");
export const ActiveCollectionSection = ({ t, stores }: ActionContext) => {
const activeCollection = stores.collections.active;
return `${t("Collection")} · ${activeCollection?.name}`;
};
ActiveCollectionSection.priority = 0.8;
export const DeveloperSection = ({ t }: ActionContext) => t("Debug");
export const DocumentSection = ({ t }: ActionContext) => t("Document");
export const DocumentsSection = ({ t }: ActionContext) => t("Documents");
export const ActiveDocumentSection = ({ t, stores }: ActionContext) => {
const activeDocument = stores.documents.active;
return `${t("Document")} · ${activeDocument?.titleWithDefault}`;
};
ActiveDocumentSection.priority = 0.9;
export const RecentSection = ({ t }: ActionContext) => t("Recently viewed");
RecentSection.priority = 1;
export const RevisionSection = ({ t }: ActionContext) => t("Revision");
export const SettingsSection = ({ t }: ActionContext) => t("Settings");
@@ -16,7 +36,13 @@ export const NotificationSection = ({ t }: ActionContext) => t("Notification");
export const UserSection = ({ t }: ActionContext) => t("People");
UserSection.priority = 0.5;
export const TeamSection = ({ t }: ActionContext) => t("Workspace");
export const RecentSearchesSection = ({ t }: ActionContext) =>
t("Recent searches");
RecentSearchesSection.priority = -0.1;
export const TrashSection = ({ t }: ActionContext) => t("Trash");
-1
View File
@@ -31,7 +31,6 @@ const Actions = styled(Flex)`
left: 0;
border-radius: 3px;
background: ${s("background")};
transition: ${s("backgroundTransition")};
padding: 12px;
backdrop-filter: blur(20px);
+53 -4
View File
@@ -2,13 +2,14 @@
/* global ga */
import escape from "lodash/escape";
import * as React from "react";
import { IntegrationService } from "@shared/types";
import { IntegrationService, PublicEnv } from "@shared/types";
import env from "~/env";
type Props = {
children?: React.ReactNode;
};
// TODO: Refactor this component to allow injection from plugins
const Analytics: React.FC = ({ children }: Props) => {
// Google Analytics 3
React.useEffect(() => {
@@ -43,12 +44,16 @@ const Analytics: React.FC = ({ children }: Props) => {
React.useEffect(() => {
const measurementIds = [];
if (env.analytics.service === IntegrationService.GoogleAnalytics) {
measurementIds.push(escape(env.analytics.settings?.measurementId));
}
if (env.GOOGLE_ANALYTICS_ID?.startsWith("G-")) {
measurementIds.push(env.GOOGLE_ANALYTICS_ID);
}
(env.analytics as PublicEnv["analytics"]).forEach((integration) => {
if (integration.service === IntegrationService.GoogleAnalytics) {
measurementIds.push(escape(integration.settings?.measurementId));
}
});
if (measurementIds.length === 0) {
return;
}
@@ -75,6 +80,50 @@ const Analytics: React.FC = ({ children }: Props) => {
document.getElementsByTagName("head")[0]?.appendChild(script);
}, []);
// Matomo
React.useEffect(() => {
(env.analytics as PublicEnv["analytics"]).forEach((integration) => {
if (integration.service !== IntegrationService.Matomo) {
return;
}
// @ts-expect-error - Matomo global variable
const _paq = (window._paq = window._paq || []);
_paq.push(["trackPageView"]);
_paq.push(["enableLinkTracking"]);
(function () {
const u = integration.settings?.instanceUrl;
_paq.push(["setTrackerUrl", u + "matomo.php"]);
_paq.push(["setSiteId", integration.settings?.measurementId]);
const d = document,
g = d.createElement("script"),
s = d.getElementsByTagName("script")[0];
g.type = "text/javascript";
g.async = true;
g.src = u + "matomo.js";
s.parentNode?.insertBefore(g, s);
})();
});
}, []);
// Umami
React.useEffect(() => {
(env.analytics as PublicEnv["analytics"]).forEach((integration) => {
if (integration.service !== IntegrationService.Umami) {
return;
}
const script = document.createElement("script");
script.defer = true;
script.src = `${integration.settings?.instanceUrl}${integration.settings?.scriptName}`;
script.setAttribute(
"data-website-id",
integration.settings?.measurementId
);
document.getElementsByTagName("head")[0]?.appendChild(script);
});
}, []);
return <>{children}</>;
};
+17 -21
View File
@@ -1,54 +1,50 @@
import { RovingTabIndexProvider } from "@getoutline/react-roving-tabindex";
import { observer } from "mobx-react";
import * as React from "react";
import {
useCompositeState,
Composite,
CompositeStateReturn,
} from "reakit/Composite";
type Props = React.HTMLAttributes<HTMLDivElement> & {
children: (composite: CompositeStateReturn) => React.ReactNode;
children: () => React.ReactNode;
onEscape?: (ev: React.KeyboardEvent<HTMLDivElement>) => void;
items: unknown[];
};
function ArrowKeyNavigation(
{ children, onEscape, ...rest }: Props,
{ children, onEscape, items, ...rest }: Props,
ref: React.RefObject<HTMLDivElement>
) {
const composite = useCompositeState();
const handleKeyDown = React.useCallback(
(ev) => {
(ev: React.KeyboardEvent<HTMLDivElement>) => {
if (onEscape) {
if (ev.nativeEvent.isComposing) {
return;
}
if (ev.key === "Escape") {
if (ev.key === "Escape" || ev.key === "Backspace") {
ev.preventDefault();
onEscape(ev);
}
if (
ev.key === "ArrowUp" &&
composite.currentId === composite.items[0].id
// If the first item is focused and the user presses ArrowUp
ev.currentTarget.firstElementChild === document.activeElement
) {
onEscape(ev);
}
}
},
[composite.currentId, composite.items, onEscape]
[onEscape]
);
return (
<Composite
{...rest}
{...composite}
onKeyDown={handleKeyDown}
role="menu"
ref={ref}
<RovingTabIndexProvider
options={{ focusOnClick: true, direction: "both" }}
items={items}
>
{children(composite)}
</Composite>
<div {...rest} onKeyDown={handleKeyDown} ref={ref}>
{children()}
</div>
</RovingTabIndexProvider>
);
}
+2 -1
View File
@@ -5,6 +5,7 @@ import { Redirect } from "react-router-dom";
import useCurrentUser from "~/hooks/useCurrentUser";
import useStores from "~/hooks/useStores";
import { changeLanguage } from "~/utils/language";
import { logoutPath } from "~/utils/routeHelpers";
import LoadingIndicator from "./LoadingIndicator";
type Props = {
@@ -32,7 +33,7 @@ const Authenticated = ({ children }: Props) => {
}
void auth.logout(true);
return <Redirect to="/" />;
return <Redirect to={logoutPath()} />;
};
export default observer(Authenticated);
+17 -21
View File
@@ -1,17 +1,14 @@
import { AnimatePresence } from "framer-motion";
import { observer, useLocalStore } from "mobx-react";
import { observer } from "mobx-react";
import * as React from "react";
import { Switch, Route, useLocation, matchPath } from "react-router-dom";
import { TeamPreference } from "@shared/types";
import ErrorSuspended from "~/scenes/ErrorSuspended";
import DocumentContext from "~/components/DocumentContext";
import type { DocumentContextValue } from "~/components/DocumentContext";
import Layout from "~/components/Layout";
import RegisterKeyDown from "~/components/RegisterKeyDown";
import Sidebar from "~/components/Sidebar";
import SidebarRight from "~/components/Sidebar/Right";
import SettingsSidebar from "~/components/Sidebar/Settings";
import type { Editor as TEditor } from "~/editor";
import useCurrentTeam from "~/hooks/useCurrentTeam";
import usePolicy from "~/hooks/usePolicy";
import useStores from "~/hooks/useStores";
@@ -25,6 +22,7 @@ import {
matchDocumentSlug as slug,
matchDocumentInsights,
} from "~/utils/routeHelpers";
import { DocumentContextProvider } from "./DocumentContext";
import Fade from "./Fade";
import { PortalContext } from "./Portal";
@@ -47,14 +45,9 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => {
const { ui, auth } = useStores();
const location = useLocation();
const layoutRef = React.useRef<HTMLDivElement>(null);
const can = usePolicy(ui.activeCollectionId);
const can = usePolicy(ui.activeDocumentId);
const canCollection = usePolicy(ui.activeCollectionId);
const team = useCurrentTeam();
const documentContext = useLocalStore<DocumentContextValue>(() => ({
editor: null,
setEditor: (editor: TEditor) => {
documentContext.editor = editor;
},
}));
const goToSearch = (ev: KeyboardEvent) => {
if (!ev.metaKey && !ev.ctrlKey) {
@@ -69,7 +62,7 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => {
return;
}
const { activeCollectionId } = ui;
if (!activeCollectionId || !can.createDocument) {
if (!activeCollectionId || !canCollection.createDocument) {
return;
}
history.push(newDocumentPath(activeCollectionId));
@@ -88,17 +81,20 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => {
</Fade>
);
const showHistory = !!matchPath(location.pathname, {
path: matchDocumentHistory,
});
const showInsights = !!matchPath(location.pathname, {
path: matchDocumentInsights,
});
const showHistory =
!!matchPath(location.pathname, {
path: matchDocumentHistory,
}) && can.listRevisions;
const showInsights =
!!matchPath(location.pathname, {
path: matchDocumentInsights,
}) && can.listViews;
const showComments =
!showInsights &&
!showHistory &&
can.comment &&
ui.activeDocumentId &&
ui.commentsExpanded.includes(ui.activeDocumentId) &&
ui.commentsExpanded &&
team.getPreference(TeamPreference.Commenting);
const sidebarRight = (
@@ -121,7 +117,7 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => {
);
return (
<DocumentContext.Provider value={documentContext}>
<DocumentContextProvider>
<PortalContext.Provider value={layoutRef.current}>
<Layout
title={team.name}
@@ -138,7 +134,7 @@ const AuthenticatedLayout: React.FC = ({ children }: Props) => {
</React.Suspense>
</Layout>
</PortalContext.Provider>
</DocumentContext.Provider>
</DocumentContextProvider>
);
};
+1 -1
View File
@@ -4,8 +4,8 @@ import { useTranslation } from "react-i18next";
import styled, { css } from "styled-components";
import { s } from "@shared/styles";
import User from "~/models/User";
import Avatar from "~/components/Avatar";
import Tooltip from "~/components/Tooltip";
import Avatar from "./Avatar";
type Props = {
user: User;
+35
View File
@@ -0,0 +1,35 @@
import { GroupIcon } from "outline-icons";
import * as React from "react";
import { useTheme } from "styled-components";
import Squircle from "@shared/components/Squircle";
import Group from "~/models/Group";
import { AvatarSize } from "../Avatar/Avatar";
type Props = {
/** The group to show an avatar for */
group: Group;
/** The size of the icon, 24px is default to match standard avatars */
size?: number;
/** The color of the avatar */
color?: string;
/** The background color of the avatar */
backgroundColor?: string;
className?: string;
};
export function GroupAvatar({
color,
backgroundColor,
size = AvatarSize.Medium,
className,
}: Props) {
const theme = useTheme();
return (
<Squircle color={color ?? theme.text} size={size} className={className}>
<GroupIcon
color={backgroundColor ?? theme.background}
size={size * 0.75}
/>
</Squircle>
);
}
+2 -1
View File
@@ -1,4 +1,5 @@
import styled from "styled-components";
import { s } from "@shared/styles";
import Flex from "~/components/Flex";
const Initials = styled(Flex)<{
@@ -11,7 +12,7 @@ const Initials = styled(Flex)<{
border-radius: 50%;
width: 100%;
height: 100%;
color: #fff;
color: ${s("white75")};
background-color: ${(props) => props.color};
width: ${(props) => props.size}px;
height: ${(props) => props.size}px;
+4 -3
View File
@@ -1,6 +1,7 @@
import Avatar from "./Avatar";
import Avatar, { IAvatar, AvatarSize } from "./Avatar";
import AvatarWithPresence from "./AvatarWithPresence";
import { GroupAvatar } from "./GroupAvatar";
export { AvatarWithPresence };
export { Avatar, GroupAvatar, AvatarSize, AvatarWithPresence };
export default Avatar;
export type { IAvatar };
+15 -12
View File
@@ -8,18 +8,16 @@ import BreadcrumbMenu from "~/menus/BreadcrumbMenu";
import { undraggableOnDesktop } from "~/styles";
import { MenuInternalLink } from "~/types";
type Props = {
type Props = React.PropsWithChildren<{
items: MenuInternalLink[];
max?: number;
highlightFirstItem?: boolean;
};
}>;
function Breadcrumb({
items,
highlightFirstItem,
children,
max = 2,
}: React.PropsWithChildren<Props>) {
function Breadcrumb(
{ items, highlightFirstItem, children, max = 2 }: Props,
ref: React.RefObject<HTMLDivElement> | null
) {
const totalItems = items.length;
const topLevelItems: MenuInternalLink[] = [...items];
let overflowItems;
@@ -37,9 +35,13 @@ function Breadcrumb({
}
return (
<Flex justify="flex-start" align="center">
<Flex justify="flex-start" align="center" ref={ref}>
{topLevelItems.map((item, index) => (
<React.Fragment key={String(item.to) || index}>
<React.Fragment
key={
(typeof item.to === "string" ? item.to : item.to.pathname) || index
}
>
{item.icon}
{item.to ? (
<Item
@@ -67,6 +69,8 @@ const Slash = styled(GoToIcon)`
const Item = styled(Link)<{ $highlight: boolean; $withIcon: boolean }>`
${ellipsis()}
${undraggableOnDesktop()}
display: flex;
flex-shrink: 1;
min-width: 0;
@@ -76,7 +80,6 @@ const Item = styled(Link)<{ $highlight: boolean; $withIcon: boolean }>`
height: 24px;
font-weight: ${(props) => (props.$highlight ? "500" : "inherit")};
margin-left: ${(props) => (props.$withIcon ? "4px" : "0")};
${undraggableOnDesktop()}
svg {
flex-shrink: 0;
@@ -87,4 +90,4 @@ const Item = styled(Link)<{ $highlight: boolean; $withIcon: boolean }>`
}
`;
export default Breadcrumb;
export default React.forwardRef<HTMLDivElement, Props>(Breadcrumb);
+10 -6
View File
@@ -1,5 +1,5 @@
import { LocationDescriptor } from "history";
import { ExpandedIcon } from "outline-icons";
import { DisclosureIcon } from "outline-icons";
import { darken, lighten, transparentize } from "polished";
import * as React from "react";
import styled from "styled-components";
@@ -25,7 +25,7 @@ const RealButton = styled(ActionButton)<RealProps>`
background: ${s("accent")};
color: ${s("accentText")};
box-shadow: rgba(0, 0, 0, 0.2) 0px 1px 2px;
border-radius: 4px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
height: 32px;
@@ -49,8 +49,8 @@ const RealButton = styled(ActionButton)<RealProps>`
&:disabled {
cursor: default;
pointer-events: none;
color: ${(props) => transparentize(0.5, props.theme.accentText)};
background: ${(props) => lighten(0.2, props.theme.accent)};
color: ${(props) => transparentize(0.3, props.theme.accentText)};
background: ${(props) => transparentize(0.1, props.theme.accent)};
svg {
fill: ${(props) => props.theme.white50};
@@ -105,7 +105,7 @@ const RealButton = styled(ActionButton)<RealProps>`
background: ${lighten(0.05, props.theme.danger)};
}
&.focus-visible {
&:focus-visible {
outline-color: ${darken(0.2, props.theme.danger)} !important;
}
`};
@@ -189,10 +189,14 @@ const Button = <T extends React.ElementType = "button">(
<Inner hasIcon={hasIcon} hasText={hasText} disclosure={disclosure}>
{hasIcon && ic}
{hasText && <Label hasIcon={hasIcon}>{children || value}</Label>}
{disclosure && <ExpandedIcon />}
{disclosure && <StyledDisclosureIcon />}
</Inner>
</RealButton>
);
};
const StyledDisclosureIcon = styled(DisclosureIcon)`
opacity: 0.8;
`;
export default React.forwardRef(Button);
+25 -10
View File
@@ -1,13 +1,13 @@
import filter from "lodash/filter";
import isEqual from "lodash/isEqual";
import sortBy from "lodash/sortBy";
import orderBy from "lodash/orderBy";
import uniq from "lodash/uniq";
import { observer } from "mobx-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { usePopoverState, PopoverDisclosure } from "reakit/Popover";
import Document from "~/models/Document";
import AvatarWithPresence from "~/components/Avatar/AvatarWithPresence";
import { AvatarWithPresence } from "~/components/Avatar";
import DocumentViews from "~/components/DocumentViews";
import Facepile from "~/components/Facepile";
import NudeButton from "~/components/NudeButton";
@@ -16,10 +16,18 @@ import useCurrentUser from "~/hooks/useCurrentUser";
import useStores from "~/hooks/useStores";
type Props = {
/** The document to display live collaborators for */
document: Document;
/** The maximum number of collaborators to display, defaults to 6 */
limit?: number;
};
/**
* Displays a list of live collaborators for a document, including their avatars
* and presence status.
*/
function Collaborators(props: Props) {
const { limit = 6 } = props;
const { t } = useTranslation();
const user = useCurrentUser();
const currentUserId = user?.id;
@@ -39,15 +47,16 @@ function Collaborators(props: Props) {
// ensure currently present via websocket are always ordered first
const collaborators = React.useMemo(
() =>
sortBy(
orderBy(
filter(
users.orderedData,
(user) =>
(presentIds.includes(user.id) ||
document.collaboratorIds.includes(user.id)) &&
!user.isSuspended
(u) =>
(presentIds.includes(u.id) ||
document.collaboratorIds.includes(u.id)) &&
!u.isSuspended
),
(user) => presentIds.includes(user.id)
[(u) => presentIds.includes(u.id), "id"],
["asc", "asc"]
),
[document.collaboratorIds, users.orderedData, presentIds]
);
@@ -72,9 +81,15 @@ function Collaborators(props: Props) {
return (
<>
<PopoverDisclosure {...popover}>
{(props) => (
<NudeButton width={collaborators.length * 32} height={32} {...props}>
{(popoverProps) => (
<NudeButton
width={Math.min(collaborators.length, limit) * 32}
height={32}
{...popoverProps}
>
<Facepile
limit={limit}
overflow={collaborators.length - limit}
users={collaborators}
renderAvatar={(collaborator) => {
const isPresent = presentIds.includes(collaborator.id);
+41 -19
View File
@@ -3,26 +3,29 @@ import * as React from "react";
import { Controller, useForm } from "react-hook-form";
import { Trans, useTranslation } from "react-i18next";
import styled from "styled-components";
import Icon from "@shared/components/Icon";
import { randomElement } from "@shared/random";
import { CollectionPermission } from "@shared/types";
import { IconLibrary } from "@shared/utils/IconLibrary";
import { colorPalette } from "@shared/utils/collections";
import { CollectionValidation } from "@shared/validations";
import Collection from "~/models/Collection";
import Button from "~/components/Button";
import Flex from "~/components/Flex";
import IconPicker from "~/components/IconPicker";
import { IconLibrary } from "~/components/Icons/IconLibrary";
import Input from "~/components/Input";
import InputSelectPermission from "~/components/InputSelectPermission";
import Switch from "~/components/Switch";
import Text from "~/components/Text";
import useBoolean from "~/hooks/useBoolean";
import useCurrentTeam from "~/hooks/useCurrentTeam";
import { EmptySelectValue } from "~/types";
const IconPicker = React.lazy(() => import("~/components/IconPicker"));
export interface FormData {
name: string;
icon: string;
color: string;
color: string | null;
sharing: boolean;
permission: CollectionPermission | undefined;
}
@@ -36,7 +39,16 @@ export const CollectionForm = observer(function CollectionForm_({
}) {
const team = useCurrentTeam();
const { t } = useTranslation();
const [hasOpenedIconPicker, setHasOpenedIconPicker] = useBoolean(false);
const iconColor = React.useMemo(
() => collection?.color ?? randomElement(colorPalette),
[collection?.color]
);
const fallbackIcon = <Icon value="collection" color={iconColor} />;
const {
register,
handleSubmit: formHandleSubmit,
@@ -52,7 +64,7 @@ export const CollectionForm = observer(function CollectionForm_({
icon: collection?.icon,
sharing: collection?.sharing ?? true,
permission: collection?.permission,
color: collection?.color ?? randomElement(colorPalette),
color: iconColor,
},
});
@@ -61,7 +73,7 @@ export const CollectionForm = observer(function CollectionForm_({
React.useEffect(() => {
// If the user hasn't picked an icon yet, go ahead and suggest one based on
// the name of the collection. It's the little things sometimes.
if (!hasOpenedIconPicker) {
if (!hasOpenedIconPicker && !collection) {
setValue(
"icon",
IconLibrary.findIconByKeyword(values.name) ??
@@ -69,16 +81,20 @@ export const CollectionForm = observer(function CollectionForm_({
"collection"
);
}
}, [values.name]);
}, [collection, hasOpenedIconPicker, setValue, values.name, values.icon]);
const handleIconPickerChange = React.useCallback(
(color: string, icon: string) => {
React.useEffect(() => {
setTimeout(() => setFocus("name", { shouldSelect: true }), 100);
}, [setFocus]);
const handleIconChange = React.useCallback(
(icon: string, color: string | null) => {
if (icon !== values.icon) {
setFocus("name");
}
setValue("color", color);
setValue("icon", icon);
setValue("color", color);
},
[setFocus, setValue, values.icon]
);
@@ -100,14 +116,18 @@ export const CollectionForm = observer(function CollectionForm_({
maxLength: CollectionValidation.maxNameLength,
})}
prefix={
<StyledIconPicker
onOpen={setHasOpenedIconPicker}
onChange={handleIconPickerChange}
initial={values.name[0]}
color={values.color}
icon={values.icon}
/>
<React.Suspense fallback={fallbackIcon}>
<StyledIconPicker
icon={values.icon}
color={values.color ?? iconColor}
initial={values.name[0]}
popoverPosition="right"
onOpen={setHasOpenedIconPicker}
onChange={handleIconChange}
/>
</React.Suspense>
}
autoComplete="off"
autoFocus
flex
/>
@@ -122,8 +142,10 @@ export const CollectionForm = observer(function CollectionForm_({
<InputSelectPermission
ref={field.ref}
value={field.value}
onChange={(value: CollectionPermission) => {
field.onChange(value);
onChange={(
value: CollectionPermission | typeof EmptySelectValue
) => {
field.onChange(value === EmptySelectValue ? null : value);
}}
note={t(
"The default access for workspace members, you can share with more users or groups later."
@@ -133,7 +155,7 @@ export const CollectionForm = observer(function CollectionForm_({
/>
)}
{team.sharing && !collection && (
{team.sharing && (
<Switch
id="sharing"
label={t("Public document sharing")}
+6 -3
View File
@@ -1,7 +1,7 @@
import { runInAction } from "mobx";
import { observer } from "mobx-react";
import * as React from "react";
import { toast } from "sonner";
import Collection from "~/models/Collection";
import useStores from "~/hooks/useStores";
import history from "~/utils/history";
import { CollectionForm, FormData } from "./CollectionForm";
@@ -17,8 +17,11 @@ export const CollectionNew = observer(function CollectionNew_({
const handleSubmit = React.useCallback(
async (data: FormData) => {
try {
const collection = new Collection(data, collections);
await collection.save();
const collection = await collections.save(data);
// Avoid flash of loading state for the new collection, we know it's empty.
runInAction(() => {
collection.documents = [];
});
onSubmit?.();
history.push(collection.path);
} catch (error) {
+45
View File
@@ -0,0 +1,45 @@
import { ArchiveIcon } from "outline-icons";
import * as React from "react";
import { useTranslation } from "react-i18next";
import Collection from "~/models/Collection";
import CollectionIcon from "~/components/Icons/CollectionIcon";
import { MenuInternalLink } from "~/types";
import { archivePath, collectionPath } from "~/utils/routeHelpers";
import Breadcrumb from "./Breadcrumb";
type Props = {
collection: Collection;
};
export const CollectionBreadcrumb: React.FC<Props> = ({ collection }) => {
const { t } = useTranslation();
const items = React.useMemo(() => {
const collectionNode: MenuInternalLink = {
type: "route",
title: collection.name,
icon: <CollectionIcon collection={collection} expanded />,
to: collectionPath(collection.path),
};
const category: MenuInternalLink | undefined = collection.isArchived
? {
type: "route",
icon: <ArchiveIcon />,
title: t("Archive"),
to: archivePath(),
}
: undefined;
const output = [];
if (category) {
output.push(category);
}
output.push(collectionNode);
return output;
}, [collection, t]);
return <Breadcrumb items={items} highlightFirstItem />;
};
+3 -4
View File
@@ -65,7 +65,7 @@ function CollectionDescription({ collection }: Props) {
debounce(async (getValue) => {
try {
await collection.save({
description: getValue(),
data: getValue(false),
});
setDirty(false);
} catch (err) {
@@ -109,7 +109,7 @@ function CollectionDescription({ collection }: Props) {
>
<Editor
key={key}
defaultValue={collection.description || ""}
defaultValue={collection.data}
onChange={handleChange}
placeholder={placeholder}
readOnly={!isEditing}
@@ -201,7 +201,6 @@ const Input = styled.div`
margin: -8px;
padding: 8px;
border-radius: 8px;
transition: ${s("backgroundTransition")};
&:after {
content: "";
@@ -226,7 +225,7 @@ const Input = styled.div`
}
&[data-editing="true"] {
background: ${s("secondaryBackground")};
background: ${s("backgroundSecondary")};
}
.block-menu-trigger,
@@ -6,20 +6,27 @@ import { Portal } from "react-portal";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { depths, s } from "@shared/styles";
import CommandBarResults from "~/components/CommandBarResults";
import SearchActions from "~/components/SearchActions";
import rootActions from "~/actions/root";
import useCommandBarActions from "~/hooks/useCommandBarActions";
import useSettingsActions from "~/hooks/useSettingsActions";
import useTemplateActions from "~/hooks/useTemplateActions";
import CommandBarResults from "./CommandBarResults";
import useRecentDocumentActions from "./useRecentDocumentActions";
import useSettingsAction from "./useSettingsAction";
import useTemplatesAction from "./useTemplatesAction";
function CommandBar() {
const { t } = useTranslation();
const settingsActions = useSettingsActions();
const templateActions = useTemplateActions();
const recentDocumentActions = useRecentDocumentActions();
const settingsAction = useSettingsAction();
const templatesAction = useTemplatesAction();
const commandBarActions = React.useMemo(
() => [...rootActions, templateActions, settingsActions],
[settingsActions, templateActions]
() => [
...recentDocumentActions,
...rootActions,
templatesAction,
settingsAction,
],
[recentDocumentActions, settingsAction, templatesAction]
);
useCommandBarActions(commandBarActions);
@@ -30,7 +37,9 @@ function CommandBar() {
<Positioner>
<Animator>
<SearchActions />
<SearchInput defaultPlaceholder={t("Type a command or search")} />
<SearchInput
defaultPlaceholder={`${t("Type a command or search")}`}
/>
<CommandBarResults />
</Animator>
</Positioner>
@@ -60,13 +69,19 @@ const Positioner = styled(KBarPositioner)`
`;
const SearchInput = styled(KBarSearch)`
padding: 16px 20px;
width: 100%;
position: relative;
padding: 16px 12px;
margin: 0 8px;
width: calc(100% - 16px);
outline: none;
border: none;
background: ${s("menuBackground")};
color: ${s("text")};
&:not(:last-child) {
border-bottom: 1px solid ${s("inputBorder")};
}
&:disabled,
&::placeholder {
color: ${s("placeholder")};
@@ -5,7 +5,7 @@ import styled, { css, useTheme } from "styled-components";
import { s, ellipsis } from "@shared/styles";
import Flex from "~/components/Flex";
import Key from "~/components/Key";
import Text from "./Text";
import Text from "~/components/Text";
type Props = {
action: ActionImpl;
@@ -69,8 +69,8 @@ function CommandBarItem(
) : (
""
)}
{sc.split("+").map((s) => (
<Key key={s}>{s}</Key>
{sc.split("+").map((key) => (
<Key key={key}>{key}</Key>
))}
</React.Fragment>
))}
@@ -1,12 +1,16 @@
import { useMatches, KBarResults } from "kbar";
import * as React from "react";
import styled from "styled-components";
import { s } from "@shared/styles";
import CommandBarItem from "~/components/CommandBarItem";
import Text from "~/components/Text";
import CommandBarItem from "./CommandBarItem";
export default function CommandBarResults() {
const { results, rootActionId } = useMatches();
if (results.length === 0) {
return null;
}
return (
<Container>
<KBarResults
@@ -14,7 +18,9 @@ export default function CommandBarResults() {
maxHeight={400}
onRender={({ item, active }) =>
typeof item === "string" ? (
<Header>{item}</Header>
<Header type="tertiary" size="xsmall" ellipsis>
{item}
</Header>
) : (
<CommandBarItem
action={item}
@@ -35,11 +41,10 @@ const Container = styled.div`
}
`;
const Header = styled.h3`
font-size: 13px;
letter-spacing: 0.04em;
const Header = styled(Text).attrs({ as: "h3" })`
letter-spacing: 0.03em;
margin: 0;
padding: 16px 0 4px 20px;
color: ${s("textTertiary")};
height: 36px;
cursor: default;
`;
+3
View File
@@ -0,0 +1,3 @@
import CommandBar from "./CommandBar";
export default CommandBar;
@@ -0,0 +1,35 @@
import { DocumentIcon } from "outline-icons";
import * as React from "react";
import Icon from "@shared/components/Icon";
import { createAction } from "~/actions";
import { RecentSection } from "~/actions/sections";
import useStores from "~/hooks/useStores";
import history from "~/utils/history";
import { documentPath } from "~/utils/routeHelpers";
const useRecentDocumentActions = (count = 6) => {
const { documents, ui } = useStores();
return React.useMemo(
() =>
documents.recentlyViewed
.filter((document) => document.id !== ui.activeDocumentId)
.slice(0, count)
.map((item) =>
createAction({
name: item.titleWithDefault,
analyticsName: "Recently viewed document",
section: RecentSection,
icon: item.icon ? (
<Icon value={item.icon} color={item.color ?? undefined} />
) : (
<DocumentIcon />
),
perform: () => history.push(documentPath(item)),
})
),
[count, ui.activeDocumentId, documents.recentlyViewed]
);
};
export default useRecentDocumentActions;
@@ -2,10 +2,10 @@ import { SettingsIcon } from "outline-icons";
import * as React from "react";
import { createAction } from "~/actions";
import { NavigationSection } from "~/actions/sections";
import useSettingsConfig from "~/hooks/useSettingsConfig";
import history from "~/utils/history";
import useSettingsConfig from "./useSettingsConfig";
const useSettingsActions = () => {
const useSettingsAction = () => {
const config = useSettingsConfig();
const actions = React.useMemo(
() =>
@@ -38,4 +38,4 @@ const useSettingsActions = () => {
return navigateToSettings;
};
export default useSettingsActions;
export default useSettingsAction;
@@ -0,0 +1,89 @@
import { NewDocumentIcon, ShapesIcon } from "outline-icons";
import * as React from "react";
import Icon from "@shared/components/Icon";
import { createAction } from "~/actions";
import {
ActiveCollectionSection,
DocumentSection,
TeamSection,
} from "~/actions/sections";
import useStores from "~/hooks/useStores";
import history from "~/utils/history";
import { newDocumentPath } from "~/utils/routeHelpers";
const useTemplatesAction = () => {
const { documents } = useStores();
React.useEffect(() => {
void documents.fetchAllTemplates();
}, [documents]);
const actions = React.useMemo(
() =>
documents.templatesAlphabetical.map((template) =>
createAction({
name: template.titleWithDefault,
analyticsName: "New document",
section: template.isWorkspaceTemplate
? TeamSection
: ActiveCollectionSection,
icon: template.icon ? (
<Icon value={template.icon} color={template.color ?? undefined} />
) : (
<NewDocumentIcon />
),
keywords: "create",
visible: ({ currentTeamId, activeCollectionId, stores }) => {
if (activeCollectionId) {
return (
stores.policies.abilities(activeCollectionId).createDocument &&
(template.collectionId === activeCollectionId ||
template.isWorkspaceTemplate)
);
}
return (
!!currentTeamId &&
stores.policies.abilities(currentTeamId).createDocument &&
template.isWorkspaceTemplate
);
},
perform: ({ activeCollectionId, sidebarContext }) =>
history.push(
newDocumentPath(template.collectionId ?? activeCollectionId, {
templateId: template.id,
}),
{
sidebarContext,
}
),
})
),
[documents.templatesAlphabetical]
);
const newFromTemplate = React.useMemo(
() =>
createAction({
id: "templates",
name: ({ t }) => t("New from template"),
placeholder: ({ t }) => t("Choose a template"),
section: DocumentSection,
icon: <ShapesIcon />,
visible: ({ currentTeamId, activeCollectionId, stores }) => {
if (activeCollectionId) {
return stores.policies.abilities(activeCollectionId).createDocument;
}
return (
!!currentTeamId &&
stores.policies.abilities(currentTeamId).createDocument
);
},
children: () => actions,
}),
[actions]
);
return newFromTemplate;
};
export default useTemplatesAction;
+64
View File
@@ -0,0 +1,64 @@
import { observer } from "mobx-react";
import * as React from "react";
import { Trans, useTranslation } from "react-i18next";
import { CollectionPermission, NavigationNode } from "@shared/types";
import type Collection from "~/models/Collection";
import ConfirmationDialog from "~/components/ConfirmationDialog";
import useStores from "~/hooks/useStores";
type Props = {
/** The navigation node to move, must represent a document. */
item: NavigationNode;
/** The collection to move the document to. */
collection: Collection;
/** The parent document to move the document under. */
parentDocumentId?: string | null;
/** The index to move the document to. */
index?: number | null;
};
function ConfirmMoveDialog({ collection, item, ...rest }: Props) {
const { documents, dialogs, collections } = useStores();
const { t } = useTranslation();
const prevCollection = collections.get(item.collectionId!);
const accessMapping: Record<Partial<CollectionPermission> | "null", string> =
{
[CollectionPermission.Admin]: t("manage access"),
[CollectionPermission.ReadWrite]: t("view and edit access"),
[CollectionPermission.Read]: t("view only access"),
null: t("no access"),
};
const handleSubmit = async () => {
await documents.move({
documentId: item.id,
collectionId: collection.id,
...rest,
});
dialogs.closeAllModals();
};
return (
<ConfirmationDialog
onSubmit={handleSubmit}
submitText={t("Move document")}
savingText={`${t("Moving")}`}
>
<Trans
defaults="Moving the document <em>{{ title }}</em> to the {{ newCollectionName }} collection will change permission for all workspace members from <em>{{ prevPermission }}</em> to <em>{{ newPermission }}</em>."
values={{
title: item.title,
prevCollectionName: prevCollection?.name,
newCollectionName: collection.name,
prevPermission: accessMapping[prevCollection?.permission || "null"],
newPermission: accessMapping[collection.permission || "null"],
}}
components={{
em: <strong />,
}}
/>
</ConfirmationDialog>
);
}
export default observer(ConfirmMoveDialog);
+6 -3
View File
@@ -8,8 +8,8 @@ import Text from "~/components/Text";
import useStores from "~/hooks/useStores";
type Props = {
/** Callback when the dialog is submitted */
onSubmit: () => Promise<void> | void;
/** Callback when the dialog is submitted. Return false to prevent closing. */
onSubmit: () => Promise<void | boolean> | void;
/** Text to display on the submit button */
submitText?: string;
/** Text to display while the form is saving */
@@ -38,7 +38,10 @@ const ConfirmationDialog: React.FC<Props> = ({
ev.preventDefault();
setIsSaving(true);
try {
await onSubmit();
const res = await onSubmit();
if (res === false) {
return;
}
dialogs.closeAllModals();
} catch (err) {
toast.error(err.message);
+4 -5
View File
@@ -2,7 +2,7 @@ import { observer } from "mobx-react";
import { DisconnectedIcon } from "outline-icons";
import * as React from "react";
import { useTranslation } from "react-i18next";
import styled, { useTheme } from "styled-components";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import Fade from "~/components/Fade";
import NudeButton from "~/components/NudeButton";
@@ -11,7 +11,6 @@ import useStores from "~/hooks/useStores";
function ConnectionStatus() {
const { ui } = useStores();
const theme = useTheme();
const { t } = useTranslation();
const codeToMessage = {
@@ -36,7 +35,7 @@ function ConnectionStatus() {
};
const message = ui.multiplayerErrorCode
? codeToMessage[ui.multiplayerErrorCode]
? codeToMessage[ui.multiplayerErrorCode as keyof typeof codeToMessage]
: undefined;
return ui.multiplayerStatus === "connecting" ||
@@ -61,7 +60,7 @@ function ConnectionStatus() {
>
<Button>
<Fade>
<DisconnectedIcon color={theme.sidebarText} />
<DisconnectedIcon />
</Fade>
</Button>
</Tooltip>
@@ -72,7 +71,7 @@ const Button = styled(NudeButton)`
display: none;
position: fixed;
bottom: 0;
margin: 24px;
margin: 20px;
transform: translateX(-32px);
${breakpoint("tablet")`
-1
View File
@@ -182,7 +182,6 @@ function placeCaret(element: HTMLElement, atStart: boolean) {
const Content = styled.span`
background: ${s("background")};
transition: ${s("backgroundTransition")};
color: ${s("text")};
-webkit-text-fill-color: ${s("text")};
outline: none;
+43 -22
View File
@@ -1,15 +1,18 @@
import { LocationDescriptor } from "history";
import { CheckmarkIcon } from "outline-icons";
import { ellipsis, transparentize } from "polished";
import * as React from "react";
import { mergeRefs } from "react-merge-refs";
import { MenuItem as BaseMenuItem } from "reakit/Menu";
import styled, { css } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { s } from "@shared/styles";
import Text from "../Text";
import MenuIconWrapper from "./MenuIconWrapper";
type Props = {
id?: string;
onClick?: (event: React.SyntheticEvent) => void | Promise<void>;
onClick?: (event: React.MouseEvent) => void | Promise<void>;
active?: boolean;
selected?: boolean;
disabled?: boolean;
@@ -20,7 +23,7 @@ type Props = {
as?: string | React.ComponentType<any>;
hide?: () => void;
level?: number;
icon?: React.ReactElement;
icon?: React.ReactNode;
children?: React.ReactNode;
ref?: React.LegacyRef<HTMLButtonElement> | undefined;
};
@@ -41,43 +44,43 @@ const MenuItem = (
) => {
const content = React.useCallback(
(props) => {
// Preventing default mousedown otherwise menu items do not work in Firefox,
// which triggers the hideOnClickOutside handler first via mousedown hiding
// and un-rendering the menu contents.
const preventDefault = (ev: React.MouseEvent) => {
ev.preventDefault();
ev.stopPropagation();
};
const handleClick = async (ev: React.MouseEvent) => {
hide?.();
if (onClick) {
ev.preventDefault();
preventDefault(ev);
await onClick(ev);
}
};
// Preventing default mousedown otherwise menu items do not work in Firefox,
// which triggers the hideOnClickOutside handler first via mousedown hiding
// and un-rendering the menu contents.
const handleMouseDown = (ev: React.MouseEvent) => {
ev.preventDefault();
ev.stopPropagation();
};
return (
<MenuAnchor
{...props}
$active={active}
as={onClick ? "button" : as}
onClick={handleClick}
onMouseDown={handleMouseDown}
onPointerDown={preventDefault}
onMouseDown={preventDefault}
ref={mergeRefs([
ref,
props.ref as React.RefObject<HTMLAnchorElement>,
])}
>
{selected !== undefined && (
<>
<SelectedWrapper aria-hidden>
{selected ? <CheckmarkIcon /> : <Spacer />}
&nbsp;
</>
</SelectedWrapper>
)}
{icon && <MenuIconWrapper>{icon}</MenuIconWrapper>}
{children}
{icon && <MenuIconWrapper aria-hidden>{icon}</MenuIconWrapper>}
<Title>{children}</Title>
</MenuAnchor>
);
},
@@ -102,6 +105,14 @@ const Spacer = styled.svg`
flex-shrink: 0;
`;
const Title = styled.div`
${ellipsis()}
flex-grow: 1;
display: flex;
align-items: center;
gap: 8px;
`;
type MenuAnchorProps = {
level?: number;
disabled?: boolean;
@@ -130,10 +141,6 @@ export const MenuAnchorCSS = css<MenuAnchorProps>`
white-space: nowrap;
position: relative;
svg:not(:last-child) {
margin-right: 4px;
}
svg {
flex-shrink: 0;
opacity: ${(props) => (props.disabled ? ".5" : 1)};
@@ -148,15 +155,20 @@ export const MenuAnchorCSS = css<MenuAnchorProps>`
@media (hover: hover) {
&:hover,
&:focus,
&.focus-visible {
&:focus-visible {
color: ${props.theme.accentText};
background: ${props.dangerous ? props.theme.danger : props.theme.accent};
box-shadow: none;
cursor: var(--pointer);
svg {
color: ${props.theme.accentText};
fill: ${props.theme.accentText};
}
${Text} {
color: ${transparentize(0.5, props.theme.accentText)};
}
}
}
`}
@@ -187,4 +199,13 @@ export const MenuAnchor = styled.a`
${MenuAnchorCSS}
`;
const SelectedWrapper = styled.span`
width: 24px;
height: 24px;
margin-right: 4px;
margin-left: -8px;
flex-shrink: 0;
color: ${s("textSecondary")};
`;
export default React.forwardRef<HTMLAnchorElement, Props>(MenuItem);
+15 -8
View File
@@ -30,6 +30,7 @@ type Props = Omit<MenuStateReturn, "items"> & {
actions?: (Action | MenuSeparator | MenuHeading)[];
context?: Partial<ActionContext>;
items?: TMenuItem[];
showIcons?: boolean;
};
const Disclosure = styled(ExpandedIcon)`
@@ -98,7 +99,7 @@ export function filterTemplateItems(items: TMenuItem[]): TMenuItem[] {
});
}
function Template({ items, actions, context, ...menu }: Props) {
function Template({ items, actions, context, showIcons, ...menu }: Props) {
const ctx = useActionContext({
isContextMenu: true,
});
@@ -124,9 +125,10 @@ function Template({ items, actions, context, ...menu }: Props) {
if (
iconIsPresentInAnyMenuItem &&
item.type !== "separator" &&
item.type !== "heading"
item.type !== "heading" &&
showIcons !== false
) {
item.icon = item.icon || <MenuIconWrapper />;
item.icon = item.icon || <MenuIconWrapper aria-hidden />;
}
if (item.type === "route") {
@@ -138,7 +140,7 @@ function Template({ items, actions, context, ...menu }: Props) {
key={index}
disabled={item.disabled}
selected={item.selected}
icon={item.icon}
icon={showIcons !== false ? item.icon : undefined}
{...menu}
>
{item.title}
@@ -156,7 +158,7 @@ function Template({ items, actions, context, ...menu }: Props) {
selected={item.selected}
level={item.level}
target={item.href.startsWith("#") ? undefined : "_blank"}
icon={item.icon}
icon={showIcons !== false ? item.icon : undefined}
{...menu}
>
{item.title}
@@ -174,7 +176,7 @@ function Template({ items, actions, context, ...menu }: Props) {
selected={item.selected}
dangerous={item.dangerous}
key={index}
icon={item.icon}
icon={showIcons !== false ? item.icon : undefined}
{...menu}
>
{item.title}
@@ -190,7 +192,12 @@ function Template({ items, actions, context, ...menu }: Props) {
id={`${item.title}-${index}`}
templateItems={item.items}
parentMenuState={menu}
title={<Title title={item.title} icon={item.icon} />}
title={
<Title
title={item.title}
icon={showIcons !== false ? item.icon : undefined}
/>
}
{...menu}
/>
);
@@ -220,7 +227,7 @@ function Title({
}) {
return (
<Flex align="center">
{icon && <MenuIconWrapper>{icon}</MenuIconWrapper>}
{icon && <MenuIconWrapper aria-hidden>{icon}</MenuIconWrapper>}
{title}
</Flex>
);
+52 -3
View File
@@ -6,6 +6,7 @@ import styled, { DefaultTheme } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { depths, s } from "@shared/styles";
import Scrollable from "~/components/Scrollable";
import useEventListener from "~/hooks/useEventListener";
import useMenuContext from "~/hooks/useMenuContext";
import useMenuHeight from "~/hooks/useMenuHeight";
import useMobile from "~/hooks/useMobile";
@@ -38,6 +39,8 @@ export type Placement =
type Props = MenuStateReturn & {
"aria-label"?: string;
/** Reference to the rendered menu div element */
menuRef?: React.RefObject<HTMLDivElement>;
/** The parent menu state if this is a submenu. */
parentMenuState?: Omit<MenuStateReturn, "items">;
/** Called when the context menu is opened. */
@@ -48,10 +51,13 @@ type Props = MenuStateReturn & {
onClick?: (ev: React.MouseEvent) => void;
/** The maximum width of the context menu. */
maxWidth?: number;
/** The minimum height of the context menu. */
minHeight?: number;
children?: React.ReactNode;
};
const ContextMenu: React.FC<Props> = ({
menuRef,
children,
onOpen,
onClose,
@@ -105,7 +111,12 @@ const ContextMenu: React.FC<Props> = ({
// trigger and the bottom of the window
return (
<>
<Menu hideOnClickOutside={!isMobile} preventBodyScroll={false} {...rest}>
<Menu
ref={menuRef}
hideOnClickOutside={!isMobile}
preventBodyScroll={false}
{...rest}
>
{(props) => (
<InnerContextMenu
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -126,6 +137,7 @@ type InnerContextMenuProps = MenuStateReturn & {
menuProps: { style?: React.CSSProperties; placement: string };
children: React.ReactNode;
maxWidth?: number;
minHeight?: number;
};
/**
@@ -163,6 +175,32 @@ const InnerContextMenu = (props: InnerContextMenuProps) => {
};
}, [props.isSubMenu, props.visible]);
useEventListener(
"animationstart",
(event) => {
if (event.target instanceof HTMLElement) {
const parent = event.target.parentElement;
if (parent) {
parent.style.pointerEvents = "none";
}
}
},
backgroundRef.current
);
useEventListener(
"animationend",
(event) => {
if (event.target instanceof HTMLElement) {
const parent = event.target.parentElement;
if (parent) {
parent.style.pointerEvents = "auto";
}
}
},
backgroundRef.current
);
const style =
topAnchor && !isMobile
? {
@@ -185,6 +223,7 @@ const InnerContextMenu = (props: InnerContextMenuProps) => {
<Background
dir="auto"
maxWidth={props.maxWidth}
minHeight={props.minHeight}
topAnchor={topAnchor}
rightAnchor={rightAnchor}
ref={backgroundRef}
@@ -215,6 +254,16 @@ export const Position = styled.div`
position: absolute;
z-index: ${depths.menu};
// Note: pointer events are re-enabled after the animation ends, see event listeners above
pointer-events: none;
&:focus-visible {
transition-delay: 250ms;
transition-property: outline-width;
transition-duration: 0;
outline: none;
}
/*
* overrides make mobile-first coding style challenging
* so we explicitly define mobile breakpoint here
@@ -233,6 +282,7 @@ type BackgroundProps = {
topAnchor?: boolean;
rightAnchor?: boolean;
maxWidth?: number;
minHeight?: number;
theme: DefaultTheme;
};
@@ -244,9 +294,8 @@ export const Background = styled(Scrollable)<BackgroundProps>`
border-radius: 6px;
padding: 6px;
min-width: 180px;
min-height: 44px;
min-height: ${(props) => props.minHeight || 44}px;
max-height: 75vh;
pointer-events: all;
font-weight: normal;
@media print {
+3
View File
@@ -26,6 +26,9 @@ function CopyToClipboard(props: Props, ref: React.Ref<HTMLElement>) {
if (elem && elem.props && typeof elem.props.onClick === "function") {
elem.props.onClick(ev);
} else {
ev.preventDefault();
ev.stopPropagation();
}
},
[children, onCopy, text]
@@ -49,7 +49,7 @@ const DefaultCollectionInputSelect = ({
const options = React.useMemo(
() =>
collections.publicCollections.reduce(
collections.nonPrivate.reduce(
(acc, collection) => [
...acc,
{
@@ -78,7 +78,7 @@ const DefaultCollectionInputSelect = ({
},
]
),
[collections.publicCollections, t]
[collections.nonPrivate, t]
);
if (fetching) {
+1
View File
@@ -25,6 +25,7 @@ function Dialogs() {
fullscreen={modal.fullscreen ?? false}
onRequestClose={() => dialogs.closeModal(id)}
title={modal.title}
style={modal.style}
>
{modal.content}
</Modal>
+30 -22
View File
@@ -3,19 +3,16 @@ import { ArchiveIcon, GoToIcon, ShapesIcon, TrashIcon } from "outline-icons";
import * as React from "react";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import Icon from "@shared/components/Icon";
import type { NavigationNode } from "@shared/types";
import Document from "~/models/Document";
import Breadcrumb from "~/components/Breadcrumb";
import CollectionIcon from "~/components/Icons/CollectionIcon";
import { useLocationSidebarContext } from "~/hooks/useLocationSidebarContext";
import usePolicy from "~/hooks/usePolicy";
import useStores from "~/hooks/useStores";
import { MenuInternalLink } from "~/types";
import {
archivePath,
collectionPath,
settingsPath,
trashPath,
} from "~/utils/routeHelpers";
import EmojiIcon from "./Icons/EmojiIcon";
import { archivePath, settingsPath, trashPath } from "~/utils/routeHelpers";
type Props = {
children?: React.ReactNode;
@@ -56,30 +53,34 @@ function useCategory(document: Document): MenuInternalLink | null {
return null;
}
const DocumentBreadcrumb: React.FC<Props> = ({
document,
children,
onlyText,
}: Props) => {
function DocumentBreadcrumb(
{ document, children, onlyText }: Props,
ref: React.RefObject<HTMLDivElement> | null
) {
const { collections } = useStores();
const { t } = useTranslation();
const category = useCategory(document);
const sidebarContext = useLocationSidebarContext();
const collection = document.collectionId
? collections.get(document.collectionId)
: undefined;
const can = usePolicy(collection);
React.useEffect(() => {
void document.loadRelations();
void document.loadRelations({ withoutPolicies: true });
}, [document]);
let collectionNode: MenuInternalLink | undefined;
if (collection) {
if (collection && can.readDocument) {
collectionNode = {
type: "route",
title: collection.name,
icon: <CollectionIcon collection={collection} expanded />,
to: collectionPath(collection.path),
to: {
pathname: collection.path,
state: { sidebarContext },
},
};
} else if (document.isCollectionDeleted) {
collectionNode = {
@@ -106,18 +107,21 @@ const DocumentBreadcrumb: React.FC<Props> = ({
path.slice(0, -1).forEach((node: NavigationNode) => {
output.push({
type: "route",
title: node.emoji ? (
title: node.icon ? (
<>
<EmojiIcon emoji={node.emoji} /> {node.title}
<StyledIcon value={node.icon} color={node.color} /> {node.title}
</>
) : (
node.title
),
to: node.url,
to: {
pathname: node.url,
state: { sidebarContext },
},
});
});
return output;
}, [path, category, collectionNode]);
}, [path, category, sidebarContext, collectionNode]);
if (!collections.isLoaded) {
return null;
@@ -138,11 +142,15 @@ const DocumentBreadcrumb: React.FC<Props> = ({
}
return (
<Breadcrumb items={items} highlightFirstItem>
<Breadcrumb items={items} ref={ref} highlightFirstItem>
{children}
</Breadcrumb>
);
};
}
const StyledIcon = styled(Icon)`
margin-right: 2px;
`;
const SmallSlash = styled(GoToIcon)`
width: 12px;
@@ -154,4 +162,4 @@ const SmallSlash = styled(GoToIcon)`
opacity: 0.5;
`;
export default observer(DocumentBreadcrumb);
export default observer(React.forwardRef(DocumentBreadcrumb));
+41 -18
View File
@@ -7,17 +7,18 @@ import * as React from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import styled, { useTheme } from "styled-components";
import { s, ellipsis } from "@shared/styles";
import Icon from "@shared/components/Icon";
import Squircle from "@shared/components/Squircle";
import { s, hover, ellipsis } from "@shared/styles";
import { IconType } from "@shared/types";
import { determineIconType } from "@shared/utils/icon";
import Document from "~/models/Document";
import Pin from "~/models/Pin";
import Flex from "~/components/Flex";
import NudeButton from "~/components/NudeButton";
import Time from "~/components/Time";
import useStores from "~/hooks/useStores";
import { hover } from "~/styles";
import CollectionIcon from "./Icons/CollectionIcon";
import EmojiIcon from "./Icons/EmojiIcon";
import Squircle from "./Squircle";
import Text from "./Text";
import Tooltip from "./Tooltip";
@@ -37,6 +38,7 @@ function DocumentCard(props: Props) {
const { collections } = useStores();
const theme = useTheme();
const { document, pin, canUpdatePin, isDraggable } = props;
const pinnedToHome = React.useRef(!pin?.collectionId).current;
const collection = document.collectionId
? collections.get(document.collectionId)
: undefined;
@@ -52,6 +54,8 @@ function DocumentCard(props: Props) {
disabled: !isDraggable || !canUpdatePin,
});
const hasEmojiInTitle = determineIconType(document.icon) === IconType.Emoji;
const style = {
transform: CSS.Transform.toString(transform),
transition,
@@ -109,16 +113,22 @@ function DocumentCard(props: Props) {
<path d="M19.5 19.5H6C2.96243 19.5 0.5 17.0376 0.5 14V0.5H0.792893L19.5 19.2071V19.5Z" />
</Fold>
{document.emoji ? (
<Squircle color={theme.slateLight}>
<EmojiIcon emoji={document.emoji} size={24} />
</Squircle>
{document.icon ? (
<DocumentSquircle
icon={document.icon}
color={document.color ?? undefined}
/>
) : (
<Squircle color={collection?.color}>
<Squircle
color={
collection?.color ??
(pinnedToHome ? theme.slateLight : theme.slateDark)
}
>
{collection?.icon &&
collection?.icon !== "letter" &&
collection?.icon !== "collection" &&
!pin?.collectionId ? (
pinnedToHome ? (
<CollectionIcon collection={collection} color="white" />
) : (
<DocumentIcon color="white" />
@@ -127,18 +137,13 @@ function DocumentCard(props: Props) {
)}
<div>
<Heading dir={document.dir}>
{document.emoji
? document.titleWithDefault.replace(document.emoji, "")
{hasEmojiInTitle
? document.titleWithDefault.replace(document.icon!, "")
: document.titleWithDefault}
</Heading>
<DocumentMeta size="xsmall">
<Clock size={18} />
<Time
dateTime={document.updatedAt}
tooltipDelay={500}
addSuffix
shorten
/>
<Time dateTime={document.updatedAt} addSuffix shorten />
</DocumentMeta>
</div>
</Content>
@@ -159,6 +164,24 @@ function DocumentCard(props: Props) {
);
}
const DocumentSquircle = ({
icon,
color,
}: {
icon: string;
color?: string;
}) => {
const theme = useTheme();
const iconType = determineIconType(icon)!;
const squircleColor = iconType === IconType.SVG ? color : theme.slateLight;
return (
<Squircle color={squircleColor}>
<Icon value={icon} color={theme.white} forceColor />
</Squircle>
);
};
const Clock = styled(ClockIcon)`
flex-shrink: 0;
`;
-37
View File
@@ -1,37 +0,0 @@
import * as React from "react";
import { Editor } from "~/editor";
import useIdle from "~/hooks/useIdle";
export type DocumentContextValue = {
/** The current editor instance for this document. */
editor: Editor | null;
/** Set the current editor instance for this document. */
setEditor: (editor: Editor) => void;
};
const DocumentContext = React.createContext<DocumentContextValue>({
editor: null,
// eslint-disable-next-line @typescript-eslint/no-empty-function
setEditor() {},
});
export const useDocumentContext = () => React.useContext(DocumentContext);
const activityEvents = [
"click",
"mousemove",
"DOMMouseScroll",
"mousewheel",
"mousedown",
"touchstart",
"touchmove",
"focus",
];
export const useEditingFocus = () => {
const { editor } = useDocumentContext();
const isIdle = useIdle(3000, activityEvents);
return isIdle && !!editor?.view.hasFocus();
};
export default DocumentContext;
+84
View File
@@ -0,0 +1,84 @@
import { action, computed, observable } from "mobx";
import React, { PropsWithChildren } from "react";
import { Heading } from "@shared/utils/ProsemirrorHelper";
import Document from "~/models/Document";
import { Editor } from "~/editor";
class DocumentContext {
/** The current document */
document?: Document;
/** The editor instance for this document */
editor?: Editor;
@observable
isEditorInitialized: boolean = false;
@observable
headings: Heading[] = [];
@computed
get hasHeadings() {
return this.headings.length > 0;
}
@action
setDocument = (document: Document) => {
this.document = document;
this.updateState();
};
@action
setEditor = (editor: Editor) => {
this.editor = editor;
this.updateState();
};
@action
setEditorInitialized = (initialized: boolean) => {
this.isEditorInitialized = initialized;
};
@action
updateState = () => {
this.updateHeadings();
this.updateTasks();
};
private updateHeadings() {
const currHeadings = this.editor?.getHeadings() ?? [];
const hasChanged =
currHeadings.map((h) => h.level + h.title).join("") !==
this.headings.map((h) => h.level + h.title).join("");
if (hasChanged) {
this.headings = currHeadings;
}
}
private updateTasks() {
const tasks = this.editor?.getTasks() ?? [];
const total = tasks.length ?? 0;
const completed = tasks.filter((t) => t.completed).length ?? 0;
this.document?.updateTasks(total, completed);
}
}
const Context = React.createContext<DocumentContext | null>(null);
export const useDocumentContext = () => {
const ctx = React.useContext(Context);
if (!ctx) {
throw new Error(
"useDocumentContext must be used within DocumentContextProvider"
);
}
return ctx;
};
export const DocumentContextProvider = ({
children,
}: PropsWithChildren<unknown>) => {
const context = React.useMemo(() => new DocumentContext(), []);
return <Context.Provider value={context}>{children}</Context.Provider>;
};
+149
View File
@@ -0,0 +1,149 @@
import flatten from "lodash/flatten";
import { observer } from "mobx-react";
import * as React from "react";
import { Trans, useTranslation } from "react-i18next";
import { toast } from "sonner";
import styled from "styled-components";
import { NavigationNode } from "@shared/types";
import Document from "~/models/Document";
import { FlexContainer, Footer, StyledText } from "~/scenes/DocumentMove";
import Button from "~/components/Button";
import DocumentExplorer from "~/components/DocumentExplorer";
import useCollectionTrees from "~/hooks/useCollectionTrees";
import useStores from "~/hooks/useStores";
import { flattenTree } from "~/utils/tree";
import Switch from "./Switch";
import Text from "./Text";
type Props = {
/** The original document to duplicate */
document: Document;
onSubmit: (documents: Document[]) => void;
};
function DocumentCopy({ document, onSubmit }: Props) {
const { t } = useTranslation();
const { policies } = useStores();
const collectionTrees = useCollectionTrees();
const [publish, setPublish] = React.useState<boolean>(!!document.publishedAt);
const [recursive, setRecursive] = React.useState<boolean>(true);
const [selectedPath, selectPath] = React.useState<NavigationNode | null>(
null
);
const items = React.useMemo(() => {
const nodes = flatten(collectionTrees.map(flattenTree)).filter((node) =>
node.collectionId
? policies.get(node.collectionId)?.abilities.createDocument
: true
);
if (document.isTemplate) {
return nodes
.filter((node) => node.type === "collection")
.map((node) => ({ ...node, children: [] }));
}
return nodes;
}, [policies, collectionTrees, document.isTemplate]);
const handlePublishChange = React.useCallback(
(ev: React.ChangeEvent<HTMLInputElement>) => {
setPublish(ev.target.checked);
},
[]
);
const handleRecursiveChange = React.useCallback(
(ev: React.ChangeEvent<HTMLInputElement>) => {
setRecursive(ev.target.checked);
},
[]
);
const copy = async () => {
if (!selectedPath) {
toast.message(t("Select a location to copy"));
return;
}
try {
const result = await document.duplicate({
publish,
recursive,
title: document.title,
collectionId: selectedPath.collectionId,
...(selectedPath.type === "document"
? { parentDocumentId: selectedPath.id }
: {}),
});
toast.success(t("Document copied"));
onSubmit(result);
} catch (err) {
toast.error(t("Couldnt copy the document, try again?"));
}
};
return (
<FlexContainer column>
<DocumentExplorer
items={items}
onSubmit={copy}
onSelect={selectPath}
defaultValue={document.parentDocumentId || document.collectionId || ""}
/>
<OptionsContainer>
{!document.isTemplate && (
<>
{document.collectionId && (
<Text size="small">
<Switch
name="publish"
label={t("Publish")}
labelPosition="right"
checked={publish}
onChange={handlePublishChange}
/>
</Text>
)}
{document.publishedAt && document.childDocuments.length > 0 && (
<Text size="small">
<Switch
name="recursive"
label={t("Include nested documents")}
labelPosition="right"
checked={recursive}
onChange={handleRecursiveChange}
/>
</Text>
)}
</>
)}
</OptionsContainer>
<Footer justify="space-between" align="center" gap={8}>
<StyledText type="secondary">
{selectedPath ? (
<Trans
defaults="Copy to <em>{{ location }}</em>"
values={{ location: selectedPath.title }}
components={{ em: <strong /> }}
/>
) : (
t("Select a location to copy")
)}
</StyledText>
<Button disabled={!selectedPath} onClick={copy}>
{t("Copy")}
</Button>
</Footer>
</FlexContainer>
);
}
const OptionsContainer = styled.div`
margin: 16px 0 8px 0;
padding-left: 24px;
padding-right: 24px;
`;
export default observer(DocumentCopy);
+44 -17
View File
@@ -11,35 +11,35 @@ import * as React from "react";
import { useTranslation } from "react-i18next";
import AutoSizer from "react-virtualized-auto-sizer";
import { FixedSizeList as List } from "react-window";
import scrollIntoView from "smooth-scroll-into-view-if-needed";
import scrollIntoView from "scroll-into-view-if-needed";
import styled, { useTheme } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import Icon from "@shared/components/Icon";
import { NavigationNode } from "@shared/types";
import { isModKey } from "@shared/utils/keyboard";
import DocumentExplorerNode from "~/components/DocumentExplorerNode";
import DocumentExplorerSearchResult from "~/components/DocumentExplorerSearchResult";
import Flex from "~/components/Flex";
import CollectionIcon from "~/components/Icons/CollectionIcon";
import EmojiIcon from "~/components/Icons/EmojiIcon";
import { Outline } from "~/components/Input";
import InputSearch from "~/components/InputSearch";
import Text from "~/components/Text";
import useMobile from "~/hooks/useMobile";
import useStores from "~/hooks/useStores";
import { isModKey } from "~/utils/keyboard";
import { ancestors, descendants } from "~/utils/tree";
type Props = {
/** Action taken upon submission of selected item, could be publish, move etc. */
onSubmit: () => void;
/** A side-effect of item selection */
onSelect: (item: NavigationNode | null) => void;
/** Items to be shown in explorer */
items: NavigationNode[];
/** Automatically expand to and select item with the given id */
defaultValue?: string;
};
function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
function DocumentExplorer({ onSubmit, onSelect, items, defaultValue }: Props) {
const isMobile = useMobile();
const { collections, documents } = useStores();
const { t } = useTranslation();
@@ -47,12 +47,25 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
const [searchTerm, setSearchTerm] = React.useState<string>();
const [selectedNode, selectNode] = React.useState<NavigationNode | null>(
null
() => {
const node =
defaultValue && items.find((item) => item.id === defaultValue);
return node || null;
}
);
const [initialScrollOffset, setInitialScrollOffset] =
React.useState<number>(0);
const [activeNode, setActiveNode] = React.useState<number>(0);
const [expandedNodes, setExpandedNodes] = React.useState<string[]>([]);
const [expandedNodes, setExpandedNodes] = React.useState<string[]>(() => {
if (defaultValue) {
const node = items.find((item) => item.id === defaultValue);
if (node) {
return ancestors(node).map((node) => node.id);
}
}
return [];
});
const [itemRefs, setItemRefs] = React.useState<
React.RefObject<HTMLSpanElement>[]
>([]);
@@ -94,6 +107,15 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
onSelect(selectedNode);
}, [selectedNode, onSelect]);
React.useEffect(() => {
if (defaultValue && selectedNode && listRef) {
const index = nodes.findIndex((node) => node.id === selectedNode.id);
if (index > 0) {
setTimeout(() => listRef.current?.scrollToItem(index, "center"), 50);
}
}
}, []);
function getNodes() {
function includeDescendants(item: NavigationNode): NavigationNode[] {
return expandedNodes.includes(item.id)
@@ -216,25 +238,30 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
}) => {
const node = data[index];
const isCollection = node.type === "collection";
let icon, title: string, emoji: string | undefined, path;
let renderedIcon,
title: string,
icon: string | undefined,
color: string | undefined,
path;
if (isCollection) {
const col = collections.get(node.collectionId as string);
icon = col && (
renderedIcon = col && (
<CollectionIcon collection={col} expanded={isExpanded(index)} />
);
title = node.title;
} else {
const doc = documents.get(node.id);
emoji = doc?.emoji ?? node.emoji;
icon = doc?.icon ?? node.icon ?? node.emoji;
color = doc?.color ?? node.color;
title = doc?.title ?? node.title;
if (emoji) {
icon = <EmojiIcon emoji={emoji} />;
if (icon) {
renderedIcon = <Icon value={icon} color={color} />;
} else if (doc?.isStarred) {
icon = <StarredIcon color={theme.yellow} />;
renderedIcon = <StarredIcon color={theme.yellow} />;
} else {
icon = <DocumentIcon color={theme.textSecondary} />;
renderedIcon = <DocumentIcon color={theme.textSecondary} />;
}
path = ancestors(node)
@@ -254,7 +281,7 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
}}
onPointerMove={() => setActiveNode(index)}
onClick={() => toggleSelect(index)}
icon={icon}
icon={renderedIcon}
title={title}
path={path}
/>
@@ -275,7 +302,7 @@ function DocumentExplorer({ onSubmit, onSelect, items }: Props) {
selected={isSelected(index)}
active={activeNode === index}
expanded={isExpanded(index)}
icon={icon}
icon={renderedIcon}
title={title}
depth={node.depth as number}
hasChildren={hasChildren(index)}
+1
View File
@@ -120,6 +120,7 @@ export const Node = styled.span<{
color: ${props.theme.white};
svg {
color: ${props.theme.white};
fill: ${props.theme.white};
}
`}
@@ -1,7 +1,7 @@
import { observer } from "mobx-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import scrollIntoView from "smooth-scroll-into-view-if-needed";
import scrollIntoView from "scroll-into-view-if-needed";
import styled from "styled-components";
import { ellipsis } from "@shared/styles";
import { Node as SearchResult } from "~/components/DocumentExplorerNode";
+44 -27
View File
@@ -1,15 +1,19 @@
import {
useFocusEffect,
useRovingTabIndex,
} from "@getoutline/react-roving-tabindex";
import { observer } from "mobx-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { CompositeStateReturn, CompositeItem } from "reakit/Composite";
import styled, { css } from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { s } from "@shared/styles";
import EventBoundary from "@shared/components/EventBoundary";
import Icon from "@shared/components/Icon";
import { s, hover } from "@shared/styles";
import Document from "~/models/Document";
import Badge from "~/components/Badge";
import DocumentMeta from "~/components/DocumentMeta";
import EventBoundary from "~/components/EventBoundary";
import Flex from "~/components/Flex";
import Highlight from "~/components/Highlight";
import NudeButton from "~/components/NudeButton";
@@ -17,10 +21,10 @@ import StarButton, { AnimatedStar } from "~/components/Star";
import Tooltip from "~/components/Tooltip";
import useBoolean from "~/hooks/useBoolean";
import useCurrentUser from "~/hooks/useCurrentUser";
import { useLocationSidebarContext } from "~/hooks/useLocationSidebarContext";
import DocumentMenu from "~/menus/DocumentMenu";
import { hover } from "~/styles";
import { documentPath } from "~/utils/routeHelpers";
import EmojiIcon from "./Icons/EmojiIcon";
import { determineSidebarContext } from "./Sidebar/components/SidebarContext";
type Props = {
document: Document;
@@ -32,14 +36,13 @@ type Props = {
showPin?: boolean;
showDraft?: boolean;
showTemplate?: boolean;
} & CompositeStateReturn;
};
const SEARCH_RESULT_REGEX = /<b\b[^>]*>(.*?)<\/b>/gi;
function replaceResultMarks(tag: string) {
// don't use SEARCH_RESULT_REGEX here as it causes
// an infinite loop to trigger a regex inside it's own callback
return tag.replace(/<b\b[^>]*>(.*?)<\/b>/gi, "$1");
// don't use SEARCH_RESULT_REGEX directly here as it causes an infinite loop
return tag.replace(new RegExp(SEARCH_RESULT_REGEX.source), "$1");
}
function DocumentListItem(
@@ -48,8 +51,18 @@ function DocumentListItem(
) {
const { t } = useTranslation();
const user = useCurrentUser();
const locationSidebarContext = useLocationSidebarContext();
const [menuOpen, handleMenuOpen, handleMenuClose] = useBoolean();
let itemRef: React.Ref<HTMLAnchorElement> =
React.useRef<HTMLAnchorElement>(null);
if (ref) {
itemRef = ref;
}
const { focused, ...rovingTabIndex } = useRovingTabIndex(itemRef, false);
useFocusEffect(focused, itemRef);
const {
document,
showParentDocuments,
@@ -65,13 +78,17 @@ function DocumentListItem(
const queryIsInTitle =
!!highlight &&
!!document.title.toLowerCase().includes(highlight.toLowerCase());
const canStar =
!document.isDraft && !document.isArchived && !document.isTemplate;
const canStar = !document.isArchived && !document.isTemplate;
const sidebarContext = determineSidebarContext({
document,
user,
currentContext: locationSidebarContext,
});
return (
<CompositeItem
as={DocumentLink}
ref={ref}
<DocumentLink
ref={itemRef}
dir={document.dir}
role="menuitem"
$isStarred={document.isStarred}
@@ -80,15 +97,17 @@ function DocumentListItem(
pathname: documentPath(document),
state: {
title: document.titleWithDefault,
sidebarContext,
},
}}
{...rest}
{...rovingTabIndex}
>
<Content>
<Heading dir={document.dir}>
{document.emoji && (
{document.icon && (
<>
<EmojiIcon emoji={document.emoji} size={24} />
<Icon value={document.icon} color={document.color ?? undefined} />
&nbsp;
</>
)}
@@ -97,23 +116,19 @@ function DocumentListItem(
highlight={highlight}
dir={document.dir}
/>
{document.isBadgedNew && document.createdBy.id !== user.id && (
{document.isBadgedNew && document.createdBy?.id !== user.id && (
<Badge yellow>{t("New")}</Badge>
)}
{document.isDraft && showDraft && (
<Tooltip content={t("Only visible to you")} placement="top">
<Badge>{t("Draft")}</Badge>
</Tooltip>
)}
{canStar && (
<StarPositioner>
<StarButton document={document} />
</StarPositioner>
)}
{document.isDraft && showDraft && (
<Tooltip
content={t("Only visible to you")}
delay={500}
placement="top"
>
<Badge>{t("Draft")}</Badge>
</Tooltip>
)}
{document.isTemplate && showTemplate && (
<Badge primary>{t("Template")}</Badge>
)}
@@ -143,7 +158,7 @@ function DocumentListItem(
modal={false}
/>
</Actions>
</CompositeItem>
</DocumentLink>
);
}
@@ -264,6 +279,8 @@ const ResultContext = styled(Highlight)`
font-size: 15px;
margin-top: -0.25em;
margin-bottom: 0.25em;
max-height: 90px;
overflow: hidden;
`;
export default observer(React.forwardRef(DocumentListItem));
+29 -13
View File
@@ -95,6 +95,21 @@ const DocumentMeta: React.FC<Props> = ({
<Time dateTime={archivedAt} addSuffix />
</span>
);
} else if (
document.sourceMetadata &&
document.sourceMetadata?.importedAt &&
document.sourceMetadata.importedAt >= updatedAt
) {
content = (
<span>
{document.sourceMetadata.createdByName
? t("{{ userName }} updated", {
userName: document.sourceMetadata.createdByName,
})
: t("Imported")}{" "}
<Time dateTime={createdAt} addSuffix />
</span>
);
} else if (createdAt === updatedAt) {
content = (
<span>
@@ -113,15 +128,6 @@ const DocumentMeta: React.FC<Props> = ({
<Time dateTime={publishedAt} addSuffix />
</span>
);
} else if (isDraft) {
content = (
<span>
{lastUpdatedByCurrentUser
? t("You saved")
: t("{{ userName }} saved", { userName })}{" "}
<Time dateTime={updatedAt} addSuffix />
</span>
);
} else {
content = (
<Modified highlight={modifiedSinceViewed && !lastUpdatedByCurrentUser}>
@@ -134,7 +140,7 @@ const DocumentMeta: React.FC<Props> = ({
}
const nestedDocumentsCount = collection
? collection.getDocumentChildren(document.id).length
? collection.getChildrenForDocument(document.id).length
: 0;
const canShowProgressBar = isTasks && !isTemplate;
@@ -162,7 +168,13 @@ const DocumentMeta: React.FC<Props> = ({
};
return (
<Container align="center" rtl={document.dir === "rtl"} {...rest} dir="ltr">
<Container
align="center"
rtl={document.dir === "rtl"}
{...rest}
dir="ltr"
lang=""
>
{to ? (
<Link to={to} replace={replace}>
{content}
@@ -173,9 +185,9 @@ const DocumentMeta: React.FC<Props> = ({
{showCollection && collection && (
<span>
&nbsp;{t("in")}&nbsp;
<strong>
<Strong>
<DocumentBreadcrumb document={document} onlyText />
</strong>
</Strong>
</span>
)}
{showParentDocuments && nestedDocumentsCount > 0 && (
@@ -198,6 +210,10 @@ const DocumentMeta: React.FC<Props> = ({
);
};
const Strong = styled.strong`
font-weight: 550;
`;
const Container = styled(Flex)<{ rtl?: boolean }>`
justify-content: ${(props) => (props.rtl ? "flex-end" : "flex-start")};
color: ${s("textTertiary")};
@@ -1,49 +0,0 @@
import invariant from "invariant";
import { observer } from "mobx-react";
import * as React from "react";
import { useTranslation, Trans } from "react-i18next";
import { useHistory } from "react-router-dom";
import { toast } from "sonner";
import ConfirmationDialog from "~/components/ConfirmationDialog";
import useStores from "~/hooks/useStores";
import { documentPath } from "~/utils/routeHelpers";
type Props = {
documentId: string;
};
function DocumentTemplatizeDialog({ documentId }: Props) {
const history = useHistory();
const { t } = useTranslation();
const { documents } = useStores();
const document = documents.get(documentId);
invariant(document, "Document must exist");
const handleSubmit = React.useCallback(async () => {
const template = await document?.templatize();
if (template) {
history.push(documentPath(template));
toast.success(t("Template created, go ahead and customize it"));
}
}, [document, history, t]);
return (
<ConfirmationDialog
onSubmit={handleSubmit}
submitText={t("Create template")}
savingText={`${t("Creating")}`}
>
<Trans
defaults="Creating a template from <em>{{titleWithDefault}}</em> is a non-destructive action we'll make a copy of the document and turn it into a template that can be used as a starting point for new documents."
values={{
titleWithDefault: document.titleWithDefault,
}}
components={{
em: <strong />,
}}
/>
</ConfirmationDialog>
);
}
export default observer(DocumentTemplatizeDialog);
+1 -1
View File
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
import { dateLocale, dateToRelative } from "@shared/utils/date";
import Document from "~/models/Document";
import User from "~/models/User";
import Avatar from "~/components/Avatar";
import { Avatar } from "~/components/Avatar";
import ListItem from "~/components/List/Item";
import PaginatedList from "~/components/PaginatedList";
import useCurrentUser from "~/hooks/useCurrentUser";
-73
View File
@@ -1,73 +0,0 @@
import { observer } from "mobx-react";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { DocumentValidation } from "@shared/validations";
import Document from "~/models/Document";
import ConfirmationDialog from "~/components/ConfirmationDialog";
import Input from "./Input";
import Switch from "./Switch";
import Text from "./Text";
type Props = {
/** The original document to duplicate */
document: Document;
onSubmit: (documents: Document[]) => void;
};
function DuplicateDialog({ document, onSubmit }: Props) {
const { t } = useTranslation();
const defaultTitle = t(`Copy of {{ documentName }}`, {
documentName: document.title,
});
const [recursive, setRecursive] = React.useState<boolean>(true);
const [title, setTitle] = React.useState<string>(defaultTitle);
const handleRecursiveChange = React.useCallback(
(ev: React.ChangeEvent<HTMLInputElement>) => {
setRecursive(ev.target.checked);
},
[]
);
const handleTitleChange = React.useCallback(
(ev: React.ChangeEvent<HTMLInputElement>) => {
setTitle(ev.target.value);
},
[]
);
const handleSubmit = async () => {
const result = await document.duplicate({
recursive,
title,
});
onSubmit(result);
};
return (
<ConfirmationDialog onSubmit={handleSubmit} submitText={t("Duplicate")}>
<Input
autoFocus
autoSelect
name="title"
label={t("Title")}
onChange={handleTitleChange}
maxLength={DocumentValidation.maxTitleLength}
defaultValue={defaultTitle}
/>
{document.publishedAt && !document.isTemplate && (
<Text size="small">
<Switch
name="recursive"
label={t("Include nested documents")}
labelPosition="right"
checked={recursive}
onChange={handleRecursiveChange}
/>
</Text>
)}
</ConfirmationDialog>
);
}
export default observer(DuplicateDialog);
+18 -105
View File
@@ -1,6 +1,4 @@
import deburr from "lodash/deburr";
import difference from "lodash/difference";
import sortBy from "lodash/sortBy";
import { observer } from "mobx-react";
import { DOMParser as ProsemirrorDOMParser } from "prosemirror-model";
import { TextSelection } from "prosemirror-state";
@@ -9,11 +7,7 @@ import { mergeRefs } from "react-merge-refs";
import { Optional } from "utility-types";
import insertFiles from "@shared/editor/commands/insertFiles";
import { AttachmentPreset } from "@shared/types";
import { Heading } from "@shared/utils/ProsemirrorHelper";
import { dateLocale, dateToRelative } from "@shared/utils/date";
import { getDataTransferFiles } from "@shared/utils/files";
import parseDocumentSlug from "@shared/utils/parseDocumentSlug";
import { isInternalUrl } from "@shared/utils/urls";
import { AttachmentValidation } from "@shared/validations";
import ClickablePadding from "~/components/ClickablePadding";
import ErrorBoundary from "~/components/ErrorBoundary";
@@ -23,11 +17,8 @@ import useDictionary from "~/hooks/useDictionary";
import useEditorClickHandlers from "~/hooks/useEditorClickHandlers";
import useEmbeds from "~/hooks/useEmbeds";
import useStores from "~/hooks/useStores";
import useUserLocale from "~/hooks/useUserLocale";
import { NotFoundError } from "~/utils/errors";
import { uploadFile } from "~/utils/files";
import lazyWithRetry from "~/utils/lazyWithRetry";
import DocumentBreadcrumb from "./DocumentBreadcrumb";
const LazyLoadedEditor = lazyWithRetry(() => import("~/editor"));
@@ -42,83 +33,21 @@ export type Props = Optional<
> & {
shareId?: string | undefined;
embedsDisabled?: boolean;
onHeadingsChange?: (headings: Heading[]) => void;
onSynced?: () => Promise<void>;
onPublish?: (event: React.MouseEvent) => void;
editorStyle?: React.CSSProperties;
};
function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
const {
id,
shareId,
onChange,
onHeadingsChange,
onCreateCommentMark,
onDeleteCommentMark,
} = props;
const userLocale = useUserLocale();
const locale = dateLocale(userLocale);
const { comments, documents } = useStores();
const { id, shareId, onChange, onCreateCommentMark, onDeleteCommentMark } =
props;
const { comments } = useStores();
const dictionary = useDictionary();
const embeds = useEmbeds(!shareId);
const localRef = React.useRef<SharedEditor>();
const preferences = useCurrentUser({ rejectOnEmpty: false })?.preferences;
const previousHeadings = React.useRef<Heading[] | null>(null);
const previousCommentIds = React.useRef<string[]>();
const handleSearchLink = React.useCallback(
async (term: string) => {
if (isInternalUrl(term)) {
// search for exact internal document
const slug = parseDocumentSlug(term);
if (!slug) {
return [];
}
try {
const document = await documents.fetch(slug);
const time = dateToRelative(Date.parse(document.updatedAt), {
addSuffix: true,
shorten: true,
locale,
});
return [
{
title: document.title,
subtitle: `Updated ${time}`,
url: document.url,
},
];
} catch (error) {
// NotFoundError could not find document for slug
if (!(error instanceof NotFoundError)) {
throw error;
}
}
}
// default search for anything that doesn't look like a URL
const results = await documents.searchTitles(term);
return sortBy(
results.map(({ document }) => ({
title: document.title,
subtitle: <DocumentBreadcrumb document={document} onlyText />,
url: document.url,
})),
(document) =>
deburr(document.title)
.toLowerCase()
.startsWith(deburr(term).toLowerCase())
? -1
: 1
);
},
[locale, documents]
);
const handleUploadFile = React.useCallback(
async (file: File) => {
const result = await uploadFile(file, {
@@ -202,24 +131,9 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
[]
);
// Calculate if headings have changed and trigger callback if so
const updateHeadings = React.useCallback(() => {
if (onHeadingsChange) {
const headings = localRef?.current?.getHeadings();
if (
headings &&
headings.map((h) => h.level + h.title).join("") !==
previousHeadings.current?.map((h) => h.level + h.title).join("")
) {
previousHeadings.current = headings;
onHeadingsChange(headings);
}
}
}, [localRef, onHeadingsChange]);
const updateComments = React.useCallback(() => {
if (onCreateCommentMark && onDeleteCommentMark) {
const commentMarks = localRef.current?.getComments();
if (onCreateCommentMark && onDeleteCommentMark && localRef.current) {
const commentMarks = localRef.current.getComments();
const commentIds = comments.orderedData.map((c) => c.id);
const commentMarkIds = commentMarks?.map((c) => c.id);
const newCommentIds = difference(
@@ -229,7 +143,7 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
);
newCommentIds.forEach((commentId) => {
const mark = commentMarks?.find((c) => c.id === commentId);
const mark = commentMarks.find((c) => c.id === commentId);
if (mark) {
onCreateCommentMark(mark.id, mark.userId);
}
@@ -251,26 +165,25 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
const handleChange = React.useCallback(
(event) => {
onChange?.(event);
updateHeadings();
updateComments();
},
[onChange, updateComments, updateHeadings]
[onChange, updateComments]
);
const handleRefChanged = React.useCallback(
(node: SharedEditor | null) => {
if (node) {
updateHeadings();
updateComments();
}
},
[updateComments, updateHeadings]
[updateComments]
);
return (
<ErrorBoundary component="div" reloadOnChunkMissing>
<>
<LazyLoadedEditor
key={props.extensions?.length || 0}
ref={mergeRefs([ref, localRef, handleRefChanged])}
uploadFile={handleUploadFile}
embeds={embeds}
@@ -278,19 +191,19 @@ function Editor(props: Props, ref: React.RefObject<SharedEditor> | null) {
dictionary={dictionary}
{...props}
onClickLink={handleClickLink}
onSearchLink={handleSearchLink}
onChange={handleChange}
placeholder={props.placeholder || ""}
defaultValue={props.defaultValue || ""}
/>
{props.editorStyle?.paddingBottom && !props.readOnly && (
<ClickablePadding
onClick={focusAtEnd}
onDrop={handleDrop}
onDragOver={handleDragOver}
minHeight={props.editorStyle.paddingBottom}
/>
)}
{props.editorStyle?.paddingBottom &&
(!props.readOnly || props.shareId) && (
<ClickablePadding
onClick={props.readOnly ? undefined : focusAtEnd}
onDrop={props.readOnly ? undefined : handleDrop}
onDragOver={props.readOnly ? undefined : handleDragOver}
minHeight={props.editorStyle.paddingBottom}
/>
)}
</>
</ErrorBoundary>
);
+20
View File
@@ -0,0 +1,20 @@
import styled from "styled-components";
import { s } from "@shared/styles";
type Props = {
/** Width of the containing element. */
width?: number | string;
/** Height of the containing element. */
height?: number | string;
/** Controls the rendered emoji size. */
size?: number;
};
export const Emoji = styled.span<Props>`
font-family: ${s("fontFamilyEmoji")};
width: ${({ width }) =>
typeof width === "string" ? width : width ? `${width}px` : "auto"};
height: ${({ height }) =>
typeof height === "string" ? height : height ? `${height}px` : "auto"};
font-size: ${({ size }) => size && `${size}px`};
`;
-23
View File
@@ -1,23 +0,0 @@
import styled from "styled-components";
import Button from "~/components/Button";
import { hover } from "~/styles";
import Flex from "../Flex";
export const EmojiButton = styled(Button)`
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
&: ${hover},
&:active,
&[aria-expanded= "true"] {
opacity: 1 !important;
}
`;
export const Emoji = styled(Flex)<{ size?: number }>`
line-height: 1.6;
${(props) => (props.size ? `font-size: ${props.size}px` : "")}
`;
-269
View File
@@ -1,269 +0,0 @@
import data from "@emoji-mart/data";
import Picker from "@emoji-mart/react";
import { SmileyIcon } from "outline-icons";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { usePopoverState, PopoverDisclosure } from "reakit/Popover";
import styled, { useTheme } from "styled-components";
import { depths, s } from "@shared/styles";
import { toRGB } from "@shared/utils/color";
import Button from "~/components/Button";
import Popover from "~/components/Popover";
import useStores from "~/hooks/useStores";
import useUserLocale from "~/hooks/useUserLocale";
import { Emoji, EmojiButton } from "./components";
/* Locales supported by emoji-mart */
const supportedLocales = [
"en",
"ar",
"be",
"cs",
"de",
"es",
"fa",
"fi",
"fr",
"hi",
"it",
"ja",
"kr",
"nl",
"pl",
"pt",
"ru",
"sa",
"tr",
"uk",
"vi",
"zh",
];
/**
* React hook to derive emoji picker's theme from UI theme
*
* @returns {string} Theme to use for emoji picker
*/
function usePickerTheme(): string {
const { ui } = useStores();
const { theme } = ui;
if (theme === "system") {
return "auto";
}
return theme;
}
type Props = {
/** The selected emoji, if any */
value?: string | null;
/** Callback when an emoji is selected */
onChange: (emoji: string | null) => void | Promise<void>;
/** Callback when the picker is opened */
onOpen?: () => void;
/** Callback when the picker is closed */
onClose?: () => void;
/** Callback when the picker is clicked outside of */
onClickOutside: () => void;
/** Whether to auto focus the search input on open */
autoFocus?: boolean;
/** Class name to apply to the trigger button */
className?: string;
};
function EmojiPicker({
value,
onOpen,
onClose,
onChange,
onClickOutside,
autoFocus,
className,
}: Props) {
const { t } = useTranslation();
const pickerTheme = usePickerTheme();
const theme = useTheme();
const locale = useUserLocale(true) ?? "en";
const popover = usePopoverState({
placement: "bottom-start",
modal: true,
unstable_offset: [0, 0],
});
const [emojisPerLine, setEmojisPerLine] = React.useState(9);
const pickerRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
if (popover.visible) {
onOpen?.();
} else {
onClose?.();
}
}, [popover.visible, onOpen, onClose]);
React.useEffect(() => {
if (popover.visible && pickerRef.current) {
// 28 is picker's observed width when perLine is set to 0
// and 36 is the default emojiButtonSize
// Ref: https://github.com/missive/emoji-mart#options--props
setEmojisPerLine(Math.floor((pickerRef.current.clientWidth - 28) / 36));
}
}, [popover.visible]);
const handleEmojiChange = React.useCallback(
async (emoji) => {
popover.hide();
await onChange(emoji ? emoji.native : null);
},
[popover, onChange]
);
const handleClick = React.useCallback(
(ev: React.MouseEvent) => {
ev.stopPropagation();
if (popover.visible) {
popover.hide();
} else {
popover.show();
}
},
[popover]
);
const handleClickOutside = React.useCallback(() => {
// It was observed that onClickOutside got triggered
// even when the picker wasn't open or opened at all.
// Hence, this guard here...
if (popover.visible) {
onClickOutside();
}
}, [popover.visible, onClickOutside]);
// Auto focus search input when picker is opened
React.useLayoutEffect(() => {
if (autoFocus && popover.visible) {
requestAnimationFrame(() => {
const searchInput = pickerRef.current
?.querySelector("em-emoji-picker")
?.shadowRoot?.querySelector(
"input[type=search]"
) as HTMLInputElement | null;
searchInput?.focus();
});
}
}, [autoFocus, popover.visible]);
return (
<>
<PopoverDisclosure {...popover}>
{(props) => (
<EmojiButton
{...props}
className={className}
onClick={handleClick}
icon={
value ? (
<Emoji size={32} align="center" justify="center">
{value}
</Emoji>
) : (
<StyledSmileyIcon size={32} color={theme.textTertiary} />
)
}
neutral
borderOnHover
/>
)}
</PopoverDisclosure>
<PickerPopover
{...popover}
tabIndex={0}
// This prevents picker from closing when any of its
// children are focused, e.g, clicking on search bar or
// a click on skin tone button
onClick={(e) => e.stopPropagation()}
width={352}
aria-label={t("Emoji Picker")}
>
{popover.visible && (
<>
{value && (
<RemoveButton neutral onClick={() => handleEmojiChange(null)}>
{t("Remove")}
</RemoveButton>
)}
<PickerStyles ref={pickerRef}>
<Picker
// https://github.com/missive/emoji-mart/issues/800
locale={
locale === "ko"
? "kr"
: supportedLocales.includes(locale)
? locale
: "en"
}
data={data}
onEmojiSelect={handleEmojiChange}
theme={pickerTheme}
previewPosition="none"
perLine={emojisPerLine}
onClickOutside={handleClickOutside}
/>
</PickerStyles>
</>
)}
</PickerPopover>
</>
);
}
const StyledSmileyIcon = styled(SmileyIcon)`
flex-shrink: 0;
@media print {
display: none;
}
`;
const RemoveButton = styled(Button)`
margin-left: -12px;
margin-bottom: 8px;
border-radius: 6px;
height: 24px;
font-size: 13px;
> :first-child {
min-height: unset;
line-height: unset;
}
`;
const PickerPopover = styled(Popover)`
z-index: ${depths.popover};
> :first-child {
padding-top: 8px;
padding-bottom: 0;
max-height: 488px;
overflow: unset;
}
`;
const PickerStyles = styled.div`
margin-left: -24px;
margin-right: -24px;
em-emoji-picker {
--shadow: none;
--font-family: ${s("fontFamily")};
--rgb-background: ${(props) => toRGB(props.theme.menuBackground)};
--rgb-accent: ${(props) => toRGB(props.theme.accent)};
--border-radius: 6px;
margin-left: auto;
margin-right: auto;
min-height: 443px;
}
`;
export default EmojiPicker;
+3 -3
View File
@@ -4,7 +4,7 @@ import * as React from "react";
import { withTranslation, Trans, WithTranslation } from "react-i18next";
import styled from "styled-components";
import { s } from "@shared/styles";
import { githubIssuesUrl, feedbackUrl } from "@shared/utils/urlHelpers";
import { UrlHelper } from "@shared/utils/UrlHelper";
import Button from "~/components/Button";
import CenteredContent from "~/components/CenteredContent";
import PageTitle from "~/components/PageTitle";
@@ -57,7 +57,7 @@ class ErrorBoundary extends React.Component<Props> {
};
handleReportBug = () => {
window.open(isCloudHosted ? feedbackUrl() : githubIssuesUrl());
window.open(isCloudHosted ? UrlHelper.contact : UrlHelper.github);
};
render() {
@@ -138,7 +138,7 @@ class ErrorBoundary extends React.Component<Props> {
}
const Pre = styled.pre`
background: ${s("secondaryBackground")};
background: ${s("backgroundSecondary")};
padding: 16px;
border-radius: 4px;
font-size: 12px;
-21
View File
@@ -1,21 +0,0 @@
import * as React from "react";
type Props = {
children?: React.ReactNode;
className?: string;
};
const EventBoundary: React.FC<Props> = ({ children, className }: Props) => {
const handleClick = React.useCallback((event: React.SyntheticEvent) => {
event.preventDefault();
event.stopPropagation();
}, []);
return (
<span onClick={handleClick} className={className}>
{children}
</span>
);
};
export default EventBoundary;
+32 -22
View File
@@ -11,33 +11,31 @@ import {
import * as React from "react";
import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { CompositeStateReturn } from "reakit/Composite";
import styled, { css } from "styled-components";
import { s } from "@shared/styles";
import EventBoundary from "@shared/components/EventBoundary";
import { s, hover } from "@shared/styles";
import Document from "~/models/Document";
import Event from "~/models/Event";
import Avatar from "~/components/Avatar";
import CompositeItem, {
Props as ItemProps,
} from "~/components/List/CompositeItem";
import Item, { Actions } from "~/components/List/Item";
import { Avatar } from "~/components/Avatar";
import Item, { Actions, Props as ItemProps } from "~/components/List/Item";
import Time from "~/components/Time";
import { useLocationSidebarContext } from "~/hooks/useLocationSidebarContext";
import useStores from "~/hooks/useStores";
import RevisionMenu from "~/menus/RevisionMenu";
import { hover } from "~/styles";
import Logger from "~/utils/Logger";
import { documentHistoryPath } from "~/utils/routeHelpers";
type Props = {
document: Document;
event: Event;
event: Event<Document>;
latest?: boolean;
} & CompositeStateReturn;
};
const EventListItem = ({ event, latest, document, ...rest }: Props) => {
const { t } = useTranslation();
const { revisions } = useStores();
const location = useLocation();
const sidebarContext = useLocationSidebarContext();
const opts = {
userName: event.actor.name,
};
@@ -69,7 +67,10 @@ const EventListItem = ({ event, latest, document, ...rest }: Props) => {
);
to = {
pathname: documentHistoryPath(document, event.modelId || "latest"),
state: { retainScrollPosition: true },
state: {
sidebarContext,
retainScrollPosition: true,
},
};
break;
@@ -86,6 +87,18 @@ const EventListItem = ({ event, latest, document, ...rest }: Props) => {
icon = <TrashIcon size={16} />;
meta = t("{{userName}} deleted", opts);
break;
case "documents.add_user":
meta = t("{{userName}} added {{addedUserName}}", {
...opts,
addedUserName: event.user?.name ?? t("a user"),
});
break;
case "documents.remove_user":
meta = t("{{userName}} removed {{removedUserName}}", {
...opts,
removedUserName: event.user?.name ?? t("a user"),
});
break;
case "documents.restore":
meta = t("{{userName}} moved from trash", opts);
@@ -131,7 +144,6 @@ const EventListItem = ({ event, latest, document, ...rest }: Props) => {
title={
<Time
dateTime={event.createdAt}
tooltipDelay={500}
format={{
en_US: "MMM do, h:mm a",
fr_FR: "'Le 'd MMMM 'à' H:mm",
@@ -150,7 +162,9 @@ const EventListItem = ({ event, latest, document, ...rest }: Props) => {
}
actions={
isRevision && isActive && event.modelId && !latest ? (
<RevisionMenu document={document} revisionId={event.modelId} />
<StyledEventBoundary>
<RevisionMenu document={document} revisionId={event.modelId} />
</StyledEventBoundary>
) : undefined
}
onMouseEnter={prefetchRevision}
@@ -164,13 +178,13 @@ const BaseItem = React.forwardRef(function _BaseItem(
{ to, ...rest }: ItemProps,
ref?: React.Ref<HTMLAnchorElement>
) {
if (to) {
return <CompositeListItem to={to} ref={ref} {...rest} />;
}
return <ListItem ref={ref} {...rest} />;
return <ListItem to={to} ref={ref} {...rest} />;
});
const StyledEventBoundary = styled(EventBoundary)`
height: 24px;
`;
const Subtitle = styled.span`
svg {
margin: -3px;
@@ -228,8 +242,4 @@ const ListItem = styled(Item)`
${ItemStyle}
`;
const CompositeListItem = styled(CompositeItem)`
${ItemStyle}
`;
export default observer(EventListItem);
+6 -6
View File
@@ -3,7 +3,7 @@ import * as React from "react";
import styled from "styled-components";
import { s } from "@shared/styles";
import User from "~/models/User";
import Avatar from "~/components/Avatar";
import { Avatar, AvatarSize } from "~/components/Avatar";
import Flex from "~/components/Flex";
type Props = {
@@ -17,7 +17,7 @@ type Props = {
function Facepile({
users,
overflow = 0,
size = 32,
size = AvatarSize.Large,
limit = 8,
renderAvatar = DefaultAvatar,
...rest
@@ -43,7 +43,7 @@ function Facepile({
}
function DefaultAvatar(user: User) {
return <Avatar model={user} size={32} />;
return <Avatar model={user} size={AvatarSize.Large} />;
}
const AvatarWrapper = styled.div`
@@ -62,11 +62,11 @@ const More = styled.div<{ size: number }>`
min-width: ${(props) => props.size}px;
height: ${(props) => props.size}px;
border-radius: 100%;
background: ${(props) => props.theme.slate};
color: ${s("text")};
background: ${(props) => props.theme.textTertiary};
color: ${s("white")};
border: 2px solid ${s("background")};
text-align: center;
font-size: 11px;
font-size: 12px;
font-weight: 600;
`;
+197 -38
View File
@@ -1,80 +1,243 @@
import deburr from "lodash/deburr";
import * as React from "react";
import { useTranslation } from "react-i18next";
import { useMenuState, MenuButton } from "reakit/Menu";
import styled from "styled-components";
import { s } from "@shared/styles";
import type { FetchPageParams } from "~/stores/base/Store";
import Button, { Inner } from "~/components/Button";
import ContextMenu from "~/components/ContextMenu";
import MenuItem from "~/components/ContextMenu/MenuItem";
import Text from "~/components/Text";
import Input, { NativeInput, Outline } from "./Input";
import PaginatedList, { PaginatedItem } from "./PaginatedList";
type TFilterOption = {
interface TFilterOption extends PaginatedItem {
key: string;
label: string;
note?: string;
icon?: React.ReactNode;
};
}
type Props = {
options: TFilterOption[];
activeKey: string | null | undefined;
selectedKeys: (string | null | undefined)[];
defaultLabel?: string;
selectedPrefix?: string;
className?: string;
onSelect: (key: string | null | undefined) => void;
showFilter?: boolean;
fetchQuery?: (options: FetchPageParams) => Promise<PaginatedItem[]>;
fetchQueryOptions?: Record<string, string>;
};
const FilterOptions = ({
options,
activeKey = "",
selectedKeys = [],
defaultLabel = "Filter options",
selectedPrefix = "",
className,
onSelect,
showFilter,
fetchQuery,
fetchQueryOptions,
}: Props) => {
const { t } = useTranslation();
const searchInputRef = React.useRef<HTMLInputElement>(null);
const listRef = React.useRef<HTMLDivElement | null>(null);
const menu = useMenuState({
modal: true,
modal: false,
});
const selected =
options.find((option) => option.key === activeKey) || options[0];
const selectedItems = options.filter((option) =>
selectedKeys.includes(option.key)
);
const [query, setQuery] = React.useState("");
const selectedLabel = selected ? `${selectedPrefix} ${selected.label}` : "";
const selectedLabel = selectedItems.length
? selectedItems
.map((selected) => `${selectedPrefix} ${selected.label}`)
.join(", ")
: "";
const renderItem = React.useCallback(
(option: TFilterOption) => (
<MenuItem
key={option.key}
onClick={() => {
onSelect(option.key);
menu.hide();
}}
selected={selectedKeys.includes(option.key)}
{...menu}
>
{option.icon && <Icon>{option.icon}</Icon>}
{option.note ? (
<LabelWithNote>
{option.label}
<Note>{option.note}</Note>
</LabelWithNote>
) : (
option.label
)}
</MenuItem>
),
[menu, onSelect, selectedKeys]
);
const handleFilter = (ev: React.ChangeEvent<HTMLInputElement>) => {
setQuery(ev.target.value);
};
const filteredOptions = React.useMemo(() => {
const normalizedQuery = deburr(query.toLowerCase());
return query
? options
.filter((option) =>
deburr(option.label).toLowerCase().includes(normalizedQuery)
)
// sort options starting with query first
.sort((a, b) => {
const aStartsWith = deburr(a.label)
.toLowerCase()
.startsWith(normalizedQuery);
const bStartsWith = deburr(b.label)
.toLowerCase()
.startsWith(normalizedQuery);
if (aStartsWith && !bStartsWith) {
return -1;
}
if (!aStartsWith && bStartsWith) {
return 1;
}
return 0;
})
: options;
}, [options, query]);
const handleKeyDown = React.useCallback(
(ev: React.KeyboardEvent) => {
if (ev.nativeEvent.isComposing || ev.shiftKey) {
return;
}
switch (ev.key) {
case "Escape":
menu.hide();
break;
case "Enter":
if (filteredOptions.length === 1) {
ev.preventDefault();
onSelect(filteredOptions[0].key);
menu.hide();
}
break;
case "ArrowDown":
ev.preventDefault();
(listRef.current?.firstElementChild as HTMLElement)?.focus();
break;
default:
break;
}
},
[filteredOptions, menu, onSelect]
);
const handleEscapeFromList = React.useCallback((ev: React.KeyboardEvent) => {
searchInputRef.current?.focus();
if (ev.key === "Backspace") {
setQuery((prev) => prev.slice(0, -1));
}
}, []);
React.useEffect(() => {
if (menu.visible) {
searchInputRef.current?.focus();
} else {
setQuery("");
}
}, [menu.visible]);
const showFilterInput = showFilter || options.length > 10;
return (
<Wrapper>
<div>
<MenuButton {...menu}>
{(props) => (
<StyledButton {...props} className={className} neutral disclosure>
{activeKey ? selectedLabel : defaultLabel}
{selectedItems.length ? selectedLabel : defaultLabel}
</StyledButton>
)}
</MenuButton>
<ContextMenu aria-label={defaultLabel} {...menu}>
{options.map((option) => (
<MenuItem
key={option.key}
onClick={() => {
onSelect(option.key);
menu.hide();
}}
selected={option.key === activeKey}
{...menu}
>
{option.icon && <Icon>{option.icon}</Icon>}
{option.note ? (
<LabelWithNote>
{option.label}
<Note>{option.note}</Note>
</LabelWithNote>
) : (
option.label
)}
</MenuItem>
))}
<ContextMenu aria-label={defaultLabel} minHeight={66} {...menu}>
<PaginatedList
listRef={listRef}
options={{ query, ...fetchQueryOptions }}
items={filteredOptions}
fetch={fetchQuery}
renderItem={renderItem}
onEscape={handleEscapeFromList}
heading={showFilterInput ? <Spacer /> : undefined}
empty={<Empty />}
/>
{showFilterInput && (
<SearchInput
ref={searchInputRef}
value={query}
onChange={handleFilter}
onKeyDown={handleKeyDown}
placeholder={`${t("Filter")}`}
autoFocus
/>
)}
</ContextMenu>
</Wrapper>
</div>
);
};
const Empty = () => {
const { t } = useTranslation();
return (
<>
<Spacer />
<Text size="small" type="tertiary" style={{ marginLeft: 6 }}>
{t("No results")}
</Text>
</>
);
};
const Spacer = styled.div`
height: 30px;
`;
const SearchInput = styled(Input)`
position: absolute;
width: 100%;
border: none;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
overflow: hidden;
margin: 0;
top: 0;
left: 0;
right: 0;
${Outline} {
border: none;
border-radius: 0;
border-bottom: 1px solid ${s("divider")};
background: ${s("menuBackground")};
}
${NativeInput} {
font-size: 14px;
}
`;
const Note = styled(Text)`
display: block;
margin: 2px 0;
@@ -93,7 +256,7 @@ const LabelWithNote = styled.div`
}
`;
const StyledButton = styled(Button)`
export const StyledButton = styled(Button)`
box-shadow: none;
text-transform: none;
border-color: transparent;
@@ -115,8 +278,4 @@ const Icon = styled.div`
height: 18px;
`;
const Wrapper = styled.div`
margin-right: 8px;
`;
export default FilterOptions;
+1 -36
View File
@@ -1,38 +1,3 @@
import { CSSProperties } from "react";
import styled from "styled-components";
type JustifyValues = CSSProperties["justifyContent"];
type AlignValues = CSSProperties["alignItems"];
const Flex = styled.div<{
auto?: boolean;
column?: boolean;
align?: AlignValues;
justify?: JustifyValues;
wrap?: boolean;
shrink?: boolean;
reverse?: boolean;
gap?: number;
}>`
display: flex;
flex: ${({ auto }) => (auto ? "1 1 auto" : "initial")};
flex-direction: ${({ column, reverse }) =>
reverse
? column
? "column-reverse"
: "row-reverse"
: column
? "column"
: "row"};
align-items: ${({ align }) => align};
justify-content: ${({ justify }) => justify};
flex-wrap: ${({ wrap }) => (wrap ? "wrap" : "initial")};
flex-shrink: ${({ shrink }) =>
shrink === true ? 1 : shrink === false ? 0 : "initial"};
gap: ${({ gap }) => (gap ? `${gap}px` : "initial")};
min-height: 0;
min-width: 0;
`;
import Flex from "@shared/components/Flex";
export default Flex;
-94
View File
@@ -1,94 +0,0 @@
import { observer } from "mobx-react";
import { GroupIcon } from "outline-icons";
import * as React from "react";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import { MAX_AVATAR_DISPLAY } from "@shared/constants";
import { s } from "@shared/styles";
import CollectionGroupMembership from "~/models/CollectionGroupMembership";
import Group from "~/models/Group";
import GroupMembers from "~/scenes/GroupMembers";
import Facepile from "~/components/Facepile";
import Flex from "~/components/Flex";
import ListItem from "~/components/List/Item";
import Modal from "~/components/Modal";
import useBoolean from "~/hooks/useBoolean";
import useStores from "~/hooks/useStores";
import { hover } from "~/styles";
import NudeButton from "./NudeButton";
type Props = {
group: Group;
membership?: CollectionGroupMembership;
showFacepile?: boolean;
showAvatar?: boolean;
renderActions: (params: { openMembersModal: () => void }) => React.ReactNode;
};
function GroupListItem({ group, showFacepile, renderActions }: Props) {
const { groupMemberships } = useStores();
const { t } = useTranslation();
const [membersModalOpen, setMembersModalOpen, setMembersModalClosed] =
useBoolean();
const memberCount = group.memberCount;
const membershipsInGroup = groupMemberships.inGroup(group.id);
const users = membershipsInGroup
.slice(0, MAX_AVATAR_DISPLAY)
.map((gm) => gm.user);
const overflow = memberCount - users.length;
return (
<>
<ListItem
image={
<Image>
<GroupIcon size={24} />
</Image>
}
title={<Title onClick={setMembersModalOpen}>{group.name}</Title>}
subtitle={t("{{ count }} member", { count: memberCount })}
actions={
<Flex align="center" gap={8}>
{showFacepile && (
<NudeButton
width="auto"
height="auto"
onClick={setMembersModalOpen}
>
<Facepile users={users} overflow={overflow} />
</NudeButton>
)}
{renderActions({
openMembersModal: setMembersModalOpen,
})}
</Flex>
}
/>
<Modal
title={t("Group members")}
onRequestClose={setMembersModalClosed}
isOpen={membersModalOpen}
>
<GroupMembers group={group} />
</Modal>
</>
);
}
const Image = styled(Flex)`
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: ${s("secondaryBackground")};
border-radius: 32px;
`;
const Title = styled.span`
&: ${hover} {
text-decoration: underline;
cursor: var(--pointer);
}
`;
export default observer(GroupListItem);
-1
View File
@@ -94,7 +94,6 @@ const Scene = styled.div`
align-items: flex-start;
width: 350px;
background: ${s("background")};
transition: ${s("backgroundTransition")};
border-radius: 8px;
outline: none;
opacity: 0;
+59 -38
View File
@@ -3,6 +3,7 @@ import { observer } from "mobx-react";
import { MenuIcon } from "outline-icons";
import { transparentize } from "polished";
import * as React from "react";
import { mergeRefs } from "react-merge-refs";
import styled from "styled-components";
import breakpoint from "styled-components-breakpoint";
import { depths, s } from "@shared/styles";
@@ -10,25 +11,35 @@ import { supportsPassiveListener } from "@shared/utils/browser";
import Button from "~/components/Button";
import Fade from "~/components/Fade";
import Flex from "~/components/Flex";
import useComponentSize from "~/hooks/useComponentSize";
import useEventListener from "~/hooks/useEventListener";
import useMobile from "~/hooks/useMobile";
import useStores from "~/hooks/useStores";
import { draggableOnDesktop, fadeOnDesktopBackgrounded } from "~/styles";
import Desktop from "~/utils/Desktop";
import { TooltipProvider } from "./TooltipContext";
export const HEADER_HEIGHT = 64;
type Props = {
left?: React.ReactNode;
title: React.ReactNode;
actions?: React.ReactNode;
actions?:
| ((props: { isCompact: boolean }) => React.ReactNode)
| React.ReactNode;
hasSidebar?: boolean;
className?: string;
};
function Header({ left, title, actions, hasSidebar, className }: Props) {
function Header(
{ left, title, actions, hasSidebar, className }: Props,
ref: React.RefObject<HTMLDivElement> | null
) {
const { ui } = useStores();
const isMobile = useMobile();
const hasMobileSidebar = hasSidebar && isMobile;
const internalRef = React.useRef<HTMLDivElement | null>(null);
const breadcrumbsRef = React.useRef<HTMLDivElement | null>(null);
const passThrough = !actions && !left && !title;
const [isScrolled, setScrolled] = React.useState(false);
@@ -51,38 +62,50 @@ function Header({ left, title, actions, hasSidebar, className }: Props) {
});
}, []);
return (
<Wrapper
align="center"
shrink={false}
className={className}
$passThrough={passThrough}
$insetTitleAdjust={ui.sidebarIsClosed && Desktop.hasInsetTitlebar()}
>
{left || hasMobileSidebar ? (
<Breadcrumbs>
{hasMobileSidebar && (
<MobileMenuButton
onClick={ui.toggleMobileSidebar}
icon={<MenuIcon />}
neutral
/>
)}
{left}
</Breadcrumbs>
) : null}
const setBreadcrumbRef = React.useCallback((node: HTMLDivElement | null) => {
breadcrumbsRef.current = node?.firstElementChild as HTMLDivElement;
}, []);
{isScrolled ? (
<Title onClick={handleClickTitle}>
<Fade>{title}</Fade>
</Title>
) : (
<div />
)}
<Actions align="center" justify="flex-end">
{actions}
</Actions>
</Wrapper>
const size = useComponentSize(internalRef);
const breadcrumbsSize = useComponentSize(breadcrumbsRef);
const breadcrumbMakesCompact = breadcrumbsSize.width > size.width / 3;
const isCompact = size.width < 1000 || breadcrumbMakesCompact;
return (
<TooltipProvider>
<Wrapper
ref={mergeRefs([ref, internalRef])}
align="center"
shrink={false}
className={className}
$passThrough={passThrough}
$insetTitleAdjust={ui.sidebarIsClosed && Desktop.hasInsetTitlebar()}
>
{left || hasMobileSidebar ? (
<Breadcrumbs ref={setBreadcrumbRef}>
{hasMobileSidebar && (
<MobileMenuButton
onClick={ui.toggleMobileSidebar}
icon={<MenuIcon />}
neutral
/>
)}
{left}
</Breadcrumbs>
) : null}
{isScrolled && !isCompact ? (
<Title onClick={handleClickTitle}>
<Fade>{title}</Fade>
</Title>
) : (
<div />
)}
<Actions align="center" justify="flex-end">
{typeof actions === "function" ? actions({ isCompact }) : actions}
</Actions>
</Wrapper>
</TooltipProvider>
);
}
@@ -128,9 +151,8 @@ const Wrapper = styled(Flex)<WrapperProps>`
`};
padding: 12px;
transition: all 100ms ease-out;
transform: translate3d(0, 0, 0);
min-height: 64px;
min-height: ${HEADER_HEIGHT}px;
justify-content: flex-start;
${draggableOnDesktop()}
@@ -150,7 +172,6 @@ const Wrapper = styled(Flex)<WrapperProps>`
${breakpoint("tablet")`
padding: 16px;
justify-content: center;
${(props: WrapperProps) => props.$insetTitleAdjust && `padding-left: 64px;`}
`};
`;
@@ -189,4 +210,4 @@ const MobileMenuButton = styled(Button)`
}
`;
export default observer(Header);
export default observer(React.forwardRef(Header));
+2 -1
View File
@@ -2,6 +2,7 @@ import escapeRegExp from "lodash/escapeRegExp";
import * as React from "react";
import replace from "string-replace-to-array";
import styled from "styled-components";
import { s } from "@shared/styles";
type Props = React.HTMLAttributes<HTMLSpanElement> & {
highlight: (string | null | undefined) | RegExp;
@@ -43,7 +44,7 @@ function Highlight({
}
export const Mark = styled.mark`
color: inherit;
color: ${s("text")};
background: transparent;
font-weight: 600;
`;
+23 -6
View File
@@ -2,6 +2,7 @@ import { transparentize } from "polished";
import { Link } from "react-router-dom";
import styled, { css } from "styled-components";
import { s } from "@shared/styles";
import { getTextColor } from "@shared/utils/color";
import Text from "~/components/Text";
export const CARD_MARGIN = 10;
@@ -24,14 +25,15 @@ export const Preview = styled(Link)`
0 0 1px 1px rgba(0, 0, 0, 0.05);
overflow: hidden;
position: absolute;
min-width: 350px;
max-width: 375px;
width: 375px;
`;
export const Title = styled.h2`
font-size: 1.25em;
margin: 0;
color: ${s("text")};
export const Title = styled(Text).attrs({ as: "h2", size: "large" })`
margin-bottom: 4px;
display: flex;
align-items: flex-start;
justify-content: flex-start;
gap: 4px;
`;
export const Info = styled(StyledText).attrs(() => ({
@@ -46,6 +48,7 @@ export const Description = styled(StyledText)`
margin-top: 0.5em;
line-height: var(--line-height);
max-height: calc(var(--line-height) * ${NUMBER_OF_LINES});
overflow: hidden;
`;
export const Thumbnail = styled.img`
@@ -54,6 +57,20 @@ export const Thumbnail = styled.img`
background: ${s("menuBackground")};
`;
export const Label = styled(Text).attrs({ size: "xsmall", weight: "bold" })<{
color?: string;
}>`
background-color: ${(props) =>
props.color ?? props.theme.backgroundSecondary};
color: ${(props) =>
props.color ? getTextColor(props.color) : props.theme.text};
width: fit-content;
border-radius: 2em;
padding: 0 8px;
margin-right: 0.5em;
margin-top: 0.5em;
`;
export const CardContent = styled.div`
overflow: hidden;
user-select: none;
+95 -93
View File
@@ -3,28 +3,30 @@ import * as React from "react";
import { Portal } from "react-portal";
import styled from "styled-components";
import { depths } from "@shared/styles";
import { UnfurlType } from "@shared/types";
import LoadingIndicator from "~/components/LoadingIndicator";
import { UnfurlResourceType } from "@shared/types";
import useEventListener from "~/hooks/useEventListener";
import useKeyDown from "~/hooks/useKeyDown";
import useMobile from "~/hooks/useMobile";
import useOnClickOutside from "~/hooks/useOnClickOutside";
import usePrevious from "~/hooks/usePrevious";
import useRequest from "~/hooks/useRequest";
import useStores from "~/hooks/useStores";
import { client } from "~/utils/ApiClient";
import LoadingIndicator from "../LoadingIndicator";
import { CARD_MARGIN } from "./Components";
import HoverPreviewDocument from "./HoverPreviewDocument";
import HoverPreviewIssue from "./HoverPreviewIssue";
import HoverPreviewLink from "./HoverPreviewLink";
import HoverPreviewMention from "./HoverPreviewMention";
import HoverPreviewPullRequest from "./HoverPreviewPullRequest";
const DELAY_CLOSE = 600;
const DELAY_CLOSE = 500;
const POINTER_HEIGHT = 22;
const POINTER_WIDTH = 22;
type Props = {
/** The HTML element that is being hovered over, or null if none. */
element: HTMLElement | null;
/** Data to be previewed */
data: Record<string, any> | null;
/** Whether the preview data is being loaded */
dataLoading: boolean;
/** A callback on close of the hover preview. */
onClose: () => void;
};
@@ -34,12 +36,10 @@ enum Direction {
DOWN,
}
function HoverPreviewDesktop({ element, onClose }: Props) {
const url = element?.getAttribute("href") || element?.dataset.url;
const previousUrl = usePrevious(url, true);
function HoverPreviewDesktop({ element, data, dataLoading, onClose }: Props) {
const [isVisible, setVisible] = React.useState(false);
const timerClose = React.useRef<ReturnType<typeof setTimeout>>();
const cardRef = React.useRef<HTMLDivElement>(null);
const cardRef = React.useRef<HTMLDivElement | null>(null);
const { cardLeft, cardTop, pointerLeft, pointerTop, pointerDir } =
useHoverPosition({
cardRef,
@@ -65,12 +65,12 @@ function HoverPreviewDesktop({ element, onClose }: Props) {
// Open and close the preview when the element changes.
React.useEffect(() => {
if (element) {
if (element && data && !dataLoading) {
setVisible(true);
} else {
startCloseTimer();
}
}, [startCloseTimer, element]);
}, [startCloseTimer, element, data, dataLoading]);
// Close the preview on Escape, scroll, or click outside.
useOnClickOutside(cardRef, closePreview);
@@ -98,83 +98,7 @@ function HoverPreviewDesktop({ element, onClose }: Props) {
};
}, [element, startCloseTimer, isVisible, stopCloseTimer]);
const displayUrl = url ?? previousUrl;
if (!isVisible || !displayUrl) {
return null;
}
return (
<Portal>
<Position top={cardTop} left={cardLeft} ref={cardRef} aria-hidden>
<DataLoader url={displayUrl}>
{(data) => (
<Animate
initial={{ opacity: 0, y: -20, pointerEvents: "none" }}
animate={{ opacity: 1, y: 0, pointerEvents: "auto" }}
>
{data.type === UnfurlType.Mention ? (
<HoverPreviewMention
url={data.thumbnailUrl}
title={data.title}
info={data.meta.info}
color={data.meta.color}
/>
) : data.type === UnfurlType.Document ? (
<HoverPreviewDocument
id={data.meta.id}
url={data.url}
title={data.title}
description={data.description}
info={data.meta.info}
/>
) : (
<HoverPreviewLink
url={data.url}
thumbnailUrl={data.thumbnailUrl}
title={data.title}
description={data.description}
/>
)}
<Pointer
top={pointerTop}
left={pointerLeft}
direction={pointerDir}
/>
</Animate>
)}
</DataLoader>
</Position>
</Portal>
);
}
function DataLoader({
url,
children,
}: {
url: string;
children: (data: any) => React.ReactNode;
}) {
const { ui } = useStores();
const { data, request, loading } = useRequest(
React.useCallback(
() =>
client.post("/urls.unfurl", {
url,
documentId: ui.activeDocumentId,
}),
[url, ui.activeDocumentId]
)
);
React.useEffect(() => {
if (url) {
void request();
}
}, [url, request]);
if (loading) {
if (dataLoading) {
return <LoadingIndicator />;
}
@@ -182,16 +106,94 @@ function DataLoader({
return null;
}
return <>{children(data)}</>;
return (
<Portal>
<Position top={cardTop} left={cardLeft} aria-hidden>
{isVisible ? (
<Animate
initial={{ opacity: 0, y: -20, pointerEvents: "none" }}
animate={{
opacity: 1,
y: 0,
transitionEnd: { pointerEvents: "auto" },
}}
>
{data.type === UnfurlResourceType.Mention ? (
<HoverPreviewMention
ref={cardRef}
name={data.name}
avatarUrl={data.avatarUrl}
color={data.color}
lastActive={data.lastActive}
email={data.email}
/>
) : data.type === UnfurlResourceType.Document ? (
<HoverPreviewDocument
ref={cardRef}
url={data.url}
id={data.id}
title={data.title}
summary={data.summary}
lastActivityByViewer={data.lastActivityByViewer}
/>
) : data.type === UnfurlResourceType.Issue ? (
<HoverPreviewIssue
ref={cardRef}
url={data.url}
id={data.id}
title={data.title}
description={data.description}
author={data.author}
labels={data.labels}
state={data.state}
createdAt={data.createdAt}
/>
) : data.type === UnfurlResourceType.PR ? (
<HoverPreviewPullRequest
ref={cardRef}
url={data.url}
id={data.id}
title={data.title}
description={data.description}
author={data.author}
createdAt={data.createdAt}
state={data.state}
/>
) : (
<HoverPreviewLink
ref={cardRef}
url={data.url}
thumbnailUrl={data.thumbnailUrl}
title={data.title}
description={data.description}
/>
)}
<Pointer
top={pointerTop}
left={pointerLeft}
direction={pointerDir}
/>
</Animate>
) : null}
</Position>
</Portal>
);
}
function HoverPreview({ element, ...rest }: Props) {
function HoverPreview({ element, data, dataLoading, ...rest }: Props) {
const isMobile = useMobile();
if (isMobile) {
return null;
}
return <HoverPreviewDesktop {...rest} element={element} />;
return (
<HoverPreviewDesktop
{...rest}
element={element}
data={data}
dataLoading={dataLoading}
/>
);
}
function useHoverPosition({
@@ -1,6 +1,9 @@
import * as React from "react";
import { richExtensions } from "@shared/editor/nodes";
import { UnfurlResourceType, UnfurlResponse } from "@shared/types";
import Editor from "~/components/Editor";
import Flex from "~/components/Flex";
import ErrorBoundary from "../ErrorBoundary";
import {
Preview,
Title,
@@ -10,41 +13,33 @@ import {
Description,
} from "./Components";
type Props = {
/** Document id associated with the editor, if any */
id?: string;
/** Document url */
url: string;
/** Title for the preview card */
title: string;
/** Info about last activity on the document */
info: string;
/** Text preview of document content */
description: string;
};
type Props = Omit<UnfurlResponse[UnfurlResourceType.Document], "type">;
const HoverPreviewDocument = React.forwardRef(function _HoverPreviewDocument(
{ id, url, title, info, description }: Props,
{ url, id, title, summary, lastActivityByViewer }: Props,
ref: React.Ref<HTMLDivElement>
) {
return (
<Preview to={url}>
<Card ref={ref}>
<CardContent>
<Flex column gap={2}>
<Title>{title}</Title>
<Info>{info}</Info>
<Description as="div">
<React.Suspense fallback={<div />}>
<Editor
key={id}
defaultValue={description}
embedsDisabled
readOnly
/>
</React.Suspense>
</Description>
</Flex>
<ErrorBoundary showTitle={false} reloadOnChunkMissing={false}>
<Flex column gap={2}>
<Title>{title}</Title>
<Info>{lastActivityByViewer}</Info>
<Description as="div">
<React.Suspense fallback={<div />}>
<Editor
key={id}
extensions={richExtensions}
defaultValue={summary}
embedsDisabled
readOnly
/>
</React.Suspense>
</Description>
</Flex>
</ErrorBoundary>
</CardContent>
</Card>
</Preview>
@@ -0,0 +1,65 @@
import * as React from "react";
import { Trans } from "react-i18next";
import { UnfurlResourceType, UnfurlResponse } from "@shared/types";
import { Avatar } from "~/components/Avatar";
import Flex from "~/components/Flex";
import { IssueStatusIcon } from "../Icons/IssueStatusIcon";
import Text from "../Text";
import Time from "../Time";
import {
Preview,
Title,
Description,
Card,
CardContent,
Label,
Info,
} from "./Components";
type Props = Omit<UnfurlResponse[UnfurlResourceType.Issue], "type">;
const HoverPreviewIssue = React.forwardRef(function _HoverPreviewIssue(
{ url, id, title, description, author, labels, state, createdAt }: Props,
ref: React.Ref<HTMLDivElement>
) {
const authorName = author.name;
return (
<Preview as="a" href={url} target="_blank" rel="noopener noreferrer">
<Flex column ref={ref}>
<Card fadeOut={false}>
<CardContent>
<Flex gap={2} column>
<Title>
<IssueStatusIcon status={state.name} color={state.color} />
<span>
{title}&nbsp;<Text type="tertiary">{id}</Text>
</span>
</Title>
<Flex align="center" gap={4}>
<Avatar src={author.avatarUrl} />
<Info>
<Trans>
{{ authorName }} created{" "}
<Time dateTime={createdAt} addSuffix />
</Trans>
</Info>
</Flex>
<Description>{description}</Description>
<Flex wrap>
{labels.map((label, index) => (
<Label key={index} color={label.color}>
{label.name}
</Label>
))}
</Flex>
</Flex>
</CardContent>
</Card>
</Flex>
</Preview>
);
});
export default HoverPreviewIssue;
@@ -1,22 +1,13 @@
import * as React from "react";
import Avatar from "~/components/Avatar";
import { AvatarSize } from "~/components/Avatar/Avatar";
import { UnfurlResourceType, UnfurlResponse } from "@shared/types";
import { Avatar, AvatarSize } from "~/components/Avatar";
import Flex from "~/components/Flex";
import { Preview, Title, Info, Card, CardContent } from "./Components";
type Props = {
/** Resource url, avatar url in case of user mention */
url: string;
/** Title for the preview card*/
title: string;
/** Info about mentioned user's recent activity */
info: string;
/** Used for avatar's background color in absence of avatar url */
color: string;
};
type Props = Omit<UnfurlResponse[UnfurlResourceType.Mention], "type">;
const HoverPreviewMention = React.forwardRef(function _HoverPreviewMention(
{ url, title, info, color }: Props,
{ avatarUrl, name, lastActive, color, email }: Props,
ref: React.Ref<HTMLDivElement>
) {
return (
@@ -26,15 +17,16 @@ const HoverPreviewMention = React.forwardRef(function _HoverPreviewMention(
<Flex gap={12}>
<Avatar
model={{
avatarUrl: url,
initial: title ? title[0] : "?",
avatarUrl,
initial: name ? name[0] : "?",
color,
}}
size={AvatarSize.XLarge}
/>
<Flex column gap={2} justify="center">
<Title>{title}</Title>
<Info>{info}</Info>
<Title>{name}</Title>
{email && <Info>{email}</Info>}
<Info>{lastActive}</Info>
</Flex>
</Flex>
</CardContent>
@@ -0,0 +1,58 @@
import * as React from "react";
import { Trans } from "react-i18next";
import { UnfurlResourceType, UnfurlResponse } from "@shared/types";
import { Avatar } from "~/components/Avatar";
import Flex from "~/components/Flex";
import { PullRequestIcon } from "../Icons/PullRequestIcon";
import Text from "../Text";
import Time from "../Time";
import {
Preview,
Title,
Description,
Card,
CardContent,
Info,
} from "./Components";
type Props = Omit<UnfurlResponse[UnfurlResourceType.PR], "type">;
const HoverPreviewPullRequest = React.forwardRef(
function _HoverPreviewPullRequest(
{ url, title, id, description, author, state, createdAt }: Props,
ref: React.Ref<HTMLDivElement>
) {
const authorName = author.name;
return (
<Preview as="a" href={url} target="_blank" rel="noopener noreferrer">
<Flex column ref={ref}>
<Card fadeOut={false}>
<CardContent>
<Flex gap={2} column>
<Title>
<PullRequestIcon status={state.name} color={state.color} />
<span>
{title}&nbsp;<Text type="tertiary">{id}</Text>
</span>
</Title>
<Flex align="center" gap={4}>
<Avatar src={author.avatarUrl} />
<Info>
<Trans>
{{ authorName }} opened{" "}
<Time dateTime={createdAt} addSuffix />
</Trans>
</Info>
</Flex>
<Description>{description}</Description>
</Flex>
</CardContent>
</Card>
</Flex>
</Preview>
);
}
);
export default HoverPreviewPullRequest;
-192
View File
@@ -1,192 +0,0 @@
import * as React from "react";
import { useTranslation } from "react-i18next";
import { PopoverDisclosure, usePopoverState } from "reakit";
import { MenuItem } from "reakit/Menu";
import styled, { useTheme } from "styled-components";
import { colorPalette } from "@shared/utils/collections";
import Flex from "~/components/Flex";
import NudeButton from "~/components/NudeButton";
import Text from "~/components/Text";
import useOnClickOutside from "~/hooks/useOnClickOutside";
import lazyWithRetry from "~/utils/lazyWithRetry";
import DelayedMount from "./DelayedMount";
import { IconLibrary } from "./Icons/IconLibrary";
import Popover from "./Popover";
const icons = IconLibrary.mapping;
const TwitterPicker = lazyWithRetry(
() => import("react-color/lib/components/twitter/Twitter")
);
type Props = {
onOpen?: () => void;
onClose?: () => void;
onChange: (color: string, icon: string) => void;
initial: string;
icon: string;
color: string;
className?: string;
};
function IconPicker({
onOpen,
onClose,
icon,
initial,
color,
onChange,
className,
}: Props) {
const { t } = useTranslation();
const theme = useTheme();
const popover = usePopoverState({
gutter: 0,
placement: "bottom",
modal: true,
});
React.useEffect(() => {
if (popover.visible) {
onOpen?.();
} else {
onClose?.();
}
}, [onOpen, onClose, popover.visible]);
const styles = React.useMemo(
() => ({
default: {
body: {
padding: 0,
marginRight: -8,
},
hash: {
color: theme.text,
background: theme.inputBorder,
},
swatch: {
cursor: "var(--cursor-pointer)",
},
input: {
color: theme.text,
boxShadow: `inset 0 0 0 1px ${theme.inputBorder}`,
background: "transparent",
},
},
}),
[theme]
);
// Custom click outside handling rather than using `hideOnClickOutside` from reakit so that we can
// prevent event bubbling.
useOnClickOutside(
popover.unstable_popoverRef,
(event) => {
if (popover.visible) {
event.stopPropagation();
event.preventDefault();
popover.hide();
}
},
{ capture: true }
);
return (
<>
<PopoverDisclosure {...popover}>
{(props) => (
<NudeButton
aria-label={t("Show menu")}
className={className}
{...props}
>
<Icon
as={IconLibrary.getComponent(icon || "collection")}
color={color}
>
{initial}
</Icon>
</NudeButton>
)}
</PopoverDisclosure>
<Popover
{...popover}
width={388}
aria-label={t("Choose icon")}
hideOnClickOutside={false}
>
<Icons>
{Object.keys(icons).map((name, index) => (
<MenuItem key={name} onClick={() => onChange(color, name)}>
{(props) => (
<IconButton
style={
{
"--delay": `${index * 8}ms`,
} as React.CSSProperties
}
{...props}
>
<Icon
as={IconLibrary.getComponent(name)}
color={color}
size={30}
>
{initial}
</Icon>
</IconButton>
)}
</MenuItem>
))}
</Icons>
<Colors>
<React.Suspense
fallback={
<DelayedMount>
<Text>{t("Loading")}</Text>
</DelayedMount>
}
>
<ColorPicker
color={color}
onChange={(color) => onChange(color.hex, icon)}
colors={colorPalette}
triangle="hide"
styles={styles}
/>
</React.Suspense>
</Colors>
</Popover>
</>
);
}
const Icon = styled.svg`
transition: fill 150ms ease-in-out;
transition-delay: var(--delay);
`;
const Colors = styled(Flex)`
padding: 8px;
`;
const Icons = styled.div`
padding: 8px;
`;
const IconButton = styled(NudeButton)`
vertical-align: top;
border-radius: 4px;
margin: 0px 6px 6px 0px;
width: 30px;
height: 30px;
`;
const ColorPicker = styled(TwitterPicker)`
box-shadow: none !important;
background: transparent !important;
width: 100% !important;
`;
export default IconPicker;
@@ -0,0 +1,217 @@
import { BackIcon } from "outline-icons";
import React from "react";
import styled from "styled-components";
import { breakpoints, s, hover } from "@shared/styles";
import { colorPalette } from "@shared/utils/collections";
import { validateColorHex } from "@shared/utils/color";
import Flex from "~/components/Flex";
import NudeButton from "~/components/NudeButton";
import Text from "~/components/Text";
enum Panel {
Builtin,
Hex,
}
type Props = {
width: number;
activeColor: string;
onSelect: (color: string) => void;
};
const ColorPicker = ({ width, activeColor, onSelect }: Props) => {
const [localValue, setLocalValue] = React.useState(activeColor);
const [panel, setPanel] = React.useState(
colorPalette.includes(activeColor) ? Panel.Builtin : Panel.Hex
);
const handleSwitcherClick = React.useCallback(() => {
setPanel(panel === Panel.Builtin ? Panel.Hex : Panel.Builtin);
}, [panel, setPanel]);
const isLargeMobile = width > breakpoints.mobileLarge + 12; // 12px for the Container padding
React.useEffect(() => {
setLocalValue(activeColor);
setPanel(colorPalette.includes(activeColor) ? Panel.Builtin : Panel.Hex);
}, [activeColor]);
return isLargeMobile ? (
<Container justify="space-between">
<LargeMobileBuiltinColors activeColor={activeColor} onClick={onSelect} />
<LargeMobileCustomColor
value={localValue}
setLocalValue={setLocalValue}
onValidHex={onSelect}
/>
</Container>
) : (
<Container gap={12}>
<PanelSwitcher align="center">
<SwitcherButton panel={panel} onClick={handleSwitcherClick}>
{panel === Panel.Builtin ? "#" : <BackIcon />}
</SwitcherButton>
</PanelSwitcher>
{panel === Panel.Builtin ? (
<BuiltinColors activeColor={activeColor} onClick={onSelect} />
) : (
<CustomColor
value={localValue}
setLocalValue={setLocalValue}
onValidHex={onSelect}
/>
)}
</Container>
);
};
const BuiltinColors = ({
activeColor,
onClick,
className,
}: {
activeColor: string;
onClick: (color: string) => void;
className?: string;
}) => (
<Flex className={className} justify="space-between" align="center" auto>
{colorPalette.map((color) => (
<ColorButton
key={color}
$color={color}
$active={color === activeColor}
onClick={() => onClick(color)}
>
<Selected />
</ColorButton>
))}
</Flex>
);
const CustomColor = ({
value,
setLocalValue,
onValidHex,
className,
}: {
value: string;
setLocalValue: (value: string) => void;
onValidHex: (color: string) => void;
className?: string;
}) => {
const hasHexChars = React.useCallback(
(color: string) => /(^#[0-9A-F]{1,6}$)/i.test(color),
[]
);
const handleInputChange = React.useCallback(
(ev: React.ChangeEvent<HTMLInputElement>) => {
const val = ev.target.value;
if (val === "" || val === "#") {
setLocalValue("#");
return;
}
const uppercasedVal = val.toUpperCase();
if (hasHexChars(uppercasedVal)) {
setLocalValue(uppercasedVal);
}
if (validateColorHex(uppercasedVal)) {
onValidHex(uppercasedVal);
}
},
[setLocalValue, hasHexChars, onValidHex]
);
return (
<Flex className={className} align="center" gap={8}>
<Text type="tertiary" size="small">
HEX
</Text>
<CustomColorInput
maxLength={7}
value={value}
onChange={handleInputChange}
/>
</Flex>
);
};
const Container = styled(Flex)`
height: 48px;
padding: 8px 12px;
border-bottom: 1px solid ${s("inputBorder")};
`;
const Selected = styled.span`
width: 10px;
height: 5px;
border-left: 2px solid white;
border-bottom: 2px solid white;
transform: translateY(-25%) rotate(-45deg);
`;
const ColorButton = styled(NudeButton)<{ $color: string; $active: boolean }>`
display: inline-flex;
justify-content: center;
align-items: center;
width: 24px;
height: 24px;
border-radius: 50%;
background-color: ${({ $color }) => $color};
&: ${hover} {
outline: 2px solid ${s("menuBackground")} !important;
box-shadow: ${({ $color }) => `0px 0px 3px 3px ${$color}`};
}
& ${Selected} {
display: ${({ $active }) => ($active ? "block" : "none")};
}
`;
const PanelSwitcher = styled(Flex)`
width: 40px;
border-right: 1px solid ${s("inputBorder")};
`;
const SwitcherButton = styled(NudeButton)<{ panel: Panel }>`
display: inline-flex;
justify-content: center;
align-items: center;
font-size: 14px;
border: 1px solid ${s("inputBorder")};
transition: all 100ms ease-in-out;
&: ${hover} {
border-color: ${s("inputBorderFocused")};
}
`;
const LargeMobileBuiltinColors = styled(BuiltinColors)`
max-width: 380px;
padding-right: 8px;
`;
const LargeMobileCustomColor = styled(CustomColor)`
padding-left: 8px;
border-left: 1px solid ${s("inputBorder")};
width: 120px;
`;
const CustomColorInput = styled.input.attrs(() => ({
type: "text",
autocomplete: "off",
}))`
font-size: 14px;
color: ${s("textSecondary")};
background: transparent;
border: 0;
outline: 0;
`;
export default ColorPicker;
@@ -0,0 +1,243 @@
import concat from "lodash/concat";
import React from "react";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import { EmojiCategory, EmojiSkinTone, IconType } from "@shared/types";
import { getEmojis, getEmojisWithCategory, search } from "@shared/utils/emoji";
import Flex from "~/components/Flex";
import InputSearch from "~/components/InputSearch";
import usePersistedState from "~/hooks/usePersistedState";
import {
FREQUENTLY_USED_COUNT,
DisplayCategory,
emojiSkinToneKey,
emojisFreqKey,
lastEmojiKey,
sortFrequencies,
} from "../utils";
import GridTemplate, { DataNode } from "./GridTemplate";
import SkinTonePicker from "./SkinTonePicker";
const GRID_HEIGHT = 410;
const useEmojiState = () => {
const [emojiSkinTone, setEmojiSkinTone] = usePersistedState<EmojiSkinTone>(
emojiSkinToneKey,
EmojiSkinTone.Default
);
const [emojisFreq, setEmojisFreq] = usePersistedState<Record<string, number>>(
emojisFreqKey,
{}
);
const [lastEmoji, setLastEmoji] = usePersistedState<string | undefined>(
lastEmojiKey,
undefined
);
const incrementEmojiCount = React.useCallback(
(emoji: string) => {
emojisFreq[emoji] = (emojisFreq[emoji] ?? 0) + 1;
setEmojisFreq({ ...emojisFreq });
setLastEmoji(emoji);
},
[emojisFreq, setEmojisFreq, setLastEmoji]
);
const getFreqEmojis = React.useCallback(() => {
const freqs = Object.entries(emojisFreq);
if (freqs.length > FREQUENTLY_USED_COUNT.Track) {
sortFrequencies(freqs).splice(FREQUENTLY_USED_COUNT.Track);
setEmojisFreq(Object.fromEntries(freqs));
}
const emojis = sortFrequencies(freqs)
.slice(0, FREQUENTLY_USED_COUNT.Get)
.map(([emoji, _]) => emoji);
const isLastPresent = emojis.includes(lastEmoji ?? "");
if (lastEmoji && !isLastPresent) {
emojis.pop();
emojis.push(lastEmoji);
}
return emojis;
}, [emojisFreq, setEmojisFreq, lastEmoji]);
return {
emojiSkinTone,
setEmojiSkinTone,
incrementEmojiCount,
getFreqEmojis,
};
};
type Props = {
panelWidth: number;
query: string;
panelActive: boolean;
height?: number;
onEmojiChange: (emoji: string) => void;
onQueryChange: (query: string) => void;
};
const EmojiPanel = ({
panelWidth,
query,
panelActive,
onEmojiChange,
onQueryChange,
height = GRID_HEIGHT,
}: Props) => {
const { t } = useTranslation();
const searchRef = React.useRef<HTMLInputElement | null>(null);
const scrollableRef = React.useRef<HTMLDivElement | null>(null);
const {
emojiSkinTone: skinTone,
setEmojiSkinTone,
incrementEmojiCount,
getFreqEmojis,
} = useEmojiState();
const freqEmojis = React.useMemo(() => getFreqEmojis(), [getFreqEmojis]);
const handleFilter = React.useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
onQueryChange(event.target.value);
},
[onQueryChange]
);
const handleSkinChange = React.useCallback(
(emojiSkinTone: EmojiSkinTone) => {
setEmojiSkinTone(emojiSkinTone);
},
[setEmojiSkinTone]
);
const handleEmojiSelection = React.useCallback(
({ id, value }: { id: string; value: string }) => {
onEmojiChange(value);
incrementEmojiCount(id);
},
[onEmojiChange, incrementEmojiCount]
);
const isSearch = query !== "";
const templateData: DataNode[] = isSearch
? getSearchResults({
query,
skinTone,
})
: getAllEmojis({
skinTone,
freqEmojis,
});
React.useEffect(() => {
if (scrollableRef.current) {
scrollableRef.current.scrollTop = 0;
}
searchRef.current?.focus();
}, [panelActive]);
return (
<Flex column>
<UserInputContainer align="center" gap={12}>
<StyledInputSearch
ref={searchRef}
value={query}
placeholder={`${t("Search emoji")}`}
onChange={handleFilter}
/>
<SkinTonePicker skinTone={skinTone} onChange={handleSkinChange} />
</UserInputContainer>
<GridTemplate
ref={scrollableRef}
width={panelWidth}
height={height - 48}
data={templateData}
onIconSelect={handleEmojiSelection}
/>
</Flex>
);
};
const getSearchResults = ({
query,
skinTone,
}: {
query: string;
skinTone: EmojiSkinTone;
}): DataNode[] => {
const emojis = search({ query, skinTone });
return [
{
category: DisplayCategory.Search,
icons: emojis.map((emoji) => ({
type: IconType.Emoji,
id: emoji.id,
value: emoji.value,
})),
},
];
};
const getAllEmojis = ({
skinTone,
freqEmojis,
}: {
skinTone: EmojiSkinTone;
freqEmojis: string[];
}): DataNode[] => {
const emojisWithCategory = getEmojisWithCategory({ skinTone });
const getFrequentEmojis = (): DataNode => {
const emojis = getEmojis({ ids: freqEmojis, skinTone });
return {
category: DisplayCategory.Frequent,
icons: emojis.map((emoji) => ({
type: IconType.Emoji,
id: emoji.id,
value: emoji.value,
})),
};
};
const getCategoryData = (emojiCategory: EmojiCategory): DataNode => {
const emojis = emojisWithCategory[emojiCategory] ?? [];
return {
category: emojiCategory,
icons: emojis.map((emoji) => ({
type: IconType.Emoji,
id: emoji.id,
value: emoji.value,
})),
};
};
return concat(
getFrequentEmojis(),
getCategoryData(EmojiCategory.People),
getCategoryData(EmojiCategory.Nature),
getCategoryData(EmojiCategory.Foods),
getCategoryData(EmojiCategory.Activity),
getCategoryData(EmojiCategory.Places),
getCategoryData(EmojiCategory.Objects),
getCategoryData(EmojiCategory.Symbols),
getCategoryData(EmojiCategory.Flags)
);
};
const UserInputContainer = styled(Flex)`
height: 48px;
padding: 6px 12px 0px;
`;
const StyledInputSearch = styled(InputSearch)`
flex-grow: 1;
`;
export default EmojiPanel;

Some files were not shown because too many files have changed in this diff Show More