feat: multi app and plugins (#1020)

Reviewed-on: daoyoucloud/tachybase#1020
This commit is contained in:
sealday 2024-05-20 20:52:05 +08:00
parent b545855729
commit 4e2a4cd9fe
15 changed files with 407 additions and 59 deletions

View File

@ -54,6 +54,7 @@
"@tachybase/cli": "workspace:*",
"@tachybase/preset-hera-rental": "workspace:*",
"@tachybase/preset-hera-sancongtou": "workspace:*",
"@tachybase/preset-mini": "workspace:*",
"@tachybase/preset-tachybase": "workspace:*",
"@tachybase/test": "workspace:*",
"@types/react": "^18.2.79",

View File

@ -9,6 +9,7 @@
"@tachybase/database": "workspace:*",
"@tachybase/preset-hera-rental": "workspace:*",
"@tachybase/preset-hera-sancongtou": "workspace:*",
"@tachybase/preset-mini": "workspace:*",
"@tachybase/preset-tachybase": "workspace:*",
"@tachybase/server": "workspace:*"
},

View File

@ -18,6 +18,49 @@ interface IPluginInfo extends IPluginCard {
onClick: () => void;
}
export const SwitchAction = (props: IPluginData) => {
const { name, enabled, builtIn, error, isCompatible } = props;
const api = useAPIClient();
const { t } = useTranslation();
const { modal } = App.useApp();
return (
<Switch
aria-label="enable"
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;
}
if (!checked) {
modal.confirm({
title: t('Are you sure to disable this plugin?'),
onOk: async () => {
await api.request({
url: `pm:disable`,
params: {
filterByTk: name,
},
});
},
});
} else {
await api.request({
url: `pm:enable`,
params: {
filterByTk: name,
},
});
}
}}
checked={!!enabled}
></Switch>
);
};
function PluginInfo(props: IPluginInfo) {
const { data, onClick } = props;
const app = useApp();

View File

@ -1,7 +1,8 @@
export * from './PluginManagerLink';
import type { TableProps } from 'antd';
import { PageHeader } from '@ant-design/pro-layout';
import { useDebounce } from 'ahooks';
import { Button, Col, Divider, Input, List, Result, Row, Space, Spin, Tabs } from 'antd';
import { Button, Card, Col, Divider, Input, List, Result, Row, Space, Spin, Tabs, Table, Tag } from 'antd';
import _ from 'lodash';
import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -11,10 +12,10 @@ import { css } from '@emotion/css';
import { useACLRoleContext } from '../acl/ACLProvider';
import { useRequest } from '../api-client';
import { useToken } from '../style';
import { PluginCard } from './PluginCard';
import { PluginAddModal } from './PluginForm/modal/PluginAddModal';
import { PluginCard, SwitchAction } from './PluginCard';
import { useStyles } from './style';
import { IPluginData } from './types';
import { fuzzysearch } from '@tachybase/utils/client';
export interface TData {
data: IPluginData[];
@ -35,12 +36,46 @@ export interface AllowedActions {
destroy: number[];
}
const columns: TableProps<IPluginData>['columns'] = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: (text) => <a>{text}</a>,
},
{
title: 'Keywords',
dataIndex: 'keywords',
key: 'keywords',
render: (keywords) => keywords?.map((keyword) => <Tag key={keyword}>{keyword}</Tag>),
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
},
{
title: 'Action',
key: 'action',
render: (_, record) => (
<Space size="middle">
<SwitchAction {...record} />
</Space>
),
},
];
const LocalPlugins = () => {
const { t } = useTranslation();
const { theme } = useStyles();
const { data, loading, refresh } = useRequest<TData>({
url: 'pm:list',
});
const [searchValue, setSearchValue] = useState('');
const filteredList = (data?.data || []).filter(
(data) => fuzzysearch(searchValue, data.name) || fuzzysearch(searchValue, data.description ?? ''),
);
const filterList = useMemo(() => {
let list = data?.data || [];
list = list.reverse();
@ -69,8 +104,6 @@ const LocalPlugins = () => {
}, [data?.data]);
const [filterIndex, setFilterIndex] = useState(0);
const [isShowAddForm, setShowAddForm] = useState(false);
const [searchValue, setSearchValue] = useState('');
const [keyword, setKeyword] = useState(null);
const debouncedSearchValue = useDebounce(searchValue, { wait: 100 });
@ -140,15 +173,7 @@ const LocalPlugins = () => {
}
return (
<>
<PluginAddModal
isShow={isShowAddForm}
onClose={(isRefresh) => {
setShowAddForm(false);
// if (isRefresh) refresh();
}}
/>
<div style={{ width: '100%' }}>
{/* <div style={{ width: '100%' }}>
<div
style={{ marginBottom: theme.marginLG }}
className={css`
@ -178,13 +203,6 @@ const LocalPlugins = () => {
/>
</Space>
</div>
<div>
<Space>
<Button onClick={() => setShowAddForm(true)} type="primary">
{t('Add new')}
</Button>
</Space>
</div>
</div>
<Row style={{ width: '100%' }} wrap={false}>
<Col flex="200px">
@ -222,8 +240,20 @@ const LocalPlugins = () => {
))}
</div>
</Col>
</Row>
</div>
</Row> */}
<Card
style={{ marginTop: '8px' }}
extra={
<Input
value={searchValue}
placeholder="Search by name or descriptions"
onChange={(e) => setSearchValue(e.target.value)}
/>
}
>
<Table columns={columns} dataSource={filteredList} rowKey="id" />
</Card>
{/* </div> */}
</>
);
};
@ -251,37 +281,8 @@ export const PluginManager = () => {
return snippets.includes('pm') ? (
<div>
<PageHeader
className={styles.pageHeader}
ghost={false}
title={t('Plugin manager')}
footer={
<Tabs
activeKey={tabName}
onChange={(activeKey) => {
navigate(`/admin/pm/list/${activeKey}`);
}}
items={[
{
key: 'local',
label: t('Local'),
},
{
key: 'marketplace',
label: t('Marketplace'),
},
]}
/>
}
/>
<div className={styles.pageContent} style={{ display: 'flex', flexFlow: 'row wrap' }}>
{React.createElement(
{
local: LocalPlugins,
marketplace: MarketplacePlugins,
}[tabName],
)}
</div>
<PageHeader className={styles.pageHeader} ghost={false} title={t('Plugin manager')}></PageHeader>
<LocalPlugins />
</div>
) : (
<Result status="404" title="404" subTitle="Sorry, the page you visited does not exist." />

View File

@ -25,7 +25,6 @@ import {
} from '../../../';
import { Plugin } from '../../../application/Plugin';
import { useAppSpin } from '../../../application/hooks/useAppSpin';
import { Help } from '../../../user/Help';
import { VariablesProvider } from '../../../variables';
const filterByACL = (schema, options) => {
@ -338,23 +337,33 @@ export const InternalAdminLayout = (props: any) => {
>
<div
className={css`
width: 200px;
display: inline-flex;
flex-shrink: 0;
color: #fff;
padding: 0;
align-items: center;
padding: 0 12px 0 12px;
`}
>
<img
className={css`
padding: 0 16px;
object-fit: contain;
width: 100%;
height: 100%;
height: 28px;
`}
src={result?.data?.data?.logo?.url}
/>
<h1
className={css`
color: #fff;
height: 32px;
margin: 0 0 0 12px;
font-weight: 600;
font-size: 18px;
line-height: 32px;
`}
>
{result?.data?.data?.title}
</h1>
</div>
<div
className={css`

View File

@ -0,0 +1,2 @@
/node_modules
/src

3
packages/presets/mini/client.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
export * from './src/client';
export { default } from './src/client';

View File

@ -0,0 +1 @@
module.exports = require('./lib/client/index.js');

View File

@ -0,0 +1,67 @@
{
"name": "@tachybase/preset-mini",
"version": "0.21.24",
"license": "Apache-2.0",
"main": "./lib/server/index.js",
"dependencies": {
"@hera/plugin-approval": "workspace:*",
"@hera/plugin-audit-logs": "workspace:*",
"@hera/plugin-core": "workspace:*",
"@hera/plugin-homepage": "workspace:*",
"@hera/plugin-rental": "workspace:*",
"@nocobase/plugin-acl": "workspace:*",
"@nocobase/plugin-action-bulk-edit": "workspace:*",
"@nocobase/plugin-action-bulk-update": "workspace:*",
"@nocobase/plugin-action-duplicate": "workspace:*",
"@nocobase/plugin-action-print": "workspace:*",
"@nocobase/plugin-api-doc": "workspace:*",
"@nocobase/plugin-api-keys": "workspace:*",
"@nocobase/plugin-auth": "workspace:*",
"@nocobase/plugin-backup-restore": "workspace:*",
"@nocobase/plugin-calendar": "workspace:*",
"@nocobase/plugin-cas": "workspace:*",
"@nocobase/plugin-china-region": "workspace:*",
"@nocobase/plugin-client": "workspace:*",
"@nocobase/plugin-collection-manager": "workspace:*",
"@nocobase/plugin-custom-request": "workspace:*",
"@nocobase/plugin-data-source-manager": "workspace:*",
"@nocobase/plugin-data-visualization": "workspace:*",
"@nocobase/plugin-error-handler": "workspace:*",
"@nocobase/plugin-export": "workspace:*",
"@nocobase/plugin-file-manager": "workspace:*",
"@nocobase/plugin-formula-field": "workspace:*",
"@nocobase/plugin-gantt": "workspace:*",
"@nocobase/plugin-graph-collection-manager": "workspace:*",
"@nocobase/plugin-iframe-block": "workspace:*",
"@nocobase/plugin-import": "workspace:*",
"@nocobase/plugin-kanban": "workspace:*",
"@nocobase/plugin-localization-management": "workspace:*",
"@nocobase/plugin-logger": "workspace:*",
"@nocobase/plugin-map": "workspace:*",
"@nocobase/plugin-mock-collections": "workspace:*",
"@nocobase/plugin-multi-app-manager": "workspace:*",
"@nocobase/plugin-multi-app-share-collection": "workspace:*",
"@nocobase/plugin-oidc": "workspace:*",
"@nocobase/plugin-saml": "workspace:*",
"@nocobase/plugin-sequence-field": "workspace:*",
"@nocobase/plugin-sms-auth": "workspace:*",
"@nocobase/plugin-snapshot-field": "workspace:*",
"@nocobase/plugin-theme-editor": "workspace:*",
"@nocobase/plugin-ui-schema-storage": "workspace:*",
"@nocobase/plugin-users": "workspace:*",
"@nocobase/plugin-verification": "workspace:*",
"@tachybase/client": "workspace:*",
"@tachybase/plugin-external-data-source": "workspace:*",
"@tachybase/plugin-mobile-client": "workspace:*",
"@tachybase/plugin-system-settings": "workspace:*",
"@tachybase/plugin-workflow": "workspace:*",
"@tachybase/preset-tachybase": "workspace:*",
"@tachybase/schema": "workspace:*",
"@tachybase/server": "workspace:*",
"cronstrue": "^2.11.0",
"lodash": "4.17.21"
},
"devDependencies": {
"@types/lodash": "^4.17.0"
}
}

3
packages/presets/mini/server.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
export * from './src/server';
export { default } from './src/server';

View File

@ -0,0 +1 @@
module.exports = require('./lib/server/index.js');

View File

@ -0,0 +1,3 @@
import { TachyBaseClientPresetPlugin } from '@tachybase/preset-tachybase/client';
export class PluginMini extends TachyBaseClientPresetPlugin {}

View File

@ -0,0 +1 @@
export { default } from './server';

View File

@ -0,0 +1,31 @@
import PresetTachyBase from '@tachybase/preset-tachybase';
import _ from 'lodash';
export class PluginMini extends PresetTachyBase {
#builtInPlugins = [
'data-source-manager',
'error-handler',
'collection-manager',
'ui-schema-storage',
'file-manager',
'system-settings',
'client',
'auth',
'verification',
'users',
'acl',
'multi-app-manager',
];
#localPlugins = [];
get builtInPlugins() {
return this.#builtInPlugins;
}
get localPlugins() {
return this.#localPlugins;
}
}
export default PluginMini;

View File

@ -55,6 +55,9 @@ importers:
'@tachybase/preset-hera-sancongtou':
specifier: workspace:*
version: link:packages/presets/sancongtou
'@tachybase/preset-mini':
specifier: workspace:*
version: link:packages/presets/mini
'@tachybase/preset-tachybase':
specifier: workspace:*
version: link:packages/presets/base
@ -176,6 +179,9 @@ importers:
'@tachybase/preset-hera-sancongtou':
specifier: workspace:*
version: link:../../presets/sancongtou
'@tachybase/preset-mini':
specifier: workspace:*
version: link:../../presets/mini
'@tachybase/preset-tachybase':
specifier: workspace:*
version: link:../../presets/base
@ -4217,6 +4223,181 @@ importers:
specifier: ^4.17.0
version: 4.17.0
packages/presets/mini:
dependencies:
'@hera/plugin-approval':
specifier: workspace:*
version: link:../../plugins/@hera/plugin-approval
'@hera/plugin-audit-logs':
specifier: workspace:*
version: link:../../plugins/@hera/plugin-audit-logs
'@hera/plugin-core':
specifier: workspace:*
version: link:../../plugins/@hera/plugin-core
'@hera/plugin-homepage':
specifier: workspace:*
version: link:../../plugins/@hera/plugin-homepage
'@hera/plugin-rental':
specifier: workspace:*
version: link:../../plugins/@hera/plugin-rental
'@nocobase/plugin-acl':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-acl
'@nocobase/plugin-action-bulk-edit':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-action-bulk-edit
'@nocobase/plugin-action-bulk-update':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-action-bulk-update
'@nocobase/plugin-action-duplicate':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-action-duplicate
'@nocobase/plugin-action-print':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-action-print
'@nocobase/plugin-api-doc':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-api-doc
'@nocobase/plugin-api-keys':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-api-keys
'@nocobase/plugin-auth':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-auth
'@nocobase/plugin-backup-restore':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-backup-restore
'@nocobase/plugin-calendar':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-calendar
'@nocobase/plugin-cas':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-cas
'@nocobase/plugin-china-region':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-china-region
'@nocobase/plugin-client':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-client
'@nocobase/plugin-collection-manager':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-collection-manager
'@nocobase/plugin-custom-request':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-custom-request
'@nocobase/plugin-data-source-manager':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-data-source-manager
'@nocobase/plugin-data-visualization':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-data-visualization
'@nocobase/plugin-error-handler':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-error-handler
'@nocobase/plugin-export':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-export
'@nocobase/plugin-file-manager':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-file-manager
'@nocobase/plugin-formula-field':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-formula-field
'@nocobase/plugin-gantt':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-gantt
'@nocobase/plugin-graph-collection-manager':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-graph-collection-manager
'@nocobase/plugin-iframe-block':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-iframe-block
'@nocobase/plugin-import':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-import
'@nocobase/plugin-kanban':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-kanban
'@nocobase/plugin-localization-management':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-localization-management
'@nocobase/plugin-logger':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-logger
'@nocobase/plugin-map':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-map
'@nocobase/plugin-mock-collections':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-mock-collections
'@nocobase/plugin-multi-app-manager':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-multi-app-manager
'@nocobase/plugin-multi-app-share-collection':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-multi-app-share-collection
'@nocobase/plugin-oidc':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-oidc
'@nocobase/plugin-saml':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-saml
'@nocobase/plugin-sequence-field':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-sequence-field
'@nocobase/plugin-sms-auth':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-sms-auth
'@nocobase/plugin-snapshot-field':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-snapshot-field
'@nocobase/plugin-theme-editor':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-theme-editor
'@nocobase/plugin-ui-schema-storage':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-ui-schema-storage
'@nocobase/plugin-users':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-users
'@nocobase/plugin-verification':
specifier: workspace:*
version: link:../../plugins/@nocobase/plugin-verification
'@tachybase/client':
specifier: workspace:*
version: link:../../core/client
'@tachybase/plugin-external-data-source':
specifier: workspace:*
version: link:../../plugins/@tachybase/plugin-external-data-source
'@tachybase/plugin-mobile-client':
specifier: workspace:*
version: link:../../plugins/@tachybase/plugin-mobile-client
'@tachybase/plugin-system-settings':
specifier: workspace:*
version: link:../../plugins/@tachybase/plugin-system-settings
'@tachybase/plugin-workflow':
specifier: workspace:*
version: link:../../plugins/@tachybase/plugin-workflow
'@tachybase/preset-tachybase':
specifier: workspace:*
version: link:../base
'@tachybase/schema':
specifier: workspace:*
version: link:../../core/schema
'@tachybase/server':
specifier: workspace:*
version: link:../../core/server
cronstrue:
specifier: ^2.11.0
version: 2.47.0
lodash:
specifier: 4.17.21
version: 4.17.21
devDependencies:
'@types/lodash':
specifier: ^4.17.0
version: 4.17.0
packages/presets/rental:
dependencies:
'@hera/plugin-approval':