import React, { useEffect, useMemo, useState, useCallback, MouseEventHandler } from 'react'; import { useAPIClient, useRequest } from '../api-client'; import { Avatar, Card, message, Modal, Popconfirm, Spin, Switch, Tabs, TabsProps, Tag, Tooltip, Typography, } from 'antd'; import { css } from '@emotion/css'; import cls from 'classnames'; import { useHistory } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { DeleteOutlined, SettingOutlined } from '@ant-design/icons'; import { useParseMarkdown } from '../schema-component/antd/markdown/util'; import type { IPluginData } from '.'; interface PluginDocumentProps { path: string; name: string; } interface ICommonCard { onClick: () => void; name: string; description: string; title: string; displayName: string; actions?: JSX.Element[]; } interface IPluginDetail { plugin: any; onCancel: () => void; items: TabsProps['items']; } /** * get color by string * TODO: real avatar * @param str */ const stringToColor = function (str: string) { let hash = 0; for (let i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); } let color = '#'; for (let i = 0; i < 3; i++) { const value = (hash >> (i * 8)) & 0xff; color += ('00' + value.toString(16)).substr(-2); } return color; }; const PluginDocument: React.FC = (props) => { const [docLang, setDocLang] = useState(''); const { name, path } = props; const { data, loading, error } = useRequest( { url: '/plugins:getTabInfo', params: { filterByTk: name, path: path, locale: docLang, }, }, { refreshDeps: [name, path, docLang], }, ); const { html, loading: parseLoading } = useParseMarkdown(data?.data?.content); const htmlWithOutRelativeDirect = useMemo(() => { if (html) { const pattern = / match + `onclick="return false;"`); // prevent the default event of } }, [html]); const handleSwitchDocLang = useCallback((e: MouseEvent) => { const lang = (e.target as HTMLDivElement).innerHTML; if (lang.trim() === '中文') { setDocLang('zh-CN'); } else if (lang.trim() === 'English') { setDocLang('en-US'); } }, []); useEffect(() => { const md = document.getElementById('pm-md-preview'); md.addEventListener('click', handleSwitchDocLang); return () => { removeEventListener('click', handleSwitchDocLang); }; }, [handleSwitchDocLang]); return (
{loading || parseLoading ? ( ) : (
)}
); }; function PluginDetail(props: IPluginDetail) { const { plugin, onCancel, items } = props; return ( {plugin?.displayName || plugin?.name} v{plugin?.version} } open={!!plugin} onCancel={onCancel} destroyOnClose > {plugin?.description &&
{plugin?.description}
}
); } function CommonCard(props: ICommonCard) { const { onClick, name, displayName, actions, description, title } = props; return ( Settings
, Remove, ]} > {name?.[0]}} description={
{description || '-'}
} title={ {displayName || name} {title} } /> ); } export const PluginCard = (props: { data: IPluginData }) => { const history = useHistory(); const { data } = props; const api = useAPIClient(); const { t } = useTranslation(); const { enabled, name, displayName, id, description, version } = data; const [plugin, setPlugin] = useState(null); const { data: tabsData, run } = useRequest( { url: '/plugins:getTabs', }, { manual: true, }, ); const items = useMemo(() => { return tabsData?.data?.tabs.map((item) => { return { label: item.title, key: item.path, children: React.createElement(PluginDocument, { name: tabsData?.data.filterByTk, path: item.path, }), }; }); }, [tabsData?.data]); const actions = useMemo( () => [ enabled ? ( { e.stopPropagation(); history.push(`/admin/settings/${name}`); }} /> ) : null, { e.stopPropagation(); await api.request({ url: `pm:remove/${name}`, }); message.success(t('插件删除成功')); window.location.reload(); }} onCancel={(e) => e.stopPropagation()} okText={t('Yes')} cancelText={t('No')} > e.stopPropagation()} /> , { e.stopPropagation(); Modal.warn({ title: checked ? t('Plugin starting') : t('Plugin stopping'), content: t('The application is reloading, please do not close the page.'), okButtonProps: { style: { display: 'none', }, }, }); await api.request({ url: `pm:${checked ? 'enable' : 'disable'}/${name}`, }); window.location.reload(); // message.success(checked ? t('插件激活成功') : t('插件禁用成功')); }} defaultChecked={enabled} >, ].filter(Boolean), [api, enabled, history, id, name, t], ); return ( <> setPlugin(null)} items={items} /> { setPlugin(data); run({ params: { filterByTk: name, }, }); }} name={name} description={description} title={version} actions={actions} displayName={displayName} /> ); }; export const BuiltInPluginCard = (props: { data: IPluginData }) => { const { data: { description, name, version, displayName }, data, } = props; const history = useHistory(); const [plugin, setPlugin] = useState(null); const { data: tabsData, run } = useRequest( { url: '/plugins:getTabs', }, { manual: true, }, ); const items = useMemo(() => { return tabsData?.data?.tabs.map((item) => { return { label: item.title, key: item.path, children: React.createElement(PluginDocument, { name: tabsData?.data.filterByTk, path: item.path, }), }; }); }, [tabsData?.data]); return ( <> setPlugin(null)} items={items} /> { setPlugin(data); run({ params: { filterByTk: name, }, }); }} name={name} displayName={displayName} description={description} title={version} actions={[
, { e.stopPropagation(); history.push(`/admin/settings/${name}`); }} />, ]} /> ); }; function useCallabck(arg0: () => void, arg1: undefined[]) { throw new Error('Function not implemented.'); }