{meta?.icon ?? }
@@ -562,7 +611,10 @@ export const IntegrationsPanel = () => {
diff --git a/packages/frontend/core/src/desktop/dialogs/setting/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/index.tsx
index 2c26374f4..825cbf6ce 100644
--- a/packages/frontend/core/src/desktop/dialogs/setting/index.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/setting/index.tsx
@@ -221,6 +221,7 @@ const SettingModalInner = ({
) : isWorkspaceSetting(settingState.activeTab) ? (
diff --git a/packages/frontend/core/src/desktop/dialogs/setting/navigation-constants.ts b/packages/frontend/core/src/desktop/dialogs/setting/navigation-constants.ts
new file mode 100644
index 000000000..513fa9f6b
--- /dev/null
+++ b/packages/frontend/core/src/desktop/dialogs/setting/navigation-constants.ts
@@ -0,0 +1 @@
+export const CALENDAR_INTEGRATION_SCROLL_ANCHOR = 'integration-calendar';
diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx
index 75856d708..51c0f50d5 100644
--- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx
@@ -28,10 +28,12 @@ import { WorkspaceSettingStorage } from './storage';
export const WorkspaceSetting = ({
activeTab,
+ scrollAnchor,
onCloseSetting,
onChangeSettingState,
}: {
activeTab: SettingTab;
+ scrollAnchor?: string;
onCloseSetting: () => void;
onChangeSettingState: (settingState: SettingState) => void;
}) => {
@@ -54,7 +56,7 @@ export const WorkspaceSetting = ({
case 'workspace:license':
return ;
case 'workspace:integrations':
- return ;
+ return ;
case 'workspace:embedding':
return ;
default:
diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx
index 7dc9a187c..bf978106f 100644
--- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx
+++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/integration/index.tsx
@@ -2,8 +2,15 @@ import { SettingHeader } from '@affine/component/setting-components';
import { WorkspaceService } from '@affine/core/modules/workspace';
import { useI18n } from '@affine/i18n';
import { useService } from '@toeverything/infra';
-import { type ReactNode, useCallback, useMemo, useState } from 'react';
+import {
+ type ReactNode,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
+import { CALENDAR_INTEGRATION_SCROLL_ANCHOR } from '../../navigation-constants';
import { SubPageProvider, useSubPageIsland } from '../../sub-page';
import {
IntegrationCard,
@@ -14,17 +21,34 @@ import { getAllowedIntegrationList } from './constants';
import { type IntegrationItem } from './constants';
import { list } from './index.css';
-export const IntegrationSetting = () => {
+export const IntegrationSetting = ({
+ scrollAnchor,
+}: {
+ scrollAnchor?: string;
+}) => {
const t = useI18n();
const [opened, setOpened] = useState(null);
const workspaceService = useService(WorkspaceService);
const isCloudWorkspace = workspaceService.workspace.flavour !== 'local';
- console.log('isCloudWorkspace', isCloudWorkspace);
const integrationList = useMemo(
() => getAllowedIntegrationList(isCloudWorkspace),
[isCloudWorkspace]
);
+
+ useEffect(() => {
+ if (scrollAnchor !== CALENDAR_INTEGRATION_SCROLL_ANCHOR) {
+ return;
+ }
+
+ const hasCalendarSetting = integrationList.some(
+ item => item.id === 'calendar' && 'setting' in item
+ );
+ if (hasCalendarSetting) {
+ setOpened('calendar');
+ }
+ }, [integrationList, scrollAnchor]);
+
const handleCardClick = useCallback((card: IntegrationItem) => {
if ('setting' in card && card.setting) {
setOpened(card.id);
diff --git a/packages/frontend/core/src/desktop/pages/workspace/settings/index.spec.tsx b/packages/frontend/core/src/desktop/pages/workspace/settings/index.spec.tsx
new file mode 100644
index 000000000..da5197071
--- /dev/null
+++ b/packages/frontend/core/src/desktop/pages/workspace/settings/index.spec.tsx
@@ -0,0 +1,77 @@
+/**
+ * @vitest-environment happy-dom
+ */
+
+import { render } from '@testing-library/react';
+import type * as ReactRouterDom from 'react-router-dom';
+import { beforeEach, describe, expect, test, vi } from 'vitest';
+
+const openAll = vi.hoisted(() => vi.fn());
+const openDialog = vi.hoisted(() => vi.fn());
+const searchParamsState = vi.hoisted(() => ({
+ value: new URLSearchParams(),
+}));
+const WorkspaceDialogServiceToken = vi.hoisted(
+ () => class WorkspaceDialogService {}
+);
+const WorkbenchServiceToken = vi.hoisted(() => class WorkbenchService {});
+
+vi.mock('@affine/core/modules/dialogs', () => ({
+ WorkspaceDialogService: WorkspaceDialogServiceToken,
+}));
+
+vi.mock('@affine/core/modules/workbench', () => ({
+ WorkbenchService: WorkbenchServiceToken,
+}));
+
+vi.mock('@toeverything/infra', () => ({
+ useService: (token: unknown) => {
+ if (token === WorkbenchServiceToken) {
+ return {
+ workbench: {
+ openAll,
+ },
+ };
+ }
+ if (token === WorkspaceDialogServiceToken) {
+ return {
+ open: openDialog,
+ };
+ }
+ return {};
+ },
+}));
+
+vi.mock('react-router-dom', async () => {
+ const actual =
+ await vi.importActual('react-router-dom');
+ return {
+ ...actual,
+ useSearchParams: () => [searchParamsState.value],
+ };
+});
+
+import { Component } from './index';
+
+describe('workspace settings page', () => {
+ beforeEach(() => {
+ openAll.mockReset();
+ openDialog.mockReset();
+ searchParamsState.value = new URLSearchParams();
+ });
+
+ test('passes tab and scrollAnchor through to the settings dialog', () => {
+ searchParamsState.value = new URLSearchParams({
+ tab: 'workspace:integrations',
+ scrollAnchor: 'integration-calendar',
+ });
+
+ render();
+
+ expect(openAll).toHaveBeenCalled();
+ expect(openDialog).toHaveBeenCalledWith('setting', {
+ activeTab: 'workspace:integrations',
+ scrollAnchor: 'integration-calendar',
+ });
+ });
+});
diff --git a/packages/frontend/core/src/desktop/pages/workspace/settings/index.tsx b/packages/frontend/core/src/desktop/pages/workspace/settings/index.tsx
index 3d04eedbe..9bb7df904 100644
--- a/packages/frontend/core/src/desktop/pages/workspace/settings/index.tsx
+++ b/packages/frontend/core/src/desktop/pages/workspace/settings/index.tsx
@@ -12,6 +12,7 @@ export const Component = () => {
const [searchParams] = useSearchParams();
const tab = searchParams.get('tab') ?? undefined;
+ const scrollAnchor = searchParams.get('scrollAnchor') ?? undefined;
const isOpened = useRef(false);
@@ -23,7 +24,8 @@ export const Component = () => {
workbench.openAll();
workspaceDialogService.open('setting', {
activeTab: tab as SettingTab,
+ scrollAnchor,
});
- }, [tab, workbench, workspaceDialogService]);
+ }, [scrollAnchor, tab, workbench, workspaceDialogService]);
return null;
};