mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-08 15:09:27 +08:00
257 lines
7.8 KiB
TypeScript
257 lines
7.8 KiB
TypeScript
/**
|
|
* This file is part of the NocoBase (R) project.
|
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
* Authors: NocoBase Team.
|
|
*
|
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
*/
|
|
|
|
import { Alert, Col, Modal, Row, Space, Spin, Table, Tabs, TabsProps, Tag, Typography } from 'antd';
|
|
import dayjs from 'dayjs';
|
|
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
import React, { FC, useMemo } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useRequest } from '../api-client';
|
|
import { useStyles } from './style';
|
|
import { IPluginData } from './types';
|
|
|
|
dayjs.extend(relativeTime);
|
|
|
|
type Author =
|
|
| string
|
|
| {
|
|
name: string;
|
|
email?: string;
|
|
url?: string;
|
|
};
|
|
|
|
interface PackageJSON {
|
|
name: string;
|
|
version: string;
|
|
description?: string;
|
|
repository?: string | { type: string; url: string };
|
|
homepage?: string;
|
|
license?: string;
|
|
author?: Author;
|
|
devDependencies?: Record<string, string>;
|
|
dependencies?: Record<string, string>;
|
|
}
|
|
|
|
interface DepCompatible {
|
|
name: string;
|
|
result: boolean;
|
|
versionRange: string;
|
|
packageVersion: string;
|
|
}
|
|
|
|
interface IPluginDetailData {
|
|
packageJson: PackageJSON;
|
|
homepage?: string;
|
|
depsCompatible: DepCompatible[] | false;
|
|
lastUpdated: string;
|
|
}
|
|
|
|
interface IPluginDetail {
|
|
plugin: IPluginData;
|
|
onCancel: () => void;
|
|
}
|
|
|
|
export const PluginDetail: FC<IPluginDetail> = ({ plugin, onCancel }) => {
|
|
const { t } = useTranslation();
|
|
const dependenciesCompatibleTableColumns = useMemo(
|
|
() => [
|
|
{
|
|
title: t('Name'),
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
},
|
|
{
|
|
title: t('Version range'),
|
|
dataIndex: 'versionRange',
|
|
key: 'versionRange',
|
|
},
|
|
{
|
|
title: t("Plugin's version"),
|
|
dataIndex: 'packageVersion',
|
|
key: 'packageVersion',
|
|
},
|
|
{
|
|
title: t('Result'),
|
|
dataIndex: 'result',
|
|
key: 'result',
|
|
render: (result: boolean) => <Tag color={result ? 'success' : 'error'}>{result ? 'Yes' : 'No'}</Tag>,
|
|
},
|
|
],
|
|
[t],
|
|
);
|
|
const { data, loading } = useRequest<{ data: IPluginDetailData }>(
|
|
{
|
|
url: `pm:get`,
|
|
params: {
|
|
filterByTk: plugin.name,
|
|
},
|
|
},
|
|
{
|
|
refreshDeps: [plugin.name],
|
|
ready: !!plugin.name,
|
|
},
|
|
);
|
|
|
|
const repository = useMemo(() => {
|
|
if (!data?.data?.packageJson?.repository) return null;
|
|
const repository = data?.data?.packageJson.repository;
|
|
const url = typeof repository === 'string' ? repository : repository.url;
|
|
return url.replace(/\.git$/, '').replace(/^git\+/, '');
|
|
}, [data]);
|
|
|
|
const author = useMemo(() => {
|
|
const author = data?.data?.packageJson.author;
|
|
if (!author) return null;
|
|
if (typeof author === 'string') return author;
|
|
return author.name;
|
|
}, [data]);
|
|
|
|
const { styles, theme } = useStyles();
|
|
|
|
const tabItems: TabsProps['items'] = [
|
|
{
|
|
key: 'readme',
|
|
label: t('Readme'),
|
|
children: (
|
|
<Row gutter={20}>
|
|
{plugin.name && (
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('Name')}</Typography.Text>
|
|
<Typography.Text strong>{plugin.name}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
)}
|
|
{plugin.displayName && (
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('DisplayName')}</Typography.Text>
|
|
<Typography.Text strong>{plugin.displayName}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
)}
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('PackageName')}</Typography.Text>
|
|
<Typography.Text strong>{plugin.packageName}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
{repository && (
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('Repository')}</Typography.Text>
|
|
<Typography.Text strong>{repository}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
)}
|
|
{data?.data?.homepage && (
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('Homepage')}</Typography.Text>
|
|
<a href={data?.data?.homepage} target="_blank" rel="noreferrer">
|
|
{data?.data?.homepage}
|
|
</a>
|
|
</div>
|
|
</Col>
|
|
)}
|
|
{plugin.description && (
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('Description')}</Typography.Text>
|
|
<Typography.Text strong>{plugin.description}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
)}
|
|
{data?.data?.packageJson.license && (
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('License')}</Typography.Text>
|
|
<Typography.Text strong>{data?.data?.packageJson.license}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
)}
|
|
{author && (
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('Author')}</Typography.Text>
|
|
<Typography.Text strong>{author}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
)}
|
|
<Col span={24}>
|
|
<div className={styles.PluginDetailBaseInfo}>
|
|
<Typography.Text type="secondary">{t('Version')}</Typography.Text>
|
|
<Typography.Text strong>{plugin?.version}</Typography.Text>
|
|
</div>
|
|
</Col>
|
|
</Row>
|
|
),
|
|
},
|
|
{
|
|
key: 'dependencies',
|
|
label: t('Dependencies compatibility check'),
|
|
children: (
|
|
<>
|
|
{data?.data?.depsCompatible === false ? (
|
|
<Typography.Text type="danger">
|
|
{t('`dist/externalVersion.js` not found or failed to `require`. Please rebuild this plugin.')}
|
|
</Typography.Text>
|
|
) : (
|
|
<>
|
|
{!data?.data?.['isCompatible'] && (
|
|
<Alert
|
|
showIcon
|
|
type={'error'}
|
|
message={t(
|
|
'Plugin dependencies check failed, you should change the dependent version to meet the version requirements.',
|
|
)}
|
|
/>
|
|
)}
|
|
<Table
|
|
style={{ marginTop: theme.margin }}
|
|
rowKey={'name'}
|
|
pagination={false}
|
|
columns={dependenciesCompatibleTableColumns}
|
|
dataSource={data?.data?.depsCompatible}
|
|
/>
|
|
</>
|
|
)}
|
|
</>
|
|
),
|
|
},
|
|
// {
|
|
// key: 'changelog',
|
|
// label: t('Changelog'),
|
|
// children: plugin?.changelogUrl ? <PluginDocument url={plugin?.changelogUrl} /> : t('No CHANGELOG.md file'),
|
|
// },
|
|
];
|
|
|
|
return (
|
|
<Modal open={!!plugin} footer={false} destroyOnClose width={600} onCancel={onCancel}>
|
|
{loading ? (
|
|
<Spin />
|
|
) : (
|
|
plugin && (
|
|
<>
|
|
<Typography.Title level={3}>{plugin.packageName}</Typography.Title>
|
|
<Space split={<span> • </span>}>
|
|
<span>{plugin.version}</span>
|
|
</Space>
|
|
<Tabs
|
|
style={{ minHeight: '50vh' }}
|
|
items={tabItems}
|
|
defaultActiveKey={!plugin.isCompatible ? 'dependencies' : undefined}
|
|
></Tabs>
|
|
</>
|
|
)
|
|
)}
|
|
</Modal>
|
|
);
|
|
};
|