mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-09 23:49:27 +08:00
* refactor: plugin manager page * fix: bug * feat: addByNpm api * fix: improve the addByNpm * feat: improve applicationPlugins:list api * fix: re-download npm package when restart app * fix: plugin delete api * feat: plugin detail api * feat: zipUrl add api * fix: upload api bug * fix: plugin detail info * feat: upgrade api * fix: upload api * feat: handle plugin load error * feat: support authToken * feat: muti lang * fix: build error * fix: self review * Update plugin-manager.ts * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bugs * fix: detail click and remove isOfficial * fix: upgrade no refresh * fix: file size and type check * fix: bug * fix: upgrade error * fix: bug * fix: bug * fix: plugin card layout * fix: handling exceptional cases * fix: tgz file support * fix: macos compress file * fix: bug * fix: bug * fix: bug * fix: bug * fix: add upgrade npm type * fix: bugs * fix: bug * fix: change plugins static expose url * fix: api prefix * fix: bug * fix: add nginx `/static/plugin/` path * fix: bugs and pr docker build no dts * fix: bug * fix: build tools bug * fix: improve code * fix: build bug * feat: improve plugin info * fix: ui bug * fix: plugin document bug * feat: improve code * feat: improve code * feat: process dev deps check * feat: improve code * feat: process.env.IS_DEV_CMD * fix: do not delete the plugin package * feat: plugin symlink * fix: tsx watch --ignore=./storage/plugins/** * fix: test error * fix: improve code * fix: improve code * fix: emitStartedEvent * fix: improve code * fix: type error * fix: test error * test: console.log * fix: createStoragePluginSymLink * fix: clientStaticMiddleware rename to clientStaticUtils * feat: build tools support plugins folder * fix: 350px * fix: error * feat: client dev support plugin folder * fix: clear cli options * fix: typeError: Converting circular structure to JSON * fix: plugin name * chore: restart application after command * feat: upgrade error & docs * Update v14-changelog.md * Update v14-changelog.md * Update v14-changelog.md * fix: gateway test * refactor(plugin-workflow): add ready state for gracefully tearing down * Revert "chore: restart application after command" This reverts commit 5015274f8e4e06e506e15754b672330330e8c7f8. * chore: stop application whe restart * T 1218 change plugin folder (#2629) * feat: change folder name * feat: change `pm create` command * feat: revert plugin name change * fix: delete samples * feat: change plugins folder * fix: pm create * feat: update docs * fix: link package error * fix: docs * fix: create command * fix: pm add error * fix: create add build * fix: pm creatre + add * feat: add tar command * fix: docs * fix: bug * fix: docs --------- Co-authored-by: chenos <chenlinxh@gmail.com> * feat: docs * Update your-fisrt-plugin.md * Update your-fisrt-plugin.md * chore: application reload * chore: test * fix: pm add error * chore: preset install skip exists plugin * fix: createIfNotExists --------- Co-authored-by: chenos <chenlinxh@gmail.com> Co-authored-by: chareice <chareice@live.com> Co-authored-by: Zhou <zhou.working@gmail.com> Co-authored-by: mytharcher <mytharcher@gmail.com>
220 lines
6.7 KiB
TypeScript
220 lines
6.7 KiB
TypeScript
import { App, Card, Divider, Popconfirm, Space, Switch, Typography, message } from 'antd';
|
|
import classnames from 'classnames';
|
|
import React, { FC, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
import { DeleteOutlined, ReadOutlined, ReloadOutlined, SettingOutlined } from '@ant-design/icons';
|
|
import { css } from '@emotion/css';
|
|
import { useAPIClient } from '../api-client';
|
|
import { PluginDetail } from './PluginDetail';
|
|
import { PluginUpgradeModal } from './PluginForm/modal/PluginUpgradeModal';
|
|
import { useStyles } from './style';
|
|
import type { IPluginData } from './types';
|
|
|
|
interface IPluginInfo extends IPluginCard {
|
|
onClick: () => void;
|
|
}
|
|
|
|
function PluginInfo(props: IPluginInfo) {
|
|
const { data, onClick } = props;
|
|
const { name, displayName, isCompatible, packageName, updatable, builtIn, enabled, description, type, error } = data;
|
|
const { styles, theme } = useStyles();
|
|
const navigate = useNavigate();
|
|
const { t } = useTranslation();
|
|
const api = useAPIClient();
|
|
const { modal } = App.useApp();
|
|
const [showUploadForm, setShowUploadForm] = useState(false);
|
|
const [enabledVal, setEnabledVal] = useState(enabled);
|
|
const reload = () => window.location.reload();
|
|
|
|
return (
|
|
<>
|
|
{showUploadForm && (
|
|
<PluginUpgradeModal
|
|
isShow={showUploadForm}
|
|
pluginData={data}
|
|
onClose={(isRefresh) => {
|
|
setShowUploadForm(false);
|
|
}}
|
|
/>
|
|
)}
|
|
<Card
|
|
size={'small'}
|
|
bordered={false}
|
|
onClick={() => {
|
|
!error && onClick();
|
|
}}
|
|
headStyle={{ border: 'none', minHeight: 'inherit', paddingTop: 14 }}
|
|
bodyStyle={{ paddingTop: 10 }}
|
|
// style={{ marginBottom: theme.marginLG }}
|
|
title={<div>{displayName || name || packageName}</div>}
|
|
hoverable
|
|
className={css`
|
|
.ant-card-actions {
|
|
li .ant-space {
|
|
gap: 2px !important;
|
|
}
|
|
li a {
|
|
.anticon {
|
|
margin-right: 3px;
|
|
/* display: none; */
|
|
}
|
|
}
|
|
li:last-child {
|
|
width: 20% !important;
|
|
}
|
|
li:first-child {
|
|
width: 80% !important;
|
|
border-inline-end: 0;
|
|
text-align: left;
|
|
padding-left: 16px;
|
|
}
|
|
}
|
|
`}
|
|
actions={[
|
|
<Space split={<Divider type="vertical" />} key={'1'}>
|
|
<a key={'5'}>
|
|
<ReadOutlined /> {t('Docs')}
|
|
</a>
|
|
{updatable && (
|
|
<a
|
|
key={'3'}
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
setShowUploadForm(true);
|
|
}}
|
|
>
|
|
<ReloadOutlined /> {t('Update')}
|
|
</a>
|
|
)}
|
|
{enabled ? (
|
|
<a
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
navigate(`/admin/settings/${name}`);
|
|
}}
|
|
>
|
|
<SettingOutlined /> {t('Setting')}
|
|
</a>
|
|
) : (
|
|
<Popconfirm
|
|
key={'delete'}
|
|
disabled={builtIn}
|
|
title={t('Are you sure to delete this plugin?')}
|
|
onConfirm={async (e) => {
|
|
e.stopPropagation();
|
|
api.request({
|
|
url: `pm:remove`,
|
|
params: {
|
|
filterByTk: name,
|
|
},
|
|
});
|
|
}}
|
|
onCancel={(e) => e.stopPropagation()}
|
|
okText={t('Yes')}
|
|
cancelText={t('No')}
|
|
>
|
|
<a
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
}}
|
|
className={classnames({ [styles.cardActionDisabled]: builtIn })}
|
|
>
|
|
<DeleteOutlined /> {t('Remove')}
|
|
</a>
|
|
</Popconfirm>
|
|
)}
|
|
</Space>,
|
|
<Switch
|
|
key={'enable'}
|
|
size={'small'}
|
|
disabled={builtIn || error}
|
|
onChange={async (checked, e) => {
|
|
e.stopPropagation();
|
|
if (!isCompatible && checked) {
|
|
message.error(t("Dependencies check failed, can't enable."));
|
|
return;
|
|
}
|
|
await api.request({
|
|
url: `pm:${checked ? 'enable' : 'disable'}`,
|
|
params: {
|
|
filterByTk: name,
|
|
},
|
|
});
|
|
}}
|
|
checked={enabledVal}
|
|
></Switch>,
|
|
].filter(Boolean)}
|
|
>
|
|
<Card.Meta
|
|
description={
|
|
!error ? (
|
|
<Typography.Paragraph
|
|
style={{ height: theme.fontSize * theme.lineHeight * 3 }}
|
|
type={isCompatible ? 'secondary' : 'danger'}
|
|
ellipsis={{ rows: 3 }}
|
|
>
|
|
{isCompatible ? description : t('Plugin dependencies check failed')}
|
|
</Typography.Paragraph>
|
|
) : (
|
|
<Typography.Text type="danger">
|
|
{t('Plugin loading failed. Please check the server logs.')}
|
|
</Typography.Text>
|
|
)
|
|
}
|
|
/>
|
|
{/* {!isCompatible && !error && (
|
|
<Button style={{ padding: 0 }} type="link">
|
|
<Typography.Text type="danger">{t('Dependencies check failed')}</Typography.Text>
|
|
</Button>
|
|
)} */}
|
|
{/*
|
|
<Col span={8}>
|
|
<Space direction="vertical" align="end" style={{ display: 'flex', marginTop: -10 }}>
|
|
{type && (
|
|
<Button
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
setShowUploadForm(true);
|
|
}}
|
|
ghost
|
|
type="primary"
|
|
>
|
|
{t('Update plugin')}
|
|
</Button>
|
|
)}
|
|
|
|
{!error && (
|
|
<Button style={{ padding: 0 }} type="link">
|
|
{t('More details')}
|
|
</Button>
|
|
)}
|
|
</Space>
|
|
</Col> */}
|
|
</Card>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export interface IPluginCard {
|
|
data: IPluginData;
|
|
}
|
|
|
|
export const PluginCard: FC<IPluginCard> = (props) => {
|
|
const { data } = props;
|
|
const [plugin, setPlugin] = useState<IPluginData>(undefined);
|
|
|
|
return (
|
|
<>
|
|
{plugin && <PluginDetail plugin={plugin} onCancel={() => setPlugin(undefined)} />}
|
|
<PluginInfo
|
|
onClick={() => {
|
|
setPlugin(data);
|
|
}}
|
|
data={data}
|
|
/>
|
|
</>
|
|
);
|
|
};
|