diff --git a/shared/model/group.ts b/shared/model/group.ts
index 2396f05f..9e16bf2f 100644
--- a/shared/model/group.ts
+++ b/shared/model/group.ts
@@ -28,6 +28,7 @@ export interface GroupInfo {
owner: string;
members: GroupMember[];
panels: GroupPanel[];
+ pinnedPanelId?: string; // 被钉选的面板Id
}
/**
diff --git a/shared/redux/slices/group.ts b/shared/redux/slices/group.ts
index a0fd1e4e..7f5d9472 100644
--- a/shared/redux/slices/group.ts
+++ b/shared/redux/slices/group.ts
@@ -42,6 +42,39 @@ const groupSlice = createSlice({
const groupId = action.payload;
delete state.groups[groupId];
},
+ pinGroupPanel(
+ state,
+ action: PayloadAction<{
+ groupId: string;
+ panelId: string;
+ }>
+ ) {
+ const { groupId, panelId } = action.payload;
+
+ if (state.groups[groupId]) {
+ // NOTICE: updateGroup 只会去更新,不会去添加新的
+ state.groups[groupId] = {
+ ...state.groups[groupId],
+ pinnedPanelId: panelId,
+ };
+ }
+ },
+ unpinGroupPanel(
+ state,
+ action: PayloadAction<{
+ groupId: string;
+ }>
+ ) {
+ const { groupId } = action.payload;
+
+ if (state.groups[groupId]) {
+ // NOTICE: updateGroup 只会去更新,不会去添加新的
+ state.groups[groupId] = {
+ ...state.groups[groupId],
+ pinnedPanelId: undefined,
+ };
+ }
+ },
},
});
diff --git a/web/plugins/com.msgbyte.webview/src/index.tsx b/web/plugins/com.msgbyte.webview/src/index.tsx
index 72058c60..0776c20b 100644
--- a/web/plugins/com.msgbyte.webview/src/index.tsx
+++ b/web/plugins/com.msgbyte.webview/src/index.tsx
@@ -1,17 +1,18 @@
import React from 'react';
-import { regGroupPanel, useCurrentGroupPanelInfo } from '@capital/common';
+import { regGroupPanel } from '@capital/common';
import { Translate } from './translate';
+import _get from 'lodash/get';
const PLUGIN_NAME = 'com.msgbyte.webview';
-const GroupWebPanelRender = () => {
- const groupPanelInfo = useCurrentGroupPanelInfo();
+const GroupWebPanelRender: React.FC<{ panelInfo: any }> = (props) => {
+ const panelInfo = props.panelInfo;
- if (!groupPanelInfo) {
+ if (!panelInfo) {
return
{Translate.notfound}
;
}
- const url = groupPanelInfo.meta?.url;
+ const url = _get(panelInfo, 'meta.url');
return (
diff --git a/web/src/components/Panel/group/PluginPanel.tsx b/web/src/components/Panel/group/PluginPanel.tsx
index 0318f914..e35c85b3 100644
--- a/web/src/components/Panel/group/PluginPanel.tsx
+++ b/web/src/components/Panel/group/PluginPanel.tsx
@@ -61,7 +61,7 @@ export const GroupPluginPanel: React.FC = React.memo(
panelId={props.panelId}
showHeader={false}
>
-
+
);
}
diff --git a/web/src/plugin/common/index.ts b/web/src/plugin/common/index.ts
index 4d6a8c3e..ec33599a 100644
--- a/web/src/plugin/common/index.ts
+++ b/web/src/plugin/common/index.ts
@@ -5,10 +5,7 @@
import _pick from 'lodash/pick';
export * from './reg';
-export {
- useGroupPanelParams,
- useCurrentGroupPanelInfo,
-} from '@/routes/Main/Content/Group/utils';
+export { useGroupPanelParams } from '@/routes/Main/Content/Group/utils';
export {
openModal,
closeModal,
diff --git a/web/src/plugin/common/reg.ts b/web/src/plugin/common/reg.ts
index 1b15a2be..4166e646 100644
--- a/web/src/plugin/common/reg.ts
+++ b/web/src/plugin/common/reg.ts
@@ -4,6 +4,7 @@ import {
buildRegList,
ChatMessage,
FastFormFieldMeta,
+ GroupPanel,
regSocketEventListener,
} from 'tailchat-shared';
@@ -71,7 +72,7 @@ export interface PluginGroupPanel {
/**
* 该面板如何渲染
*/
- render: React.ComponentType;
+ render: React.ComponentType<{ panelInfo: GroupPanel }>;
}
export const [pluginGroupPanel, regGroupPanel] =
buildRegList();
diff --git a/web/src/routes/Main/Content/Group/Panel.tsx b/web/src/routes/Main/Content/Group/Panel.tsx
index ab06def4..a71c9822 100644
--- a/web/src/routes/Main/Content/Group/Panel.tsx
+++ b/web/src/routes/Main/Content/Group/Panel.tsx
@@ -11,47 +11,60 @@ import {
} from 'tailchat-shared';
import { useGroupPanelParams } from './utils';
-export const GroupPanelRender: React.FC = React.memo(() => {
- const { groupId, panelId } = useGroupPanelParams();
- const groupInfo = useGroupInfo(groupId);
- const panelInfo = useGroupPanel(groupId, panelId);
+interface GroupPanelRenderProps {
+ groupId: string;
+ panelId: string;
+}
+export const GroupPanelRender: React.FC = React.memo(
+ (props) => {
+ const { groupId, panelId } = props;
+ const groupInfo = useGroupInfo(groupId);
+ const panelInfo = useGroupPanel(groupId, panelId);
- if (groupInfo === null) {
- return (
-
- );
- }
+ if (groupInfo === null) {
+ return (
+
+ );
+ }
+
+ if (panelInfo === null) {
+ return (
+
+ );
+ }
+
+ if (panelInfo.type === GroupPanelType.TEXT) {
+ return (
+
+
+
+ );
+ } else if (panelInfo.type === GroupPanelType.PLUGIN) {
+ return ;
+ }
- if (panelInfo === null) {
return (
);
}
+);
+GroupPanelRender.displayName = 'GroupPanelRender';
- if (panelInfo.type === GroupPanelType.TEXT) {
- return (
-
-
-
- );
- } else if (panelInfo.type === GroupPanelType.PLUGIN) {
- return ;
- }
+export const GroupPanelRoute: React.FC = React.memo(() => {
+ const { groupId, panelId } = useGroupPanelParams();
- return (
-
- );
+ return ;
});
-GroupPanelRender.displayName = 'GroupPanelRender';
+GroupPanelRoute.displayName = 'GroupPanelRoute';
diff --git a/web/src/routes/Main/Content/Group/SidebarItem.tsx b/web/src/routes/Main/Content/Group/SidebarItem.tsx
index 11bffbb3..b2672785 100644
--- a/web/src/routes/Main/Content/Group/SidebarItem.tsx
+++ b/web/src/routes/Main/Content/Group/SidebarItem.tsx
@@ -1,10 +1,20 @@
import React from 'react';
-import { GroupPanel, GroupPanelType, showToasts, t } from 'tailchat-shared';
+import {
+ groupActions,
+ GroupPanel,
+ GroupPanelType,
+ isValidStr,
+ showToasts,
+ t,
+ useAppDispatch,
+ useGroupInfo,
+} from 'tailchat-shared';
import { GroupPanelItem } from '@/components/GroupPanelItem';
import { GroupTextPanelItem } from './TextPanelItem';
import { Dropdown, Menu } from 'antd';
import copy from 'copy-to-clipboard';
import { usePanelWindow } from '@/hooks/usePanelWindow';
+import { LoadingSpinner } from '@/components/LoadingSpinner';
/**
* 群组面板侧边栏组件
@@ -17,6 +27,12 @@ export const SidebarItem: React.FC<{
const { hasOpenedPanel, openPanelWindow } = usePanelWindow(
`/panel/group/${groupId}/${panel.id}`
);
+ const groupInfo = useGroupInfo(groupId);
+ const dispatch = useAppDispatch();
+
+ if (!groupInfo) {
+ return ;
+ }
const menu = (
);
diff --git a/web/src/routes/Main/Content/Group/index.tsx b/web/src/routes/Main/Content/Group/index.tsx
index 6cce469a..c2cc93df 100644
--- a/web/src/routes/Main/Content/Group/index.tsx
+++ b/web/src/routes/Main/Content/Group/index.tsx
@@ -1,24 +1,48 @@
+import { LoadingSpinner } from '@/components/LoadingSpinner';
+import { SplitPanel } from '@/components/SplitPanel';
import React from 'react';
-import { Route, Switch } from 'react-router-dom';
+import { Route, Switch, useParams } from 'react-router-dom';
+import { isValidStr, useGroupInfo } from 'tailchat-shared';
import { PageContent } from '../PageContent';
-import { GroupPanelRender } from './Panel';
+import { GroupPanelRender, GroupPanelRoute } from './Panel';
import { GroupPanelRedirect } from './PanelRedirect';
import { Sidebar } from './Sidebar';
export const Group: React.FC = React.memo(() => {
+ const { groupId } = useParams<{
+ groupId: string;
+ }>();
+ const groupInfo = useGroupInfo(groupId);
+
+ if (!groupInfo) {
+ return ;
+ }
+
+ const pinnedPanelId = groupInfo.pinnedPanelId;
+
+ const routeMatch = (
+
+
+
+
+ );
+
return (
}>
-
-
-
-
+ {isValidStr(pinnedPanelId) ? (
+
+ {routeMatch}
+
+
+
+
+ ) : (
+ routeMatch
+ )}
);
});
diff --git a/web/src/routes/Main/Content/Group/utils.ts b/web/src/routes/Main/Content/Group/utils.ts
index f792ca87..63c08892 100644
--- a/web/src/routes/Main/Content/Group/utils.ts
+++ b/web/src/routes/Main/Content/Group/utils.ts
@@ -15,10 +15,3 @@ export function useGroupPanelParams(): {
return { groupId, panelId };
}
-
-export function useCurrentGroupPanelInfo(): GroupPanel | null {
- const { groupId, panelId } = useGroupPanelParams();
- const panelInfo = useGroupPanel(groupId, panelId);
-
- return panelInfo;
-}