@nocobase/client-v2 2.1.0-alpha.40 → 2.1.0-alpha.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/es/Application.d.ts +7 -0
  2. package/es/BaseApplication.d.ts +13 -0
  3. package/es/RouterManager.d.ts +1 -0
  4. package/es/collection-field-interface/CollectionFieldInterface.d.ts +51 -15
  5. package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +82 -3
  6. package/es/collection-manager/field-configure.d.ts +80 -0
  7. package/es/collection-manager/field-validation.d.ts +43 -0
  8. package/es/collection-manager/filter-operators/index.d.ts +46 -0
  9. package/es/collection-manager/filter-operators/operators.d.ts +30 -0
  10. package/es/collection-manager/interfaces/checkbox.d.ts +1 -41
  11. package/es/collection-manager/interfaces/checkboxGroup.d.ts +12 -44
  12. package/es/collection-manager/interfaces/collection.d.ts +12 -51
  13. package/es/collection-manager/interfaces/color.d.ts +1 -16
  14. package/es/collection-manager/interfaces/createdAt.d.ts +1 -44
  15. package/es/collection-manager/interfaces/createdBy.d.ts +0 -4
  16. package/es/collection-manager/interfaces/dateOnly.d.ts +7 -44
  17. package/es/collection-manager/interfaces/datetime.d.ts +1 -44
  18. package/es/collection-manager/interfaces/datetimeNoTz.d.ts +1 -44
  19. package/es/collection-manager/interfaces/email.d.ts +1 -29
  20. package/es/collection-manager/interfaces/id.d.ts +1 -16
  21. package/es/collection-manager/interfaces/index.d.ts +2 -3
  22. package/es/collection-manager/interfaces/input.d.ts +1 -102
  23. package/es/collection-manager/interfaces/integer.d.ts +1 -95
  24. package/es/collection-manager/interfaces/json.d.ts +16 -7
  25. package/es/collection-manager/interfaces/m2m.d.ts +11 -19
  26. package/es/collection-manager/interfaces/m2o.d.ts +11 -19
  27. package/es/collection-manager/interfaces/markdown.d.ts +1 -63
  28. package/es/collection-manager/interfaces/multipleSelect.d.ts +12 -44
  29. package/es/collection-manager/interfaces/nanoid.d.ts +1 -34
  30. package/es/collection-manager/interfaces/number.d.ts +1 -87
  31. package/es/collection-manager/interfaces/o2m.d.ts +12 -24
  32. package/es/collection-manager/interfaces/obo.d.ts +207 -0
  33. package/es/collection-manager/interfaces/oho.d.ts +207 -0
  34. package/es/collection-manager/interfaces/password.d.ts +1 -56
  35. package/es/collection-manager/interfaces/percent.d.ts +1 -84
  36. package/es/collection-manager/interfaces/phone.d.ts +1 -25
  37. package/es/collection-manager/interfaces/properties/index.d.ts +0 -28
  38. package/es/collection-manager/interfaces/radioGroup.d.ts +1 -29
  39. package/es/collection-manager/interfaces/richText.d.ts +1 -63
  40. package/es/collection-manager/interfaces/select.d.ts +12 -44
  41. package/es/collection-manager/interfaces/snowflake-id.d.ts +1 -34
  42. package/es/collection-manager/interfaces/tableoid.d.ts +1 -10
  43. package/es/collection-manager/interfaces/textarea.d.ts +1 -51
  44. package/es/collection-manager/interfaces/time.d.ts +1 -16
  45. package/es/collection-manager/interfaces/types.d.ts +3 -12
  46. package/es/collection-manager/interfaces/unixTimestamp.d.ts +1 -44
  47. package/es/collection-manager/interfaces/updatedAt.d.ts +1 -44
  48. package/es/collection-manager/interfaces/updatedBy.d.ts +0 -4
  49. package/es/collection-manager/interfaces/url.d.ts +1 -20
  50. package/es/collection-manager/interfaces/uuid.d.ts +1 -34
  51. package/es/collection-manager/template-fields.d.ts +53 -0
  52. package/es/components/KeepAlive.d.ts +22 -0
  53. package/es/components/RouterBridge.d.ts +9 -0
  54. package/es/components/form/DialogFormLayout.d.ts +5 -29
  55. package/es/components/form/VariableInput.d.ts +53 -2
  56. package/es/components/form/filter/CollectionFilter.d.ts +49 -0
  57. package/es/components/form/filter/CollectionFilterItem.d.ts +49 -0
  58. package/es/components/form/filter/DateFilterDynamicComponent.d.ts +57 -0
  59. package/es/components/form/filter/FilterValueInput.d.ts +29 -0
  60. package/es/components/form/filter/index.d.ts +11 -0
  61. package/es/components/form/filter/useFilterActionProps.d.ts +96 -0
  62. package/es/components/form/index.d.ts +1 -0
  63. package/es/data-source/ExtendCollectionsProvider.d.ts +50 -0
  64. package/es/data-source/index.d.ts +9 -0
  65. package/es/flow/FlowPage.d.ts +2 -1
  66. package/es/flow/admin-shell/AdminLayoutRouteCoordinator.d.ts +8 -40
  67. package/es/flow/admin-shell/BaseLayoutModel.d.ts +89 -0
  68. package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +74 -0
  69. package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +12 -0
  70. package/es/flow/admin-shell/admin-layout/AdminLayoutModel.d.ts +7 -92
  71. package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +11 -0
  72. package/es/flow/admin-shell/admin-layout/index.d.ts +3 -0
  73. package/es/flow/admin-shell/admin-layout/useApplications.d.ts +3 -2
  74. package/es/flow/admin-shell/useAdminLayoutRoutePage.d.ts +2 -2
  75. package/es/flow/admin-shell/useLayoutRoutePage.d.ts +23 -0
  76. package/es/flow/components/FlowRoute.d.ts +10 -1
  77. package/es/flow/components/filter/index.d.ts +2 -0
  78. package/es/flow/components/filter/useFilterOptions.d.ts +66 -0
  79. package/es/flow/index.d.ts +4 -0
  80. package/es/flow/models/base/PageModel/PageModel.d.ts +3 -1
  81. package/es/flow/models/blocks/assign-form/assignFieldValuesFlow.d.ts +84 -0
  82. package/es/flow/models/blocks/assign-form/index.d.ts +1 -0
  83. package/es/flow/models/blocks/form/FormActionGroupModel.d.ts +1 -0
  84. package/es/flow/models/blocks/form/FormActionModel.d.ts +9 -2
  85. package/es/flow/models/blocks/table/TableBlockModel.d.ts +10 -0
  86. package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.d.ts +1 -1
  87. package/es/flow-compat/passwordUtils.d.ts +1 -1
  88. package/es/index.d.ts +6 -0
  89. package/es/index.mjs +552 -459
  90. package/es/layout-manager/LayoutContentRoute.d.ts +14 -0
  91. package/es/layout-manager/LayoutManager.d.ts +22 -0
  92. package/es/layout-manager/LayoutRoute.d.ts +14 -0
  93. package/es/layout-manager/index.d.ts +13 -0
  94. package/es/layout-manager/types.d.ts +20 -0
  95. package/es/layout-manager/utils.d.ts +14 -0
  96. package/es/nocobase-buildin-plugin/index.d.ts +3 -10
  97. package/es/settings-center/index.d.ts +1 -1
  98. package/es/settings-center/plugin-manager/BulkEnableButton.d.ts +15 -0
  99. package/es/settings-center/plugin-manager/PluginCard.d.ts +15 -0
  100. package/es/settings-center/plugin-manager/PluginDetail.d.ts +16 -0
  101. package/es/settings-center/{PluginManagerPage.d.ts → plugin-manager/index.d.ts} +1 -7
  102. package/es/settings-center/plugin-manager/types.d.ts +34 -0
  103. package/lib/index.js +552 -459
  104. package/package.json +8 -7
  105. package/src/Application.tsx +51 -12
  106. package/src/BaseApplication.tsx +32 -0
  107. package/src/PluginSettingsManager.ts +1 -1
  108. package/src/RouterManager.tsx +17 -1
  109. package/src/__tests__/PluginSettingsManager.test.ts +41 -2
  110. package/src/__tests__/app.test.tsx +17 -1
  111. package/src/__tests__/globalDeps.test.ts +1 -0
  112. package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +45 -2
  113. package/src/__tests__/plugin-manager.test.tsx +177 -0
  114. package/src/__tests__/settings-center.test.tsx +24 -2
  115. package/src/collection-field-interface/CollectionFieldInterface.ts +71 -77
  116. package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +201 -4
  117. package/src/collection-manager/field-configure.ts +548 -0
  118. package/src/collection-manager/field-validation.ts +195 -0
  119. package/src/collection-manager/filter-operators/index.ts +176 -0
  120. package/src/collection-manager/{interfaces/properties → filter-operators}/operators.ts +24 -13
  121. package/src/collection-manager/interfaces/checkbox.ts +2 -9
  122. package/src/collection-manager/interfaces/checkboxGroup.ts +2 -10
  123. package/src/collection-manager/interfaces/collection.ts +2 -15
  124. package/src/collection-manager/interfaces/color.ts +2 -2
  125. package/src/collection-manager/interfaces/createdAt.ts +2 -2
  126. package/src/collection-manager/interfaces/createdBy.ts +1 -12
  127. package/src/collection-manager/interfaces/dateOnly.ts +8 -2
  128. package/src/collection-manager/interfaces/datetime.ts +2 -2
  129. package/src/collection-manager/interfaces/datetimeNoTz.ts +2 -2
  130. package/src/collection-manager/interfaces/email.ts +2 -9
  131. package/src/collection-manager/interfaces/id.ts +1 -2
  132. package/src/collection-manager/interfaces/index.ts +2 -3
  133. package/src/collection-manager/interfaces/input.ts +2 -133
  134. package/src/collection-manager/interfaces/integer.ts +2 -71
  135. package/src/collection-manager/interfaces/json.tsx +17 -11
  136. package/src/collection-manager/interfaces/m2m.tsx +0 -21
  137. package/src/collection-manager/interfaces/m2o.tsx +0 -22
  138. package/src/collection-manager/interfaces/markdown.ts +2 -51
  139. package/src/collection-manager/interfaces/multipleSelect.ts +2 -14
  140. package/src/collection-manager/interfaces/nanoid.ts +2 -2
  141. package/src/collection-manager/interfaces/number.ts +2 -85
  142. package/src/collection-manager/interfaces/o2m.tsx +1 -22
  143. package/src/collection-manager/interfaces/obo.tsx +145 -0
  144. package/src/collection-manager/interfaces/oho.tsx +145 -0
  145. package/src/collection-manager/interfaces/password.ts +2 -44
  146. package/src/collection-manager/interfaces/percent.ts +2 -74
  147. package/src/collection-manager/interfaces/phone.ts +2 -2
  148. package/src/collection-manager/interfaces/properties/index.ts +0 -133
  149. package/src/collection-manager/interfaces/radioGroup.ts +2 -2
  150. package/src/collection-manager/interfaces/richText.ts +2 -51
  151. package/src/collection-manager/interfaces/select.ts +2 -14
  152. package/src/collection-manager/interfaces/snowflake-id.ts +2 -2
  153. package/src/collection-manager/interfaces/tableoid.ts +1 -2
  154. package/src/collection-manager/interfaces/textarea.ts +2 -51
  155. package/src/collection-manager/interfaces/time.ts +2 -2
  156. package/src/collection-manager/interfaces/types.ts +4 -12
  157. package/src/collection-manager/interfaces/unixTimestamp.tsx +2 -2
  158. package/src/collection-manager/interfaces/updatedAt.ts +2 -2
  159. package/src/collection-manager/interfaces/updatedBy.ts +1 -12
  160. package/src/collection-manager/interfaces/url.ts +2 -4
  161. package/src/collection-manager/interfaces/uuid.ts +2 -2
  162. package/src/collection-manager/template-fields.ts +109 -0
  163. package/src/components/KeepAlive.tsx +131 -0
  164. package/src/components/README.md +90 -6
  165. package/src/components/README.zh-CN.md +90 -7
  166. package/src/components/RouterBridge.tsx +28 -4
  167. package/src/components/__tests__/KeepAlive.test.tsx +63 -0
  168. package/src/components/__tests__/RouterBridge.test.tsx +27 -0
  169. package/src/components/form/DialogFormLayout.tsx +5 -29
  170. package/src/components/form/VariableInput.tsx +101 -28
  171. package/src/components/form/__tests__/VariableInput.test.ts +85 -0
  172. package/src/components/form/filter/CollectionFilter.tsx +111 -0
  173. package/src/components/form/filter/CollectionFilterItem.tsx +184 -0
  174. package/src/components/form/filter/DateFilterDynamicComponent.tsx +283 -0
  175. package/src/components/form/filter/FilterValueInput.tsx +198 -0
  176. package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +247 -0
  177. package/src/components/form/filter/__tests__/DateFilterDynamicComponent.test.tsx +148 -0
  178. package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +243 -0
  179. package/src/components/form/filter/__tests__/compileFilterGroup.test.ts +146 -0
  180. package/src/components/form/filter/index.ts +13 -0
  181. package/src/components/form/filter/useFilterActionProps.ts +203 -0
  182. package/src/components/form/index.tsx +1 -0
  183. package/src/data-source/ExtendCollectionsProvider.tsx +144 -0
  184. package/src/data-source/__tests__/ExtendCollectionsProvider.test.tsx +264 -0
  185. package/src/data-source/index.ts +10 -0
  186. package/src/flow/FlowPage.tsx +35 -7
  187. package/src/flow/__tests__/FlowPage.test.tsx +79 -0
  188. package/src/flow/__tests__/FlowRoute.test.tsx +529 -2
  189. package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +191 -0
  190. package/src/flow/actions/__tests__/openView.subModelKey.test.tsx +33 -0
  191. package/src/flow/actions/aclCheck.tsx +4 -0
  192. package/src/flow/actions/aclCheckRefresh.tsx +4 -0
  193. package/src/flow/actions/dateTimeFormat.tsx +12 -8
  194. package/src/flow/actions/linkageRules.tsx +122 -0
  195. package/src/flow/actions/openView.tsx +28 -4
  196. package/src/flow/admin-shell/AdminLayoutRouteCoordinator.ts +11 -329
  197. package/src/flow/admin-shell/BaseLayoutModel.tsx +455 -0
  198. package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +502 -0
  199. package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +547 -3
  200. package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +35 -7
  201. package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +160 -0
  202. package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +0 -12
  203. package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +28 -201
  204. package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +11 -2
  205. package/src/flow/admin-shell/admin-layout/AppListRender.tsx +139 -0
  206. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +1 -26
  207. package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +149 -27
  208. package/src/flow/admin-shell/admin-layout/index.ts +3 -0
  209. package/src/flow/admin-shell/admin-layout/useApplications.tsx +34 -1
  210. package/src/flow/admin-shell/useAdminLayoutRoutePage.ts +10 -26
  211. package/src/flow/admin-shell/useLayoutRoutePage.ts +61 -0
  212. package/src/flow/components/AdminLayout.tsx +4 -154
  213. package/src/flow/components/FlowRoute.tsx +105 -15
  214. package/src/flow/components/filter/index.ts +3 -0
  215. package/src/flow/components/filter/useFilterOptions.ts +102 -0
  216. package/src/flow/index.ts +4 -0
  217. package/src/flow/models/actions/UpdateRecordActionModel.tsx +14 -95
  218. package/src/flow/models/actions/UpdateRecordActionUtils.ts +4 -7
  219. package/src/flow/models/actions/__tests__/AssignFormRefill.test.ts +26 -1
  220. package/src/flow/models/base/ActionModel.tsx +8 -1
  221. package/src/flow/models/base/PageModel/PageModel.tsx +51 -18
  222. package/src/flow/models/base/PageModel/RootPageModel.tsx +6 -13
  223. package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +102 -1
  224. package/src/flow/models/base/RouteModel.tsx +1 -1
  225. package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +63 -2
  226. package/src/flow/models/blocks/assign-form/assignFieldValuesFlow.tsx +206 -0
  227. package/src/flow/models/blocks/assign-form/index.ts +1 -0
  228. package/src/flow/models/blocks/form/FormActionGroupModel.tsx +14 -0
  229. package/src/flow/models/blocks/form/FormActionModel.tsx +30 -3
  230. package/src/flow/models/blocks/form/FormItemModel.tsx +8 -1
  231. package/src/flow/models/blocks/form/__tests__/FormActionGroupModel.test.ts +46 -0
  232. package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +71 -0
  233. package/src/flow/models/blocks/form/submitHandler.ts +8 -1
  234. package/src/flow/models/blocks/form/submitValues.ts +4 -1
  235. package/src/flow/models/blocks/table/TableBlockModel.tsx +118 -16
  236. package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +114 -0
  237. package/src/flow/models/fields/AssociationFieldModel/SubFormFieldModel.tsx +7 -1
  238. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +1 -1
  239. package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -5
  240. package/src/flow/models/fields/ClickableFieldModel.tsx +9 -1
  241. package/src/flow/models/fields/CollectionSelectorFieldModel.tsx +8 -2
  242. package/src/flow/models/fields/DisplayEnumFieldModel.tsx +8 -2
  243. package/src/flow/models/fields/DisplayTimeFieldModel.tsx +1 -1
  244. package/src/flow/models/fields/TimeFieldModel.tsx +1 -1
  245. package/src/flow/models/fields/__tests__/TimeFieldModel.test.tsx +61 -0
  246. package/src/flow/models/fields/mobile-components/MobileDatePicker.tsx +19 -3
  247. package/src/flow/models/fields/mobile-components/__tests__/MobileDatePicker.test.tsx +94 -0
  248. package/src/flow/models/topbar/TopbarActionModel.tsx +1 -1
  249. package/src/flow/utils/__tests__/dateTimeFormat.test.ts +91 -0
  250. package/src/index.ts +6 -0
  251. package/src/layout-manager/LayoutContentRoute.tsx +90 -0
  252. package/src/layout-manager/LayoutManager.tsx +185 -0
  253. package/src/layout-manager/LayoutRoute.tsx +138 -0
  254. package/src/layout-manager/__tests__/LayoutManager.test.tsx +335 -0
  255. package/src/layout-manager/__tests__/LayoutRoute.test.tsx +473 -0
  256. package/src/layout-manager/index.ts +14 -0
  257. package/src/layout-manager/types.ts +22 -0
  258. package/src/layout-manager/utils.ts +37 -0
  259. package/src/nocobase-buildin-plugin/index.tsx +69 -67
  260. package/src/nocobase-buildin-plugin/plugins/LocalePlugin.ts +1 -0
  261. package/src/settings-center/index.ts +1 -1
  262. package/src/settings-center/plugin-manager/BulkEnableButton.tsx +111 -0
  263. package/src/settings-center/plugin-manager/PluginCard.tsx +270 -0
  264. package/src/settings-center/plugin-manager/PluginDetail.tsx +195 -0
  265. package/src/settings-center/plugin-manager/index.tsx +254 -0
  266. package/src/settings-center/plugin-manager/types.ts +35 -0
  267. package/src/settings-center/utils.tsx +8 -1
  268. package/src/theme/__tests__/globalStyles.test.ts +24 -0
  269. package/src/theme/globalStyles.ts +10 -0
  270. package/src/utils/globalDeps.ts +2 -0
  271. package/es/collection-manager/interfaces/linkTo.d.ts +0 -90
  272. package/es/collection-manager/interfaces/o2o.d.ts +0 -621
  273. package/es/collection-manager/interfaces/properties/operators.d.ts +0 -294
  274. package/es/collection-manager/interfaces/subTable.d.ts +0 -172
  275. package/src/collection-manager/interfaces/linkTo.ts +0 -120
  276. package/src/collection-manager/interfaces/o2o.tsx +0 -561
  277. package/src/collection-manager/interfaces/subTable.ts +0 -218
  278. package/src/settings-center/PluginManagerPage.tsx +0 -162
@@ -0,0 +1,195 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { useRequest } from 'ahooks';
11
+ import { Alert, Col, Modal, Row, Space, Spin, Table, Tabs, theme, Typography } from 'antd';
12
+ import type { TabsProps } from 'antd';
13
+ import React, { FC, useMemo } from 'react';
14
+ import { useTranslation } from 'react-i18next';
15
+ import { useApp } from '../../hooks/useApp';
16
+ import type { IPluginData } from './types';
17
+
18
+ type Author =
19
+ | string
20
+ | {
21
+ name: string;
22
+ email?: string;
23
+ url?: string;
24
+ };
25
+
26
+ interface PackageJSON {
27
+ name: string;
28
+ version: string;
29
+ description?: string;
30
+ repository?: string | { type: string; url: string };
31
+ homepage?: string;
32
+ license?: string;
33
+ author?: Author;
34
+ devDependencies?: Record<string, string>;
35
+ dependencies?: Record<string, string>;
36
+ }
37
+
38
+ interface DepCompatible {
39
+ name: string;
40
+ result: boolean;
41
+ versionRange: string;
42
+ packageVersion: string;
43
+ }
44
+
45
+ interface IPluginDetailData {
46
+ packageJson: PackageJSON;
47
+ homepage?: string;
48
+ depsCompatible: DepCompatible[] | false;
49
+ isCompatible?: boolean;
50
+ lastUpdated: string;
51
+ }
52
+
53
+ interface IPluginDetailProps {
54
+ plugin: IPluginData;
55
+ onCancel: () => void;
56
+ }
57
+
58
+ export const PluginDetail: FC<IPluginDetailProps> = ({ plugin, onCancel }) => {
59
+ const { t } = useTranslation();
60
+ const { token } = theme.useToken();
61
+ const app = useApp();
62
+
63
+ const { data, loading } = useRequest<IPluginDetailData | undefined, []>(
64
+ async () => {
65
+ const response = await app.apiClient.request({
66
+ url: 'pm:get',
67
+ params: { filterByTk: plugin.name },
68
+ skipNotify: true,
69
+ });
70
+ return response?.data?.data as IPluginDetailData | undefined;
71
+ },
72
+ {
73
+ refreshDeps: [plugin.name],
74
+ ready: !!plugin.name,
75
+ },
76
+ );
77
+
78
+ const dependenciesCompatibleTableColumns = useMemo(
79
+ () => [
80
+ { title: t('Name'), dataIndex: 'name', key: 'name' },
81
+ { title: t('Version range'), dataIndex: 'versionRange', key: 'versionRange' },
82
+ { title: t("Plugin's version"), dataIndex: 'packageVersion', key: 'packageVersion' },
83
+ {
84
+ title: t('Result'),
85
+ dataIndex: 'result',
86
+ key: 'result',
87
+ render: (result: boolean) => (
88
+ <Typography.Text type={result ? 'success' : 'danger'}>{result ? t('Yes') : t('No')}</Typography.Text>
89
+ ),
90
+ },
91
+ ],
92
+ [t],
93
+ );
94
+
95
+ const repository = useMemo(() => {
96
+ const repo = data?.packageJson?.repository;
97
+ if (!repo) return null;
98
+ const url = typeof repo === 'string' ? repo : repo.url;
99
+ return url.replace(/\.git$/, '').replace(/^git\+/, '');
100
+ }, [data]);
101
+
102
+ const author = useMemo(() => {
103
+ const a = data?.packageJson?.author;
104
+ if (!a) return null;
105
+ if (typeof a === 'string') return a;
106
+ return a.name;
107
+ }, [data]);
108
+
109
+ const infoRow = (label: string, value: React.ReactNode) => (
110
+ <Col span={24}>
111
+ <div style={{ display: 'flex', flexDirection: 'column', gap: token.marginXXS, marginBottom: token.marginSM }}>
112
+ <Typography.Text type="secondary">{label}</Typography.Text>
113
+ <Typography.Text strong>{value}</Typography.Text>
114
+ </div>
115
+ </Col>
116
+ );
117
+
118
+ const tabItems: TabsProps['items'] = [
119
+ {
120
+ key: 'readme',
121
+ label: t('Readme'),
122
+ children: (
123
+ <Row gutter={token.marginLG}>
124
+ {plugin.name && infoRow(t('Name'), plugin.name)}
125
+ {plugin.displayName && infoRow(t('DisplayName'), plugin.displayName)}
126
+ {infoRow(t('PackageName'), plugin.packageName)}
127
+ {repository && infoRow(t('Repository'), repository)}
128
+ {data?.homepage &&
129
+ infoRow(
130
+ t('Homepage'),
131
+ <a href={data.homepage} target="_blank" rel="noreferrer">
132
+ {data.homepage}
133
+ </a>,
134
+ )}
135
+ {plugin.description && infoRow(t('Description'), plugin.description)}
136
+ {data?.packageJson?.license && infoRow(t('License'), data.packageJson.license)}
137
+ {author && infoRow(t('Author'), author)}
138
+ {infoRow(t('Version'), plugin.version)}
139
+ </Row>
140
+ ),
141
+ },
142
+ {
143
+ key: 'dependencies',
144
+ label: t('Dependencies compatibility check'),
145
+ children: (
146
+ <>
147
+ {data?.depsCompatible === false ? (
148
+ <Typography.Text type="danger">
149
+ {t('`dist/externalVersion.js` not found or failed to `require`. Please rebuild this plugin.')}
150
+ </Typography.Text>
151
+ ) : (
152
+ <>
153
+ {data && !data.isCompatible && (
154
+ <Alert
155
+ showIcon
156
+ type="error"
157
+ message={t(
158
+ 'Plugin dependencies check failed, you should change the dependent version to meet the version requirements.',
159
+ )}
160
+ />
161
+ )}
162
+ <Table
163
+ style={{ marginTop: token.margin }}
164
+ rowKey="name"
165
+ pagination={false}
166
+ columns={dependenciesCompatibleTableColumns}
167
+ dataSource={Array.isArray(data?.depsCompatible) ? data.depsCompatible : []}
168
+ />
169
+ </>
170
+ )}
171
+ </>
172
+ ),
173
+ },
174
+ ];
175
+
176
+ return (
177
+ <Modal open footer={false} destroyOnClose width={600} onCancel={onCancel}>
178
+ {loading ? (
179
+ <Spin />
180
+ ) : (
181
+ <>
182
+ <Typography.Title level={3}>{plugin.packageName}</Typography.Title>
183
+ <Space split={<span>&nbsp;•&nbsp;</span>}>
184
+ <span>{plugin.version}</span>
185
+ </Space>
186
+ <Tabs
187
+ style={{ minHeight: '50vh' }}
188
+ items={tabItems}
189
+ defaultActiveKey={plugin.isCompatible === false ? 'dependencies' : 'readme'}
190
+ />
191
+ </>
192
+ )}
193
+ </Modal>
194
+ );
195
+ };
@@ -0,0 +1,254 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { MenuOutlined } from '@ant-design/icons';
11
+ import { useDebounce, useMemoizedFn, useRequest } from 'ahooks';
12
+ import { Alert, Button, Card, Divider, Flex, Grid, Input, List, Popover, Space, Spin, theme } from 'antd';
13
+ import _ from 'lodash';
14
+ import React, { useMemo, useState } from 'react';
15
+ import { useTranslation } from 'react-i18next';
16
+ import { useApp } from '../../hooks/useApp';
17
+ import { BulkEnableButton } from './BulkEnableButton';
18
+ import { PluginCard } from './PluginCard';
19
+ import type { IPluginData } from './types';
20
+
21
+ const KEYWORDS = [
22
+ 'Data model tools',
23
+ 'Data sources',
24
+ 'Collections',
25
+ 'Collection fields',
26
+ 'Blocks',
27
+ 'Actions',
28
+ 'Workflow',
29
+ 'Users & permissions',
30
+ 'AI',
31
+ 'Authentication',
32
+ 'Notification',
33
+ 'System management',
34
+ 'Security',
35
+ 'Architecture',
36
+ 'Logging and monitoring',
37
+ 'Others',
38
+ ];
39
+
40
+ const FILTER_TYPES = ['All', 'Built-in', 'Enabled', 'Not enabled', 'Problematic'] as const;
41
+ type FilterType = (typeof FILTER_TYPES)[number];
42
+
43
+ const SIDEBAR_WIDTH = 200;
44
+
45
+ function hasIntersection(arr1?: string[], arr2?: string[]) {
46
+ if (!Array.isArray(arr1) || !Array.isArray(arr2)) return false;
47
+ return arr1.some((item) => arr2.includes(item));
48
+ }
49
+
50
+ function CategoryList({
51
+ items,
52
+ activeKeyword,
53
+ onSelect,
54
+ }: {
55
+ items: { key: string; list?: IPluginData[] }[];
56
+ activeKeyword: string | null;
57
+ onSelect: (key: string) => void;
58
+ }) {
59
+ const { t } = useTranslation();
60
+ return (
61
+ <List
62
+ size="small"
63
+ dataSource={items}
64
+ split={false}
65
+ renderItem={(item) => (
66
+ <List.Item style={{ padding: '3px 0', cursor: 'pointer' }} onClick={() => onSelect(item.key)}>
67
+ <a style={{ fontWeight: activeKeyword === item.key ? 'bold' : 'normal' }}>{t(item.key)}</a>
68
+ </List.Item>
69
+ )}
70
+ />
71
+ );
72
+ }
73
+
74
+ export const PluginManagerPage: React.FC = () => {
75
+ const { t } = useTranslation();
76
+ const { token } = theme.useToken();
77
+ const app = useApp();
78
+ const screens = Grid.useBreakpoint();
79
+ const isWide = !!screens.md;
80
+
81
+ const {
82
+ data: plugins = [],
83
+ loading,
84
+ error,
85
+ } = useRequest<IPluginData[], []>(
86
+ async () => {
87
+ const response = await app.apiClient.request({
88
+ url: 'pm:list',
89
+ skipNotify: true,
90
+ });
91
+ return Array.isArray(response?.data?.data) ? response.data.data : [];
92
+ },
93
+ { cacheKey: 'pm:list' },
94
+ );
95
+
96
+ const filterBuckets = useMemo<{ type: FilterType; list: IPluginData[] }[]>(() => {
97
+ const list = [...plugins].reverse();
98
+ return [
99
+ { type: 'All', list },
100
+ { type: 'Built-in', list: _.filter(list, (item) => item.builtIn) },
101
+ { type: 'Enabled', list: _.filter(list, (item) => item.enabled) },
102
+ { type: 'Not enabled', list: _.filter(list, (item) => !item.enabled) },
103
+ { type: 'Problematic', list: _.filter(list, (item) => !item.isCompatible) },
104
+ ];
105
+ }, [plugins]);
106
+
107
+ const [filterIndex, setFilterIndex] = useState(0);
108
+ const [searchValue, setSearchValue] = useState('');
109
+ const [keyword, setKeyword] = useState<string | null>(null);
110
+ const [categoryOpen, setCategoryOpen] = useState(false);
111
+ const debouncedSearchValue = useDebounce(searchValue, { wait: 100 });
112
+
113
+ const keywordBuckets = useMemo(
114
+ () =>
115
+ KEYWORDS.map((k) => {
116
+ if (k === 'Others') {
117
+ return { key: k, list: plugins.filter((v) => !hasIntersection(v.keywords, KEYWORDS)) };
118
+ }
119
+ return { key: k, list: plugins.filter((v) => v.keywords?.includes(k)) };
120
+ }),
121
+ [plugins],
122
+ );
123
+
124
+ const pluginList = useMemo(() => {
125
+ let list = filterBuckets[filterIndex]?.list || [];
126
+ if (keyword) {
127
+ const byKeyword = keywordBuckets.find((v) => v.key === keyword)?.list || [];
128
+ if (filterIndex === 0) {
129
+ list = byKeyword;
130
+ } else {
131
+ list = byKeyword.filter((v) => list.find((k) => k.name === v.name));
132
+ }
133
+ }
134
+ const searchLower = debouncedSearchValue.toLowerCase().trim();
135
+ if (searchLower) {
136
+ list = _.filter(
137
+ list,
138
+ (item) =>
139
+ String(item.displayName || '')
140
+ .toLowerCase()
141
+ .includes(searchLower) ||
142
+ String(item.description || '')
143
+ .toLowerCase()
144
+ .includes(searchLower),
145
+ );
146
+ }
147
+ return [...list].sort((a, b) => (a.displayName || '').localeCompare(b.displayName || ''));
148
+ }, [filterIndex, filterBuckets, debouncedSearchValue, keyword, keywordBuckets]);
149
+
150
+ const handleKeywordSelect = useMemoizedFn((key: string) => {
151
+ setKeyword((prev) => (prev === key ? null : key));
152
+ setCategoryOpen(false);
153
+ });
154
+
155
+ const handleSearchChange = useMemoizedFn((e: React.ChangeEvent<HTMLInputElement>) => {
156
+ setSearchValue(e.target.value);
157
+ });
158
+
159
+ if (loading) {
160
+ return <Spin />;
161
+ }
162
+
163
+ const filterTabs = (
164
+ <Space size={token.marginXXS} split={<Divider type="vertical" />} wrap>
165
+ {!isWide && (
166
+ <Popover
167
+ trigger="click"
168
+ placement="bottomLeft"
169
+ open={categoryOpen}
170
+ onOpenChange={setCategoryOpen}
171
+ content={
172
+ <div style={{ minWidth: 180, maxHeight: '60vh', overflowY: 'auto' }}>
173
+ <CategoryList items={keywordBuckets} activeKeyword={keyword} onSelect={handleKeywordSelect} />
174
+ </div>
175
+ }
176
+ >
177
+ <Button type="text" size="small" icon={<MenuOutlined />} aria-label={t('Category')} />
178
+ </Popover>
179
+ )}
180
+ {filterBuckets.map((item, index) => (
181
+ <a
182
+ role="button"
183
+ aria-label={item.type}
184
+ onClick={() => setFilterIndex(index)}
185
+ key={item.type}
186
+ style={{ fontWeight: filterIndex === index ? 'bold' : 'normal' }}
187
+ >
188
+ {t(item.type)}
189
+ {filterIndex === index ? `(${pluginList.length})` : null}
190
+ </a>
191
+ ))}
192
+ </Space>
193
+ );
194
+
195
+ const topBar = (
196
+ <Flex
197
+ wrap="wrap"
198
+ gap={token.margin}
199
+ align="center"
200
+ justify="space-between"
201
+ style={{ marginBottom: token.marginLG }}
202
+ >
203
+ {filterTabs}
204
+ <Flex gap={token.marginSM} align="center" style={{ flex: '1 1 auto', justifyContent: 'flex-end' }}>
205
+ <Input
206
+ allowClear
207
+ placeholder={t('Search plugin')}
208
+ onChange={handleSearchChange}
209
+ style={{ flex: '1 1 auto', maxWidth: 320, minWidth: 160 }}
210
+ />
211
+ <div style={{ flexShrink: 0 }}>
212
+ <BulkEnableButton plugins={plugins} />
213
+ </div>
214
+ </Flex>
215
+ </Flex>
216
+ );
217
+
218
+ return (
219
+ <>
220
+ {error ? (
221
+ <Alert
222
+ showIcon
223
+ type="error"
224
+ message={t('Failed to load plugins')}
225
+ description={error.message}
226
+ style={{ marginBottom: token.marginLG }}
227
+ />
228
+ ) : null}
229
+ {topBar}
230
+ <Flex gap={token.margin} align="flex-start">
231
+ {isWide && (
232
+ <Card style={{ width: SIDEBAR_WIDTH, flexShrink: 0 }} size="small">
233
+ <CategoryList items={keywordBuckets} activeKeyword={keyword} onSelect={handleKeywordSelect} />
234
+ </Card>
235
+ )}
236
+ <div
237
+ style={{
238
+ flex: '1 1 auto',
239
+ minWidth: 0,
240
+ display: 'grid',
241
+ gap: token.margin,
242
+ gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))',
243
+ }}
244
+ >
245
+ {pluginList.map((item) => (
246
+ <PluginCard key={item.name} data={item} />
247
+ ))}
248
+ </div>
249
+ </Flex>
250
+ </>
251
+ );
252
+ };
253
+
254
+ export default PluginManagerPage;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ export interface IPluginData {
11
+ id: number;
12
+ createdAt: Date;
13
+ updatedAt: Date;
14
+ name: string;
15
+ displayName: string;
16
+ packageName: string;
17
+ version: string;
18
+ enabled: boolean;
19
+ removable?: boolean;
20
+ installed: boolean;
21
+ builtIn: boolean;
22
+ registry?: string;
23
+ authToken?: string;
24
+ compressedFileUrl?: string;
25
+ options: Record<string, unknown>;
26
+ description?: string;
27
+ type: 'npm' | 'upload' | 'url';
28
+ isCompatible?: boolean;
29
+ readmeUrl: string;
30
+ changelogUrl: string;
31
+ error: boolean;
32
+ updatable?: boolean;
33
+ homepage?: string;
34
+ keywords?: string[];
35
+ }
@@ -142,7 +142,14 @@ export function matchSettingsRoute(data: Record<string, PluginSettingsPageType>,
142
142
  }
143
143
  }
144
144
 
145
- return null;
145
+ const matchedPrefix = paths
146
+ .filter((pattern) => {
147
+ const regexPattern = pattern.replace(/:[^/]+/g, '[^/]+');
148
+ return url.match(new RegExp(`^${regexPattern}/`));
149
+ })
150
+ .sort((a, b) => b.length - a.length)[0];
151
+
152
+ return matchedPrefix ? data[matchedPrefix] : null;
146
153
  }
147
154
 
148
155
  /**
@@ -0,0 +1,24 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { describe, expect, it } from 'vitest';
11
+ import '../globalStyles';
12
+
13
+ describe('client-v2 global styles', () => {
14
+ it('includes flow view visibility classes used by drawer and dialog views', () => {
15
+ const styleText = Array.from(document.querySelectorAll('style'))
16
+ .map((style) => style.textContent || '')
17
+ .join('\n');
18
+
19
+ expect(styleText).toContain('.nb-hidden');
20
+ expect(styleText).toContain('display:none');
21
+ expect(styleText).toContain('.nb-dialog-overflow-hidden .ant-modal-content');
22
+ expect(styleText).toContain('overflow:hidden');
23
+ });
24
+ });
@@ -18,4 +18,14 @@ injectGlobal`
18
18
  .ant-form-item-label > label {
19
19
  font-weight: 600;
20
20
  }
21
+
22
+ .nb-hidden {
23
+ display: none;
24
+ }
25
+
26
+ .nb-dialog-overflow-hidden {
27
+ .ant-modal-content {
28
+ overflow: hidden;
29
+ }
30
+ }
21
31
  `;
@@ -10,6 +10,7 @@
10
10
  import * as antdCssinjs from '@ant-design/cssinjs';
11
11
  import * as antdIcons from '@ant-design/icons';
12
12
  import * as antdStyle from 'antd-style';
13
+ import * as ctrlTinycolor from '@ctrl/tinycolor';
13
14
  import * as emotionCss from '@emotion/css';
14
15
  import * as formilyAntdV5 from '@formily/antd-v5';
15
16
  import * as formilyCore from '@formily/core';
@@ -96,6 +97,7 @@ export function defineGlobalDeps(requirejs: RequireJS) {
96
97
  defineGlobalDep(requirejs, '@dnd-kit/sortable', dndKitSortable);
97
98
 
98
99
  // utils
100
+ defineGlobalDep(requirejs, '@ctrl/tinycolor', ctrlTinycolor);
99
101
  defineGlobalDep(requirejs, 'ahooks', ahooks);
100
102
  defineGlobalDep(requirejs, 'axios', axios);
101
103
  defineGlobalDep(requirejs, 'dayjs', dayjs);
@@ -1,90 +0,0 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
- import { ISchema } from '@formily/react';
10
- import { CollectionFieldInterface } from '../../collection-field-interface/CollectionFieldInterface';
11
- export declare class LinkToFieldInterface extends CollectionFieldInterface {
12
- name: string;
13
- type: string;
14
- group: string;
15
- order: number;
16
- title: string;
17
- description: string;
18
- isAssociation: boolean;
19
- default: {
20
- type: string;
21
- uiSchema: {
22
- 'x-component': string;
23
- 'x-component-props': {
24
- multiple: boolean;
25
- fieldNames: {
26
- label: string;
27
- value: string;
28
- };
29
- };
30
- };
31
- reverseField: {
32
- interface: string;
33
- type: string;
34
- uiSchema: {
35
- 'x-component': string;
36
- 'x-component-props': {
37
- multiple: boolean;
38
- fieldNames: {
39
- label: string;
40
- value: string;
41
- };
42
- };
43
- };
44
- };
45
- };
46
- schemaInitialize(schema: ISchema, { readPretty, block, targetCollection }: {
47
- readPretty: any;
48
- block: any;
49
- targetCollection: any;
50
- }): void;
51
- initialize: (values: any) => void;
52
- properties: {
53
- target: {
54
- type: string;
55
- title: string;
56
- required: boolean;
57
- 'x-reactions': string[];
58
- 'x-decorator': string;
59
- 'x-component': string;
60
- 'x-disabled': string;
61
- };
62
- 'uiSchema.x-component-props.multiple': {
63
- type: string;
64
- 'x-content': string;
65
- 'x-decorator': string;
66
- 'x-component': string;
67
- };
68
- 'uiSchema.title': {
69
- type: string;
70
- title: string;
71
- required: boolean;
72
- 'x-decorator': string;
73
- 'x-component': string;
74
- };
75
- name: {
76
- type: string;
77
- title: string;
78
- required: boolean;
79
- 'x-disabled': string;
80
- 'x-decorator': string;
81
- 'x-component': string;
82
- 'x-validator': string;
83
- description: string;
84
- };
85
- };
86
- filterable: {
87
- nested: boolean;
88
- children: any[];
89
- };
90
- }