Compare commits

...

16 Commits

Author SHA1 Message Date
Peng Xiao
f4c20056a0 feat(core): moving in affine-reader doc parsers (#12840)
fix AI-191

#### PR Dependency Tree


* **PR #12840** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced the ability to convert rich text documents into Markdown,
supporting a wide range of content types such as headings, lists,
tables, images, code blocks, attachments, and embedded documents.
- Added support for parsing collaborative document structures and
rendering them as structured Markdown or parsed representations.
- Enhanced handling of database and table blocks, including conversion
to Markdown tables with headers and cell content.

- **Documentation**
  - Added a README noting the use of a forked Markdown converter.

- **Tests**
  - Added new test coverage for document parsing features.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


#### PR Dependency Tree


* **PR #12840** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
2025-06-17 16:32:11 +08:00
Cats Juice
dfe4c22a75 feat(core): linked doc visiblity setting and new sidebar layout (#12836)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a setting to control the visibility of linked document
structures in the sidebar, enabled by default.
- Introduced a "dense" mode for workspace selectors and cards, providing
a more compact display.

- **Improvements**
- Refined sidebar and navigation panel layouts with updated padding,
spacing, and avatar/button sizing for a cleaner and more consistent
appearance.
- Enhanced sidebar appearance settings UI, including new localization
for the linked doc visibility option.
- Updated color theming and spacing in sidebar menu items and quick
search input for better usability.
- Enabled collapsible behavior control for navigation panel tree nodes,
improving user interaction flexibility.

- **Style**
- Adjusted various component styles for improved compactness and
alignment across the sidebar and navigation panels.
- Reduced sizes and padding of buttons and icons for a tidier interface.
- Updated CSS variables and dynamic sizing for workspace cards to
support dense mode.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-17 16:09:34 +08:00
L-Sun
ba718b955a fix(editor): unexpectedly update edgeless note in readonly mode (#12839)
#### PR Dependency Tree


* **PR #12839** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
2025-06-17 15:42:47 +08:00
DarkSky
09c3aa0a92 chore(server): improve semantic search (#12838)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Updated document-related tools in chat prompts, including new options
for document keyword and semantic search.

- **Refactor**
- Renamed and reorganized document search tools for improved clarity in
tool selection and results display.

- **Bug Fixes**
- Ensured tool identifiers and results are consistent across chat and
search features.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-17 15:01:02 +08:00
Yii
a4d929b19c ci: remove graphite pre check (#12834)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Chores**
- Updated the CI workflow by removing the "optimize_ci" job and all
related dependencies and conditions. All remaining jobs now run
unconditionally.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-17 13:37:10 +08:00
EYHN
c1691157f9 feat(core): enable socket cors (#12823)
fix android & ios selfhost syncing

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Improved WebSocket connection compatibility by enabling cross-origin
requests with credentials and restricting allowed HTTP methods to GET
and POST.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: fengmk2 <fengmk2@gmail.com>
2025-06-17 09:40:08 +08:00
Cats Juice
2366c1aba6 feat(core): adjust the layout, style, and structure of the AI chat input (#12828)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added support for image uploads in the chat panel, including upload
limits and user feedback when limits are exceeded.
- Introduced a unified chat input preference menu for selecting AI
models, toggling extended thinking, and enabling web search.
- Menu buttons and menus now support test identifiers for improved
testing.

- **Improvements**
- Updated chat input UI with enhanced styling, consolidated controls,
and simplified feature toggling.
  - Improved layout and spacing for chat chips and image preview grids.
  - Chat abort icon now adapts to the current color theme.

- **Refactor**
- Replaced the separate AI model selection component with the new chat
input preference menu.
- Streamlined imports and custom element registrations for chat input
preferences.

- **Tests**
- Enhanced test utilities to support the new chat input preference menu
interactions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-17 09:26:29 +08:00
DarkSky
cdaaa52845 feat(server): embedding search tool (#12810) 2025-06-17 09:22:56 +08:00
Mirone
0785438cfe docs(editor): add typedoc for schema module (#12830)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Documentation**
- Added comprehensive documentation for the `Schema` class, detailing
its methods, properties, and usage.
- Improved formatting and linking in the documentation for the `Store`
class, enhancing clarity and navigation.
- Updated the README to include a direct link to the new `Schema` class
documentation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-16 22:24:40 +08:00
Mirone
8f5851e8bf chore: disable code block html preview (#12829)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Chores**
- Updated the default setting for the code block HTML preview feature
flag; it is now disabled by default. This change affects only
experimental builds.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: L-Sun <zover.v@gmail.com>
2025-06-16 21:28:42 +08:00
Aadi
1fb68e3933 fix(editor): filterableList - prevent undefined item selection in keyboard nav (#12818)
Fixes error in FilterableList when pressing Enter on empty search
results.


![image](https://github.com/user-attachments/assets/3929c7ab-b20e-40d9-bc3d-808762ada8f3)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Resolved an issue where pressing Enter could cause errors if no item
was focused in filterable lists. Now, selection only occurs when a valid
item is focused.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-16 18:05:49 +08:00
DarkSky
e118db4387 chore(ios): update gql schema (#12825)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced advanced search and aggregation capabilities, including
support for new search query types, options, and pagination.
- Added new GraphQL mutations and queries for managing workspace
embedding files and ignored documents.
- Extended user and workspace management with new fields and
configuration options.
- Added support for sending test emails and validating app
configuration.

- **Improvements**
- Enhanced license management with updated fragments and additional
fields.
- Improved invitation and member management workflows, including removal
of deprecated arguments and streamlined APIs.
- Expanded support for audio transcription actions and retry
functionality.
- Added new enum values for OAuth providers, server features, and
workspace member status.

- **Removals**
- Deprecated and removed legacy queries and mutations related to user
roles and invitations.

- **Bug Fixes**
- Corrected field types and documentation comments for improved
consistency and clarity.

- **Other**
- Numerous schema and type updates to support new features and enhance
data modeling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-16 16:35:15 +08:00
fengmk2
c0c813edfd feat(server): search blob names from indexer (#12822)
#### PR Dependency Tree


* **PR #12822** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added the ability to search for blob names by their IDs within a
workspace.
- **Tests**
- Introduced new test cases and snapshot tests to validate searching
blob names and reading filenames from document snapshots.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2025-06-16 16:34:23 +08:00
renovate[bot]
4f75111055 chore: bump up sinon version to v21 (#12827)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [sinon](https://sinonjs.org/)
([source](https://redirect.github.com/sinonjs/sinon)) | [`^20.0.0` ->
`^21.0.0`](https://renovatebot.com/diffs/npm/sinon/20.0.0/21.0.0) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/sinon/21.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/sinon/21.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/sinon/20.0.0/21.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/sinon/20.0.0/21.0.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>sinonjs/sinon (sinon)</summary>

###
[`v21.0.0`](https://redirect.github.com/sinonjs/sinon/blob/HEAD/CHANGES.md#2100)

[Compare
Source](https://redirect.github.com/sinonjs/sinon/compare/v20.0.0...52b0d97a0ff32888a26941325b9dc0a059fdf739)

-
[`fd10f13f`](fd10f13f3f)
chore!: remove assert.failException property
([#&#8203;2659](https://redirect.github.com/sinonjs/sinon/issues/2659))
(Morgan Roderick)
> This was used for allowing customisation of the thrown error between
> sandboxes and for customisation for integrations (most likely from the
    > days of BusterJS).
    >
> To my knowledge and what I've been able to find on GitHub, this has
    > never had any *production* use by end users.
    >
    > BREAKING CHANGE: this removes assert.failException from the API

*Released by Morgan Roderick on 2025-06-13.*

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/toeverything/AFFiNE).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6ImNhbmFyeSIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 16:23:37 +08:00
renovate[bot]
3335f9bb00 chore: bump up @nestjs-cls/transactional-adapter-prisma version to v1.2.24 (#12826)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
|
[@nestjs-cls/transactional-adapter-prisma](https://papooch.github.io/nestjs-cls/)
([source](https://redirect.github.com/Papooch/nestjs-cls)) | [`1.2.23`
->
`1.2.24`](https://renovatebot.com/diffs/npm/@nestjs-cls%2ftransactional-adapter-prisma/1.2.23/1.2.24)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/@nestjs-cls%2ftransactional-adapter-prisma/1.2.24?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@nestjs-cls%2ftransactional-adapter-prisma/1.2.24?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@nestjs-cls%2ftransactional-adapter-prisma/1.2.23/1.2.24?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nestjs-cls%2ftransactional-adapter-prisma/1.2.23/1.2.24?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>Papooch/nestjs-cls
(@&#8203;nestjs-cls/transactional-adapter-prisma)</summary>

###
[`v1.2.24`](https://redirect.github.com/Papooch/nestjs-cls/compare/@nestjs-cls/transactional-adapter-prisma@1.2.23...@nestjs-cls/transactional-adapter-prisma@1.2.24)

[Compare
Source](https://redirect.github.com/Papooch/nestjs-cls/compare/@nestjs-cls/transactional-adapter-prisma@1.2.23...@nestjs-cls/transactional-adapter-prisma@1.2.24)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/toeverything/AFFiNE).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC41MC4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6ImNhbmFyeSIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 15:54:27 +08:00
renovate[bot]
566ff7470e chore: bump up oxlint version to v1.1.0 (#12509)
This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [oxlint](https://oxc.rs)
([source](https://redirect.github.com/oxc-project/oxc/tree/HEAD/npm/oxlint))
| [`0.16.11` ->
`0.18.1`](https://renovatebot.com/diffs/npm/oxlint/0.16.11/0.18.1) |
[![age](https://developer.mend.io/api/mc/badges/age/npm/oxlint/0.18.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/oxlint/0.18.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/oxlint/0.16.11/0.18.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/oxlint/0.16.11/0.18.1?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

---

### Release Notes

<details>
<summary>oxc-project/oxc (oxlint)</summary>

###
[`v0.18.1`](https://redirect.github.com/oxc-project/oxc/releases/tag/oxlint_v0.18.1):
oxlint v0.18.1

[Compare
Source](https://redirect.github.com/oxc-project/oxc/compare/oxlint_v0.18.0...oxlint_v0.18.1)

#### \[0.18.1] - 2025-06-09

##### 🐛 Bug Fixes

-
[`6d68568`](https://redirect.github.com/oxc-project/oxc/commit/6d68568)
linter: False negative in typescript/array-type
([#&#8203;11574](https://redirect.github.com/oxc-project/oxc/issues/11574))
(camc314)
-
[`6a856a0`](https://redirect.github.com/oxc-project/oxc/commit/6a856a0)
linter/no-magic-numbers: Fix typo in error message
([#&#8203;11560](https://redirect.github.com/oxc-project/oxc/issues/11560))
(overlookmotel)
-
[`3952e01`](https://redirect.github.com/oxc-project/oxc/commit/3952e01)
linter: False negative in jsx-a11y/aria-role
([#&#8203;11547](https://redirect.github.com/oxc-project/oxc/issues/11547))
(camc314)
-
[`b0e3e08`](https://redirect.github.com/oxc-project/oxc/commit/b0e3e08)
linter: Misplaced quote in jsx-curly-brace-presence test case
([#&#8203;11546](https://redirect.github.com/oxc-project/oxc/issues/11546))
(camc314)
-
[`a833ed1`](https://redirect.github.com/oxc-project/oxc/commit/a833ed1)
linter: Misplaced quote in anchor-is-valid test case
([#&#8203;11545](https://redirect.github.com/oxc-project/oxc/issues/11545))
(camc314)
-
[`4e53b80`](https://redirect.github.com/oxc-project/oxc/commit/4e53b80)
linter: Misplaced backtick in exhaustive-deps test case
([#&#8203;11544](https://redirect.github.com/oxc-project/oxc/issues/11544))
(camc314)
-
[`e8a04b6`](https://redirect.github.com/oxc-project/oxc/commit/e8a04b6)
linter: Misplaced backtick in no-object-constructor test case
([#&#8203;11543](https://redirect.github.com/oxc-project/oxc/issues/11543))
(camc314)
-
[`65311d0`](https://redirect.github.com/oxc-project/oxc/commit/65311d0)
linter: Remove duplicate rule/scope from diagnostic
([#&#8203;11531](https://redirect.github.com/oxc-project/oxc/issues/11531))
(camc314)

##### 🚜 Refactor

-
[`7ab84c2`](https://redirect.github.com/oxc-project/oxc/commit/7ab84c2)
editor: Use pattern for textDocument filter
([#&#8203;11559](https://redirect.github.com/oxc-project/oxc/issues/11559))
(Sysix)
-
[`9b475ad`](https://redirect.github.com/oxc-project/oxc/commit/9b475ad)
linter: Use one instance of rope per file
([#&#8203;11552](https://redirect.github.com/oxc-project/oxc/issues/11552))
(Sysix)

##### 📚 Documentation

-
[`e13ed51`](https://redirect.github.com/oxc-project/oxc/commit/e13ed51)
editor/vscode: Fix typo in README
([#&#8203;11572](https://redirect.github.com/oxc-project/oxc/issues/11572))
(David)
-
[`fa924ab`](https://redirect.github.com/oxc-project/oxc/commit/fa924ab)
linter: Cleanup docs for multiple linter rules
([#&#8203;11551](https://redirect.github.com/oxc-project/oxc/issues/11551))
(Ulrich Stark)

#####  Performance

-
[`7bf25cb`](https://redirect.github.com/oxc-project/oxc/commit/7bf25cb)
language_server: Transform `MessageWithPosition` to `Diagnostic` with
less allocations
([#&#8203;11561](https://redirect.github.com/oxc-project/oxc/issues/11561))
(Sysix)

###
[`v0.18.0`](https://redirect.github.com/oxc-project/oxc/releases/tag/oxlint_v0.18.0):
oxlint v0.18.0

[Compare
Source](https://redirect.github.com/oxc-project/oxc/compare/oxlint_v0.17.0...oxlint_v0.18.0)

#### \[0.18.0] - 2025-06-06

-
[`bd9dd88`](https://redirect.github.com/oxc-project/oxc/commit/bd9dd88)
linter: \[**BREAKING**] Add more info to json reporter
([#&#8203;11524](https://redirect.github.com/oxc-project/oxc/issues/11524))
(camc314)

##### Features

-
[`825d40c`](https://redirect.github.com/oxc-project/oxc/commit/825d40c)
linter: Fix casing in unicorn/no-useless-promise-resolve-reject
([#&#8203;11528](https://redirect.github.com/oxc-project/oxc/issues/11528))
(camc314)
-
[`2faee3d`](https://redirect.github.com/oxc-project/oxc/commit/2faee3d)
linter: Fix grammer in react/exhaustive-deps
([#&#8203;11527](https://redirect.github.com/oxc-project/oxc/issues/11527))
(camc314)

##### Bug Fixes

-
[`1a71d7c`](https://redirect.github.com/oxc-project/oxc/commit/1a71d7c)
linter: Misplaced backtick in unicorn/no-array-for-each diagnostic
([#&#8203;11529](https://redirect.github.com/oxc-project/oxc/issues/11529))
(camc314)
-
[`7430b14`](https://redirect.github.com/oxc-project/oxc/commit/7430b14)
linter: Grammer in jest/valid-expect diagnostic
([#&#8203;11522](https://redirect.github.com/oxc-project/oxc/issues/11522))
(camc314)
-
[`b92ac41`](https://redirect.github.com/oxc-project/oxc/commit/b92ac41)
linter: Grammer in eslint/no-redeclare diagnostic
([#&#8203;11521](https://redirect.github.com/oxc-project/oxc/issues/11521))
(camc314)
-
[`17883e3`](https://redirect.github.com/oxc-project/oxc/commit/17883e3)
linter: Improve eslint/no-unsafe-negation diagnostic
([#&#8203;11520](https://redirect.github.com/oxc-project/oxc/issues/11520))
(camc314)
-
[`8c89937`](https://redirect.github.com/oxc-project/oxc/commit/8c89937)
linter: Improve eslint/no-shadow-restricted-names diagnostic
([#&#8203;11519](https://redirect.github.com/oxc-project/oxc/issues/11519))
(camc314)
-
[`3f0d889`](https://redirect.github.com/oxc-project/oxc/commit/3f0d889)
linter: Add missing article to oxc/bad-array-method-on-arguments
diagnostic
([#&#8203;11518](https://redirect.github.com/oxc-project/oxc/issues/11518))
(camc314)
-
[`cf0c24c`](https://redirect.github.com/oxc-project/oxc/commit/cf0c24c)
linter: Improve message in react/prefer-es6-class diagnostic
([#&#8203;11516](https://redirect.github.com/oxc-project/oxc/issues/11516))
(camc314)
-
[`91855df`](https://redirect.github.com/oxc-project/oxc/commit/91855df)
linter: Fix message in react/rules-of-hooks diagnostic
([#&#8203;11515](https://redirect.github.com/oxc-project/oxc/issues/11515))
(camc314)
-
[`b272194`](https://redirect.github.com/oxc-project/oxc/commit/b272194)
linter: Misplaced backtick in jest/no-conditional-expect diagnostic
([#&#8203;11514](https://redirect.github.com/oxc-project/oxc/issues/11514))
(camc314)
-
[`3403303`](https://redirect.github.com/oxc-project/oxc/commit/3403303)
linter: Misplaced backtick in unicorn/prefer-dom-node-dataset diagnostic
([#&#8203;11513](https://redirect.github.com/oxc-project/oxc/issues/11513))
(camc314)
-
[`d5ca872`](https://redirect.github.com/oxc-project/oxc/commit/d5ca872)
linter: Misplaced backtick in eslint/radix diagnostic
([#&#8203;11512](https://redirect.github.com/oxc-project/oxc/issues/11512))
(camc314)
-
[`2dcf8be`](https://redirect.github.com/oxc-project/oxc/commit/2dcf8be)
linter: Improve diagnostic message when function name is referenced
([#&#8203;11509](https://redirect.github.com/oxc-project/oxc/issues/11509))
(camc314)
-
[`0de0c9c`](https://redirect.github.com/oxc-project/oxc/commit/0de0c9c)
linter: Improve diagnostic message for no-unsafe-declaration-merging
([#&#8203;11508](https://redirect.github.com/oxc-project/oxc/issues/11508))
(camc314)
-
[`0946dac`](https://redirect.github.com/oxc-project/oxc/commit/0946dac)
linter: Correctly inherit categories when plugins are enabled
([#&#8203;11353](https://redirect.github.com/oxc-project/oxc/issues/11353))
(Cameron)
-
[`510c1c6`](https://redirect.github.com/oxc-project/oxc/commit/510c1c6)
linter: Add missing `allowArrowFunctions` option for eslint/func-style
([#&#8203;11455](https://redirect.github.com/oxc-project/oxc/issues/11455))
(yefan)
-
[`c77787c`](https://redirect.github.com/oxc-project/oxc/commit/c77787c)
linter: Improve `eslint/no-loss-of-precision`
([#&#8203;11437](https://redirect.github.com/oxc-project/oxc/issues/11437))
(magic-akari)
-
[`11d4523`](https://redirect.github.com/oxc-project/oxc/commit/11d4523)
linter: False positive in react/exhaustive-deps
([#&#8203;11438](https://redirect.github.com/oxc-project/oxc/issues/11438))
(camc314)
-
[`616b613`](https://redirect.github.com/oxc-project/oxc/commit/616b613)
linter/switch-case-braces: Align the logic with `unicorn`
([#&#8203;11405](https://redirect.github.com/oxc-project/oxc/issues/11405))
(shulaoda)

##### Refactor

-
[`db0b099`](https://redirect.github.com/oxc-project/oxc/commit/db0b099)
language_server: Convert only once uri to path when creating
`ServerLinter`
([#&#8203;11503](https://redirect.github.com/oxc-project/oxc/issues/11503))
(Sysix)
-
[`ccceb52`](https://redirect.github.com/oxc-project/oxc/commit/ccceb52)
language_server: Simplify `workspace/didChangeConfiguration` call
([#&#8203;11462](https://redirect.github.com/oxc-project/oxc/issues/11462))
(Sysix)
-
[`0fdc51e`](https://redirect.github.com/oxc-project/oxc/commit/0fdc51e)
linter: Simplify `OxlintRules::override_rules`
([#&#8203;11510](https://redirect.github.com/oxc-project/oxc/issues/11510))
(camc314)

##### Testing

-
[`2ba2893`](https://redirect.github.com/oxc-project/oxc/commit/2ba2893)
editor: Fix test for auto `fixAll` on save
([#&#8203;11448](https://redirect.github.com/oxc-project/oxc/issues/11448))
(Sysix)

###
[`v0.17.0`](https://redirect.github.com/oxc-project/oxc/releases/tag/oxlint_v0.17.0):
oxlint v0.17.0

[Compare
Source](https://redirect.github.com/oxc-project/oxc/compare/oxlint_v0.16.12...oxlint_v0.17.0)

#### \[0.17.0] - 2025-05-30

-
[`ead5309`](https://redirect.github.com/oxc-project/oxc/commit/ead5309)
linter: \[**BREAKING**] Remove react from default plugin set
([#&#8203;11382](https://redirect.github.com/oxc-project/oxc/issues/11382))
(camc314)

##### Features

-
[`2d25bd8`](https://redirect.github.com/oxc-project/oxc/commit/2d25bd8)
linter: Remove `unicorn/no-for-loop` over `typescript/prefer-for-of`
([#&#8203;11354](https://redirect.github.com/oxc-project/oxc/issues/11354))
(camc314)
-
[`bbb7eb1`](https://redirect.github.com/oxc-project/oxc/commit/bbb7eb1)
linter: Add auto-fix to react/forward-ref-uses-ref
([#&#8203;11342](https://redirect.github.com/oxc-project/oxc/issues/11342))
(yefan)
-
[`590c27b`](https://redirect.github.com/oxc-project/oxc/commit/590c27b)
linter: Add auto-fix to unicorn/no-await-expression-member
([#&#8203;11306](https://redirect.github.com/oxc-project/oxc/issues/11306))
(yefan)
-
[`7824f01`](https://redirect.github.com/oxc-project/oxc/commit/7824f01)
linter: Implement suggestion for `jsx/no-useless-fragment`
([#&#8203;10800](https://redirect.github.com/oxc-project/oxc/issues/10800))
(Cam McHenry)
-
[`2083d33`](https://redirect.github.com/oxc-project/oxc/commit/2083d33)
linter/language_server: Add second editor suggestion for
`react/forward-ref-uses-ref`
([#&#8203;11375](https://redirect.github.com/oxc-project/oxc/issues/11375))
(Sysix)

##### Bug Fixes

-
[`f6424dd`](https://redirect.github.com/oxc-project/oxc/commit/f6424dd)
linter: Reflect react plugin is disabled by default in cli
([#&#8203;11397](https://redirect.github.com/oxc-project/oxc/issues/11397))
(camc314)
-
[`25ecbfe`](https://redirect.github.com/oxc-project/oxc/commit/25ecbfe)
linter: Remove use of `FrameworkFlags::React` to decide whether rules
should run
([#&#8203;11383](https://redirect.github.com/oxc-project/oxc/issues/11383))
(camc314)
-
[`0d240e4`](https://redirect.github.com/oxc-project/oxc/commit/0d240e4)
linter: False positive in react/exhaustive-deps with default formal
parameter
([#&#8203;11395](https://redirect.github.com/oxc-project/oxc/issues/11395))
(camc314)
-
[`c91697e`](https://redirect.github.com/oxc-project/oxc/commit/c91697e)
linter: Fix panic in multi byte char in `TryFrom` aria
([#&#8203;11350](https://redirect.github.com/oxc-project/oxc/issues/11350))
(camc314)
-
[`9798ef1`](https://redirect.github.com/oxc-project/oxc/commit/9798ef1)
linter: Stack overflow in no-async-endpoint-handlers
([#&#8203;11317](https://redirect.github.com/oxc-project/oxc/issues/11317))
(camc314)
-
[`348ad97`](https://redirect.github.com/oxc-project/oxc/commit/348ad97)
linter: Skip no-unused-vars on astro files
([#&#8203;11303](https://redirect.github.com/oxc-project/oxc/issues/11303))
(camc314)
-
[`183d7f0`](https://redirect.github.com/oxc-project/oxc/commit/183d7f0)
linter: Make `jest/no-large-snapshots` error easier to comprehend
([#&#8203;11294](https://redirect.github.com/oxc-project/oxc/issues/11294))
(Ulrich Stark)
-
[`4e606a5`](https://redirect.github.com/oxc-project/oxc/commit/4e606a5)
linter: Improve `jest/no-large-snapshots`
([#&#8203;11291](https://redirect.github.com/oxc-project/oxc/issues/11291))
(Ulrich Stark)
-
[`14f790f`](https://redirect.github.com/oxc-project/oxc/commit/14f790f)
linter: Improve `jest/no-restricted-matchers`
([#&#8203;11292](https://redirect.github.com/oxc-project/oxc/issues/11292))
(Ulrich Stark)
-
[`a2c82be`](https://redirect.github.com/oxc-project/oxc/commit/a2c82be)
linter/block-scoped-var: Better diagnostic messages
([#&#8203;11290](https://redirect.github.com/oxc-project/oxc/issues/11290))
(DonIsaac)
-
[`19772e5`](https://redirect.github.com/oxc-project/oxc/commit/19772e5)
linter/no-unused-vars: Panic when variable is redeclared as function in
same scope
([#&#8203;11280](https://redirect.github.com/oxc-project/oxc/issues/11280))
(Dunqing)
-
[`7af5bb1`](https://redirect.github.com/oxc-project/oxc/commit/7af5bb1)
oxc_language_server: Include save option for text document sync
capability
([#&#8203;11297](https://redirect.github.com/oxc-project/oxc/issues/11297))
(Nicholas Rayburn)

##### Performance

-
[`0ed6c1a`](https://redirect.github.com/oxc-project/oxc/commit/0ed6c1a)
language_server: Use `Arc<RwLock>` instead of `Mutex` for workspace
workers
([#&#8203;11328](https://redirect.github.com/oxc-project/oxc/issues/11328))
(Sysix)
-
[`a0ee946`](https://redirect.github.com/oxc-project/oxc/commit/a0ee946)
linter: Reduce code size in `globals`
([#&#8203;11333](https://redirect.github.com/oxc-project/oxc/issues/11333))
(shulaoda)
-
[`c90c5e9`](https://redirect.github.com/oxc-project/oxc/commit/c90c5e9)
linter/no-unused-vars: Simplify checking self call usage
([#&#8203;11281](https://redirect.github.com/oxc-project/oxc/issues/11281))
(Dunqing)

##### Documentation

-
[`eae51ca`](https://redirect.github.com/oxc-project/oxc/commit/eae51ca)
linter: Clarify jsdoc/check-tag-names configuration
([#&#8203;11394](https://redirect.github.com/oxc-project/oxc/issues/11394))
(Rägnar O'ock)
-
[`cd354d4`](https://redirect.github.com/oxc-project/oxc/commit/cd354d4)
oxlint: Remove incorrect doc comment
([#&#8203;11326](https://redirect.github.com/oxc-project/oxc/issues/11326))
(camc314)

##### Refactor

-
[`42738f0`](https://redirect.github.com/oxc-project/oxc/commit/42738f0)
linter: Shorten code of match arms
([#&#8203;11389](https://redirect.github.com/oxc-project/oxc/issues/11389))
(Ulrich Stark)
-
[`8a34447`](https://redirect.github.com/oxc-project/oxc/commit/8a34447)
linter: Improve `unicorn/text-encoding-identifier-case`
([#&#8203;11386](https://redirect.github.com/oxc-project/oxc/issues/11386))
(shulaoda)
-
[`eaa605e`](https://redirect.github.com/oxc-project/oxc/commit/eaa605e)
linter: Avoid some `Arc::clone` in linter runtime
([#&#8203;11388](https://redirect.github.com/oxc-project/oxc/issues/11388))
(Boshen)
-
[`1cd8b9c`](https://redirect.github.com/oxc-project/oxc/commit/1cd8b9c)
linter: Fixes in `react/forward-ref-uses-ref` are suggestions
([#&#8203;11376](https://redirect.github.com/oxc-project/oxc/issues/11376))
(Sysix)
-
[`50ef691`](https://redirect.github.com/oxc-project/oxc/commit/50ef691)
linter: Add `diagnostics_with_multiple_fixes` to `LintContext`
([#&#8203;11357](https://redirect.github.com/oxc-project/oxc/issues/11357))
(Sysix)
-
[`606bb34`](https://redirect.github.com/oxc-project/oxc/commit/606bb34)
linter: Accept `PossibleFixes` instead of `Fix` for `Messages`
([#&#8203;11295](https://redirect.github.com/oxc-project/oxc/issues/11295))
(Sysix)
-
[`042a3f3`](https://redirect.github.com/oxc-project/oxc/commit/042a3f3)
linter: Use `PossibleFixes` instead of `Option<Fix>`
([#&#8203;11284](https://redirect.github.com/oxc-project/oxc/issues/11284))
(Sysix)
-
[`ffcfb46`](https://redirect.github.com/oxc-project/oxc/commit/ffcfb46)
linter: Improve `unicorn/throw-new-error`
([#&#8203;11364](https://redirect.github.com/oxc-project/oxc/issues/11364))
(shulaoda)
-
[`8fb55c3`](https://redirect.github.com/oxc-project/oxc/commit/8fb55c3)
linter: Cleanup docs and simplify code of `eslint/no-fallthrough`
([#&#8203;11331](https://redirect.github.com/oxc-project/oxc/issues/11331))
(Ulrich Stark)
-
[`e2f0f0a`](https://redirect.github.com/oxc-project/oxc/commit/e2f0f0a)
linter: Improve docs and simplify code of `eslint/no-duplicate-imports`
([#&#8203;11320](https://redirect.github.com/oxc-project/oxc/issues/11320))
(Ulrich Stark)
-
[`b53b053`](https://redirect.github.com/oxc-project/oxc/commit/b53b053)
linter: Simplify accessing span of NameSpan
([#&#8203;11305](https://redirect.github.com/oxc-project/oxc/issues/11305))
(Ulrich Stark)
-
[`4bc2650`](https://redirect.github.com/oxc-project/oxc/commit/4bc2650)
linter: Improve `eslint/no-void`
([#&#8203;11285](https://redirect.github.com/oxc-project/oxc/issues/11285))
(shulaoda)

##### Styling

-
[`49b664c`](https://redirect.github.com/oxc-project/oxc/commit/49b664c)
linter: Remove needless newline in `declare_oxc_lint`
([#&#8203;11400](https://redirect.github.com/oxc-project/oxc/issues/11400))
(camc314)

##### Testing

-
[`c4f64aa`](https://redirect.github.com/oxc-project/oxc/commit/c4f64aa)
linter: Explicitly disable correctness for clarity
([#&#8203;11327](https://redirect.github.com/oxc-project/oxc/issues/11327))
(camc314)
-
[`a404b2c`](https://redirect.github.com/oxc-project/oxc/commit/a404b2c)
linter: `eslint/no-duplicate-imports` shouldn't report the same span
([#&#8203;11324](https://redirect.github.com/oxc-project/oxc/issues/11324))
(Ulrich Stark)

###
[`v0.16.12`](https://redirect.github.com/oxc-project/oxc/blob/HEAD/npm/oxlint/CHANGELOG.md#01612---2025-05-25)

[Compare
Source](https://redirect.github.com/oxc-project/oxc/compare/oxlint_v0.16.11...oxlint_v0.16.12)

##### Features

-
[`6a7018e`](https://redirect.github.com/oxc-project/oxc/commit/6a7018e)
linter: Generate stricter json schema for lint plugins
([#&#8203;11219](https://redirect.github.com/oxc-project/oxc/issues/11219))
(camc314)

##### Bug Fixes

-
[`e8470d9`](https://redirect.github.com/oxc-project/oxc/commit/e8470d9)
linter: Delay merging of oxlintrc configs
([#&#8203;10835](https://redirect.github.com/oxc-project/oxc/issues/10835))
(camc314)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/toeverything/AFFiNE).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MC4xNi4wIiwidXBkYXRlZEluVmVyIjoiNDAuNTAuMCIsInRhcmdldEJyYW5jaCI6ImNhbmFyeSIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Refactor**
- Simplified array element retrieval across multiple components and
utilities by replacing `.filter(...)[0]` with `.find(...)` or
`.findLast(...)`, improving code readability and efficiency.
- Improved JSX structure in the audio player component by nesting
elements directly rather than using a `children` prop.
- Enhanced code organization in the modal container by repositioning
functions and updating dependency arrays for better maintainability.
- Added a comment to disable a specific lint rule in a React hook for
clarity.

- **Chores**
- Updated the `oxlint` development dependency to allow for newer
compatible versions.

- **Tests**
- Refactored test setup logic for more direct and clear retrieval of
test data.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: LongYinan <lynweklm@gmail.com>
2025-06-16 15:20:48 +08:00
181 changed files with 5300 additions and 874 deletions

View File

@@ -27,26 +27,11 @@ concurrency:
cancel-in-progress: true
jobs:
optimize_ci:
name: Optimize CI
runs-on: ubuntu-latest
outputs:
skip: ${{ steps.check_skip.outputs.skip }}
steps:
- uses: actions/checkout@v4
- name: Graphite CI Optimizer
uses: withgraphite/graphite-ci-action@main
id: check_skip
with:
graphite_token: ${{ secrets.GRAPHITE_CI_OPTIMIZER_TOKEN }}
analyze:
name: Analyze
runs-on: ubuntu-latest
env:
NODE_OPTIONS: --max-old-space-size=14384
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
permissions:
actions: read
contents: read
@@ -80,9 +65,6 @@ jobs:
lint:
name: Lint
runs-on: ubuntu-24.04-arm
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
steps:
- uses: actions/checkout@v4
- name: Run oxlint
@@ -108,8 +90,6 @@ jobs:
typecheck:
name: Typecheck
runs-on: ubuntu-24.04-arm
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
NODE_OPTIONS: --max-old-space-size=14384
steps:
@@ -137,8 +117,6 @@ jobs:
lint-rust:
name: Lint Rust
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/build-rust
@@ -159,9 +137,7 @@ jobs:
name: Check Git Status
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-server-native
if: needs.optimize_ci.outputs.skip == 'false'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
@@ -197,8 +173,6 @@ jobs:
check-yarn-binary:
name: Check yarn binary
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
steps:
- uses: actions/checkout@v4
- name: Run check
@@ -209,8 +183,6 @@ jobs:
e2e-blocksuite-test:
name: E2E BlockSuite Test
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
strategy:
fail-fast: false
matrix:
@@ -242,8 +214,6 @@ jobs:
e2e-blocksuite-cross-browser-test:
name: E2E BlockSuite Cross Browser Test
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
strategy:
fail-fast: false
matrix:
@@ -278,8 +248,6 @@ jobs:
e2e-test:
name: E2E Test
runs-on: ubuntu-24.04-arm
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
DISTRIBUTION: web
IN_CI_TEST: true
@@ -312,8 +280,6 @@ jobs:
e2e-mobile-test:
name: E2E Mobile Test
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
DISTRIBUTION: mobile
IN_CI_TEST: true
@@ -345,9 +311,7 @@ jobs:
name: Unit Test
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-native
if: needs.optimize_ci.outputs.skip == 'false'
env:
DISTRIBUTION: web
strategy:
@@ -384,8 +348,6 @@ jobs:
build-native:
name: Build AFFiNE native (${{ matrix.spec.target }})
runs-on: ${{ matrix.spec.os }}
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
CARGO_PROFILE_RELEASE_DEBUG: '1'
strategy:
@@ -428,8 +390,6 @@ jobs:
build-windows-native:
name: Build AFFiNE native (${{ matrix.spec.target }})
runs-on: ${{ matrix.spec.os }}
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
CARGO_PROFILE_RELEASE_DEBUG: '1'
strategy:
@@ -477,8 +437,6 @@ jobs:
build-server-native:
name: Build Server native
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
CARGO_PROFILE_RELEASE_DEBUG: '1'
steps:
@@ -504,8 +462,6 @@ jobs:
build-electron-renderer:
name: Build @affine/electron renderer
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
@@ -531,9 +487,7 @@ jobs:
name: Native Unit Test
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-native
if: needs.optimize_ci.outputs.skip == 'false'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
@@ -553,9 +507,7 @@ jobs:
name: Server Test
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-server-native
if: needs.optimize_ci.outputs.skip == 'false'
strategy:
fail-fast: false
matrix:
@@ -628,9 +580,7 @@ jobs:
name: Server Test with Elasticsearch
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-server-native
if: needs.optimize_ci.outputs.skip == 'false'
strategy:
fail-fast: false
env:
@@ -713,9 +663,7 @@ jobs:
name: Server E2E Test
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-server-native
if: needs.optimize_ci.outputs.skip == 'false'
env:
NODE_ENV: test
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
@@ -773,9 +721,6 @@ jobs:
miri:
name: miri code check
runs-on: ubuntu-latest
needs:
- optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
RUST_BACKTRACE: full
CARGO_TERM_COLOR: always
@@ -799,9 +744,6 @@ jobs:
loom:
name: loom thread test
runs-on: ubuntu-latest
needs:
- optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
RUSTFLAGS: --cfg loom
RUST_BACKTRACE: full
@@ -823,9 +765,6 @@ jobs:
fuzzing:
name: fuzzing
runs-on: ubuntu-latest
needs:
- optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
CARGO_TERM_COLOR: always
steps:
@@ -872,9 +811,6 @@ jobs:
- { target: 'aarch64-apple-darwin', os: 'macos-latest' }
- { target: 'x86_64-pc-windows-msvc', os: 'windows-latest' }
- { target: 'aarch64-pc-windows-msvc', os: 'windows-11-arm' }
needs:
- optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
@@ -908,8 +844,6 @@ jobs:
rust-test:
name: Run native tests
runs-on: ubuntu-latest
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
env:
CARGO_TERM_COLOR: always
steps:
@@ -930,9 +864,7 @@ jobs:
name: Server Copilot Api Test
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-server-native
if: needs.optimize_ci.outputs.skip == 'false'
env:
NODE_ENV: test
DISTRIBUTION: web
@@ -1114,10 +1046,8 @@ jobs:
name: ${{ matrix.tests.name }}
runs-on: ubuntu-latest
needs:
- optimize_ci
- build-server-native
- build-native
if: needs.optimize_ci.outputs.skip == 'false'
env:
DISTRIBUTION: web
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
@@ -1221,10 +1151,8 @@ jobs:
name: Desktop Test (${{ matrix.spec.os }}, ${{ matrix.spec.platform }}, ${{ matrix.spec.arch }}, ${{ matrix.spec.target }}, ${{ matrix.spec.test }})
runs-on: ${{ matrix.spec.os }}
needs:
- optimize_ci
- build-electron-renderer
- build-native
if: needs.optimize_ci.outputs.skip == 'false'
strategy:
fail-fast: false
matrix:
@@ -1319,10 +1247,8 @@ jobs:
name: Desktop bundle check (${{ matrix.spec.os }}, ${{ matrix.spec.platform }}, ${{ matrix.spec.arch }}, ${{ matrix.spec.target }}, ${{ matrix.spec.test }})
runs-on: ${{ matrix.spec.os }}
needs:
- optimize_ci
- build-electron-renderer
- build-native
if: needs.optimize_ci.outputs.skip == 'false'
strategy:
fail-fast: false
matrix:
@@ -1428,8 +1354,6 @@ jobs:
test-build-mobile-app:
uses: ./.github/workflows/release-mobile.yml
needs: optimize_ci
if: needs.optimize_ci.outputs.skip == 'false'
with:
build-type: canary
build-target: development

View File

@@ -62,13 +62,11 @@ const builtinSurfaceToolbarConfig = {
if (!rootModel) return;
const { id: frameId, xywh } = model;
let lastNoteId = rootModel.children
.filter(
note =>
matchModels(note, [NoteBlockModel]) &&
note.props.displayMode !== NoteDisplayMode.EdgelessOnly
)
.pop()?.id;
let lastNoteId = rootModel.children.findLast(
note =>
matchModels(note, [NoteBlockModel]) &&
note.props.displayMode !== NoteDisplayMode.EdgelessOnly
)?.id;
if (!lastNoteId) {
const bounds = Bound.deserialize(xywh);

View File

@@ -14,6 +14,7 @@ export class EdgelessNoteMask extends SignalWatcher(
protected override firstUpdated() {
const maskDOM = this.renderRoot!.querySelector('.affine-note-mask');
const observer = new ResizeObserver(entries => {
if (this.model.store.readonly) return;
for (const entry of entries) {
if (!this.model.props.edgeless.collapse) {
const bound = Bound.deserialize(this.model.xywh);

View File

@@ -11,6 +11,7 @@ import { property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { keyed } from 'lit/directives/keyed.js';
import type { ClassInfo } from 'lit-html/directives/class-map.js';
import { ifDefined } from 'lit-html/directives/if-defined.js';
import { MenuFocusable } from './focusable.js';
import type { Menu } from './menu.js';
@@ -21,6 +22,7 @@ export type MenuButtonData = {
class: ClassInfo;
select: (ele: HTMLElement) => void | false;
onHover?: (hover: boolean) => void;
testId?: string;
};
export class MenuButton extends MenuFocusable {
@@ -97,7 +99,12 @@ export class MenuButton extends MenuFocusable {
focused: this.isFocused$.value,
...this.data.class,
});
return html` <div class="${classString}">${this.data.content()}</div>`;
return html` <div
class="${classString}"
data-testid=${ifDefined(this.data.testId)}
>
${this.data.content()}
</div>`;
}
@property({ attribute: false })
@@ -157,7 +164,12 @@ export class MobileMenuButton extends MenuFocusable {
focused: this.isFocused$.value,
...this.data.class,
});
return html` <div class="${classString}">${this.data.content()}</div>`;
return html` <div
class="${classString}"
data-testid=${ifDefined(this.data.testId)}
>
${this.data.content()}
</div>`;
}
@property({ attribute: false })
@@ -188,6 +200,7 @@ export const menuButtonItems = {
onHover?: (hover: boolean) => void;
class?: MenuClass;
hide?: () => boolean;
testId?: string;
}) =>
menu => {
if (config.hide?.() || !menu.search(config.name)) {
@@ -209,6 +222,7 @@ export const menuButtonItems = {
'selected-item': config.isSelected ?? false,
...config.class,
},
testId: config.testId,
};
return renderButton(data, menu);
},
@@ -220,6 +234,7 @@ export const menuButtonItems = {
label?: () => TemplateResult;
select: (checked: boolean) => boolean;
class?: ClassInfo;
testId?: string;
}) =>
menu => {
if (!menu.search(config.name)) {
@@ -240,6 +255,7 @@ export const menuButtonItems = {
return false;
},
class: config.class ?? {},
testId: config.testId,
};
return html`${keyed(config.name, renderButton(data, menu))}`;
},
@@ -247,10 +263,12 @@ export const menuButtonItems = {
(config: {
name: string;
on: boolean;
prefix?: TemplateResult;
postfix?: TemplateResult;
label?: () => TemplateResult;
onChange: (on: boolean) => void;
class?: ClassInfo;
testId?: string;
}) =>
menu => {
if (!menu.search(config.name)) {
@@ -262,6 +280,7 @@ export const menuButtonItems = {
const data: MenuButtonData = {
content: () => html`
${config.prefix}
<div class="affine-menu-action-text">
${config.label?.() ?? config.name}
</div>
@@ -276,6 +295,7 @@ export const menuButtonItems = {
return false;
},
class: config.class ?? {},
testId: config.testId,
};
return html`${keyed(config.name, renderButton(data, menu))}`;
},

View File

@@ -23,6 +23,7 @@ export type MenuOptions = {
placeholder?: string;
};
items: MenuConfig[];
testId?: string;
};
// Global menu open listener type
@@ -72,6 +73,9 @@ export class Menu {
? document.createElement('mobile-menu')
: document.createElement('affine-menu');
this.menuElement.menu = this;
if (this.options.testId) {
this.menuElement.dataset.testid = this.options.testId;
}
// Call global menu open listeners
menuOpenListeners.forEach(listener => {

View File

@@ -111,6 +111,7 @@ export class FilterableListComponent<Props = unknown> extends WithDisposable(
if (ev.isComposing) break;
ev.preventDefault();
const item = filteredItems[this._curFocusIndex];
if (!item) return;
this._select(item);
break;
}

View File

@@ -35,7 +35,7 @@ export const selectPropertyModelConfig = selectPropertyType.modelConfig({
const name = oldValue
.split(',')
.map(v => v.trim())
.filter(v => v)[0];
.find(v => v);
if (!name) {
return { value: null, data: data };
}

View File

@@ -40,13 +40,11 @@ export const groupToolbarConfig = {
if (!rootModel) return;
const { id: groupId, xywh } = model;
let lastNoteId = rootModel.children
.filter(
note =>
matchModels(note, [NoteBlockModel]) &&
note.props.displayMode !== NoteDisplayMode.EdgelessOnly
)
.pop()?.id;
let lastNoteId = rootModel.children.findLast(
note =>
matchModels(note, [NoteBlockModel]) &&
note.props.displayMode !== NoteDisplayMode.EdgelessOnly
)?.id;
if (!lastNoteId) {
const bounds = Bound.deserialize(xywh);

View File

@@ -3,7 +3,7 @@ import { SurfaceSelection } from '@blocksuite/std';
import type { GetSelectionCommand } from './types';
export const getSurfaceSelectionCommand: GetSelectionCommand = (ctx, next) => {
const currentSurfaceSelection = ctx.std.selection.filter(SurfaceSelection)[0];
const currentSurfaceSelection = ctx.std.selection.find(SurfaceSelection);
if (!currentSurfaceSelection) return;
next({ currentSurfaceSelection });

View File

@@ -20,3 +20,7 @@
- [Store](classes/Store.md)
- [StoreSlots](interfaces/StoreSlots.md)
## Other
- [Schema](classes/Schema.md)

View File

@@ -0,0 +1,297 @@
[**BlockSuite API Documentation**](../../../README.md)
***
[BlockSuite API Documentation](../../../README.md) / [@blocksuite/store](../README.md) / Schema
# Class: Schema
Represents a schema manager for block flavours and their relationships.
Provides methods to register, validate, and query block schemas.
## Properties
### flavourSchemaMap
> `readonly` **flavourSchemaMap**: `Map`\<`string`, \{ `model`: \{ `children?`: `string`[]; `flavour`: `string`; `isFlatData?`: `boolean`; `parent?`: `string`[]; `props?`: (...`args`) => `Record`\<`string`, `any`\>; `role`: `string`; `toModel?`: (...`args`) => `BlockModel`\<`object`\>; \}; `transformer?`: (...`args`) => `BaseBlockTransformer`\<`object`\>; `version`: `number`; \}\>
A map storing block flavour names to their corresponding schema definitions.
## Accessors
### versions
#### Get Signature
> **get** **versions**(): `object`
Returns an object mapping each registered flavour to its version number.
##### Returns
`object`
## Methods
### get()
> **get**(`flavour`): `undefined` \| \{ `model`: \{ `children?`: `string`[]; `flavour`: `string`; `isFlatData?`: `boolean`; `parent?`: `string`[]; `props?`: (...`args`) => `Record`\<`string`, `any`\>; `role`: `string`; `toModel?`: (...`args`) => `BlockModel`\<`object`\>; \}; `transformer?`: (...`args`) => `BaseBlockTransformer`\<`object`\>; `version`: `number`; \}
Retrieves the schema for a given block flavour.
#### Parameters
##### flavour
`string`
The block flavour name.
#### Returns
`undefined` \| \{ `model`: \{ `children?`: `string`[]; `flavour`: `string`; `isFlatData?`: `boolean`; `parent?`: `string`[]; `props?`: (...`args`) => `Record`\<`string`, `any`\>; `role`: `string`; `toModel?`: (...`args`) => `BlockModel`\<`object`\>; \}; `transformer?`: (...`args`) => `BaseBlockTransformer`\<`object`\>; `version`: `number`; \}
The corresponding BlockSchemaType or undefined if not found.
***
### isValid()
> **isValid**(`child`, `parent`): `boolean`
Checks if the child flavour is valid under the parent flavour.
#### Parameters
##### child
`string`
The child block flavour name.
##### parent
`string`
The parent block flavour name.
#### Returns
`boolean`
True if the relationship is valid, false otherwise.
***
### register()
> **register**(`blockSchema`): `Schema`
Registers an array of block schemas into the schema manager.
#### Parameters
##### blockSchema
`object`[]
An array of block schema definitions to register.
#### Returns
`Schema`
The Schema instance (for chaining).
***
### safeValidate()
> **safeValidate**(`flavour`, `parentFlavour?`, `childFlavours?`): `boolean`
Safely validates the schema relationship for a given flavour, parent, and children.
Returns true if valid, false otherwise (does not throw).
#### Parameters
##### flavour
`string`
The block flavour to validate.
##### parentFlavour?
`string`
The parent block flavour (optional).
##### childFlavours?
`string`[]
The child block flavours (optional).
#### Returns
`boolean`
True if the schema relationship is valid, false otherwise.
***
### toJSON()
> **toJSON**(): `object`
Serializes the schema map to a plain object for JSON output.
#### Returns
`object`
An object mapping each flavour to its role, parent, and children.
***
### validate()
> **validate**(`flavour`, `parentFlavour?`, `childFlavours?`): `void`
Validates the schema relationship for a given flavour, parent, and children.
Throws SchemaValidateError if invalid.
#### Parameters
##### flavour
`string`
The block flavour to validate.
##### parentFlavour?
`string`
The parent block flavour (optional).
##### childFlavours?
`string`[]
The child block flavours (optional).
#### Returns
`void`
#### Throws
If the schema relationship is invalid.
***
### validateSchema()
> **validateSchema**(`child`, `parent`): `void`
Validates the relationship between a child and parent schema.
Throws if the relationship is invalid.
#### Parameters
##### child
The child block schema.
###### model
\{ `children?`: `string`[]; `flavour`: `string`; `isFlatData?`: `boolean`; `parent?`: `string`[]; `props?`: (...`args`) => `Record`\<`string`, `any`\>; `role`: `string`; `toModel?`: (...`args`) => `BlockModel`\<`object`\>; \} = `...`
###### model.children?
`string`[] = `ContentSchema`
###### model.flavour
`string` = `FlavourSchema`
###### model.isFlatData?
`boolean` = `...`
###### model.parent?
`string`[] = `ParentSchema`
###### model.props?
(...`args`) => `Record`\<`string`, `any`\> = `...`
###### model.role
`string` = `RoleSchema`
###### model.toModel?
(...`args`) => `BlockModel`\<`object`\> = `...`
###### transformer?
(...`args`) => `BaseBlockTransformer`\<`object`\> = `...`
###### version
`number` = `...`
##### parent
The parent block schema.
###### model
\{ `children?`: `string`[]; `flavour`: `string`; `isFlatData?`: `boolean`; `parent?`: `string`[]; `props?`: (...`args`) => `Record`\<`string`, `any`\>; `role`: `string`; `toModel?`: (...`args`) => `BlockModel`\<`object`\>; \} = `...`
###### model.children?
`string`[] = `ContentSchema`
###### model.flavour
`string` = `FlavourSchema`
###### model.isFlatData?
`boolean` = `...`
###### model.parent?
`string`[] = `ParentSchema`
###### model.props?
(...`args`) => `Record`\<`string`, `any`\> = `...`
###### model.role
`string` = `RoleSchema`
###### model.toModel?
(...`args`) => `BlockModel`\<`object`\> = `...`
###### transformer?
(...`args`) => `BaseBlockTransformer`\<`object`\> = `...`
###### version
`number` = `...`
#### Returns
`void`
#### Throws
If the relationship is invalid.

View File

@@ -1035,13 +1035,13 @@ Get the Doc instance for current store.
#### Get Signature
> **get** **schema**(): `Schema`
> **get** **schema**(): [`Schema`](Schema.md)
Get the Schema instance of the store.
Get the [Schema](Schema.md) instance of the store.
##### Returns
`Schema`
[`Schema`](Schema.md)
***

View File

@@ -4,9 +4,25 @@ import { SCHEMA_NOT_FOUND_MESSAGE } from '../consts.js';
import { BlockSchema, type BlockSchemaType } from '../model/index.js';
import { SchemaValidateError } from './error.js';
/**
* Represents a schema manager for block flavours and their relationships.
* Provides methods to register, validate, and query block schemas.
*/
export class Schema {
/**
* A map storing block flavour names to their corresponding schema definitions.
*/
readonly flavourSchemaMap = new Map<string, BlockSchemaType>();
/**
* Safely validates the schema relationship for a given flavour, parent, and children.
* Returns true if valid, false otherwise (does not throw).
*
* @param flavour - The block flavour to validate.
* @param parentFlavour - The parent block flavour (optional).
* @param childFlavours - The child block flavours (optional).
* @returns True if the schema relationship is valid, false otherwise.
*/
safeValidate = (
flavour: string,
parentFlavour?: string,
@@ -20,10 +36,25 @@ export class Schema {
}
};
/**
* Retrieves the schema for a given block flavour.
*
* @param flavour - The block flavour name.
* @returns The corresponding BlockSchemaType or undefined if not found.
*/
get(flavour: string) {
return this.flavourSchemaMap.get(flavour);
}
/**
* Validates the schema relationship for a given flavour, parent, and children.
* Throws SchemaValidateError if invalid.
*
* @param flavour - The block flavour to validate.
* @param parentFlavour - The parent block flavour (optional).
* @param childFlavours - The child block flavours (optional).
* @throws {SchemaValidateError} If the schema relationship is invalid.
*/
validate = (
flavour: string,
parentFlavour?: string,
@@ -71,6 +102,9 @@ export class Schema {
validateChildren();
};
/**
* Returns an object mapping each registered flavour to its version number.
*/
get versions() {
return Object.fromEntries(
Array.from(this.flavourSchemaMap.values()).map(
@@ -79,6 +113,13 @@ export class Schema {
);
}
/**
* Checks if two flavours match, using minimatch for wildcard support.
*
* @param childFlavour - The child block flavour.
* @param parentFlavour - The parent block flavour.
* @returns True if the flavours match, false otherwise.
*/
private _matchFlavour(childFlavour: string, parentFlavour: string) {
return (
minimatch(childFlavour, parentFlavour) ||
@@ -86,6 +127,15 @@ export class Schema {
);
}
/**
* Checks if two values match as either flavours or roles, supporting role syntax (e.g., '@role').
*
* @param childValue - The child value (flavour or role).
* @param parentValue - The parent value (flavour or role).
* @param childRole - The actual role of the child.
* @param parentRole - The actual role of the parent.
* @returns True if the values match as flavours or roles, false otherwise.
*/
private _matchFlavourOrRole(
childValue: string,
parentValue: string,
@@ -112,6 +162,13 @@ export class Schema {
return this._matchFlavour(childValue, parentValue);
}
/**
* Validates if the parent schema is a valid parent for the child schema.
*
* @param child - The child block schema.
* @param parent - The parent block schema.
* @returns True if the parent is valid for the child, false otherwise.
*/
private _validateParent(
child: BlockSchemaType,
parent: BlockSchemaType
@@ -169,6 +226,14 @@ export class Schema {
});
}
/**
* Validates the role relationship between child and parent schemas.
* Throws if the child is a root block but has a parent.
*
* @param child - The child block schema.
* @param parent - The parent block schema.
* @throws {SchemaValidateError} If the child is a root block with a parent.
*/
private _validateRole(child: BlockSchemaType, parent: BlockSchemaType) {
const childRole = child.model.role;
const childFlavour = child.model.flavour;
@@ -182,6 +247,13 @@ export class Schema {
}
}
/**
* Checks if the child flavour is valid under the parent flavour.
*
* @param child - The child block flavour name.
* @param parent - The parent block flavour name.
* @returns True if the relationship is valid, false otherwise.
*/
isValid(child: string, parent: string) {
const childSchema = this.flavourSchemaMap.get(child);
const parentSchema = this.flavourSchemaMap.get(parent);
@@ -196,6 +268,12 @@ export class Schema {
}
}
/**
* Registers an array of block schemas into the schema manager.
*
* @param blockSchema - An array of block schema definitions to register.
* @returns The Schema instance (for chaining).
*/
register(blockSchema: BlockSchemaType[]) {
blockSchema.forEach(schema => {
BlockSchema.parse(schema);
@@ -204,6 +282,11 @@ export class Schema {
return this;
}
/**
* Serializes the schema map to a plain object for JSON output.
*
* @returns An object mapping each flavour to its role, parent, and children.
*/
toJSON() {
return Object.fromEntries(
Array.from(this.flavourSchemaMap.values()).map(
@@ -219,6 +302,14 @@ export class Schema {
);
}
/**
* Validates the relationship between a child and parent schema.
* Throws if the relationship is invalid.
*
* @param child - The child block schema.
* @param parent - The parent block schema.
* @throws {SchemaValidateError} If the relationship is invalid.
*/
validateSchema(child: BlockSchemaType, parent: BlockSchemaType) {
this._validateRole(child, parent);

View File

@@ -82,7 +82,7 @@
"husky": "^9.1.7",
"lint-staged": "^16.0.0",
"msw": "^2.6.8",
"oxlint": "0.16.11",
"oxlint": "^1.1.0",
"prettier": "^3.4.2",
"semver": "^7.6.3",
"serve": "^14.2.4",

View File

@@ -147,7 +147,7 @@
"c8": "^10.1.3",
"nodemon": "^3.1.7",
"react-email": "4.0.11",
"sinon": "^20.0.0",
"sinon": "^21.0.0",
"supertest": "^7.0.0",
"why-is-node-running": "^3.2.2"
},

View File

@@ -12,6 +12,7 @@ export type MockDocSnapshotInput = {
docId?: string;
blob?: Uint8Array;
updatedAt?: Date;
snapshotFile?: string;
};
export type MockedDocSnapshot = Snapshot;
@@ -23,7 +24,10 @@ export class MockDocSnapshot extends Mocker<
override async create(input: MockDocSnapshotInput) {
if (!input.blob) {
const snapshot = await readFile(
path.join(import.meta.dirname, '../__fixtures__/test-doc.snapshot.bin')
path.join(
import.meta.dirname,
`../__fixtures__/${input.snapshotFile ?? 'test-doc.snapshot.bin'}`
)
);
input.blob = snapshot;
}

View File

@@ -20,6 +20,12 @@ export class SocketIoAdapter extends IoAdapter {
const server: Server = super.createIOServer(port, {
...config,
...options,
// Enable CORS for Socket.IO
cors: {
origin: true, // Allow all origins
credentials: true, // Allow credentials (cookies, auth headers)
methods: ['GET', 'POST'],
},
});
if (config.canActivate) {

View File

@@ -646,6 +646,93 @@ Generated by [AVA](https://avajs.dev).
title: 'Write, Draw, Plan all at Once.',
}
## can read blob filename from doc snapshot
> Snapshot 1
{
blocks: [
{
additional: {
displayMode: 'edgeless',
},
blockId: '4YHKIhPzAK',
content: 'index file name',
docId: 'doc-0',
flavour: 'affine:page',
yblock: {
'prop:title': 'index file name',
'sys:children': [
'WypcCGdupE',
'hZ1-cdLW5e',
],
'sys:flavour': 'affine:page',
'sys:id': '4YHKIhPzAK',
'sys:version': 2,
},
},
{
additional: {
displayMode: 'edgeless',
},
blockId: 'WypcCGdupE',
content: [],
docId: 'doc-0',
flavour: 'affine:surface',
parentBlockId: '4YHKIhPzAK',
parentFlavour: 'affine:page',
yblock: {
'prop:elements': {
type: '$blocksuite:internal:native$',
value: {},
},
'sys:children': [],
'sys:flavour': 'affine:surface',
'sys:id': 'WypcCGdupE',
'sys:version': 5,
},
},
{
additional: {
displayMode: 'page',
noteBlockId: 'hZ1-cdLW5e',
},
blob: [
'ldZMrM4PDlsNG4Q4YvCsz623h6TKu4qI9_FpTqIypfw=',
],
blockId: 'tfz1yFZdnn',
content: 'test file name here.txt',
docId: 'doc-0',
flavour: 'affine:attachment',
parentBlockId: 'hZ1-cdLW5e',
parentFlavour: 'affine:note',
yblock: {
'prop:embed': false,
'prop:footnoteIdentifier': null,
'prop:index': 'a0',
'prop:lockedBySelf': false,
'prop:meta:createdAt': 1750036953927,
'prop:meta:createdBy': '46ce597c-098a-4c61-a106-ce79827ec1de',
'prop:meta:updatedAt': 1750036953928,
'prop:meta:updatedBy': '46ce597c-098a-4c61-a106-ce79827ec1de',
'prop:name': 'test file name here.txt',
'prop:rotate': 0,
'prop:size': 3,
'prop:sourceId': 'ldZMrM4PDlsNG4Q4YvCsz623h6TKu4qI9_FpTqIypfw=',
'prop:style': 'horizontalThin',
'prop:type': 'text/plain',
'prop:xywh': '[0,0,0,0]',
'sys:children': [],
'sys:flavour': 'affine:attachment',
'sys:id': 'tfz1yFZdnn',
'sys:version': 1,
},
},
],
summary: '',
title: 'index file name',
}
## can read all blocks from doc snapshot without workspace snapshot
> Snapshot 1

View File

@@ -56,6 +56,23 @@ test('can read all blocks from doc snapshot', async t => {
});
});
test('can read blob filename from doc snapshot', async t => {
const docSnapshot = await module.create(Mockers.DocSnapshot, {
workspaceId: workspace.id,
user: owner,
snapshotFile: 'test-doc-with-blob.snapshot.bin',
});
const result = await readAllBlocksFromDocSnapshot(
workspace.id,
'doc-0',
docSnapshot.blob
);
// NOTE: avoid snapshot result directly, because it will cause hanging
t.snapshot(JSON.parse(JSON.stringify(result)));
});
test('can read all blocks from doc snapshot without workspace snapshot', async t => {
const doc = await models.doc.get(workspace.id, docSnapshot.id);
t.truthy(doc);

View File

@@ -1,4 +1,5 @@
import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import {
Cache,
@@ -15,8 +16,6 @@ import {
Models,
} from '../../../models';
import { type EmbeddingClient, getEmbeddingClient } from '../embedding';
import { PromptService } from '../prompt';
import { CopilotProviderFactory } from '../providers';
import { ContextSession } from './session';
const CONTEXT_SESSION_KEY = 'context-session';
@@ -27,10 +26,9 @@ export class CopilotContextService implements OnApplicationBootstrap {
private client: EmbeddingClient | undefined;
constructor(
private readonly moduleRef: ModuleRef,
private readonly cache: Cache,
private readonly models: Models,
private readonly providerFactory: CopilotProviderFactory,
private readonly prompt: PromptService
private readonly models: Models
) {}
@OnEvent('config.init')
@@ -44,7 +42,7 @@ export class CopilotContextService implements OnApplicationBootstrap {
}
private async setup() {
this.client = await getEmbeddingClient(this.providerFactory, this.prompt);
this.client = await getEmbeddingClient(this.moduleRef);
}
async onApplicationBootstrap() {
@@ -165,7 +163,7 @@ export class CopilotContextService implements OnApplicationBootstrap {
);
if (!fileChunks.length) return [];
return this.embeddingClient.reRank(content, fileChunks, topK, signal);
return await this.embeddingClient.reRank(content, fileChunks, topK, signal);
}
async matchWorkspaceDocs(
@@ -188,7 +186,48 @@ export class CopilotContextService implements OnApplicationBootstrap {
);
if (!workspaceChunks.length) return [];
return this.embeddingClient.reRank(content, workspaceChunks, topK, signal);
return await this.embeddingClient.reRank(
content,
workspaceChunks,
topK,
signal
);
}
async matchWorkspaceAll(
workspaceId: string,
content: string,
topK: number = 5,
signal?: AbortSignal,
threshold: number = 0.5
) {
if (!this.embeddingClient) return [];
const embedding = await this.embeddingClient.getEmbedding(content, signal);
if (!embedding) return [];
const [fileChunks, workspaceChunks] = await Promise.all([
this.models.copilotWorkspace.matchFileEmbedding(
workspaceId,
embedding,
topK * 2,
threshold
),
this.models.copilotContext.matchWorkspaceEmbedding(
embedding,
workspaceId,
topK * 2,
threshold
),
]);
if (!fileChunks.length && !workspaceChunks.length) return [];
return await this.embeddingClient.reRank(
content,
[...fileChunks, ...workspaceChunks],
topK,
signal
);
}
@OnEvent('workspace.doc.embed.failed')

View File

@@ -234,6 +234,7 @@ export class CopilotController implements BeforeApplicationShutdown {
...session.config.promptConfig,
signal: this.getSignal(req),
user: user.id,
workspace: session.config.workspaceId,
reasoning,
webSearch,
});
@@ -304,6 +305,7 @@ export class CopilotController implements BeforeApplicationShutdown {
...session.config.promptConfig,
signal: this.getSignal(req),
user: user.id,
workspace: session.config.workspaceId,
reasoning,
webSearch,
})
@@ -378,6 +380,7 @@ export class CopilotController implements BeforeApplicationShutdown {
...session.config.promptConfig,
signal: this.getSignal(req),
user: user.id,
workspace: session.config.workspaceId,
})
).pipe(
connect(shared$ =>
@@ -500,6 +503,7 @@ export class CopilotController implements BeforeApplicationShutdown {
seed: this.parseNumber(params.seed),
signal: this.getSignal(req),
user: user.id,
workspace: session.config.workspaceId,
}
)
).pipe(

View File

@@ -1,4 +1,5 @@
import { Logger } from '@nestjs/common';
import type { ModuleRef } from '@nestjs/core';
import {
CopilotPromptNotFound,
@@ -193,12 +194,16 @@ class ProductionEmbeddingClient extends EmbeddingClient {
let EMBEDDING_CLIENT: EmbeddingClient | undefined;
export async function getEmbeddingClient(
providerFactory: CopilotProviderFactory,
prompt: PromptService
moduleRef: ModuleRef
): Promise<EmbeddingClient | undefined> {
if (EMBEDDING_CLIENT) {
return EMBEDDING_CLIENT;
}
const providerFactory = moduleRef.get(CopilotProviderFactory, {
strict: false,
});
const prompt = moduleRef.get(PromptService, { strict: false });
const client = new ProductionEmbeddingClient(providerFactory, prompt);
if (await client.configured()) {
EMBEDDING_CLIENT = client;

View File

@@ -1,4 +1,5 @@
import { Injectable } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import {
AFFiNELogger,
@@ -14,8 +15,6 @@ import {
} from '../../../base';
import { DocReader } from '../../../core/doc';
import { Models } from '../../../models';
import { PromptService } from '../prompt';
import { CopilotProviderFactory } from '../providers';
import { CopilotStorage } from '../storage';
import { readStream } from '../utils';
import { getEmbeddingClient } from './client';
@@ -31,12 +30,11 @@ export class CopilotEmbeddingJob {
private client: EmbeddingClient | undefined;
constructor(
private readonly moduleRef: ModuleRef,
private readonly doc: DocReader,
private readonly event: EventBus,
private readonly logger: AFFiNELogger,
private readonly models: Models,
private readonly providerFactory: CopilotProviderFactory,
private readonly prompt: PromptService,
private readonly queue: JobQueue,
private readonly storage: CopilotStorage
) {
@@ -57,7 +55,7 @@ export class CopilotEmbeddingJob {
this.supportEmbedding =
await this.models.copilotContext.checkEmbeddingAvailable();
if (this.supportEmbedding) {
this.client = await getEmbeddingClient(this.providerFactory, this.prompt);
this.client = await getEmbeddingClient(this.moduleRef);
}
}

View File

@@ -1791,7 +1791,13 @@ Below is the user's query. Please respond in the user's preferred language witho
},
],
config: {
tools: ['webSearch'],
tools: [
'docRead',
'docEdit',
'docKeywordSearch',
'docSemanticSearch',
'webSearch',
],
},
};

View File

@@ -10,7 +10,6 @@ import {
metrics,
UserFriendlyError,
} from '../../../../base';
import { createExaCrawlTool, createExaSearchTool } from '../../tools';
import { CopilotProvider } from '../provider';
import type {
CopilotChatOptions,
@@ -68,7 +67,7 @@ export abstract class AnthropicProvider<T> extends CopilotProvider<T> {
providerOptions: {
anthropic: this.getAnthropicOptions(options, model.id),
},
tools: this.getTools(),
tools: await this.getTools(options, model.id),
maxSteps: this.MAX_STEPS,
experimental_continueSteps: true,
});
@@ -103,7 +102,7 @@ export abstract class AnthropicProvider<T> extends CopilotProvider<T> {
providerOptions: {
anthropic: this.getAnthropicOptions(options, model.id),
},
tools: this.getTools(),
tools: await this.getTools(options, model.id),
maxSteps: this.MAX_STEPS,
experimental_continueSteps: true,
});
@@ -123,13 +122,6 @@ export abstract class AnthropicProvider<T> extends CopilotProvider<T> {
}
}
private getTools() {
return {
web_search_exa: createExaSearchTool(this.AFFiNEConfig),
web_crawl_exa: createExaCrawlTool(this.AFFiNEConfig),
};
}
private getAnthropicOptions(options: CopilotChatOptions, model: string) {
const result: AnthropicProviderOptions = {};
if (options?.reasoning && this.isReasoningModel(model)) {

View File

@@ -180,7 +180,7 @@ export class FalProvider extends CopilotProvider<FalConfig> {
? v.attachment
: undefined
)
.filter(v => !!v)[0],
.find(v => !!v),
prompt: content.trim(),
loras: lora.length ? lora : undefined,
controlnets: controlnets.length ? controlnets : undefined,

View File

@@ -11,7 +11,7 @@ import {
generateObject,
generateText,
streamText,
ToolSet,
Tool,
} from 'ai';
import { z } from 'zod';
@@ -21,10 +21,10 @@ import {
metrics,
UserFriendlyError,
} from '../../../base';
import { createExaCrawlTool, createExaSearchTool } from '../tools';
import { CopilotProvider } from './provider';
import type {
CopilotChatOptions,
CopilotChatTools,
CopilotEmbeddingOptions,
CopilotImageOptions,
CopilotStructuredOptions,
@@ -248,25 +248,14 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
}
}
private getTools(options: CopilotChatOptions, model: string): ToolSet {
const tools: ToolSet = {};
if (options?.tools?.length) {
for (const tool of options.tools) {
switch (tool) {
case 'webSearch': {
if (this.isReasoningModel(model)) {
tools.web_search_exa = createExaSearchTool(this.AFFiNEConfig);
tools.web_crawl_exa = createExaCrawlTool(this.AFFiNEConfig);
} else {
tools.web_search_preview = openai.tools.webSearchPreview();
}
break;
}
}
}
return tools;
override getProviderSpecificTools(
toolName: CopilotChatTools,
model: string
): [string, Tool] | undefined {
if (toolName === 'webSearch' && !this.isReasoningModel(model)) {
return ['web_search_preview', openai.tools.webSearchPreview()];
}
return tools;
return;
}
async text(
@@ -297,7 +286,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
providerOptions: {
openai: this.getOpenAIOptions(options, model.id),
},
tools: this.getTools(options, model.id),
tools: await this.getTools(options, model.id),
maxSteps: this.MAX_STEPS,
abortSignal: options.signal,
});
@@ -338,7 +327,7 @@ export class OpenAIProvider extends CopilotProvider<OpenAIConfig> {
providerOptions: {
openai: this.getOpenAIOptions(options, model.id),
},
tools: this.getTools(options, model.id),
tools: await this.getTools(options, model.id),
maxSteps: this.MAX_STEPS,
abortSignal: options.signal,
});

View File

@@ -1,4 +1,6 @@
import { Inject, Injectable, Logger } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { Tool, ToolSet } from 'ai';
import { z } from 'zod';
import {
@@ -7,9 +9,18 @@ import {
CopilotProviderNotSupported,
OnEvent,
} from '../../../base';
import { AccessController } from '../../../core/permission';
import { CopilotContextService } from '../context';
import {
buildDocSearchGetter,
createDocSemanticSearchTool,
createExaCrawlTool,
createExaSearchTool,
} from '../tools';
import { CopilotProviderFactory } from './factory';
import {
type CopilotChatOptions,
CopilotChatTools,
type CopilotEmbeddingOptions,
type CopilotImageOptions,
CopilotProviderModel,
@@ -33,6 +44,7 @@ export abstract class CopilotProvider<C = any> {
@Inject() protected readonly AFFiNEConfig!: Config;
@Inject() protected readonly factory!: CopilotProviderFactory;
@Inject() protected readonly moduleRef!: ModuleRef;
get config(): C {
return this.AFFiNEConfig.copilot.providers[this.type] as C;
@@ -98,6 +110,50 @@ export abstract class CopilotProvider<C = any> {
);
}
protected getProviderSpecificTools(
_toolName: CopilotChatTools,
_model: string
): [string, Tool] | undefined {
return;
}
// use for tool use, shared between providers
protected async getTools(
options: CopilotChatOptions,
model: string
): Promise<ToolSet> {
const tools: ToolSet = {};
if (options?.tools?.length) {
for (const tool of options.tools) {
const toolDef = this.getProviderSpecificTools(tool, model);
if (toolDef) {
tools[toolDef[0]] = toolDef[1];
continue;
}
switch (tool) {
case 'docSemanticSearch': {
const ac = this.moduleRef.get(AccessController, { strict: false });
const context = this.moduleRef.get(CopilotContextService, {
strict: false,
});
const searchDocs = buildDocSearchGetter(ac, context);
tools.doc_semantic_search = createDocSemanticSearchTool(
searchDocs.bind(null, options)
);
break;
}
case 'webSearch': {
tools.web_search_exa = createExaSearchTool(this.AFFiNEConfig);
tools.web_crawl_exa = createExaCrawlTool(this.AFFiNEConfig);
break;
}
}
}
return tools;
}
return tools;
}
private handleZodError(ret: z.SafeParseReturnType<any, any>) {
if (ret.success) return;
const issues = ret.error.issues.map(i => {

View File

@@ -57,7 +57,21 @@ export const VertexSchema: JSONSchema = {
// ========== prompt ==========
export const PromptConfigStrictSchema = z.object({
tools: z.enum(['webSearch']).array().nullable().optional(),
tools: z
.enum([
// work with morph
'docEdit',
// work with indexer
'docRead',
'docKeywordSearch',
// work with embeddings
'docSemanticSearch',
// work with exa/model internal tools
'webSearch',
])
.array()
.nullable()
.optional(),
// params requirements
requireContent: z.boolean().nullable().optional(),
requireAttachment: z.boolean().nullable().optional(),
@@ -121,6 +135,7 @@ export type PromptParams = NonNullable<PromptMessage['params']>;
const CopilotProviderOptionsSchema = z.object({
signal: z.instanceof(AbortSignal).optional(),
user: z.string().optional(),
workspace: z.string().optional(),
});
export const CopilotChatOptionsSchema = CopilotProviderOptionsSchema.merge(
@@ -133,6 +148,9 @@ export const CopilotChatOptionsSchema = CopilotProviderOptionsSchema.merge(
.optional();
export type CopilotChatOptions = z.infer<typeof CopilotChatOptionsSchema>;
export type CopilotChatTools = NonNullable<
NonNullable<CopilotChatOptions>['tools']
>[number];
export const CopilotStructuredOptionsSchema =
CopilotProviderOptionsSchema.merge(PromptConfigStrictSchema).optional();

View File

@@ -9,7 +9,11 @@ import {
} from 'ai';
import { ZodType } from 'zod';
import { createExaCrawlTool, createExaSearchTool } from '../tools';
import {
createDocSemanticSearchTool,
createExaCrawlTool,
createExaSearchTool,
} from '../tools';
import { PromptMessage } from './types';
type ChatMessage = CoreUserMessage | CoreAssistantMessage;
@@ -376,6 +380,7 @@ export class CitationParser {
}
export interface CustomAITools extends ToolSet {
doc_semantic_search: ReturnType<typeof createDocSemanticSearchTool>;
web_search_exa: ReturnType<typeof createExaSearchTool>;
web_crawl_exa: ReturnType<typeof createExaCrawlTool>;
}
@@ -424,6 +429,12 @@ export class TextStreamParser {
case 'tool-result': {
result = this.addPrefix(result);
switch (chunk.toolName) {
case 'doc_semantic_search': {
if (Array.isArray(chunk.result)) {
result += `\nFound ${chunk.result.length} document${chunk.result.length !== 1 ? 's' : ''} related to “${chunk.args.query}”.\n`;
}
break;
}
case 'web_search_exa': {
if (Array.isArray(chunk.result)) {
result += `\n${this.getWebSearchLinks(chunk.result)}\n`;

View File

@@ -0,0 +1,54 @@
import { tool } from 'ai';
import { z } from 'zod';
import type { AccessController } from '../../../core/permission';
import type { ChunkSimilarity } from '../../../models';
import type { CopilotContextService } from '../context';
import type { CopilotChatOptions } from '../providers';
export const buildDocSearchGetter = (
ac: AccessController,
context: CopilotContextService
) => {
const searchDocs = async (options: CopilotChatOptions, query?: string) => {
if (!options || !query?.trim() || !options.user || !options.workspace) {
return undefined;
}
const canAccess = await ac
.user(options.user)
.workspace(options.workspace)
.can('Workspace.Read');
if (!canAccess) return undefined;
const chunks = await context.matchWorkspaceAll(options.workspace, query);
const docChunks = await ac
.user(options.user)
.workspace(options.workspace)
.docs(
chunks.filter(c => 'docId' in c),
'Doc.Read'
);
const fileChunks = chunks.filter(c => 'fileId' in c);
if (!docChunks.length && !fileChunks.length) return undefined;
return [...fileChunks, ...docChunks];
};
return searchDocs;
};
export const createDocSemanticSearchTool = (
searchDocs: (query: string) => Promise<ChunkSimilarity[] | undefined>
) => {
return tool({
description:
'Semantic search for relevant documents in the current workspace',
parameters: z.object({
query: z.string().describe('The query to search for.'),
}),
execute: async ({ query }) => {
try {
return await searchDocs(query);
} catch {
return 'Failed to search documents.';
}
},
});
};

View File

@@ -1 +1,2 @@
export * from './doc-semantic-search';
export * from './web-search';

View File

@@ -494,3 +494,30 @@ Generated by [AVA](https://avajs.dev).
],
},
]
## should search blob names from doc snapshot work
> Snapshot 1
Map {
'ldZMrM4PDlsNG4Q4YvCsz623h6TKu4qI9_FpTqIypfw=' => 'test file name here.txt',
}
## should search blob names work
> Snapshot 1
[
[
'blob1',
'blob1 name.txt',
],
[
'blob2',
'blob2 name.md',
],
[
'blob3',
'blob3 name.docx',
],
]

View File

@@ -2113,3 +2113,103 @@ test('should index doc work', async t => {
t.is(module.event.count('doc.indexer.updated'), count + 1);
});
// #endregion
// #region searchBlobNames()
test('should search blob names from doc snapshot work', async t => {
const docSnapshot = await module.create(Mockers.DocSnapshot, {
workspaceId: workspace.id,
user,
snapshotFile: 'test-doc-with-blob.snapshot.bin',
});
await indexerService.indexDoc(workspace.id, docSnapshot.id, {
refresh: true,
});
const blobNameMap = await indexerService.searchBlobNames(workspace.id, [
'ldZMrM4PDlsNG4Q4YvCsz623h6TKu4qI9_FpTqIypfw=',
]);
t.snapshot(blobNameMap);
});
test('should search blob names work', async t => {
const workspaceId = randomUUID();
const blobId1 = 'blob1';
const blobId2 = 'blob2';
const blobId3 = 'blob3';
const blobId4 = 'blob4';
await indexerService.write(
SearchTable.block,
[
{
workspaceId,
blob: blobId1,
content: 'blob1 name.txt',
flavour: 'affine:attachment',
docId: randomUUID(),
blockId: randomUUID(),
createdByUserId: user.id,
updatedByUserId: user.id,
createdAt: new Date(),
updatedAt: new Date(),
},
{
workspaceId,
blob: blobId2,
content: 'blob2 name.md',
flavour: 'affine:attachment',
docId: randomUUID(),
blockId: randomUUID(),
createdByUserId: user.id,
updatedByUserId: user.id,
createdAt: new Date(),
updatedAt: new Date(),
},
{
workspaceId,
blob: blobId3,
content: 'blob3 name.docx',
flavour: 'affine:attachment',
docId: randomUUID(),
blockId: randomUUID(),
createdByUserId: user.id,
updatedByUserId: user.id,
createdAt: new Date(),
updatedAt: new Date(),
},
// no attachment
{
workspaceId,
blob: blobId3,
content: 'mock blob3 content',
flavour: 'affine:page',
docId: randomUUID(),
blockId: randomUUID(),
createdByUserId: user.id,
updatedByUserId: user.id,
createdAt: new Date(),
updatedAt: new Date(),
},
],
{
refresh: true,
}
);
const blobNameMap = await indexerService.searchBlobNames(workspaceId, [
blobId1,
blobId2,
blobId3,
blobId4,
]);
t.is(blobNameMap.size, 3);
t.snapshot(
Array.from(blobNameMap.entries()).sort((a, b) => a[0].localeCompare(b[0]))
);
});
// #endregion

View File

@@ -387,6 +387,52 @@ export class IndexerService {
await searchProvider.deleteByQuery(table, dsl, options);
}
async searchBlobNames(workspaceId: string, blobIds: string[]) {
const result = await this.search({
table: SearchTable.block,
query: {
type: SearchQueryType.boolean,
occur: SearchQueryOccur.must,
queries: [
{
type: SearchQueryType.match,
field: 'workspaceId',
match: workspaceId,
},
{
type: SearchQueryType.match,
field: 'flavour',
match: 'affine:attachment',
},
{
type: SearchQueryType.boolean,
occur: SearchQueryOccur.should,
queries: blobIds.map(blobId => ({
type: SearchQueryType.match,
field: 'blob',
match: blobId,
})),
},
],
},
options: {
fields: ['blob', 'content'],
pagination: {
limit: 10000,
},
},
});
const blobNameMap = new Map<string, string>();
for (const node of result.nodes) {
const blobId = node.fields.blob[0] as string;
const content = node.fields.content[0] as string;
if (blobId && content) {
blobNameMap.set(blobId, content);
}
}
return blobNameMap;
}
#formatSearchNodes(nodes: SearchNode[]) {
return nodes.map(node => ({
...node,

View File

@@ -15,7 +15,7 @@ export const passwordLimitsFragment = `fragment PasswordLimits on PasswordLimits
minLength
maxLength
}`;
export const licenseFragment = `fragment license on License {
export const licenseBodyFragment = `fragment licenseBody on License {
expiredAt
installedAt
quantity
@@ -1443,10 +1443,10 @@ export const activateLicenseMutation = {
op: 'activateLicense',
query: `mutation activateLicense($workspaceId: String!, $license: String!) {
activateLicense(workspaceId: $workspaceId, license: $license) {
...license
...licenseBody
}
}
${licenseFragment}`,
${licenseBodyFragment}`,
};
export const deactivateLicenseMutation = {
@@ -1463,11 +1463,11 @@ export const getLicenseQuery = {
query: `query getLicense($workspaceId: String!) {
workspace(id: $workspaceId) {
license {
...license
...licenseBody
}
}
}
${licenseFragment}`,
${licenseBodyFragment}`,
};
export const installLicenseMutation = {
@@ -1475,10 +1475,10 @@ export const installLicenseMutation = {
op: 'installLicense',
query: `mutation installLicense($workspaceId: String!, $license: Upload!) {
installLicense(workspaceId: $workspaceId, license: $license) {
...license
...licenseBody
}
}
${licenseFragment}`,
${licenseBodyFragment}`,
file: true,
};

View File

@@ -1,7 +1,7 @@
#import './license.gql'
#import './license-body.gql'
mutation activateLicense($workspaceId: String!, $license: String!) {
activateLicense(workspaceId: $workspaceId, license: $license) {
...license
...licenseBody
}
}

View File

@@ -1,9 +1,9 @@
#import './license.gql'
#import './license-body.gql'
query getLicense($workspaceId: String!) {
workspace(id: $workspaceId) {
license {
...license
...licenseBody
}
}
}

View File

@@ -1,7 +1,7 @@
#import './license.gql'
#import './license-body.gql'
mutation installLicense($workspaceId: String!, $license: Upload!) {
installLicense(workspaceId: $workspaceId, license: $license) {
...license
...licenseBody
}
}

View File

@@ -1,4 +1,4 @@
fragment license on License {
fragment licenseBody on License {
expiredAt
installedAt
quantity

View File

@@ -4401,7 +4401,7 @@ export type InstallLicenseMutation = {
};
};
export type LicenseFragment = {
export type LicenseBodyFragment = {
__typename?: 'License';
expiredAt: string | null;
installedAt: string;

View File

@@ -16,6 +16,7 @@ export type AppSetting = {
autoCheckUpdate: boolean;
autoDownloadUpdate: boolean;
enableTelemetry: boolean;
showLinkedDocInSidebar: boolean;
};
export const windowFrameStyleOptions: AppSetting['windowFrameStyle'][] = [
'frameless',
@@ -33,6 +34,7 @@ const appSettingBaseAtom = atomWithStorage<AppSetting>(
autoCheckUpdate: true,
autoDownloadUpdate: true,
enableTelemetry: true,
showLinkedDocInSidebar: true,
},
undefined,
{

View File

@@ -52,6 +52,509 @@ exports[`should get all docs from root doc work 2`] = `
]
`;
exports[`should parse page doc work 1`] = `
{
"md": "AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro.
# You own your data, with no compromises
## Local-first & Real-time collaborative
We love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.
AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.
### Blocks that assemble your next docs, tasks kanban or whiteboard
There is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further.
We are building AFFiNE to be a fundamental open source platform that contains all the building blocks for docs, task management and visual collaboration, hoping you can shape your next workflow with us that can make your life better and also connect others, too.
If you want to learn more about the product design of AFFiNE, here goes the concepts:
To Shape, not to adapt. AFFiNE is built for individuals & teams who care about their data, who refuse vendor lock-in, and who want to have control over their essential tools.
## A true canvas for blocks in any form
[Many editor apps](http://notion.so) claimed to be a canvas for productivity. Since _the Mother of All Demos,_ Douglas Engelbart, a creative and programable digital workspace has been a pursuit and an ultimate mission for generations of tool makers.
"We shape our tools and thereafter our tools shape us”. A lot of pioneers have inspired us a long the way, e.g.:
* Quip & Notion with their great concept of "everything is a block"
* Trello with their Kanban
* Airtable & Miro with their no-code programable datasheets
* Miro & Whimiscal with their edgeless visual whiteboard
* Remnote & Capacities with their object-based tag system
For more details, please refer to our [RoadMap](https://docs.affine.pro/docs/core-concepts/roadmap)
## Self Host
Self host AFFiNE
||Title|Tag|
|---|---|---|
|Affine Development|Affine Development|<span data-affine-option data-value="AxSe-53xjX" data-option-color="var(--affine-tag-pink)">AFFiNE</span>|
|For developers or installations guides, please go to AFFiNE Doc|For developers or installations guides, please go to AFFiNE Doc|<span data-affine-option data-value="0jh9gNw4Yl" data-option-color="var(--affine-tag-orange)">Developers</span>|
|Quip & Notion with their great concept of "everything is a block"|Quip & Notion with their great concept of "everything is a block"|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Trello with their Kanban|Trello with their Kanban|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Airtable & Miro with their no-code programable datasheets|Airtable & Miro with their no-code programable datasheets|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Miro & Whimiscal with their edgeless visual whiteboard|Miro & Whimiscal with their edgeless visual whiteboard|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Remnote & Capacities with their object-based tag system|Remnote & Capacities with their object-based tag system||
## Affine Development
For developer or installation guides, please go to [AFFiNE Development](https://docs.affine.pro/docs/development/quick-start)
",
"parsedBlock": {
"children": [
{
"children": [
{
"children": [],
"content": "AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro.
",
"flavour": "affine:paragraph",
"id": "FoPQcAyV_m",
"type": "text",
},
{
"children": [],
"content": "
",
"flavour": "affine:paragraph",
"id": "oz48nn_zp8",
"type": "text",
},
{
"children": [],
"content": "# You own your data, with no compromises
",
"flavour": "affine:paragraph",
"id": "g8a-D9-jXS",
"type": "h1",
},
{
"children": [],
"content": "## Local-first & Real-time collaborative
",
"flavour": "affine:paragraph",
"id": "J8lHN1GR_5",
"type": "h2",
},
{
"children": [],
"content": "We love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.
",
"flavour": "affine:paragraph",
"id": "xCuWdM0VLz",
"type": "text",
},
{
"children": [],
"content": "AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.
",
"flavour": "affine:paragraph",
"id": "zElMi0tViK",
"type": "text",
},
{
"children": [],
"content": "
",
"flavour": "affine:paragraph",
"id": "Z4rK0OF9Wk",
"type": "text",
},
],
"content": "",
"flavour": "affine:note",
"id": "RX4CG2zsBk",
"type": undefined,
},
{
"children": [
{
"children": [],
"content": "### Blocks that assemble your next docs, tasks kanban or whiteboard
",
"flavour": "affine:paragraph",
"id": "DQ0Ryb-SpW",
"type": "h3",
},
],
"content": "",
"flavour": "affine:note",
"id": "S1mkc8zUoU",
"type": undefined,
},
{
"children": [
{
"children": [],
"content": "There is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further.
",
"flavour": "affine:paragraph",
"id": "HAZC3URZp_",
"type": "text",
},
{
"children": [],
"content": "We are building AFFiNE to be a fundamental open source platform that contains all the building blocks for docs, task management and visual collaboration, hoping you can shape your next workflow with us that can make your life better and also connect others, too.
",
"flavour": "affine:paragraph",
"id": "0H87ypiuv8",
"type": "text",
},
{
"children": [],
"content": "If you want to learn more about the product design of AFFiNE, here goes the concepts:
",
"flavour": "affine:paragraph",
"id": "Sp4G1KD0Wn",
"type": "text",
},
{
"children": [],
"content": "To Shape, not to adapt. AFFiNE is built for individuals & teams who care about their data, who refuse vendor lock-in, and who want to have control over their essential tools.
",
"flavour": "affine:paragraph",
"id": "RsUhDuEqXa",
"type": "text",
},
],
"content": "",
"flavour": "affine:note",
"id": "yGlBdshAqN",
"type": undefined,
},
{
"children": [
{
"children": [],
"content": "## A true canvas for blocks in any form
",
"flavour": "affine:paragraph",
"id": "Z2HibKzAr-",
"type": "h2",
},
{
"children": [],
"content": "[Many editor apps](http://notion.so) claimed to be a canvas for productivity. Since _the Mother of All Demos,_ Douglas Engelbart, a creative and programable digital workspace has been a pursuit and an ultimate mission for generations of tool makers.
",
"flavour": "affine:paragraph",
"id": "UwvWddamzM",
"type": "text",
},
{
"children": [],
"content": "
",
"flavour": "affine:paragraph",
"id": "g9xKUjhJj1",
"type": "text",
},
{
"children": [],
"content": ""We shape our tools and thereafter our tools shape us”. A lot of pioneers have inspired us a long the way, e.g.:
",
"flavour": "affine:paragraph",
"id": "wDTn4YJ4pm",
"type": "text",
},
{
"children": [],
"content": "* Quip & Notion with their great concept of "everything is a block"
",
"flavour": "affine:list",
"id": "xFrrdiP3-V",
"type": "bulleted",
},
{
"children": [],
"content": "* Trello with their Kanban
",
"flavour": "affine:list",
"id": "Tp9xyN4Okl",
"type": "bulleted",
},
{
"children": [],
"content": "* Airtable & Miro with their no-code programable datasheets
",
"flavour": "affine:list",
"id": "K_4hUzKZFQ",
"type": "bulleted",
},
{
"children": [],
"content": "* Miro & Whimiscal with their edgeless visual whiteboard
",
"flavour": "affine:list",
"id": "QwMzON2s7x",
"type": "bulleted",
},
{
"children": [],
"content": "* Remnote & Capacities with their object-based tag system
",
"flavour": "affine:list",
"id": "FFVmit6u1T",
"type": "bulleted",
},
],
"content": "",
"flavour": "affine:note",
"id": "6lDiuDqZGL",
"type": undefined,
},
{
"children": [
{
"children": [],
"content": "For more details, please refer to our [RoadMap](https://docs.affine.pro/docs/core-concepts/roadmap)
",
"flavour": "affine:paragraph",
"id": "YqnG5O6AE6",
"type": "text",
},
{
"children": [],
"content": "## Self Host
",
"flavour": "affine:paragraph",
"id": "sbDTmZMZcq",
"type": "h2",
},
{
"children": [],
"content": "Self host AFFiNE
",
"flavour": "affine:paragraph",
"id": "QVvitesfbj",
"type": "text",
},
],
"content": "",
"flavour": "affine:note",
"id": "cauvaHOQmh",
"type": undefined,
},
{
"children": [
{
"children": [],
"content": "||Title|Tag|
|---|---|---|
|Affine Development|Affine Development|<span data-affine-option data-value="AxSe-53xjX" data-option-color="var(--affine-tag-pink)">AFFiNE</span>|
|For developers or installations guides, please go to AFFiNE Doc|For developers or installations guides, please go to AFFiNE Doc|<span data-affine-option data-value="0jh9gNw4Yl" data-option-color="var(--affine-tag-orange)">Developers</span>|
|Quip & Notion with their great concept of "everything is a block"|Quip & Notion with their great concept of "everything is a block"|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Trello with their Kanban|Trello with their Kanban|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Airtable & Miro with their no-code programable datasheets|Airtable & Miro with their no-code programable datasheets|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Miro & Whimiscal with their edgeless visual whiteboard|Miro & Whimiscal with their edgeless visual whiteboard|<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>|
|Remnote & Capacities with their object-based tag system|Remnote & Capacities with their object-based tag system||
",
"flavour": "affine:database",
"id": "U_GoHFD9At",
"rows": [
{
"Tag": "<span data-affine-option data-value="AxSe-53xjX" data-option-color="var(--affine-tag-pink)">AFFiNE</span>",
"Title": "Affine Development
",
"undefined": "Affine Development
",
},
{
"Tag": "<span data-affine-option data-value="0jh9gNw4Yl" data-option-color="var(--affine-tag-orange)">Developers</span>",
"Title": "For developers or installations guides, please go to AFFiNE Doc
",
"undefined": "For developers or installations guides, please go to AFFiNE Doc
",
},
{
"Tag": "<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>",
"Title": "Quip & Notion with their great concept of "everything is a block"
",
"undefined": "Quip & Notion with their great concept of "everything is a block"
",
},
{
"Tag": "<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>",
"Title": "Trello with their Kanban
",
"undefined": "Trello with their Kanban
",
},
{
"Tag": "<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>",
"Title": "Airtable & Miro with their no-code programable datasheets
",
"undefined": "Airtable & Miro with their no-code programable datasheets
",
},
{
"Tag": "<span data-affine-option data-value="HgHsKOUINZ" data-option-color="var(--affine-tag-blue)">Reference</span>",
"Title": "Miro & Whimiscal with their edgeless visual whiteboard
",
"undefined": "Miro & Whimiscal with their edgeless visual whiteboard
",
},
{
"Tag": "",
"Title": "Remnote & Capacities with their object-based tag system
",
"undefined": "Remnote & Capacities with their object-based tag system
",
},
],
"title": "Learning From",
"type": undefined,
},
],
"content": "",
"flavour": "affine:note",
"id": "2jwCeO8Yot",
"type": undefined,
},
{
"children": [
{
"children": [],
"content": "## Affine Development
",
"flavour": "affine:paragraph",
"id": "NyHXrMX3R1",
"type": "h2",
},
{
"children": [],
"content": "For developer or installation guides, please go to [AFFiNE Development](https://docs.affine.pro/docs/development/quick-start)
",
"flavour": "affine:paragraph",
"id": "9-K49otbCv",
"type": "text",
},
{
"children": [],
"content": "
",
"flavour": "affine:paragraph",
"id": "faFteK9eG-",
"type": "text",
},
],
"content": "",
"flavour": "affine:note",
"id": "c9MF_JiRgx",
"type": undefined,
},
],
"content": "",
"flavour": "affine:page",
"id": "TnUgtVg7Eu",
"type": undefined,
},
"title": "Write, Draw, Plan all at Once.",
}
`;
exports[`should read all doc ids from root doc snapshot work 1`] = `
[
"5nS9BSp3Px",

View File

@@ -5,6 +5,7 @@ import { expect, test } from 'vitest';
import { applyUpdate, Array as YArray, Doc as YDoc, Map as YMap } from 'yjs';
import {
parsePageDoc,
readAllBlocksFromDoc,
readAllDocIdsFromRootDoc,
readAllDocsFromRootDoc,
@@ -100,3 +101,20 @@ test('should read all doc ids from root doc snapshot work', async () => {
const docIds = readAllDocIdsFromRootDoc(rootDoc);
expect(docIds).toMatchSnapshot();
});
test('should parse page doc work', () => {
const doc = new YDoc({
guid: 'test-doc',
});
applyUpdate(doc, docSnapshot);
const result = parsePageDoc({
workspaceId: 'test-space',
doc,
buildBlobUrl: id => `blob://${id}`,
buildDocUrl: id => `doc://${id}`,
renderDocTitle: id => `Doc Title ${id}`,
});
expect(result).toMatchSnapshot();
});

View File

@@ -0,0 +1 @@
A fork of https://github.com/frysztak/quill-delta-to-markdown

View File

@@ -0,0 +1,95 @@
// eslint-disable
// @ts-nocheck
import { Node } from './utils/node';
import { encodeLink } from './utils/url';
export interface InlineReference {
type: 'LinkedPage';
pageId: string;
title?: string;
params?: { mode: 'doc' | 'edgeless' };
}
export interface ConverterOptions {
convertInlineReferenceLink?: (reference: InlineReference) => {
title: string;
link: string;
};
}
const defaultConvertInlineReferenceLink = (reference: InlineReference) => {
return {
title: reference.title || '',
link: [reference.type, reference.pageId, reference.params?.mode]
.filter(Boolean)
.join(':'),
};
};
export function getConverters(opts: ConverterOptions = {}) {
const { convertInlineReferenceLink = defaultConvertInlineReferenceLink } =
opts;
return {
embed: {
image: function (src) {
this.append('![](' + encodeLink(src) + ')');
},
// Not a default Quill feature, converts custom divider embed blot added when
// creating quill editor instance.
// See https://quilljs.com/guides/cloning-medium-with-parchment/#dividers
thematic_break: function () {
this.open = '\n---\n' + this.open;
},
},
inline: {
italic: function () {
return ['_', '_'];
},
bold: function () {
return ['**', '**'];
},
link: function (url) {
return ['[', '](' + url + ')'];
},
reference: function (reference: InlineReference) {
const { title, link } = convertInlineReferenceLink(reference);
return ['[', `${title}](${link})`];
},
strike: function () {
return ['~~', '~~'];
},
code: function () {
return ['`', '`'];
},
},
block: {
header: function ({ header }) {
this.open = '#'.repeat(header) + ' ' + this.open;
},
blockquote: function () {
this.open = '> ' + this.open;
},
list: {
group: function () {
return new Node(['', '\n']);
},
line: function (attrs, group) {
if (attrs.list === 'bullet') {
this.open = '- ' + this.open;
} else if (attrs.list === 'checked') {
this.open = '- [x] ' + this.open;
} else if (attrs.list === 'unchecked') {
this.open = '- [ ] ' + this.open;
} else if (attrs.list === 'ordered') {
group.count = group.count || 0;
var count = ++group.count;
this.open = count + '. ' + this.open;
}
},
},
},
};
}

View File

@@ -0,0 +1,147 @@
// eslint-disable
// @ts-nocheck
import { Node } from './utils/node';
export const deltaToMd = (delta, converters) => {
return convert(delta, converters).render().trimEnd() + '\n';
};
function convert(ops, converters) {
let group, line, el, activeInline, beginningOfLine;
let root = new Node();
function newLine() {
el = line = new Node(['', '\n']);
root.append(line);
activeInline = {};
}
newLine();
for (let i = 0; i < ops.length; i++) {
let op = ops[i];
if (typeof op.insert === 'object') {
for (let k in op.insert) {
if (converters.embed[k]) {
applyInlineAttributes(op.attributes);
converters.embed[k].call(el, op.insert[k], op.attributes);
}
}
} else {
let lines = op.insert.split('\n');
if (hasBlockLevelAttribute(op.attributes, converters)) {
// Some line-level styling (ie headings) is applied by inserting a \n
// with the style; the style applies back to the previous \n.
// There *should* only be one style in an insert operation.
for (let j = 1; j < lines.length; j++) {
for (let attr in op.attributes) {
if (converters.block[attr]) {
let fn = converters.block[attr];
if (typeof fn === 'object') {
if (group && group.type !== attr) {
group = null;
}
if (!group && fn.group) {
group = {
el: fn.group(),
type: attr,
value: op.attributes[attr],
distance: 0,
};
root.append(group.el);
}
if (group) {
group.el.append(line);
group.distance = 0;
}
fn = fn.line;
}
fn.call(line, op.attributes, group);
newLine();
break;
}
}
}
beginningOfLine = true;
} else {
for (let l = 0; l < lines.length; l++) {
if ((l > 0 || beginningOfLine) && group && ++group.distance >= 2) {
group = null;
}
applyInlineAttributes(
op.attributes,
ops[i + 1] && ops[i + 1].attributes
);
el.append(lines[l]);
if (l < lines.length - 1) {
newLine();
}
}
beginningOfLine = false;
}
}
}
return root;
function applyInlineAttributes(attrs, next?: any) {
let first: any[] = [];
let then: any[] = [];
attrs = attrs || {};
let tag = el,
seen = {};
while (tag._format) {
seen[tag._format] = true;
if (!attrs[tag._format] || tag.open !== tag.close) {
for (let k in seen) {
delete activeInline[k];
}
el = tag.parent();
}
tag = tag.parent();
}
for (let attr in attrs) {
if (converters.inline[attr] && attrs[attr]) {
if (activeInline[attr] && activeInline[attr] === attrs[attr]) {
continue; // do nothing -- we should already be inside this style's tag
}
if (next && attrs[attr] === next[attr]) {
first.push(attr); // if the next operation has the same style, this should be the outermost tag
} else {
then.push(attr);
}
activeInline[attr] = attrs[attr];
}
}
first.forEach(apply);
then.forEach(apply);
function apply(fmt) {
let newEl = converters.inline[fmt].call(null, attrs[fmt]);
if (Array.isArray(newEl)) {
newEl = new Node(newEl);
}
newEl._format = fmt;
el.append(newEl);
el = newEl;
}
}
}
function hasBlockLevelAttribute(attrs, converters) {
for (let k in attrs) {
if (Object.keys(converters.block).includes(k)) {
return true;
}
}
return false;
}

View File

@@ -0,0 +1,2 @@
export { getConverters } from './delta-converters';
export { deltaToMd } from './delta-to-md';

View File

@@ -0,0 +1,66 @@
// eslint-disable
// @ts-nocheck
let id = 0;
export class Node {
id = ++id;
children: Node[];
open: string;
close: string;
text: string;
_format: string;
_parent: Node;
constructor(data?: string[] | string) {
if (Array.isArray(data)) {
this.open = data[0];
this.close = data[1];
} else if (typeof data === 'string') {
this.text = data;
}
this.children = [];
}
append(e: Node) {
if (!(e instanceof Node)) {
e = new Node(e);
}
if (e._parent) {
const idx = e._parent.children.indexOf(e);
e._parent.children.splice(idx, 1);
}
e._parent = this;
this.children = this.children.concat(e);
}
render() {
const inner =
(this.text || '') + this.children.map(c => c.render()).join('');
if (
inner.trim() === '' &&
this.open === this.close &&
this.open &&
this.close
) {
return '';
}
const wrapped = this.open && this.close;
const emptyInner = inner.trim() === '';
const fragments = [
inner.startsWith(' ') && !emptyInner && wrapped ? ' ' : '',
this.open,
wrapped ? inner.trim() : inner,
this.close,
inner.endsWith(' ') && !emptyInner && wrapped ? ' ' : '',
].filter(f => f);
return fragments.join('');
}
parent() {
return this._parent;
}
}

View File

@@ -0,0 +1,5 @@
export const encodeLink = (link: string) =>
encodeURI(link)
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/(\?|&)response-content-disposition=attachment.*$/, '');

View File

@@ -0,0 +1,437 @@
import type { ColumnDataType } from '@blocksuite/affine/model';
import { Array as YArray, type Map as YMap, type Text as YText } from 'yjs';
import { deltaToMd, getConverters } from './delta-to-md';
import type {
BaseParsedBlock,
Flavour,
ParsedBlock,
ParsedDoc,
ParserContext,
SerializedCells,
YBlock,
YBlocks,
} from './types';
export const parseBlockToMd = (
block: BaseParsedBlock,
padding = ''
): string => {
if (block.content) {
return (
block.content
.split('\n')
.map(line => padding + line)
.join('\n') +
'\n' +
block.children.map(b => parseBlockToMd(b, padding + ' ')).join('')
);
} else {
return block.children.map(b => parseBlockToMd(b, padding)).join('');
}
};
export function parseBlock(
context: ParserContext,
yBlock: YBlock | undefined,
yBlocks: YBlocks // all blocks
): ParsedBlock | null {
if (!yBlock) {
return null;
}
const deltaConverters = getConverters({
convertInlineReferenceLink: ref => {
return {
title: ref.title || context.renderDocTitle?.(ref.pageId) || '',
link: context.buildDocUrl(ref.pageId),
};
},
});
const id = yBlock.get('sys:id') as string;
const flavour = yBlock.get('sys:flavour') as Flavour;
const type = yBlock.get('prop:type') as string;
const toMd = () =>
deltaToMd((yBlock.get('prop:text') as YText).toDelta(), deltaConverters);
const hidden = yBlock.get('prop:hidden') as boolean;
const displayMode = yBlock.get('prop:displayMode') as string;
const childrenIds =
yBlock.get('sys:children') instanceof YArray
? (yBlock.get('sys:children') as YArray<string>).toJSON()
: [];
let result: ParsedBlock = {
id,
flavour,
content: '',
children: [],
type,
};
if (hidden || displayMode === 'edgeless') {
return result;
}
try {
switch (flavour) {
case 'affine:paragraph': {
let initial = '';
if (type === 'h1') {
initial = '# ';
} else if (type === 'h2') {
initial = '## ';
} else if (type === 'h3') {
initial = '### ';
} else if (type === 'h4') {
initial = '#### ';
} else if (type === 'h5') {
initial = '##### ';
} else if (type === 'h6') {
initial = '###### ';
} else if (type === 'quote') {
initial = '> ';
}
result.content = initial + toMd() + '\n';
break;
}
case 'affine:divider': {
result.content = '\n---\n\n';
break;
}
case 'affine:list': {
result.content = (type === 'bulleted' ? '* ' : '1. ') + toMd() + '\n';
break;
}
case 'affine:code': {
const lang =
(yBlock.get('prop:language') as string)?.toLowerCase() || 'txt';
// do not transform to delta for code block
const caption = yBlock.get('prop:caption') as string;
result.content =
'```' +
lang +
(caption ? ` ${caption}` : '') +
'\n' +
(yBlock.get('prop:text') as YText).toJSON() +
'\n```\n\n';
break;
}
case 'affine:image': {
const sourceId = yBlock.get('prop:sourceId') as string;
const width = yBlock.get('prop:width');
const height = yBlock.get('prop:height');
// fixme: this may not work if workspace is not public
const blobUrl = context.buildBlobUrl(sourceId);
const caption = yBlock.get('prop:caption') as string;
if (width || height || caption) {
result.content =
`<img
src="${blobUrl}"
alt="${caption}"
width="${width || 'auto'}"
height="${height || 'auto'}"
/>
` + '\n\n';
} else {
result.content = `\n![${caption || sourceId}](${blobUrl})\n\n`;
}
Object.assign(result, {
sourceId,
width,
height,
caption,
blobUrl,
});
break;
}
case 'affine:attachment': {
const sourceId = yBlock.get('prop:sourceId') as string;
const blobUrl = context.buildBlobUrl(sourceId);
const caption = yBlock.get('prop:caption') as string;
if (type.startsWith('video')) {
result.content =
`<video muted autoplay loop preload="auto" playsinline>
<source src="${blobUrl}" type="${type}" />
</video>
` + '\n\n';
} else {
// assume it is an image
result.content = `\n![${caption || sourceId}](${blobUrl})\n\n`;
}
Object.assign(result, {
sourceId,
blobUrl,
caption,
});
break;
}
case 'affine:embed-youtube': {
const videoId = yBlock.get('prop:videoId') as string;
// prettier-ignore
result.content = `
<iframe
type="text/html"
width="100%"
height="410px"
src="https://www.youtube.com/embed/${videoId}"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen
credentialless>
</iframe>` + '\n\n';
break;
}
case 'affine:bookmark': {
const url = yBlock.get('prop:url') as string;
const caption = yBlock.get('prop:caption') as string;
result.content = `\n[](Bookmark,${url})\n\n`;
Object.assign(result, {
url,
caption,
});
break;
}
case 'affine:embed-linked-doc':
case 'affine:embed-synced-doc': {
const pageId = yBlock.get('prop:pageId') as string;
const caption = yBlock.get('prop:caption') as string;
result.content = `\n[${caption}](${context.buildDocUrl(pageId)})\n\n`;
Object.assign(result, {
pageId,
caption,
});
break;
}
case 'affine:surface':
case 'affine:page':
case 'affine:note':
case 'affine:frame': {
result.content = '';
break;
}
case 'affine:database': {
const title = (yBlock.get('prop:title') as YText).toJSON();
const childrenTitleById = Object.fromEntries(
childrenIds.map(cid => {
const child = parseBlock(
context,
yBlocks.get(cid) as YBlock | undefined,
yBlocks
);
if (!child) {
return [cid, ''];
}
return [cid, parseBlockToMd(child)] as const;
})
);
const cols = (
yBlock.get('prop:columns') as YArray<ColumnDataType>
).toJSON() as ColumnDataType[];
const cells = (
yBlock.get('prop:cells') as YMap<SerializedCells>
).toJSON() as SerializedCells;
const optionToTagHtml = (option: any) => {
return `<span data-affine-option data-value="${option.id}" data-option-color="${option.color}">${option.value}</span>`;
};
const dbRows: string[][] = childrenIds
.map(cid => {
const row = cells[cid];
return cols.map(col => {
const value = row?.[col.id]?.value;
if (col.type !== 'title' && !value) {
return '';
}
switch (col.type) {
case 'title':
return childrenTitleById[cid];
case 'select':
return optionToTagHtml(
(col.data['options'] as any).find(
(opt: any) => opt.id === value
)
);
case 'multi-select':
return (col.data['options'] as any)
.filter((opt: any) => (value as string[]).includes(opt.id))
.map(optionToTagHtml)
.join('');
default:
return value ?? '';
}
});
})
.filter(row => !row.every(v => !v));
const header = cols.map(col => {
return col.name;
});
const divider = cols.map(() => {
return '---';
});
// convert to markdown table
result.content =
[header, divider, ...dbRows]
.map(row => {
return (
'|' +
row
.map(cell => String(cell || '')?.trim())
.join('|')
.replace(/\n+/g, '<br />') +
'|'
);
})
.join('\n') + '\n\n';
Object.assign(result, {
title,
rows: dbRows.map(row => {
return Object.fromEntries(row.map((v, i) => [cols[i].name, v]));
}),
});
break;
}
case 'affine:table': {
// Extract row IDs and their order
const rowEntries = Object.entries(yBlock.toJSON())
.filter(
([key]) => key.startsWith('prop:rows.') && key.endsWith('.rowId')
)
.map(([key, value]) => {
const rowId = value as string;
const orderKey = key.replace('.rowId', '.order');
const order = yBlock.get(orderKey) as string;
const backgroundColor = yBlock.get(
key.replace('.rowId', '.backgroundColor')
) as string | undefined;
return { rowId, order, backgroundColor };
})
.sort((a, b) => a.order.localeCompare(b.order));
// Extract column IDs and their order
const columnEntries = Object.entries(yBlock.toJSON())
.filter(
([key]) =>
key.startsWith('prop:columns.') && key.endsWith('.columnId')
)
.map(([key, value]) => {
const columnId = value as string;
const orderKey = key.replace('.columnId', '.order');
const order = yBlock.get(orderKey) as string;
return { columnId, order };
})
.sort((a, b) => a.order.localeCompare(b.order));
// Build the table rows with cell data
const tableRows = rowEntries.map(({ rowId }) => {
return columnEntries.map(({ columnId }) => {
const cellKey = `prop:cells.${rowId}:${columnId}.text`;
const cellText = yBlock.get(cellKey) as string | undefined;
return cellText || '';
});
});
// Store column IDs for reference
const columnIds = columnEntries.map(({ columnId }) => columnId);
// Use the first row as header and the rest as data rows
if (tableRows.length > 0) {
const headerRow = tableRows[0];
const dataRows = tableRows.slice(1);
const separators = headerRow.map(() => '---');
// Convert to markdown table with first row as header
result.content =
[headerRow, separators, ...dataRows]
.map(row => {
return (
'|' +
row
.map(cell => String(cell || '')?.trim())
.join('|')
.replace(/\n+/g, '<br />') +
'|'
);
})
.join('\n') + '\n\n';
} else {
// Handle empty table case
result.content = '';
}
Object.assign(result, {
columns: columnIds,
rows: tableRows,
});
break;
}
default: {
// console.warn("Unknown or unsupported flavour", flavour);
}
}
result.children =
flavour !== 'affine:database'
? childrenIds
.map(cid =>
parseBlock(
context,
yBlocks.get(cid) as YBlock | undefined,
yBlocks
)
)
.filter(
(block): block is ParsedBlock =>
!!block &&
!(block.content === '' && block.children.length === 0)
)
: [];
} catch (e) {
console.warn('Error converting block to md', e);
}
return result;
}
export const parsePageDoc = (ctx: ParserContext): ParsedDoc => {
// we assume that the first block is the page block
const yBlocks: YBlocks = ctx.doc.getMap('blocks');
const maybePageBlock = Object.entries(yBlocks.toJSON()).findLast(
([_, b]) => b['sys:flavour'] === 'affine:page'
);
// there are cases that the page is empty due to some weird issues
if (!maybePageBlock) {
return {
title: '',
md: '',
};
} else {
const yPage = yBlocks.get(maybePageBlock[0]) as YBlock;
const title = yPage.get('prop:title') as YText;
const rootBlock = parseBlock(ctx, yPage, yBlocks);
if (!rootBlock) {
return {
title: '',
md: '',
};
}
rootBlock.children = rootBlock.children.filter(
(block): block is BaseParsedBlock => block.flavour === 'affine:note'
);
const md = parseBlockToMd(rootBlock);
return {
title: title.toJSON(),
parsedBlock: rootBlock,
md,
};
}
};

View File

@@ -0,0 +1,152 @@
import { type CellDataType } from '@blocksuite/affine/model';
import { type Doc as YDoc, type Map as YMap } from 'yjs';
export interface WorkspacePage {
id: string;
guid: string;
title: string;
createDate: number;
trash?: boolean;
favorite?: boolean;
properties?: Record<string, any>;
}
export type BaseFlavour<T extends string> = `affine:${T}`;
export type Flavour = BaseFlavour<
| 'page'
| 'frame'
| 'paragraph'
| 'code'
| 'note'
| 'list'
| 'divider'
| 'embed'
| 'image'
| 'surface'
| 'database'
| 'table'
| 'attachment'
| 'bookmark'
| 'embed-youtube'
| 'embed-linked-doc'
| 'embed-synced-doc'
>;
export interface BaseParsedBlock {
id: string;
flavour: Flavour;
content: string;
children: BaseParsedBlock[];
type?: string;
}
export interface ParsedDoc {
title: string;
md: string;
parsedBlock?: ParsedBlock;
}
export interface ParagraphBlock extends BaseParsedBlock {
flavour: 'affine:paragraph';
type: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'quote';
}
export interface DividerBlock extends BaseParsedBlock {
flavour: 'affine:divider';
}
export interface ListBlock extends BaseParsedBlock {
flavour: 'affine:list';
type: 'bulleted' | 'numbered';
}
export interface CodeBlock extends BaseParsedBlock {
flavour: 'affine:code';
language: string;
}
export interface ImageBlock extends BaseParsedBlock {
flavour: 'affine:image';
sourceId: string;
blobUrl: string;
width?: number;
height?: number;
caption?: string;
}
export interface AttachmentBlock extends BaseParsedBlock {
flavour: 'affine:attachment';
type: string;
sourceId: string;
}
export interface EmbedYoutubeBlock extends BaseParsedBlock {
flavour: 'affine:embed-youtube';
videoId: string;
}
export interface BookmarkBlock extends BaseParsedBlock {
flavour: 'affine:bookmark';
url: string;
}
export interface EmbedLinkedDocBlock extends BaseParsedBlock {
flavour: 'affine:embed-linked-doc';
pageId: string;
}
export interface EmbedSyncedDocBlock extends BaseParsedBlock {
flavour: 'affine:embed-synced-doc';
pageId: string;
}
export interface DatabaseBlock extends BaseParsedBlock {
title: string;
flavour: 'affine:database';
rows: Record<string, string>[];
}
export interface TableBlock extends BaseParsedBlock {
flavour: 'affine:table';
rows: string[][];
columns: string[];
}
export type ParsedBlock =
| ParagraphBlock
| DividerBlock
| ListBlock
| CodeBlock
| ImageBlock
| AttachmentBlock
| EmbedYoutubeBlock
| BookmarkBlock
| DatabaseBlock
| TableBlock
| BaseParsedBlock;
export interface ParsedDoc {
title: string;
md: string;
parsedBlock?: ParsedBlock;
}
export type SerializedCells = {
// row
[key: string]: {
// column
[key: string]: CellDataType;
};
};
export type YBlock = YMap<unknown>;
export type YBlocks = YMap<YBlock>;
export interface ParserContext {
workspaceId: string;
doc: YDoc;
buildBlobUrl: (blobId: string) => string;
buildDocUrl: (docId: string) => string;
renderDocTitle?: (docId: string) => string;
}

View File

@@ -915,3 +915,5 @@ export function readAllDocIdsFromRootDoc(
}
return Array.from(docIds);
}
export { parseBlock, parseBlockToMd, parsePageDoc } from './doc-parser/parser';

View File

@@ -0,0 +1,31 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public struct LicenseBody: AffineGraphQL.SelectionSet, Fragment {
public static var fragmentDefinition: StaticString {
#"fragment licenseBody on License { __typename expiredAt installedAt quantity recurring validatedAt variant }"#
}
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.License }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("expiredAt", AffineGraphQL.DateTime?.self),
.field("installedAt", AffineGraphQL.DateTime.self),
.field("quantity", Int.self),
.field("recurring", GraphQLEnum<AffineGraphQL.SubscriptionRecurring>.self),
.field("validatedAt", AffineGraphQL.DateTime.self),
.field("variant", GraphQLEnum<AffineGraphQL.SubscriptionVariant>?.self),
] }
public var expiredAt: AffineGraphQL.DateTime? { __data["expiredAt"] }
public var installedAt: AffineGraphQL.DateTime { __data["installedAt"] }
public var quantity: Int { __data["quantity"] }
public var recurring: GraphQLEnum<AffineGraphQL.SubscriptionRecurring> { __data["recurring"] }
public var validatedAt: AffineGraphQL.DateTime { __data["validatedAt"] }
public var variant: GraphQLEnum<AffineGraphQL.SubscriptionVariant>? { __data["variant"] }
}

View File

@@ -7,27 +7,23 @@ public class AcceptInviteByInviteIdMutation: GraphQLMutation {
public static let operationName: String = "acceptInviteByInviteId"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation acceptInviteByInviteId($workspaceId: String!, $inviteId: String!, $sendAcceptMail: Boolean) { acceptInviteById( workspaceId: $workspaceId inviteId: $inviteId sendAcceptMail: $sendAcceptMail ) }"#
#"mutation acceptInviteByInviteId($workspaceId: String!, $inviteId: String!) { acceptInviteById(workspaceId: $workspaceId, inviteId: $inviteId) }"#
))
public var workspaceId: String
public var inviteId: String
public var sendAcceptMail: GraphQLNullable<Bool>
public init(
workspaceId: String,
inviteId: String,
sendAcceptMail: GraphQLNullable<Bool>
inviteId: String
) {
self.workspaceId = workspaceId
self.inviteId = inviteId
self.sendAcceptMail = sendAcceptMail
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"inviteId": inviteId,
"sendAcceptMail": sendAcceptMail
"inviteId": inviteId
] }
public struct Data: AffineGraphQL.SelectionSet {
@@ -35,12 +31,11 @@ public class AcceptInviteByInviteIdMutation: GraphQLMutation {
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
#warning("Argument 'sendAcceptMail' of field 'acceptInviteById' is deprecated. Reason: 'never used'")
#warning("Argument 'workspaceId' of field 'acceptInviteById' is deprecated. Reason: 'never used'")
public static var __selections: [ApolloAPI.Selection] { [
.field("acceptInviteById", Bool.self, arguments: [
"workspaceId": .variable("workspaceId"),
"inviteId": .variable("inviteId"),
"sendAcceptMail": .variable("sendAcceptMail")
"inviteId": .variable("inviteId")
]),
] }

View File

@@ -7,7 +7,8 @@ public class ActivateLicenseMutation: GraphQLMutation {
public static let operationName: String = "activateLicense"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation activateLicense($workspaceId: String!, $license: String!) { activateLicense(workspaceId: $workspaceId, license: $license) { __typename installedAt validatedAt } }"#
#"mutation activateLicense($workspaceId: String!, $license: String!) { activateLicense(workspaceId: $workspaceId, license: $license) { __typename ...licenseBody } }"#,
fragments: [LicenseBody.self]
))
public var workspaceId: String
@@ -50,12 +51,22 @@ public class ActivateLicenseMutation: GraphQLMutation {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.License }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("installedAt", AffineGraphQL.DateTime.self),
.field("validatedAt", AffineGraphQL.DateTime.self),
.fragment(LicenseBody.self),
] }
public var expiredAt: AffineGraphQL.DateTime? { __data["expiredAt"] }
public var installedAt: AffineGraphQL.DateTime { __data["installedAt"] }
public var quantity: Int { __data["quantity"] }
public var recurring: GraphQLEnum<AffineGraphQL.SubscriptionRecurring> { __data["recurring"] }
public var validatedAt: AffineGraphQL.DateTime { __data["validatedAt"] }
public var variant: GraphQLEnum<AffineGraphQL.SubscriptionVariant>? { __data["variant"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var licenseBody: LicenseBody { _toFragment() }
}
}
}
}

View File

@@ -7,7 +7,7 @@ public class AddContextFileMutation: GraphQLMutation {
public static let operationName: String = "addContextFile"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation addContextFile($content: Upload!, $options: AddContextFileInput!) { addContextFile(content: $content, options: $options) { __typename id createdAt name chunkSize error status blobId } }"#
#"mutation addContextFile($content: Upload!, $options: AddContextFileInput!) { addContextFile(content: $content, options: $options) { __typename id createdAt name mimeType chunkSize error status blobId } }"#
))
public var content: Upload
@@ -54,6 +54,7 @@ public class AddContextFileMutation: GraphQLMutation {
.field("id", AffineGraphQL.ID.self),
.field("createdAt", AffineGraphQL.SafeInt.self),
.field("name", String.self),
.field("mimeType", String.self),
.field("chunkSize", AffineGraphQL.SafeInt.self),
.field("error", String?.self),
.field("status", GraphQLEnum<AffineGraphQL.ContextEmbedStatus>.self),
@@ -63,6 +64,7 @@ public class AddContextFileMutation: GraphQLMutation {
public var id: AffineGraphQL.ID { __data["id"] }
public var createdAt: AffineGraphQL.SafeInt { __data["createdAt"] }
public var name: String { __data["name"] }
public var mimeType: String { __data["mimeType"] }
public var chunkSize: AffineGraphQL.SafeInt { __data["chunkSize"] }
public var error: String? { __data["error"] }
public var status: GraphQLEnum<AffineGraphQL.ContextEmbedStatus> { __data["status"] }

View File

@@ -0,0 +1,70 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class AddWorkspaceEmbeddingFilesMutation: GraphQLMutation {
public static let operationName: String = "addWorkspaceEmbeddingFiles"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation addWorkspaceEmbeddingFiles($workspaceId: String!, $blob: Upload!) { addWorkspaceEmbeddingFiles(workspaceId: $workspaceId, blob: $blob) { __typename fileId fileName blobId mimeType size createdAt } }"#
))
public var workspaceId: String
public var blob: Upload
public init(
workspaceId: String,
blob: Upload
) {
self.workspaceId = workspaceId
self.blob = blob
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"blob": blob
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("addWorkspaceEmbeddingFiles", AddWorkspaceEmbeddingFiles.self, arguments: [
"workspaceId": .variable("workspaceId"),
"blob": .variable("blob")
]),
] }
/// Update workspace embedding files
public var addWorkspaceEmbeddingFiles: AddWorkspaceEmbeddingFiles { __data["addWorkspaceEmbeddingFiles"] }
/// AddWorkspaceEmbeddingFiles
///
/// Parent Type: `CopilotWorkspaceFile`
public struct AddWorkspaceEmbeddingFiles: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceFile }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("fileId", String.self),
.field("fileName", String.self),
.field("blobId", String.self),
.field("mimeType", String.self),
.field("size", AffineGraphQL.SafeInt.self),
.field("createdAt", AffineGraphQL.DateTime.self),
] }
public var fileId: String { __data["fileId"] }
public var fileName: String { __data["fileName"] }
public var blobId: String { __data["blobId"] }
public var mimeType: String { __data["mimeType"] }
public var size: AffineGraphQL.SafeInt { __data["size"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
}
}
}

View File

@@ -0,0 +1,44 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class AddWorkspaceEmbeddingIgnoredDocsMutation: GraphQLMutation {
public static let operationName: String = "addWorkspaceEmbeddingIgnoredDocs"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation addWorkspaceEmbeddingIgnoredDocs($workspaceId: String!, $add: [String!]!) { updateWorkspaceEmbeddingIgnoredDocs(workspaceId: $workspaceId, add: $add) }"#
))
public var workspaceId: String
public var add: [String]
public init(
workspaceId: String,
add: [String]
) {
self.workspaceId = workspaceId
self.add = add
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"add": add
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("updateWorkspaceEmbeddingIgnoredDocs", Int.self, arguments: [
"workspaceId": .variable("workspaceId"),
"add": .variable("add")
]),
] }
/// Update ignored docs
public var updateWorkspaceEmbeddingIgnoredDocs: Int { __data["updateWorkspaceEmbeddingIgnoredDocs"] }
}
}

View File

@@ -7,7 +7,7 @@ public class ClaimAudioTranscriptionMutation: GraphQLMutation {
public static let operationName: String = "claimAudioTranscription"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation claimAudioTranscription($jobId: String!) { claimAudioTranscription(jobId: $jobId) { __typename id status title summary transcription { __typename speaker start end transcription } } }"#
#"mutation claimAudioTranscription($jobId: String!) { claimAudioTranscription(jobId: $jobId) { __typename id status title summary actions transcription { __typename speaker start end transcription } } }"#
))
public var jobId: String
@@ -43,6 +43,7 @@ public class ClaimAudioTranscriptionMutation: GraphQLMutation {
.field("status", GraphQLEnum<AffineGraphQL.AiJobStatus>.self),
.field("title", String?.self),
.field("summary", String?.self),
.field("actions", String?.self),
.field("transcription", [Transcription]?.self),
] }
@@ -50,6 +51,7 @@ public class ClaimAudioTranscriptionMutation: GraphQLMutation {
public var status: GraphQLEnum<AffineGraphQL.AiJobStatus> { __data["status"] }
public var title: String? { __data["title"] }
public var summary: String? { __data["summary"] }
public var actions: String? { __data["actions"] }
public var transcription: [Transcription]? { __data["transcription"] }
/// ClaimAudioTranscription.Transcription

View File

@@ -0,0 +1,72 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class InstallLicenseMutation: GraphQLMutation {
public static let operationName: String = "installLicense"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation installLicense($workspaceId: String!, $license: Upload!) { installLicense(workspaceId: $workspaceId, license: $license) { __typename ...licenseBody } }"#,
fragments: [LicenseBody.self]
))
public var workspaceId: String
public var license: Upload
public init(
workspaceId: String,
license: Upload
) {
self.workspaceId = workspaceId
self.license = license
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"license": license
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("installLicense", InstallLicense.self, arguments: [
"workspaceId": .variable("workspaceId"),
"license": .variable("license")
]),
] }
public var installLicense: InstallLicense { __data["installLicense"] }
/// InstallLicense
///
/// Parent Type: `License`
public struct InstallLicense: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.License }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.fragment(LicenseBody.self),
] }
public var expiredAt: AffineGraphQL.DateTime? { __data["expiredAt"] }
public var installedAt: AffineGraphQL.DateTime { __data["installedAt"] }
public var quantity: Int { __data["quantity"] }
public var recurring: GraphQLEnum<AffineGraphQL.SubscriptionRecurring> { __data["recurring"] }
public var validatedAt: AffineGraphQL.DateTime { __data["validatedAt"] }
public var variant: GraphQLEnum<AffineGraphQL.SubscriptionVariant>? { __data["variant"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var licenseBody: LicenseBody { _toFragment() }
}
}
}
}

View File

@@ -1,71 +0,0 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class InviteBatchMutation: GraphQLMutation {
public static let operationName: String = "inviteBatch"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation inviteBatch($workspaceId: String!, $emails: [String!]!, $sendInviteMail: Boolean) { inviteBatch( workspaceId: $workspaceId emails: $emails sendInviteMail: $sendInviteMail ) { __typename email inviteId sentSuccess } }"#
))
public var workspaceId: String
public var emails: [String]
public var sendInviteMail: GraphQLNullable<Bool>
public init(
workspaceId: String,
emails: [String],
sendInviteMail: GraphQLNullable<Bool>
) {
self.workspaceId = workspaceId
self.emails = emails
self.sendInviteMail = sendInviteMail
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"emails": emails,
"sendInviteMail": sendInviteMail
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
#warning("Argument 'sendInviteMail' of field 'inviteBatch' is deprecated. Reason: 'never used'")
public static var __selections: [ApolloAPI.Selection] { [
.field("inviteBatch", [InviteBatch].self, arguments: [
"workspaceId": .variable("workspaceId"),
"emails": .variable("emails"),
"sendInviteMail": .variable("sendInviteMail")
]),
] }
public var inviteBatch: [InviteBatch] { __data["inviteBatch"] }
/// InviteBatch
///
/// Parent Type: `InviteResult`
public struct InviteBatch: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.InviteResult }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("email", String.self),
.field("inviteId", String?.self),
.field("sentSuccess", Bool.self),
] }
public var email: String { __data["email"] }
/// Invite id, null if invite record create failed
public var inviteId: String? { __data["inviteId"] }
/// Invite email sent success
public var sentSuccess: Bool { __data["sentSuccess"] }
}
}
}

View File

@@ -1,49 +0,0 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class InviteByEmailMutation: GraphQLMutation {
public static let operationName: String = "inviteByEmail"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation inviteByEmail($workspaceId: String!, $email: String!, $sendInviteMail: Boolean) { invite( workspaceId: $workspaceId email: $email sendInviteMail: $sendInviteMail ) }"#
))
public var workspaceId: String
public var email: String
public var sendInviteMail: GraphQLNullable<Bool>
public init(
workspaceId: String,
email: String,
sendInviteMail: GraphQLNullable<Bool>
) {
self.workspaceId = workspaceId
self.email = email
self.sendInviteMail = sendInviteMail
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"email": email,
"sendInviteMail": sendInviteMail
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
#warning("Argument 'sendInviteMail' of field 'invite' is deprecated. Reason: 'never used'")
public static var __selections: [ApolloAPI.Selection] { [
.field("invite", String.self, arguments: [
"workspaceId": .variable("workspaceId"),
"email": .variable("email"),
"sendInviteMail": .variable("sendInviteMail")
]),
] }
public var invite: String { __data["invite"] }
}
}

View File

@@ -7,27 +7,23 @@ public class InviteByEmailsMutation: GraphQLMutation {
public static let operationName: String = "inviteByEmails"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation inviteByEmails($workspaceId: String!, $emails: [String!]!, $sendInviteMail: Boolean) { inviteBatch( workspaceId: $workspaceId emails: $emails sendInviteMail: $sendInviteMail ) { __typename email inviteId sentSuccess } }"#
#"mutation inviteByEmails($workspaceId: String!, $emails: [String!]!) { inviteMembers(workspaceId: $workspaceId, emails: $emails) { __typename email inviteId sentSuccess } }"#
))
public var workspaceId: String
public var emails: [String]
public var sendInviteMail: GraphQLNullable<Bool>
public init(
workspaceId: String,
emails: [String],
sendInviteMail: GraphQLNullable<Bool>
emails: [String]
) {
self.workspaceId = workspaceId
self.emails = emails
self.sendInviteMail = sendInviteMail
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"emails": emails,
"sendInviteMail": sendInviteMail
"emails": emails
] }
public struct Data: AffineGraphQL.SelectionSet {
@@ -35,21 +31,19 @@ public class InviteByEmailsMutation: GraphQLMutation {
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
#warning("Argument 'sendInviteMail' of field 'inviteBatch' is deprecated. Reason: 'never used'")
public static var __selections: [ApolloAPI.Selection] { [
.field("inviteBatch", [InviteBatch].self, arguments: [
.field("inviteMembers", [InviteMember].self, arguments: [
"workspaceId": .variable("workspaceId"),
"emails": .variable("emails"),
"sendInviteMail": .variable("sendInviteMail")
"emails": .variable("emails")
]),
] }
public var inviteBatch: [InviteBatch] { __data["inviteBatch"] }
public var inviteMembers: [InviteMember] { __data["inviteMembers"] }
/// InviteBatch
/// InviteMember
///
/// Parent Type: `InviteResult`
public struct InviteBatch: AffineGraphQL.SelectionSet {
public struct InviteMember: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
@@ -65,6 +59,7 @@ public class InviteByEmailsMutation: GraphQLMutation {
/// Invite id, null if invite record create failed
public var inviteId: String? { __data["inviteId"] }
/// Invite email sent success
@available(*, deprecated, message: "Notification will be sent asynchronously")
public var sentSuccess: Bool { __data["sentSuccess"] }
}
}

View File

@@ -31,6 +31,7 @@ public class LeaveWorkspaceMutation: GraphQLMutation {
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
#warning("Argument 'sendLeaveMail' of field 'leaveWorkspace' is deprecated. Reason: 'no used anymore'")
public static var __selections: [ApolloAPI.Selection] { [
.field("leaveWorkspace", Bool.self, arguments: [
"workspaceId": .variable("workspaceId"),

View File

@@ -0,0 +1,44 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class RemoveWorkspaceEmbeddingFilesMutation: GraphQLMutation {
public static let operationName: String = "removeWorkspaceEmbeddingFiles"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation removeWorkspaceEmbeddingFiles($workspaceId: String!, $fileId: String!) { removeWorkspaceEmbeddingFiles(workspaceId: $workspaceId, fileId: $fileId) }"#
))
public var workspaceId: String
public var fileId: String
public init(
workspaceId: String,
fileId: String
) {
self.workspaceId = workspaceId
self.fileId = fileId
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"fileId": fileId
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("removeWorkspaceEmbeddingFiles", Bool.self, arguments: [
"workspaceId": .variable("workspaceId"),
"fileId": .variable("fileId")
]),
] }
/// Remove workspace embedding files
public var removeWorkspaceEmbeddingFiles: Bool { __data["removeWorkspaceEmbeddingFiles"] }
}
}

View File

@@ -0,0 +1,44 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class RemoveWorkspaceEmbeddingIgnoredDocsMutation: GraphQLMutation {
public static let operationName: String = "removeWorkspaceEmbeddingIgnoredDocs"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation removeWorkspaceEmbeddingIgnoredDocs($workspaceId: String!, $remove: [String!]!) { updateWorkspaceEmbeddingIgnoredDocs(workspaceId: $workspaceId, remove: $remove) }"#
))
public var workspaceId: String
public var remove: [String]
public init(
workspaceId: String,
remove: [String]
) {
self.workspaceId = workspaceId
self.remove = remove
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"remove": remove
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("updateWorkspaceEmbeddingIgnoredDocs", Int.self, arguments: [
"workspaceId": .variable("workspaceId"),
"remove": .variable("remove")
]),
] }
/// Update ignored docs
public var updateWorkspaceEmbeddingIgnoredDocs: Int { __data["updateWorkspaceEmbeddingIgnoredDocs"] }
}
}

View File

@@ -0,0 +1,61 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class RetryAudioTranscriptionMutation: GraphQLMutation {
public static let operationName: String = "retryAudioTranscription"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation retryAudioTranscription($workspaceId: String!, $jobId: String!) { retryAudioTranscription(workspaceId: $workspaceId, jobId: $jobId) { __typename id status } }"#
))
public var workspaceId: String
public var jobId: String
public init(
workspaceId: String,
jobId: String
) {
self.workspaceId = workspaceId
self.jobId = jobId
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"jobId": jobId
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("retryAudioTranscription", RetryAudioTranscription?.self, arguments: [
"workspaceId": .variable("workspaceId"),
"jobId": .variable("jobId")
]),
] }
public var retryAudioTranscription: RetryAudioTranscription? { __data["retryAudioTranscription"] }
/// RetryAudioTranscription
///
/// Parent Type: `TranscriptionResultType`
public struct RetryAudioTranscription: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.TranscriptionResultType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("status", GraphQLEnum<AffineGraphQL.AiJobStatus>.self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
public var status: GraphQLEnum<AffineGraphQL.AiJobStatus> { __data["status"] }
}
}
}

View File

@@ -7,7 +7,7 @@ public class RevokeMemberPermissionMutation: GraphQLMutation {
public static let operationName: String = "revokeMemberPermission"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation revokeMemberPermission($workspaceId: String!, $userId: String!) { revoke(workspaceId: $workspaceId, userId: $userId) }"#
#"mutation revokeMemberPermission($workspaceId: String!, $userId: String!) { revokeMember(workspaceId: $workspaceId, userId: $userId) }"#
))
public var workspaceId: String
@@ -32,12 +32,12 @@ public class RevokeMemberPermissionMutation: GraphQLMutation {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("revoke", Bool.self, arguments: [
.field("revokeMember", Bool.self, arguments: [
"workspaceId": .variable("workspaceId"),
"userId": .variable("userId")
]),
] }
public var revoke: Bool { __data["revoke"] }
public var revokeMember: Bool { __data["revokeMember"] }
}
}

View File

@@ -0,0 +1,63 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class SendTestEmailMutation: GraphQLMutation {
public static let operationName: String = "sendTestEmail"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation sendTestEmail($host: String!, $port: Int!, $sender: String!, $username: String!, $password: String!, $ignoreTLS: Boolean!) { sendTestEmail( config: { host: $host port: $port sender: $sender username: $username password: $password ignoreTLS: $ignoreTLS } ) }"#
))
public var host: String
public var port: Int
public var sender: String
public var username: String
public var password: String
public var ignoreTLS: Bool
public init(
host: String,
port: Int,
sender: String,
username: String,
password: String,
ignoreTLS: Bool
) {
self.host = host
self.port = port
self.sender = sender
self.username = username
self.password = password
self.ignoreTLS = ignoreTLS
}
public var __variables: Variables? { [
"host": host,
"port": port,
"sender": sender,
"username": username,
"password": password,
"ignoreTLS": ignoreTLS
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("sendTestEmail", Bool.self, arguments: ["config": [
"host": .variable("host"),
"port": .variable("port"),
"sender": .variable("sender"),
"username": .variable("username"),
"password": .variable("password"),
"ignoreTLS": .variable("ignoreTLS")
]]),
] }
public var sendTestEmail: Bool { __data["sendTestEmail"] }
}
}

View File

@@ -0,0 +1,60 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class SetEnableDocEmbeddingMutation: GraphQLMutation {
public static let operationName: String = "setEnableDocEmbedding"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation setEnableDocEmbedding($id: ID!, $enableDocEmbedding: Boolean!) { updateWorkspace(input: { id: $id, enableDocEmbedding: $enableDocEmbedding }) { __typename id } }"#
))
public var id: ID
public var enableDocEmbedding: Bool
public init(
id: ID,
enableDocEmbedding: Bool
) {
self.id = id
self.enableDocEmbedding = enableDocEmbedding
}
public var __variables: Variables? { [
"id": id,
"enableDocEmbedding": enableDocEmbedding
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("updateWorkspace", UpdateWorkspace.self, arguments: ["input": [
"id": .variable("id"),
"enableDocEmbedding": .variable("enableDocEmbedding")
]]),
] }
/// Update workspace
public var updateWorkspace: UpdateWorkspace { __data["updateWorkspace"] }
/// UpdateWorkspace
///
/// Parent Type: `WorkspaceType`
public struct UpdateWorkspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
}
}
}

View File

@@ -7,27 +7,31 @@ public class SubmitAudioTranscriptionMutation: GraphQLMutation {
public static let operationName: String = "submitAudioTranscription"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation submitAudioTranscription($workspaceId: String!, $blobId: String!, $blob: Upload!) { submitAudioTranscription( blob: $blob blobId: $blobId workspaceId: $workspaceId ) { __typename id status } }"#
#"mutation submitAudioTranscription($workspaceId: String!, $blobId: String!, $blob: Upload, $blobs: [Upload!]) { submitAudioTranscription( blob: $blob blobs: $blobs blobId: $blobId workspaceId: $workspaceId ) { __typename id status } }"#
))
public var workspaceId: String
public var blobId: String
public var blob: Upload
public var blob: GraphQLNullable<Upload>
public var blobs: GraphQLNullable<[Upload]>
public init(
workspaceId: String,
blobId: String,
blob: Upload
blob: GraphQLNullable<Upload>,
blobs: GraphQLNullable<[Upload]>
) {
self.workspaceId = workspaceId
self.blobId = blobId
self.blob = blob
self.blobs = blobs
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"blobId": blobId,
"blob": blob
"blob": blob,
"blobs": blobs
] }
public struct Data: AffineGraphQL.SelectionSet {
@@ -38,6 +42,7 @@ public class SubmitAudioTranscriptionMutation: GraphQLMutation {
public static var __selections: [ApolloAPI.Selection] { [
.field("submitAudioTranscription", SubmitAudioTranscription?.self, arguments: [
"blob": .variable("blob"),
"blobs": .variable("blobs"),
"blobId": .variable("blobId"),
"workspaceId": .variable("workspaceId")
]),

View File

@@ -7,7 +7,7 @@ public class UpdatePromptMutation: GraphQLMutation {
public static let operationName: String = "updatePrompt"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation updatePrompt($name: String!, $messages: [CopilotPromptMessageInput!]!) { updateCopilotPrompt(name: $name, messages: $messages) { __typename name model action config { __typename jsonMode frequencyPenalty presencePenalty temperature topP } messages { __typename role content params } } }"#
#"mutation updatePrompt($name: String!, $messages: [CopilotPromptMessageInput!]!) { updateCopilotPrompt(name: $name, messages: $messages) { __typename name model action config { __typename frequencyPenalty presencePenalty temperature topP } messages { __typename role content params } } }"#
))
public var name: String
@@ -74,14 +74,12 @@ public class UpdatePromptMutation: GraphQLMutation {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotPromptConfigType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("jsonMode", Bool?.self),
.field("frequencyPenalty", Double?.self),
.field("presencePenalty", Double?.self),
.field("temperature", Double?.self),
.field("topP", Double?.self),
] }
public var jsonMode: Bool? { __data["jsonMode"] }
public var frequencyPenalty: Double? { __data["frequencyPenalty"] }
public var presencePenalty: Double? { __data["presencePenalty"] }
public var temperature: Double? { __data["temperature"] }

View File

@@ -0,0 +1,57 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class ValidateConfigMutation: GraphQLMutation {
public static let operationName: String = "validateConfig"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"mutation validateConfig($updates: [UpdateAppConfigInput!]!) { validateAppConfig(updates: $updates) { __typename module key value valid error } }"#
))
public var updates: [UpdateAppConfigInput]
public init(updates: [UpdateAppConfigInput]) {
self.updates = updates
}
public var __variables: Variables? { ["updates": updates] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Mutation }
public static var __selections: [ApolloAPI.Selection] { [
.field("validateAppConfig", [ValidateAppConfig].self, arguments: ["updates": .variable("updates")]),
] }
/// validate app configuration
public var validateAppConfig: [ValidateAppConfig] { __data["validateAppConfig"] }
/// ValidateAppConfig
///
/// Parent Type: `AppConfigValidateResult`
public struct ValidateAppConfig: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.AppConfigValidateResult }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("module", String.self),
.field("key", String.self),
.field("value", AffineGraphQL.JSON.self),
.field("valid", Bool.self),
.field("error", String?.self),
] }
public var module: String { __data["module"] }
public var key: String { __data["key"] }
public var value: AffineGraphQL.JSON { __data["value"] }
public var valid: Bool { __data["valid"] }
public var error: String? { __data["error"] }
}
}
}

View File

@@ -0,0 +1,83 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetAllWorkspaceEmbeddingIgnoredDocsQuery: GraphQLQuery {
public static let operationName: String = "getAllWorkspaceEmbeddingIgnoredDocs"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getAllWorkspaceEmbeddingIgnoredDocs($workspaceId: String!) { workspace(id: $workspaceId) { __typename embedding { __typename allIgnoredDocs { __typename docId createdAt } } } }"#
))
public var workspaceId: String
public init(workspaceId: String) {
self.workspaceId = workspaceId
}
public var __variables: Variables? { ["workspaceId": workspaceId] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("embedding", Embedding.self),
] }
public var embedding: Embedding { __data["embedding"] }
/// Workspace.Embedding
///
/// Parent Type: `CopilotWorkspaceConfig`
public struct Embedding: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceConfig }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("allIgnoredDocs", [AllIgnoredDoc].self),
] }
public var allIgnoredDocs: [AllIgnoredDoc] { __data["allIgnoredDocs"] }
/// Workspace.Embedding.AllIgnoredDoc
///
/// Parent Type: `CopilotWorkspaceIgnoredDoc`
public struct AllIgnoredDoc: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceIgnoredDoc }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("docId", String.self),
.field("createdAt", AffineGraphQL.DateTime.self),
] }
public var docId: String { __data["docId"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
}
}
}
}
}

View File

@@ -0,0 +1,98 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetCopilotSessionQuery: GraphQLQuery {
public static let operationName: String = "getCopilotSession"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotSession($workspaceId: String!, $sessionId: String!) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename session(sessionId: $sessionId) { __typename id parentSessionId promptName model optionalModels } } } }"#
))
public var workspaceId: String
public var sessionId: String
public init(
workspaceId: String,
sessionId: String
) {
self.workspaceId = workspaceId
self.sessionId = sessionId
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"sessionId": sessionId
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("currentUser", CurrentUser?.self),
] }
/// Get current user
public var currentUser: CurrentUser? { __data["currentUser"] }
/// CurrentUser
///
/// Parent Type: `UserType`
public struct CurrentUser: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.UserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("copilot", Copilot.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
public var copilot: Copilot { __data["copilot"] }
/// CurrentUser.Copilot
///
/// Parent Type: `Copilot`
public struct Copilot: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Copilot }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("session", Session.self, arguments: ["sessionId": .variable("sessionId")]),
] }
/// Get the session by id
public var session: Session { __data["session"] }
/// CurrentUser.Copilot.Session
///
/// Parent Type: `CopilotSessionType`
public struct Session: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotSessionType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("parentSessionId", AffineGraphQL.ID?.self),
.field("promptName", String.self),
.field("model", String.self),
.field("optionalModels", [String].self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
public var parentSessionId: AffineGraphQL.ID? { __data["parentSessionId"] }
public var promptName: String { __data["promptName"] }
public var model: String { __data["model"] }
public var optionalModels: [String] { __data["optionalModels"] }
}
}
}
}
}

View File

@@ -7,7 +7,7 @@ public class GetCopilotSessionsQuery: GraphQLQuery {
public static let operationName: String = "getCopilotSessions"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getCopilotSessions($workspaceId: String!, $docId: String, $options: QueryChatSessionsInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename sessions(docId: $docId, options: $options) { __typename id parentSessionId promptName } } } }"#
#"query getCopilotSessions($workspaceId: String!, $docId: String, $options: QueryChatSessionsInput) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename sessions(docId: $docId, options: $options) { __typename id parentSessionId promptName model optionalModels } } } }"#
))
public var workspaceId: String
@@ -89,11 +89,15 @@ public class GetCopilotSessionsQuery: GraphQLQuery {
.field("id", AffineGraphQL.ID.self),
.field("parentSessionId", AffineGraphQL.ID?.self),
.field("promptName", String.self),
.field("model", String.self),
.field("optionalModels", [String].self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
public var parentSessionId: AffineGraphQL.ID? { __data["parentSessionId"] }
public var promptName: String { __data["promptName"] }
public var model: String { __data["model"] }
public var optionalModels: [String] { __data["optionalModels"] }
}
}
}

View File

@@ -0,0 +1,131 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetDocCreatedByUpdatedByListQuery: GraphQLQuery {
public static let operationName: String = "getDocCreatedByUpdatedByList"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getDocCreatedByUpdatedByList($workspaceId: String!, $pagination: PaginationInput!) { workspace(id: $workspaceId) { __typename docs(pagination: $pagination) { __typename totalCount pageInfo { __typename endCursor hasNextPage } edges { __typename node { __typename id creatorId lastUpdaterId } } } } }"#
))
public var workspaceId: String
public var pagination: PaginationInput
public init(
workspaceId: String,
pagination: PaginationInput
) {
self.workspaceId = workspaceId
self.pagination = pagination
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"pagination": pagination
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("docs", Docs.self, arguments: ["pagination": .variable("pagination")]),
] }
public var docs: Docs { __data["docs"] }
/// Workspace.Docs
///
/// Parent Type: `PaginatedDocType`
public struct Docs: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedDocType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("totalCount", Int.self),
.field("pageInfo", PageInfo.self),
.field("edges", [Edge].self),
] }
public var totalCount: Int { __data["totalCount"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
/// Workspace.Docs.PageInfo
///
/// Parent Type: `PageInfo`
public struct PageInfo: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PageInfo }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("endCursor", String?.self),
.field("hasNextPage", Bool.self),
] }
public var endCursor: String? { __data["endCursor"] }
public var hasNextPage: Bool { __data["hasNextPage"] }
}
/// Workspace.Docs.Edge
///
/// Parent Type: `DocTypeEdge`
public struct Edge: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.DocTypeEdge }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("node", Node.self),
] }
public var node: Node { __data["node"] }
/// Workspace.Docs.Edge.Node
///
/// Parent Type: `DocType`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.DocType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", String.self),
.field("creatorId", String?.self),
.field("lastUpdaterId", String?.self),
] }
public var id: String { __data["id"] }
public var creatorId: String? { __data["creatorId"] }
public var lastUpdaterId: String? { __data["lastUpdaterId"] }
}
}
}
}
}
}

View File

@@ -27,7 +27,7 @@ public class GetInviteInfoQuery: GraphQLQuery {
.field("getInviteInfo", GetInviteInfo.self, arguments: ["inviteId": .variable("inviteId")]),
] }
/// send workspace invitation
/// get workspace invitation info
public var getInviteInfo: GetInviteInfo { __data["getInviteInfo"] }
/// GetInviteInfo

View File

@@ -1,34 +0,0 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetIsAdminQuery: GraphQLQuery {
public static let operationName: String = "getIsAdmin"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getIsAdmin($workspaceId: String!) { isAdmin(workspaceId: $workspaceId) }"#
))
public var workspaceId: String
public init(workspaceId: String) {
self.workspaceId = workspaceId
}
public var __variables: Variables? { ["workspaceId": workspaceId] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("isAdmin", Bool.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
/// Get is admin of workspace
@available(*, deprecated, message: "use WorkspaceType[role] instead")
public var isAdmin: Bool { __data["isAdmin"] }
}
}

View File

@@ -1,34 +0,0 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetIsOwnerQuery: GraphQLQuery {
public static let operationName: String = "getIsOwner"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getIsOwner($workspaceId: String!) { isOwner(workspaceId: $workspaceId) }"#
))
public var workspaceId: String
public init(workspaceId: String) {
self.workspaceId = workspaceId
}
public var __variables: Variables? { ["workspaceId": workspaceId] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("isOwner", Bool.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
/// Get is owner of workspace
@available(*, deprecated, message: "use WorkspaceType[role] instead")
public var isOwner: Bool { __data["isOwner"] }
}
}

View File

@@ -7,7 +7,8 @@ public class GetLicenseQuery: GraphQLQuery {
public static let operationName: String = "getLicense"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getLicense($workspaceId: String!) { workspace(id: $workspaceId) { __typename license { __typename expiredAt installedAt quantity recurring validatedAt } } }"#
#"query getLicense($workspaceId: String!) { workspace(id: $workspaceId) { __typename license { __typename ...licenseBody } } }"#,
fragments: [LicenseBody.self]
))
public var workspaceId: String
@@ -56,11 +57,7 @@ public class GetLicenseQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.License }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("expiredAt", AffineGraphQL.DateTime?.self),
.field("installedAt", AffineGraphQL.DateTime.self),
.field("quantity", Int.self),
.field("recurring", GraphQLEnum<AffineGraphQL.SubscriptionRecurring>.self),
.field("validatedAt", AffineGraphQL.DateTime.self),
.fragment(LicenseBody.self),
] }
public var expiredAt: AffineGraphQL.DateTime? { __data["expiredAt"] }
@@ -68,6 +65,14 @@ public class GetLicenseQuery: GraphQLQuery {
public var quantity: Int { __data["quantity"] }
public var recurring: GraphQLEnum<AffineGraphQL.SubscriptionRecurring> { __data["recurring"] }
public var validatedAt: AffineGraphQL.DateTime { __data["validatedAt"] }
public var variant: GraphQLEnum<AffineGraphQL.SubscriptionVariant>? { __data["variant"] }
public struct Fragments: FragmentContainer {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public var licenseBody: LicenseBody { _toFragment() }
}
}
}
}

View File

@@ -7,7 +7,7 @@ public class GetPromptsQuery: GraphQLQuery {
public static let operationName: String = "getPrompts"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getPrompts { listCopilotPrompts { __typename name model action config { __typename jsonMode frequencyPenalty presencePenalty temperature topP } messages { __typename role content params } } }"#
#"query getPrompts { listCopilotPrompts { __typename name model action config { __typename frequencyPenalty presencePenalty temperature topP } messages { __typename role content params } } }"#
))
public init() {}
@@ -57,14 +57,12 @@ public class GetPromptsQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotPromptConfigType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("jsonMode", Bool?.self),
.field("frequencyPenalty", Double?.self),
.field("presencePenalty", Double?.self),
.field("temperature", Double?.self),
.field("topP", Double?.self),
] }
public var jsonMode: Bool? { __data["jsonMode"] }
public var frequencyPenalty: Double? { __data["frequencyPenalty"] }
public var presencePenalty: Double? { __data["presencePenalty"] }
public var temperature: Double? { __data["temperature"] }

View File

@@ -1,27 +0,0 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetUsersCountQuery: GraphQLQuery {
public static let operationName: String = "getUsersCount"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getUsersCount { usersCount }"#
))
public init() {}
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("usersCount", Int.self),
] }
/// Get users count
public var usersCount: Int { __data["usersCount"] }
}
}

View File

@@ -7,7 +7,7 @@ public class GetWorkspaceConfigQuery: GraphQLQuery {
public static let operationName: String = "getWorkspaceConfig"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getWorkspaceConfig($id: String!) { workspace(id: $id) { __typename enableAi enableUrlPreview inviteLink { __typename link expireTime } } }"#
#"query getWorkspaceConfig($id: String!) { workspace(id: $id) { __typename enableAi enableUrlPreview enableDocEmbedding inviteLink { __typename link expireTime } } }"#
))
public var id: String
@@ -42,6 +42,7 @@ public class GetWorkspaceConfigQuery: GraphQLQuery {
.field("__typename", String.self),
.field("enableAi", Bool.self),
.field("enableUrlPreview", Bool.self),
.field("enableDocEmbedding", Bool.self),
.field("inviteLink", InviteLink?.self),
] }
@@ -49,6 +50,8 @@ public class GetWorkspaceConfigQuery: GraphQLQuery {
public var enableAi: Bool { __data["enableAi"] }
/// Enable url previous when sharing
public var enableUrlPreview: Bool { __data["enableUrlPreview"] }
/// Enable doc embedding
public var enableDocEmbedding: Bool { __data["enableDocEmbedding"] }
/// invite link for workspace
public var inviteLink: InviteLink? { __data["inviteLink"] }

View File

@@ -0,0 +1,153 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetWorkspaceEmbeddingFilesQuery: GraphQLQuery {
public static let operationName: String = "getWorkspaceEmbeddingFiles"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getWorkspaceEmbeddingFiles($workspaceId: String!, $pagination: PaginationInput!) { workspace(id: $workspaceId) { __typename embedding { __typename files(pagination: $pagination) { __typename totalCount pageInfo { __typename endCursor hasNextPage } edges { __typename node { __typename fileId fileName blobId mimeType size createdAt } } } } } }"#
))
public var workspaceId: String
public var pagination: PaginationInput
public init(
workspaceId: String,
pagination: PaginationInput
) {
self.workspaceId = workspaceId
self.pagination = pagination
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"pagination": pagination
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("embedding", Embedding.self),
] }
public var embedding: Embedding { __data["embedding"] }
/// Workspace.Embedding
///
/// Parent Type: `CopilotWorkspaceConfig`
public struct Embedding: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceConfig }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("files", Files.self, arguments: ["pagination": .variable("pagination")]),
] }
public var files: Files { __data["files"] }
/// Workspace.Embedding.Files
///
/// Parent Type: `PaginatedCopilotWorkspaceFileType`
public struct Files: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedCopilotWorkspaceFileType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("totalCount", Int.self),
.field("pageInfo", PageInfo.self),
.field("edges", [Edge].self),
] }
public var totalCount: Int { __data["totalCount"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
/// Workspace.Embedding.Files.PageInfo
///
/// Parent Type: `PageInfo`
public struct PageInfo: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PageInfo }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("endCursor", String?.self),
.field("hasNextPage", Bool.self),
] }
public var endCursor: String? { __data["endCursor"] }
public var hasNextPage: Bool { __data["hasNextPage"] }
}
/// Workspace.Embedding.Files.Edge
///
/// Parent Type: `CopilotWorkspaceFileTypeEdge`
public struct Edge: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceFileTypeEdge }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("node", Node.self),
] }
public var node: Node { __data["node"] }
/// Workspace.Embedding.Files.Edge.Node
///
/// Parent Type: `CopilotWorkspaceFile`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceFile }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("fileId", String.self),
.field("fileName", String.self),
.field("blobId", String.self),
.field("mimeType", String.self),
.field("size", AffineGraphQL.SafeInt.self),
.field("createdAt", AffineGraphQL.DateTime.self),
] }
public var fileId: String { __data["fileId"] }
public var fileName: String { __data["fileName"] }
public var blobId: String { __data["blobId"] }
public var mimeType: String { __data["mimeType"] }
public var size: AffineGraphQL.SafeInt { __data["size"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
}
}
}
}
}
}
}

View File

@@ -0,0 +1,157 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class GetWorkspaceEmbeddingIgnoredDocsQuery: GraphQLQuery {
public static let operationName: String = "getWorkspaceEmbeddingIgnoredDocs"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getWorkspaceEmbeddingIgnoredDocs($workspaceId: String!, $pagination: PaginationInput!) { workspace(id: $workspaceId) { __typename embedding { __typename ignoredDocs(pagination: $pagination) { __typename totalCount pageInfo { __typename endCursor hasNextPage } edges { __typename node { __typename docId createdAt docCreatedAt docUpdatedAt title createdBy createdByAvatar updatedBy } } } } } }"#
))
public var workspaceId: String
public var pagination: PaginationInput
public init(
workspaceId: String,
pagination: PaginationInput
) {
self.workspaceId = workspaceId
self.pagination = pagination
}
public var __variables: Variables? { [
"workspaceId": workspaceId,
"pagination": pagination
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("embedding", Embedding.self),
] }
public var embedding: Embedding { __data["embedding"] }
/// Workspace.Embedding
///
/// Parent Type: `CopilotWorkspaceConfig`
public struct Embedding: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceConfig }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("ignoredDocs", IgnoredDocs.self, arguments: ["pagination": .variable("pagination")]),
] }
public var ignoredDocs: IgnoredDocs { __data["ignoredDocs"] }
/// Workspace.Embedding.IgnoredDocs
///
/// Parent Type: `PaginatedIgnoredDocsType`
public struct IgnoredDocs: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PaginatedIgnoredDocsType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("totalCount", Int.self),
.field("pageInfo", PageInfo.self),
.field("edges", [Edge].self),
] }
public var totalCount: Int { __data["totalCount"] }
public var pageInfo: PageInfo { __data["pageInfo"] }
public var edges: [Edge] { __data["edges"] }
/// Workspace.Embedding.IgnoredDocs.PageInfo
///
/// Parent Type: `PageInfo`
public struct PageInfo: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.PageInfo }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("endCursor", String?.self),
.field("hasNextPage", Bool.self),
] }
public var endCursor: String? { __data["endCursor"] }
public var hasNextPage: Bool { __data["hasNextPage"] }
}
/// Workspace.Embedding.IgnoredDocs.Edge
///
/// Parent Type: `CopilotWorkspaceIgnoredDocTypeEdge`
public struct Edge: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceIgnoredDocTypeEdge }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("node", Node.self),
] }
public var node: Node { __data["node"] }
/// Workspace.Embedding.IgnoredDocs.Edge.Node
///
/// Parent Type: `CopilotWorkspaceIgnoredDoc`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotWorkspaceIgnoredDoc }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("docId", String.self),
.field("createdAt", AffineGraphQL.DateTime.self),
.field("docCreatedAt", AffineGraphQL.DateTime?.self),
.field("docUpdatedAt", AffineGraphQL.DateTime?.self),
.field("title", String?.self),
.field("createdBy", String?.self),
.field("createdByAvatar", String?.self),
.field("updatedBy", String?.self),
] }
public var docId: String { __data["docId"] }
public var createdAt: AffineGraphQL.DateTime { __data["createdAt"] }
public var docCreatedAt: AffineGraphQL.DateTime? { __data["docCreatedAt"] }
public var docUpdatedAt: AffineGraphQL.DateTime? { __data["docUpdatedAt"] }
public var title: String? { __data["title"] }
public var createdBy: String? { __data["createdBy"] }
public var createdByAvatar: String? { __data["createdByAvatar"] }
public var updatedBy: String? { __data["updatedBy"] }
}
}
}
}
}
}
}

View File

@@ -7,7 +7,7 @@ public class GetWorkspaceInfoQuery: GraphQLQuery {
public static let operationName: String = "getWorkspaceInfo"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query getWorkspaceInfo($workspaceId: String!) { isAdmin(workspaceId: $workspaceId) isOwner(workspaceId: $workspaceId) workspace(id: $workspaceId) { __typename team } }"#
#"query getWorkspaceInfo($workspaceId: String!) { workspace(id: $workspaceId) { __typename role team } }"#
))
public var workspaceId: String
@@ -24,17 +24,9 @@ public class GetWorkspaceInfoQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("isAdmin", Bool.self, arguments: ["workspaceId": .variable("workspaceId")]),
.field("isOwner", Bool.self, arguments: ["workspaceId": .variable("workspaceId")]),
.field("workspace", Workspace.self, arguments: ["id": .variable("workspaceId")]),
] }
/// Get is admin of workspace
@available(*, deprecated, message: "use WorkspaceType[role] instead")
public var isAdmin: Bool { __data["isAdmin"] }
/// Get is owner of workspace
@available(*, deprecated, message: "use WorkspaceType[role] instead")
public var isOwner: Bool { __data["isOwner"] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
@@ -48,9 +40,12 @@ public class GetWorkspaceInfoQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("role", GraphQLEnum<AffineGraphQL.Permission>.self),
.field("team", Bool.self),
] }
/// Role of current signed in user in workspace
public var role: GraphQLEnum<AffineGraphQL.Permission> { __data["role"] }
/// if workspace is team workspace
public var team: Bool { __data["team"] }
}

View File

@@ -52,16 +52,17 @@ public class GetWorkspacePageMetaByIdQuery: GraphQLQuery {
] }
/// Cloud page metadata of workspace
@available(*, deprecated, message: "use [WorkspaceType.doc] instead")
public var pageMeta: PageMeta { __data["pageMeta"] }
/// Workspace.PageMeta
///
/// Parent Type: `WorkspacePageMeta`
/// Parent Type: `WorkspaceDocMeta`
public struct PageMeta: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspacePageMeta }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceDocMeta }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("createdAt", AffineGraphQL.DateTime.self),

View File

@@ -0,0 +1,153 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class IndexerAggregateQuery: GraphQLQuery {
public static let operationName: String = "indexerAggregate"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query indexerAggregate($id: String!, $input: AggregateInput!) { workspace(id: $id) { __typename aggregate(input: $input) { __typename buckets { __typename key count hits { __typename nodes { __typename fields highlights } } } pagination { __typename count hasMore nextCursor } } } }"#
))
public var id: String
public var input: AggregateInput
public init(
id: String,
input: AggregateInput
) {
self.id = id
self.input = input
}
public var __variables: Variables? { [
"id": id,
"input": input
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("id")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("aggregate", Aggregate.self, arguments: ["input": .variable("input")]),
] }
/// Search a specific table with aggregate
public var aggregate: Aggregate { __data["aggregate"] }
/// Workspace.Aggregate
///
/// Parent Type: `AggregateResultObjectType`
public struct Aggregate: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.AggregateResultObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("buckets", [Bucket].self),
.field("pagination", Pagination.self),
] }
public var buckets: [Bucket] { __data["buckets"] }
public var pagination: Pagination { __data["pagination"] }
/// Workspace.Aggregate.Bucket
///
/// Parent Type: `AggregateBucketObjectType`
public struct Bucket: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.AggregateBucketObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("key", String.self),
.field("count", Int.self),
.field("hits", Hits.self),
] }
public var key: String { __data["key"] }
public var count: Int { __data["count"] }
/// The hits object
public var hits: Hits { __data["hits"] }
/// Workspace.Aggregate.Bucket.Hits
///
/// Parent Type: `AggregateBucketHitsObjectType`
public struct Hits: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.AggregateBucketHitsObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("nodes", [Node].self),
] }
public var nodes: [Node] { __data["nodes"] }
/// Workspace.Aggregate.Bucket.Hits.Node
///
/// Parent Type: `SearchNodeObjectType`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.SearchNodeObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("fields", AffineGraphQL.JSONObject.self),
.field("highlights", AffineGraphQL.JSONObject?.self),
] }
/// The search result fields, see UnionSearchItemObjectType
public var fields: AffineGraphQL.JSONObject { __data["fields"] }
/// The search result fields, see UnionSearchItemObjectType
public var highlights: AffineGraphQL.JSONObject? { __data["highlights"] }
}
}
}
/// Workspace.Aggregate.Pagination
///
/// Parent Type: `SearchResultPagination`
public struct Pagination: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.SearchResultPagination }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("count", Int.self),
.field("hasMore", Bool.self),
.field("nextCursor", String?.self),
] }
public var count: Int { __data["count"] }
public var hasMore: Bool { __data["hasMore"] }
public var nextCursor: String? { __data["nextCursor"] }
}
}
}
}
}

View File

@@ -0,0 +1,116 @@
// @generated
// This file was automatically generated and should not be edited.
@_exported import ApolloAPI
public class IndexerSearchQuery: GraphQLQuery {
public static let operationName: String = "indexerSearch"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query indexerSearch($id: String!, $input: SearchInput!) { workspace(id: $id) { __typename search(input: $input) { __typename nodes { __typename fields highlights } pagination { __typename count hasMore nextCursor } } } }"#
))
public var id: String
public var input: SearchInput
public init(
id: String,
input: SearchInput
) {
self.id = id
self.input = input
}
public var __variables: Variables? { [
"id": id,
"input": input
] }
public struct Data: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("workspace", Workspace.self, arguments: ["id": .variable("id")]),
] }
/// Get workspace by id
public var workspace: Workspace { __data["workspace"] }
/// Workspace
///
/// Parent Type: `WorkspaceType`
public struct Workspace: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.WorkspaceType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("search", Search.self, arguments: ["input": .variable("input")]),
] }
/// Search a specific table
public var search: Search { __data["search"] }
/// Workspace.Search
///
/// Parent Type: `SearchResultObjectType`
public struct Search: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.SearchResultObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("nodes", [Node].self),
.field("pagination", Pagination.self),
] }
public var nodes: [Node] { __data["nodes"] }
public var pagination: Pagination { __data["pagination"] }
/// Workspace.Search.Node
///
/// Parent Type: `SearchNodeObjectType`
public struct Node: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.SearchNodeObjectType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("fields", AffineGraphQL.JSONObject.self),
.field("highlights", AffineGraphQL.JSONObject?.self),
] }
/// The search result fields, see UnionSearchItemObjectType
public var fields: AffineGraphQL.JSONObject { __data["fields"] }
/// The search result fields, see UnionSearchItemObjectType
public var highlights: AffineGraphQL.JSONObject? { __data["highlights"] }
}
/// Workspace.Search.Pagination
///
/// Parent Type: `SearchResultPagination`
public struct Pagination: AffineGraphQL.SelectionSet {
public let __data: DataDict
public init(_dataDict: DataDict) { __data = _dataDict }
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.SearchResultPagination }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("count", Int.self),
.field("hasMore", Bool.self),
.field("nextCursor", String?.self),
] }
public var count: Int { __data["count"] }
public var hasMore: Bool { __data["hasMore"] }
public var nextCursor: String? { __data["nextCursor"] }
}
}
}
}
}

View File

@@ -7,7 +7,7 @@ public class ListContextObjectQuery: GraphQLQuery {
public static let operationName: String = "listContextObject"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query listContextObject($workspaceId: String!, $sessionId: String!, $contextId: String!) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename contexts(sessionId: $sessionId, contextId: $contextId) { __typename docs { __typename id status error createdAt } files { __typename id name blobId chunkSize error status createdAt } tags { __typename type id docs { __typename id status createdAt } createdAt } collections { __typename type id docs { __typename id status createdAt } createdAt } } } } }"#
#"query listContextObject($workspaceId: String!, $sessionId: String!, $contextId: String!) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename contexts(sessionId: $sessionId, contextId: $contextId) { __typename docs { __typename id status error createdAt } files { __typename id name mimeType blobId chunkSize error status createdAt } tags { __typename type id docs { __typename id status createdAt } createdAt } collections { __typename type id docs { __typename id status createdAt } createdAt } } } } }"#
))
public var workspaceId: String
@@ -135,6 +135,7 @@ public class ListContextObjectQuery: GraphQLQuery {
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("name", String.self),
.field("mimeType", String.self),
.field("blobId", String.self),
.field("chunkSize", AffineGraphQL.SafeInt.self),
.field("error", String?.self),
@@ -144,6 +145,7 @@ public class ListContextObjectQuery: GraphQLQuery {
public var id: AffineGraphQL.ID { __data["id"] }
public var name: String { __data["name"] }
public var mimeType: String { __data["mimeType"] }
public var blobId: String { __data["blobId"] }
public var chunkSize: AffineGraphQL.SafeInt { __data["chunkSize"] }
public var error: String? { __data["error"] }

View File

@@ -79,11 +79,11 @@ public class ListContextQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.CopilotContext }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("id", AffineGraphQL.ID.self),
.field("id", AffineGraphQL.ID?.self),
.field("workspaceId", String.self),
] }
public var id: AffineGraphQL.ID { __data["id"] }
public var id: AffineGraphQL.ID? { __data["id"] }
public var workspaceId: String { __data["workspaceId"] }
}
}

View File

@@ -7,7 +7,7 @@ public class ListUsersQuery: GraphQLQuery {
public static let operationName: String = "listUsers"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query listUsers($filter: ListUserInput!) { users(filter: $filter) { __typename id name email disabled features hasPassword emailVerified avatarUrl } }"#
#"query listUsers($filter: ListUserInput!) { users(filter: $filter) { __typename id name email disabled features hasPassword emailVerified avatarUrl } usersCount }"#
))
public var filter: ListUserInput
@@ -25,10 +25,13 @@ public class ListUsersQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.Query }
public static var __selections: [ApolloAPI.Selection] { [
.field("users", [User].self, arguments: ["filter": .variable("filter")]),
.field("usersCount", Int.self),
] }
/// List registered users
public var users: [User] { __data["users"] }
/// Get users count
public var usersCount: Int { __data["usersCount"] }
/// User
///

View File

@@ -7,30 +7,38 @@ public class MatchContextQuery: GraphQLQuery {
public static let operationName: String = "matchContext"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query matchContext($contextId: String!, $content: String!, $limit: SafeInt, $threshold: Float) { currentUser { __typename copilot { __typename contexts(contextId: $contextId) { __typename matchFiles(content: $content, limit: $limit, threshold: $threshold) { __typename fileId chunk content distance } matchWorkspaceDocs(content: $content, limit: $limit, threshold: $threshold) { __typename docId chunk content distance } } } } }"#
#"query matchContext($contextId: String, $workspaceId: String, $content: String!, $limit: SafeInt, $scopedThreshold: Float, $threshold: Float) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename contexts(contextId: $contextId) { __typename matchFiles( content: $content limit: $limit scopedThreshold: $scopedThreshold threshold: $threshold ) { __typename fileId blobId name mimeType chunk content distance } matchWorkspaceDocs( content: $content limit: $limit scopedThreshold: $scopedThreshold threshold: $threshold ) { __typename docId chunk content distance } } } } }"#
))
public var contextId: String
public var contextId: GraphQLNullable<String>
public var workspaceId: GraphQLNullable<String>
public var content: String
public var limit: GraphQLNullable<SafeInt>
public var scopedThreshold: GraphQLNullable<Double>
public var threshold: GraphQLNullable<Double>
public init(
contextId: String,
contextId: GraphQLNullable<String>,
workspaceId: GraphQLNullable<String>,
content: String,
limit: GraphQLNullable<SafeInt>,
scopedThreshold: GraphQLNullable<Double>,
threshold: GraphQLNullable<Double>
) {
self.contextId = contextId
self.workspaceId = workspaceId
self.content = content
self.limit = limit
self.scopedThreshold = scopedThreshold
self.threshold = threshold
}
public var __variables: Variables? { [
"contextId": contextId,
"workspaceId": workspaceId,
"content": content,
"limit": limit,
"scopedThreshold": scopedThreshold,
"threshold": threshold
] }
@@ -56,7 +64,7 @@ public class MatchContextQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.UserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("copilot", Copilot.self),
.field("copilot", Copilot.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
public var copilot: Copilot { __data["copilot"] }
@@ -90,11 +98,13 @@ public class MatchContextQuery: GraphQLQuery {
.field("matchFiles", [MatchFile].self, arguments: [
"content": .variable("content"),
"limit": .variable("limit"),
"scopedThreshold": .variable("scopedThreshold"),
"threshold": .variable("threshold")
]),
.field("matchWorkspaceDocs", [MatchWorkspaceDoc].self, arguments: [
"content": .variable("content"),
"limit": .variable("limit"),
"scopedThreshold": .variable("scopedThreshold"),
"threshold": .variable("threshold")
]),
] }
@@ -115,12 +125,18 @@ public class MatchContextQuery: GraphQLQuery {
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("fileId", String.self),
.field("blobId", String.self),
.field("name", String.self),
.field("mimeType", String.self),
.field("chunk", AffineGraphQL.SafeInt.self),
.field("content", String.self),
.field("distance", Double?.self),
] }
public var fileId: String { __data["fileId"] }
public var blobId: String { __data["blobId"] }
public var name: String { __data["name"] }
public var mimeType: String { __data["mimeType"] }
public var chunk: AffineGraphQL.SafeInt { __data["chunk"] }
public var content: String { __data["content"] }
public var distance: Double? { __data["distance"] }

View File

@@ -7,27 +7,39 @@ public class MatchFilesQuery: GraphQLQuery {
public static let operationName: String = "matchFiles"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query matchFiles($contextId: String!, $content: String!, $limit: SafeInt) { currentUser { __typename copilot { __typename contexts(contextId: $contextId) { __typename matchFiles(content: $content, limit: $limit) { __typename fileId chunk content distance } } } } }"#
#"query matchFiles($contextId: String, $workspaceId: String, $content: String!, $limit: SafeInt, $scopedThreshold: Float, $threshold: Float) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename contexts(contextId: $contextId) { __typename matchFiles( content: $content limit: $limit scopedThreshold: $scopedThreshold threshold: $threshold ) { __typename fileId blobId chunk content distance } } } } }"#
))
public var contextId: String
public var contextId: GraphQLNullable<String>
public var workspaceId: GraphQLNullable<String>
public var content: String
public var limit: GraphQLNullable<SafeInt>
public var scopedThreshold: GraphQLNullable<Double>
public var threshold: GraphQLNullable<Double>
public init(
contextId: String,
contextId: GraphQLNullable<String>,
workspaceId: GraphQLNullable<String>,
content: String,
limit: GraphQLNullable<SafeInt>
limit: GraphQLNullable<SafeInt>,
scopedThreshold: GraphQLNullable<Double>,
threshold: GraphQLNullable<Double>
) {
self.contextId = contextId
self.workspaceId = workspaceId
self.content = content
self.limit = limit
self.scopedThreshold = scopedThreshold
self.threshold = threshold
}
public var __variables: Variables? { [
"contextId": contextId,
"workspaceId": workspaceId,
"content": content,
"limit": limit
"limit": limit,
"scopedThreshold": scopedThreshold,
"threshold": threshold
] }
public struct Data: AffineGraphQL.SelectionSet {
@@ -52,7 +64,7 @@ public class MatchFilesQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.UserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("copilot", Copilot.self),
.field("copilot", Copilot.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
public var copilot: Copilot { __data["copilot"] }
@@ -85,7 +97,9 @@ public class MatchFilesQuery: GraphQLQuery {
.field("__typename", String.self),
.field("matchFiles", [MatchFile].self, arguments: [
"content": .variable("content"),
"limit": .variable("limit")
"limit": .variable("limit"),
"scopedThreshold": .variable("scopedThreshold"),
"threshold": .variable("threshold")
]),
] }
@@ -103,12 +117,14 @@ public class MatchFilesQuery: GraphQLQuery {
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("fileId", String.self),
.field("blobId", String.self),
.field("chunk", AffineGraphQL.SafeInt.self),
.field("content", String.self),
.field("distance", Double?.self),
] }
public var fileId: String { __data["fileId"] }
public var blobId: String { __data["blobId"] }
public var chunk: AffineGraphQL.SafeInt { __data["chunk"] }
public var content: String { __data["content"] }
public var distance: Double? { __data["distance"] }

View File

@@ -7,27 +7,39 @@ public class MatchWorkspaceDocsQuery: GraphQLQuery {
public static let operationName: String = "matchWorkspaceDocs"
public static let operationDocument: ApolloAPI.OperationDocument = .init(
definition: .init(
#"query matchWorkspaceDocs($contextId: String!, $content: String!, $limit: SafeInt) { currentUser { __typename copilot { __typename contexts(contextId: $contextId) { __typename matchWorkspaceDocs(content: $content, limit: $limit) { __typename docId chunk content distance } } } } }"#
#"query matchWorkspaceDocs($contextId: String, $workspaceId: String, $content: String!, $limit: SafeInt, $scopedThreshold: Float, $threshold: Float) { currentUser { __typename copilot(workspaceId: $workspaceId) { __typename contexts(contextId: $contextId) { __typename matchWorkspaceDocs( content: $content limit: $limit scopedThreshold: $scopedThreshold threshold: $threshold ) { __typename docId chunk content distance } } } } }"#
))
public var contextId: String
public var contextId: GraphQLNullable<String>
public var workspaceId: GraphQLNullable<String>
public var content: String
public var limit: GraphQLNullable<SafeInt>
public var scopedThreshold: GraphQLNullable<Double>
public var threshold: GraphQLNullable<Double>
public init(
contextId: String,
contextId: GraphQLNullable<String>,
workspaceId: GraphQLNullable<String>,
content: String,
limit: GraphQLNullable<SafeInt>
limit: GraphQLNullable<SafeInt>,
scopedThreshold: GraphQLNullable<Double>,
threshold: GraphQLNullable<Double>
) {
self.contextId = contextId
self.workspaceId = workspaceId
self.content = content
self.limit = limit
self.scopedThreshold = scopedThreshold
self.threshold = threshold
}
public var __variables: Variables? { [
"contextId": contextId,
"workspaceId": workspaceId,
"content": content,
"limit": limit
"limit": limit,
"scopedThreshold": scopedThreshold,
"threshold": threshold
] }
public struct Data: AffineGraphQL.SelectionSet {
@@ -52,7 +64,7 @@ public class MatchWorkspaceDocsQuery: GraphQLQuery {
public static var __parentType: any ApolloAPI.ParentType { AffineGraphQL.Objects.UserType }
public static var __selections: [ApolloAPI.Selection] { [
.field("__typename", String.self),
.field("copilot", Copilot.self),
.field("copilot", Copilot.self, arguments: ["workspaceId": .variable("workspaceId")]),
] }
public var copilot: Copilot { __data["copilot"] }
@@ -85,7 +97,9 @@ public class MatchWorkspaceDocsQuery: GraphQLQuery {
.field("__typename", String.self),
.field("matchWorkspaceDocs", [MatchWorkspaceDoc].self, arguments: [
"content": .variable("content"),
"limit": .variable("limit")
"limit": .variable("limit"),
"scopedThreshold": .variable("scopedThreshold"),
"threshold": .variable("threshold")
]),
] }

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