akumatus
|
47206b8d47
|
feat(core): support tag search for ai chat (#10965)
Close [BS-2785](https://linear.app/affine-design/issue/BS-2785).
Close [BS-2786](https://linear.app/affine-design/issue/BS-2786).

|
2025-03-19 04:22:11 +00:00 |
|
JimmFly
|
0cb06668cd
|
refactor(core): split the billing component into a separate file (#10924)
refactor(core): split the billing component into a separate file
feat(core): show subscription status in billing settings


|
2025-03-18 10:05:45 +00:00 |
|
fengmk2
|
4fc3e92205
|
feat(server): separate storage quota limit and blob size limit (#10957)
close CLOUD-171
|
2025-03-18 09:28:50 +00:00 |
|
fengmk2
|
86c4e0705f
|
fix(server): convert 4xx status HttpError to UserFriendlyError (#10956)
|
2025-03-18 09:28:50 +00:00 |
|
CatsJuice
|
ff8c3d1cee
|
feat(core): intilize integration module and basic readwise impl (#10726)
close AF-2257, AF-2261, AF-2260, AF-2259
### Feat
- New `Integration` Module
- Basic Readwise integration
- connect
- import
- disconnect
- Common Integration UI
- Common Integration Writer (Transform markdown to AFFiNE Doc)
### Not Implemented
> will be implemented in down-stack
- delete docs when disconnect
- readwise settiing UI
- integration property rendering
|
2025-03-18 08:13:58 +00:00 |
|
fengmk2
|
8880cef20b
|
test(infra): add check job to verify committed changes (#10829)
|
2025-03-14 02:58:27 +00:00 |
|
Saul-Mirone
|
05f3069efd
|
feat(editor): add i18n support for block meta display (#10831)
|
2025-03-13 11:28:56 +00:00 |
|
JimmFly
|
0c9591f08e
|
feat(core): add an entry for admin panel (#10813)

|
2025-03-13 10:46:26 +00:00 |
|
donteatfriedrice
|
d2c62602a4
|
feat(editor): support embed iframe block (#10740)
To close:
[BS-2660](https://linear.app/affine-design/issue/BS-2660/slash-menu-支持-iframe-embed)
[BS-2661](https://linear.app/affine-design/issue/BS-2661/iframe-embed-block-model-and-block-component)
[BS-2662](https://linear.app/affine-design/issue/BS-2662/iframe-embed-block-toolbar)
[BS-2768](https://linear.app/affine-design/issue/BS-2768/iframe-embed-block-loading-和-error-态)
[BS-2670](https://linear.app/affine-design/issue/BS-2670/iframe-embed-block-导出)
# PR Description
# Add Embed Iframe Block Support
## Overview
This PR introduces a new `EmbedIframeBlock` to enhance content embedding capabilities within our editor. This block allows users to seamlessly embed external content from various providers (Google Drive, Spotify, etc.) directly into their docs.
## New Blocks
### EmbedIframeBlock
The core block that renders embedded iframe content. This block:
* Displays external content within a secure iframe
* Handles loading states with visual feedback
* Provides error handling with edit and retry options
* Supports customization of width, height, and other iframe attributes
### Supporting Components
* **EmbedIframeCreateModal**: Modal interface for creating new iframe embeds
* **EmbedIframeLinkEditPopup**: UI for editing existing embed links
* **EmbedIframeLoadingCard**: Visual feedback during content loading
* **EmbedIframeErrorCard**: Error handling with retry functionality
## New Store Extensions
### EmbedIframeConfigExtension
This extension provides configuration for different embed providers:
```typescript
/**
* The options for the iframe
* @example
* {
* defaultWidth: '100%',
* defaultHeight: '152px',
* style: 'border-radius: 8px;',
* allow: 'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
* }
* =>
* <iframe
* width="100%"
* height="152px"
* style="border-radius: 8px;"
* allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture"
* ></iframe>
*/
export type IframeOptions = {
defaultWidth?: string;
defaultHeight?: string;
style?: string;
referrerpolicy?: string;
scrolling?: boolean;
allow?: string;
allowFullscreen?: boolean;
};
/**
* Define the config of an embed iframe block provider
*/
export type EmbedIframeConfig = {
/**
* The name of the embed iframe block provider
*/
name: string;
/**
* The function to match the url
*/
match: (url: string) => boolean;
/**
* The function to build the oEmbed URL for fetching embed data
*/
buildOEmbedUrl: (url: string) => string | undefined;
/**
* Use oEmbed URL directly as iframe src without fetching oEmbed data
*/
useOEmbedUrlDirectly: boolean;
/**
* The options for the iframe
*/
options?: IframeOptions;
};
export const EmbedIframeConfigIdentifier =
createIdentifier<EmbedIframeConfig>('EmbedIframeConfig');
export function EmbedIframeConfigExtension(
config: EmbedIframeConfig
): ExtensionType & {
identifier: ServiceIdentifier<EmbedIframeConfig>;
} {
const identifier = EmbedIframeConfigIdentifier(config.name);
return {
setup: di => {
di.addImpl(identifier, () => config);
},
identifier,
};
}
```
**example:**
```typescript
// blocksuite/affine/blocks/block-embed/src/embed-iframe-block/configs/providers/spotify.ts
const SPOTIFY_DEFAULT_WIDTH = '100%';
const SPOTIFY_DEFAULT_HEIGHT = '152px';
// https://developer.spotify.com/documentation/embeds/reference/oembed
const spotifyEndpoint = 'https://open.spotify.com/oembed';
const spotifyUrlValidationOptions: EmbedIframeUrlValidationOptions = {
protocols: ['https:'],
hostnames: ['open.spotify.com', 'spotify.link'],
};
const spotifyConfig = {
name: 'spotify',
match: (url: string) =>
validateEmbedIframeUrl(url, spotifyUrlValidationOptions),
buildOEmbedUrl: (url: string) => {
const match = validateEmbedIframeUrl(url, spotifyUrlValidationOptions);
if (!match) {
return undefined;
}
const encodedUrl = encodeURIComponent(url);
const oEmbedUrl = `${spotifyEndpoint}?url=${encodedUrl}`;
return oEmbedUrl;
},
useOEmbedUrlDirectly: false,
options: {
defaultWidth: SPOTIFY_DEFAULT_WIDTH,
defaultHeight: SPOTIFY_DEFAULT_HEIGHT,
allow:
'autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture',
style: 'border-radius: 12px;',
allowFullscreen: true,
},
};
// add the config extension to store
export const SpotifyEmbedConfig = EmbedIframeConfigExtension(spotifyConfig);
```
**Key features:**
* Provider registration and discovery
* URL pattern matching
* Provider-specific embed options (width, height, features)
### EmbedIframeService
This service provides abilities to handle URL validation, data fetching, and block creation
**Type:**
```typescript
/**
* Service for handling embeddable URLs
*/
export interface EmbedIframeProvider {
/**
* Check if a URL can be embedded
* @param url URL to check
* @returns true if the URL can be embedded, false otherwise
*/
canEmbed: (url: string) => boolean;
/**
* Build a API URL for fetching embed data
* @param url URL to build API URL
* @returns API URL if the URL can be embedded, undefined otherwise
*/
buildOEmbedUrl: (url: string) => string | undefined;
/**
* Get the embed iframe config
* @param url URL to get embed iframe config
* @returns Embed iframe config if the URL can be embedded, undefined otherwise
*/
getConfig: (url: string) => EmbedIframeConfig | undefined;
/**
* Get embed iframe data
* @param url URL to get embed iframe data
* @returns Embed iframe data if the URL can be embedded, undefined otherwise
*/
getEmbedIframeData: (url: string) => Promise<EmbedIframeData | null>;
/**
* Parse an embeddable URL and add an EmbedIframeBlock to doc
* @param url Original url to embed
* @param parentId Parent block ID
* @param index Optional index to insert at
* @returns Created block id if successful, undefined if the URL cannot be embedded
*/
addEmbedIframeBlock: (
props: Partial<EmbedIframeBlockProps>,
parentId: string,
index?: number
) => string | undefined;
}
```
**Implemetation:**
```typescript
export class EmbedIframeService
extends StoreExtension
implements EmbedIframeProvider
{
static override key = 'embed-iframe-service';
private readonly _configs: EmbedIframeConfig[];
constructor(store: Store) {
super(store);
this._configs = Array.from(
store.provider.getAll(EmbedIframeConfigIdentifier).values()
);
}
canEmbed = (url: string): boolean => {
return this._configs.some(config => config.match(url));
};
buildOEmbedUrl = (url: string): string | undefined => {
return this._configs.find(config => config.match(url))?.buildOEmbedUrl(url);
};
getConfig = (url: string): EmbedIframeConfig | undefined => {
return this._configs.find(config => config.match(url));
};
getEmbedIframeData = async (
url: string,
signal?: AbortSignal
): Promise<EmbedIframeData | null> => {
try {
const config = this._configs.find(config => config.match(url));
if (!config) {
return null;
}
const oEmbedUrl = config.buildOEmbedUrl(url);
if (!oEmbedUrl) {
return null;
}
// if the config useOEmbedUrlDirectly is true, return the url directly as iframe_url
if (config.useOEmbedUrlDirectly) {
return {
iframe_url: oEmbedUrl,
};
}
// otherwise, fetch the oEmbed data
const response = await fetch(oEmbedUrl, { signal });
if (!response.ok) {
console.warn(
`Failed to fetch oEmbed data: ${response.status} ${response.statusText}`
);
return null;
}
const data = await response.json();
return data as EmbedIframeData;
} catch (error) {
if (error instanceof Error && error.name !== 'AbortError') {
console.error('Error fetching embed iframe data:', error);
}
return null;
}
};
addEmbedIframeBlock = (
props: Partial<EmbedIframeBlockProps>,
parentId: string,
index?: number
): string | undefined => {
const blockId = this.store.addBlock(
'affine:embed-iframe',
props,
parentId,
index
);
return blockId;
};
}
```
**Usage:**
```typescript
// Usage example
const embedIframeService = this.std.get(EmbedIframeService);
// Check if a URL can be embedded
const canEmbed = embedIframeService.canEmbed(url);
// Get embed data for a URL
const embedData = await embedIframeService.getEmbedIframeData(url);
// Add an embed iframe block to the document
const block = embedIframeService.addEmbedIframeBlock({
url,
iframeUrl: embedData.iframe_url,
title: embedData.title,
description: embedData.description
}, parentId, index);
```
**Key features:**
* URL validation and transformation
* Provider-specific data fetching
* Block creation and management
## Adaptations
### Toolbar Integration
Added toolbar actions for embedded content:
* Copy link
* Edit embed title and description
* Toggle between inline/card views
* Add caption
* And more
### Slash Menu Integration
Added a new slash menu option for embedding content:
* Embed item for inserting embed iframe block
* Conditional rendering based on feature flags
### Adapters
Implemented adapters for various formats:
* **HTML Adapter**: Exports embed original urls as html links
* **Markdown Adapter**: Exports embed original urls as markdown links
* **Plain Text Adapter**: Exports embed original urls as link text
## To Be Continued:
- [ ] **UI Optimization**
- [ ] **Edgeless Mode Support**
- [ ] **Mobile Support**
|
2025-03-13 04:11:46 +00:00 |
|
EYHN
|
ea07aa8607
|
feat(core): add notification list (#10480)
|
2025-03-11 06:23:33 +00:00 |
|
CatsJuice
|
9f3580263a
|
feat(core): support removing journal template from right sidebar (#10571)
|
2025-03-07 12:32:42 +00:00 |
|
forehalo
|
e02fb4fa94
|
refactor(core): standardize frontend error handling (#10667)
|
2025-03-06 13:10:18 +00:00 |
|
fundon
|
93920f9895
|
fix(editor): circular dependencies (#10661)
Closes: [BS-2766](https://linear.app/affine-design/issue/BS-2766/把-converttodatabase-移到-root-block-中,避免循环依赖)
|
2025-03-06 09:41:01 +00:00 |
|
Flrande
|
bd62634a76
|
feat(editor): add callout block (#10563)
- Add `CalloutBlockModel `
- Implement `CalloutBlockComponent `
- Integrate with slash menu (/)
|
2025-03-05 09:28:51 +00:00 |
|
EYHN
|
61635aa77a
|
feat(core): add clipper import interface (#10619)
|
2025-03-05 04:22:03 +00:00 |
|
Saul-Mirone
|
fdde818ddd
|
feat(editor): add block meta feature flag (#10548)
|
2025-03-03 01:45:33 +00:00 |
|
liuyi
|
e5e5c0a8ba
|
perf(core): only full sync before exporting (#10408)
|
2025-02-25 04:41:56 +00:00 |
|
CatsJuice
|
8b4175c44d
|
chore(core): update free pricing plan description (#10393)
|
2025-02-24 07:37:30 +00:00 |
|
Cats Juice
|
09cc5c392b
|
refactor(core): new workspace selector and create dialog (#10323)
|
2025-02-21 17:16:38 +08:00 |
|
DarkSky
|
fa86f71853
|
feat(server): client version check (#9205)
Co-authored-by: forehalo <forehalo@gmail.com>
|
2025-02-20 15:50:22 +08:00 |
|
github-actions[bot]
|
a0e3f9909c
|
chore(i18n): sync translations (#10184)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
2025-02-20 02:25:19 +00:00 |
|
forehalo
|
02f567f2c0
|
chore(core): better doc action error message (#10288)
|
2025-02-19 10:38:38 +00:00 |
|
pengx17
|
78346be4fe
|
fix(electron): update settings styles (#10193)
|
2025-02-18 09:54:59 +00:00 |
|
L-Sun
|
e639f08b71
|
chore(editor): remove page block feature flag (#10251)
|
2025-02-18 09:25:05 +00:00 |
|
forehalo
|
fdddaf651f
|
chore(core): adjust selfhost sign in ui (#10226)
close AF-2227
|
2025-02-18 03:38:01 +00:00 |
|
JimmFly
|
9048b38069
|
fix(core): adjust share menu (#10164)
close AF-2218 AF-2215 AF-2221
|
2025-02-14 10:32:12 +00:00 |
|
forehalo
|
cc6fdef10e
|
chore(electron): remove offline mode (#10152)
close AF-2177
|
2025-02-14 10:04:01 +00:00 |
|
pengx17
|
f20e3f6d8f
|
feat(electron): show a warning for drop folder to split view (#10178)
fix PD-2310

|
2025-02-14 06:42:56 +00:00 |
|
github-actions[bot]
|
e4e06f35bb
|
chore(i18n): sync translations (#10026)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
2025-02-12 12:18:24 +00:00 |
|
pengx17
|
c5c59ba00a
|
fix(core): adjust settings names (#10061)
fix AF-2190
|
2025-02-11 02:14:10 +00:00 |
|
Oleg
|
d4f0c53a0c
|
feat(core): frame editor settings (#9970)
Co-authored-by: L-Sun <zover.v@gmail.com>
Co-authored-by: Mirone <Saul-Mirone@outlook.com>
|
2025-02-10 15:23:32 +08:00 |
|
EYHN
|
92f4f0c2d9
|
feat(core): guard service (#9816)
|
2025-02-09 23:26:38 +00:00 |
|
JimmFly
|
5ae5fd88f1
|
feat(core): add doc grant feature to share menu (#9672)
|
2025-02-07 13:05:58 +00:00 |
|
donteatfriedrice
|
b38389c670
|
feat(core): add tooltip for import dialog snapshot item (#10013)
[PD-2132](https://linear.app/affine-design/issue/PD-2132/import-导入优化:snapshot-需要一个问号,解释文档)
|
2025-02-07 10:23:59 +00:00 |
|
JimmFly
|
d5a626d9c3
|
feat(core): optimize team workspace member management (#9737)
close AF-2106 AF-2077 AF-2089
feat(core): handle need more seat status
feat(core): prevent invite members when team plan is canceled
|
2025-02-07 10:08:00 +00:00 |
|
CatsJuice
|
b4f078b9c9
|
feat(core): add deleted state for sidebar journal template (#9980)
|
2025-02-07 09:09:58 +00:00 |
|
JimmFly
|
e68bdbde3e
|
feat(core): add self host team plan (#9569)
|
2025-02-07 03:35:24 +00:00 |
|
pengx17
|
86de184593
|
fix(electron): split view drag indicator tooltip (#9979)
fix PD-2244
|
2025-02-06 16:14:54 +00:00 |
|
forehalo
|
4ed03c9f0e
|
feat(i18n): introduce server error i18n (#9953)
close AF-2054
|
2025-02-05 12:30:19 +00:00 |
|
L-Sun
|
3f4311ff1c
|
chore(editor): add RTL experiement flag for editor (#9882)
|
2025-01-24 08:23:24 +00:00 |
|
pengx17
|
6ac6a8d6d6
|
feat(core): unused blob management in settings (#9795)
fix AF-2144, PD-2064, PD-2065, PD-2066
|
2025-01-23 07:12:17 +00:00 |
|
pengx17
|
088ae0ac0a
|
feat(electron): backup panel (#9738)
fix PD-2071, PD-2059, PD-2069, PD-2068
|
2025-01-22 22:52:31 +08:00 |
|
github-actions[bot]
|
795c5c9a8c
|
chore(i18n): sync translations (#9846)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: liuyi <forehalo@gmail.com>
|
2025-01-22 09:16:53 +00:00 |
|
forehalo
|
5828eb53b6
|
feat(core): support one time password (#9798)
|
2025-01-22 07:33:10 +00:00 |
|
github-actions[bot]
|
a5025cf470
|
chore(i18n): sync translations (#9842)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: liuyi <forehalo@gmail.com>
|
2025-01-22 06:41:39 +00:00 |
|
pengx17
|
defb0de4dd
|
feat(core): reorg workspace settings (#9718)
fix AF-2118
|
2025-01-22 03:11:27 +00:00 |
|
github-actions[bot]
|
24cd7e367c
|
chore(i18n): sync translations (#9741)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: liuyi <forehalo@gmail.com>
|
2025-01-17 07:24:27 +00:00 |
|
EYHN
|
a2ffdb4047
|
feat(core): new worker workspace engine (#9257)
|
2025-01-16 16:22:18 +00:00 |
|
CatsJuice
|
ad86292f45
|
test(core): add basic tests for template doc setting (#9702)
close AF-2112, AF-2114, AF-2115
|
2025-01-16 02:28:29 +00:00 |
|
L-Sun
|
9df338274d
|
chore(core): update tooltip of mode switcher (#9711)
Close [BS-2325](https://linear.app/affine-design/issue/BS-2325/tooltips-显示)
https://github.com/user-attachments/assets/bd4c6045-8de1-4e72-87ab-2d1d3262e6b7
|
2025-01-15 12:22:37 +00:00 |
|