feat: 增加pin面板的功能,并移除useCurrentGroupPanelInfo

pull/81/head
moonrailgun
parent 1db87df614
commit c903b3adaa

@ -28,6 +28,7 @@ export interface GroupInfo {
owner: string;
members: GroupMember[];
panels: GroupPanel[];
pinnedPanelId?: string; // 被钉选的面板Id
}
/**

@ -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,
};
}
},
},
});

@ -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 <div>{Translate.notfound}</div>;
}
const url = groupPanelInfo.meta?.url;
const url = _get(panelInfo, 'meta.url');
return (
<iframe key={String(url)} className="w-full h-full bg-white" src={url} />

@ -61,7 +61,7 @@ export const GroupPluginPanel: React.FC<GroupPluginPanelProps> = React.memo(
panelId={props.panelId}
showHeader={false}
>
<Component />
<Component panelInfo={panelInfo} />
</GroupPanelWrapper>
);
}

@ -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,

@ -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<PluginGroupPanel>();

@ -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<GroupPanelRenderProps> = React.memo(
(props) => {
const { groupId, panelId } = props;
const groupInfo = useGroupInfo(groupId);
const panelInfo = useGroupPanel(groupId, panelId);
if (groupInfo === null) {
return (
<Alert
className="w-full text-center"
type="error"
message={t('群组不存在')}
/>
);
}
if (groupInfo === null) {
return (
<Alert
className="w-full text-center"
type="error"
message={t('群组不存在')}
/>
);
}
if (panelInfo === null) {
return (
<Alert
className="w-full text-center"
type="error"
message={t('面板不存在')}
/>
);
}
if (panelInfo.type === GroupPanelType.TEXT) {
return (
<GroupInfoContextProvider groupInfo={groupInfo}>
<TextPanel groupId={groupId} panelId={panelInfo.id} />
</GroupInfoContextProvider>
);
} else if (panelInfo.type === GroupPanelType.PLUGIN) {
return <GroupPluginPanel groupId={groupId} panelId={panelInfo.id} />;
}
if (panelInfo === null) {
return (
<Alert
className="w-full text-center"
type="error"
message={t('面板不存在')}
message={t('未知的面板类型')}
/>
);
}
);
GroupPanelRender.displayName = 'GroupPanelRender';
if (panelInfo.type === GroupPanelType.TEXT) {
return (
<GroupInfoContextProvider groupInfo={groupInfo}>
<TextPanel groupId={groupId} panelId={panelInfo.id} />
</GroupInfoContextProvider>
);
} else if (panelInfo.type === GroupPanelType.PLUGIN) {
return <GroupPluginPanel groupId={groupId} panelId={panelInfo.id} />;
}
export const GroupPanelRoute: React.FC = React.memo(() => {
const { groupId, panelId } = useGroupPanelParams();
return (
<Alert
className="w-full text-center"
type="error"
message={t('未知的面板类型')}
/>
);
return <GroupPanelRender groupId={groupId} panelId={panelId} />;
});
GroupPanelRender.displayName = 'GroupPanelRender';
GroupPanelRoute.displayName = 'GroupPanelRoute';

@ -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 <LoadingSpinner />;
}
const menu = (
<Menu>
@ -33,6 +49,34 @@ export const SidebarItem: React.FC<{
<Menu.Item disabled={hasOpenedPanel} onClick={openPanelWindow}>
{t('在新窗口打开')}
</Menu.Item>
{isValidStr(groupInfo.pinnedPanelId) &&
groupInfo.pinnedPanelId === panel.id ? (
<Menu.Item
onClick={() => {
dispatch(
groupActions.unpinGroupPanel({
groupId,
})
);
}}
>
{t('Unpin')}
</Menu.Item>
) : (
<Menu.Item
onClick={() => {
dispatch(
groupActions.pinGroupPanel({
groupId,
panelId: panel.id,
})
);
}}
>
{t('Pin')}
</Menu.Item>
)}
</Menu>
);

@ -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 <LoadingSpinner />;
}
const pinnedPanelId = groupInfo.pinnedPanelId;
const routeMatch = (
<Switch>
<Route path="/main/group/:groupId/:panelId" component={GroupPanelRoute} />
<Route
path="/main/group/:groupId"
exact={true}
component={GroupPanelRedirect}
/>
</Switch>
);
return (
<PageContent data-tc-role="content-group" sidebar={<Sidebar />}>
<Switch>
<Route
path="/main/group/:groupId/:panelId"
component={GroupPanelRender}
/>
<Route
path="/main/group/:groupId"
exact={true}
component={GroupPanelRedirect}
/>
</Switch>
{isValidStr(pinnedPanelId) ? (
<SplitPanel className="flex-auto">
<div>{routeMatch}</div>
<div>
<GroupPanelRender groupId={groupId} panelId={pinnedPanelId} />
</div>
</SplitPanel>
) : (
routeMatch
)}
</PageContent>
);
});

@ -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;
}

Loading…
Cancel
Save