plugin-migration-manager 2.0.1 → 2.0.3

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.
@@ -0,0 +1,22 @@
1
+ import { Application, Plugin } from '@nocobase/client-v2';
2
+
3
+ export class PluginMigrationManagerClient extends Plugin<Record<string, never>, Application> {
4
+ async load() {
5
+ this.pluginSettingsManager.addMenuItem({
6
+ key: 'migration-manager',
7
+ title: this.t('Migration Manager'),
8
+ icon: 'SwapOutlined',
9
+ aclSnippet: 'pm.plugin-migration-manager',
10
+ });
11
+
12
+ this.pluginSettingsManager.addPageTabItem({
13
+ menuKey: 'migration-manager',
14
+ key: 'index',
15
+ title: this.t('Migration Manager'),
16
+ aclSnippet: 'pm.plugin-migration-manager',
17
+ componentLoader: () => import('./pages/MigrationPage'),
18
+ });
19
+ }
20
+ }
21
+
22
+ export default PluginMigrationManagerClient;
@@ -1,8 +1,68 @@
1
- {
2
- "Migration Manager": "Migration Manager",
3
- "Export": "Export",
4
- "Import": "Import",
5
- "Collections": "Collections",
6
- "Workflows": "Workflows",
7
- "UI Schemas": "UI Schemas"
8
- }
1
+ {
2
+ "Migration Manager": "Migration Manager",
3
+ "Export and import collections, workflows, and UI schemas across NocoBase instances": "Export and import collections, workflows, and UI schemas across NocoBase instances",
4
+ "Export": "Export",
5
+ "Import": "Import",
6
+ "Collections": "Collections",
7
+ "Workflows": "Workflows",
8
+ "UI Schemas": "UI Schemas",
9
+ "UI Schemas/Routes": "UI Schemas/Routes",
10
+ "Filter by Title": "Filter by Title",
11
+ "Name": "Name",
12
+ "Title": "Title",
13
+ "Fields": "Fields",
14
+ "Key": "Key",
15
+ "Status": "Status",
16
+ "Enabled": "Enabled",
17
+ "Disabled": "Disabled",
18
+ "Menu / Page": "Menu / Page",
19
+ "UID": "UID",
20
+ "Untitled": "Untitled",
21
+ "Export Selected Items": "Export Selected Items",
22
+ "Import from Development to Production": "Import from Development to Production",
23
+ "Upload the exported JSON file from the development server.": "Upload the exported JSON file from the development server.",
24
+ "What will be imported:": "What will be imported:",
25
+ "Collection structure (without data)": "Collection structure (without data)",
26
+ "Workflow configuration": "Workflow configuration",
27
+ "UI Schema/Page design": "UI Schema/Page design",
28
+ "What will NOT be affected:": "What will NOT be affected:",
29
+ "Data within collections": "Data within collections",
30
+ "Collections not present in the import file": "Collections not present in the import file",
31
+ "Upload Migration File (.json)": "Upload Migration File (.json)",
32
+ "Export succeeded but no data.": "Export succeeded but no data.",
33
+ "Export successful! {{collections}} collections, {{workflows}} workflows, {{uiSchemas}} UI schemas, {{routes}} routes": "Export successful! {{collections}} collections, {{workflows}} workflows, {{uiSchemas}} UI schemas, {{routes}} routes",
34
+ "Export failed: {{message}}": "Export failed: {{message}}",
35
+ "Import failed: {{message}}": "Import failed: {{message}}",
36
+ "Unknown error": "Unknown error",
37
+ "Apply failed after several attempts.": "Apply failed after several attempts.",
38
+ "Confirm Potentially Data-Altering Changes": "Confirm Potentially Data-Altering Changes",
39
+ "Proceed & Override": "Proceed & Override",
40
+ "Cancel": "Cancel",
41
+ "Conflicts were found on existing fields.": "Conflicts were found on existing fields.",
42
+ "Collection": "Collection",
43
+ "Field": "Field",
44
+ "Current": "Current",
45
+ "Incoming": "Incoming",
46
+ "Import Successful": "Import Successful",
47
+ "succeeded": "succeeded",
48
+ "failed": "failed",
49
+ "Some errors occurred": "Some errors occurred",
50
+ "Continue": "Continue",
51
+ "Apply Complete": "Apply Complete",
52
+ "The changes have been successfully applied. Click Continue to refresh the page for the changes to take effect.": "The changes have been successfully applied. Click Continue to refresh the page for the changes to take effect.",
53
+ "Errors occurred during apply": "Errors occurred during apply",
54
+ "item": "item",
55
+ "Apply failed": "Apply failed",
56
+ "Select at least one item to export": "Select at least one item to export",
57
+ "Export Confirmation": "Export Confirmation",
58
+ "You will export:": "You will export:",
59
+ "Note": "Note",
60
+ "Export includes collection structure, workflow config, UI schema subtree, and desktop routes.": "Export includes collection structure, workflow config, UI schema subtree, and desktop routes.",
61
+ "Import Confirmation": "Import Confirmation",
62
+ "The file will import:": "The file will import:",
63
+ "Warning": "Warning",
64
+ "The first step will run a PREVIEW. If safe, the process will proceed automatically.": "The first step will run a PREVIEW. If safe, the process will proceed automatically.",
65
+ "Invalid or corrupt file": "Invalid or corrupt file",
66
+ "Restarting...": "Restarting...",
67
+ "Applying...": "Applying..."
68
+ }
@@ -1,8 +1,10 @@
1
- {
2
- "Migration Manager": "Manajer Migrasi",
3
- "Export": "Ekspor",
4
- "Import": "Impor",
5
- "Collections": "Koleksi",
6
- "Workflows": "Alur Kerja",
7
- "UI Schemas": "Skema UI"
8
- }
1
+ {
2
+ "Migration Manager": "Manajer Migrasi",
3
+ "Export": "Ekspor",
4
+ "Import": "Impor",
5
+ "Collections": "Koleksi",
6
+ "Workflows": "Alur Kerja",
7
+ "UI Schemas": "Skema UI",
8
+ "Export Selected Items": "Ekspor Item Terpilih",
9
+ "Upload Migration File (.json)": "Unggah File Migrasi (.json)"
10
+ }
@@ -0,0 +1,68 @@
1
+ {
2
+ "Migration Manager": "迁移管理器",
3
+ "Export and import collections, workflows, and UI schemas across NocoBase instances": "在 NocoBase 实例之间导出和导入数据表、工作流和 UI Schema",
4
+ "Export": "导出",
5
+ "Import": "导入",
6
+ "Collections": "数据表",
7
+ "Workflows": "工作流",
8
+ "UI Schemas": "UI Schema",
9
+ "UI Schemas/Routes": "UI Schema/路由",
10
+ "Filter by Title": "按标题筛选",
11
+ "Name": "名称",
12
+ "Title": "标题",
13
+ "Fields": "字段",
14
+ "Key": "标识",
15
+ "Status": "状态",
16
+ "Enabled": "已启用",
17
+ "Disabled": "已禁用",
18
+ "Menu / Page": "菜单/页面",
19
+ "UID": "UID",
20
+ "Untitled": "未命名",
21
+ "Export Selected Items": "导出所选项目",
22
+ "Import from Development to Production": "从开发环境导入到生产环境",
23
+ "Upload the exported JSON file from the development server.": "上传从开发服务器导出的 JSON 文件。",
24
+ "What will be imported:": "将导入:",
25
+ "Collection structure (without data)": "数据表结构(不含数据)",
26
+ "Workflow configuration": "工作流配置",
27
+ "UI Schema/Page design": "UI Schema/页面设计",
28
+ "What will NOT be affected:": "不会影响:",
29
+ "Data within collections": "数据表中的业务数据",
30
+ "Collections not present in the import file": "导入文件中不存在的数据表",
31
+ "Upload Migration File (.json)": "上传迁移文件(.json)",
32
+ "Export succeeded but no data.": "导出成功,但没有数据。",
33
+ "Export successful! {{collections}} collections, {{workflows}} workflows, {{uiSchemas}} UI schemas, {{routes}} routes": "导出成功:{{collections}} 个数据表、{{workflows}} 个工作流、{{uiSchemas}} 个 UI Schema、{{routes}} 个路由",
34
+ "Export failed: {{message}}": "导出失败:{{message}}",
35
+ "Import failed: {{message}}": "导入失败:{{message}}",
36
+ "Unknown error": "未知错误",
37
+ "Apply failed after several attempts.": "多次尝试后应用失败。",
38
+ "Confirm Potentially Data-Altering Changes": "确认可能影响数据的变更",
39
+ "Proceed & Override": "继续并覆盖",
40
+ "Cancel": "取消",
41
+ "Conflicts were found on existing fields.": "发现现有字段存在冲突。",
42
+ "Collection": "数据表",
43
+ "Field": "字段",
44
+ "Current": "当前",
45
+ "Incoming": "导入内容",
46
+ "Import Successful": "导入成功",
47
+ "succeeded": "成功",
48
+ "failed": "失败",
49
+ "Some errors occurred": "发生了一些错误",
50
+ "Continue": "继续",
51
+ "Apply Complete": "应用完成",
52
+ "The changes have been successfully applied. Click Continue to refresh the page for the changes to take effect.": "变更已成功应用。点击继续刷新页面以使变更生效。",
53
+ "Errors occurred during apply": "应用过程中发生错误",
54
+ "item": "项目",
55
+ "Apply failed": "应用失败",
56
+ "Select at least one item to export": "请至少选择一个要导出的项目",
57
+ "Export Confirmation": "导出确认",
58
+ "You will export:": "将导出:",
59
+ "Note": "提示",
60
+ "Export includes collection structure, workflow config, UI schema subtree, and desktop routes.": "导出包含数据表结构、工作流配置、UI Schema 子树和桌面路由。",
61
+ "Import Confirmation": "导入确认",
62
+ "The file will import:": "文件将导入:",
63
+ "Warning": "警告",
64
+ "The first step will run a PREVIEW. If safe, the process will proceed automatically.": "第一步将执行预览。确认安全后流程会自动继续。",
65
+ "Invalid or corrupt file": "文件无效或已损坏",
66
+ "Restarting...": "正在重启...",
67
+ "Applying...": "正在应用..."
68
+ }
@@ -221,6 +221,23 @@ export class MigrationController {
221
221
  if (row) selectedRoots.push(row);
222
222
  }
223
223
 
224
+ const pickRouteFields = (r: any) => ({
225
+ title: r.title ?? null,
226
+ tooltip: r.tooltip ?? null,
227
+ icon: r.icon ?? null,
228
+ schemaUid: r.schemaUid ?? null,
229
+ menuSchemaUid: r.menuSchemaUid ?? null,
230
+ tabSchemaName: r.tabSchemaName ?? null,
231
+ type: r.type ?? null,
232
+ options: r.options ?? null,
233
+ sort: r.sort ?? null,
234
+ hideInMenu: r.hideInMenu ?? null,
235
+ enableTabs: r.enableTabs ?? null,
236
+ enableHeader: r.enableHeader ?? null,
237
+ displayTitle: r.displayTitle ?? null,
238
+ hidden: r.hidden ?? null,
239
+ });
240
+
224
241
  const buildTree = async (node: any, parentType: string | null): Promise<any | null> => {
225
242
  const t = String(node.type || '').toLowerCase();
226
243
 
@@ -1,37 +1,33 @@
1
- import { Plugin } from '@nocobase/server';
2
- // @ts-ignore
3
- import { name } from '../../package.json';
4
- import { MigrationController } from './controllers/migration';
5
-
6
- export const namespace = name;
7
-
8
- export class PluginMigrationManagerServer extends Plugin {
9
- async afterAdd() {}
10
- async beforeLoad() {}
11
-
12
- async load() {
13
- this.app.resource({
14
- name: 'migration',
15
- actions: {
16
- export: MigrationController.export,
17
- import: MigrationController.import,
18
- list: MigrationController.list,
19
- validate: MigrationController.validate,
20
- apply: MigrationController.apply,
21
- },
22
- });
23
-
24
- this.app.acl.allow('migration', '*', (ctx) => {
25
- const role = ctx.state?.currentRole;
26
- return role === 'root' || role === 'admin';
27
- });
28
- }
29
-
30
- async install() {}
31
- async afterEnable() {}
32
- async afterDisable() {}
33
- async remove() {}
34
- }
35
-
36
- export default PluginMigrationManagerServer;
37
-
1
+ import { Plugin } from '@nocobase/server';
2
+ import { MigrationController } from './controllers/migration';
3
+
4
+ export class PluginMigrationManagerServer extends Plugin {
5
+ async afterAdd() {}
6
+ async beforeLoad() {}
7
+
8
+ async load() {
9
+ this.app.resource({
10
+ name: 'migration',
11
+ actions: {
12
+ export: MigrationController.export,
13
+ import: MigrationController.import,
14
+ list: MigrationController.list,
15
+ validate: MigrationController.validate,
16
+ apply: MigrationController.apply,
17
+ },
18
+ });
19
+
20
+ this.app.acl.registerSnippet({
21
+ name: 'pm.plugin-migration-manager',
22
+ actions: ['migration:*'],
23
+ });
24
+ this.app.acl.allow('migration', '*', 'admin');
25
+ }
26
+
27
+ async install() {}
28
+ async afterEnable() {}
29
+ async afterDisable() {}
30
+ async remove() {}
31
+ }
32
+
33
+ export default PluginMigrationManagerServer;
package/INSTALL.md DELETED
@@ -1,100 +0,0 @@
1
- # Installation Guide - Migration Manager Plugin
2
-
3
- ## Prerequisites
4
-
5
- - Nocobase installed (Git source or create-nocobase-app)
6
- - Node.js >= 18
7
- - Yarn package manager
8
- - Admin access to Nocobase
9
-
10
- ## Installation Steps
11
-
12
- ### Step 1: Extract ZIP
13
- ```bash
14
- unzip plugin-migration-manager.zip
15
- ```
16
-
17
- ### Step 2: Copy to Nocobase
18
- ```bash
19
- # Copy plugin to Nocobase plugins directory
20
- cp -r plugin-migration-manager /path/to/your/nocobase/packages/plugins/@nocobase/
21
-
22
- # Example:
23
- # cp -r plugin-migration-manager D:/work/diawan/nocobase-new/packages/plugins/@nocobase/
24
- ```
25
-
26
- ### Step 3: Install Dependencies
27
- ```bash
28
- cd /path/to/your/nocobase
29
- yarn install
30
- ```
31
-
32
- ### Step 4: Build Plugin
33
- ```bash
34
- # Build specific plugin
35
- yarn build packages/plugins/@nocobase/plugin-migration-manager
36
-
37
- # Or build all
38
- yarn build
39
- ```
40
-
41
- ### Step 5: Enable Plugin
42
-
43
- **Option A: Via UI**
44
- 1. Start server: `yarn dev`
45
- 2. Login as admin
46
- 3. Open **Plugin Manager**
47
- 4. Find "Migration Manager"
48
- 5. Click **Enable**
49
-
50
- **Option B: Via CLI**
51
- ```bash
52
- yarn pm enable @nocobase/plugin-migration-manager
53
- ```
54
-
55
- ### Step 6: Restart Server
56
- ```bash
57
- # Stop server (Ctrl+C)
58
- # Start again
59
- yarn dev
60
- ```
61
-
62
- ### Step 7: Verify Installation
63
- 1. Login to Nocobase
64
- 2. Click **Settings** (gear icon)
65
- 3. You should see **Migration Manager** menu
66
- 4. Click to open the plugin
67
-
68
- ## Troubleshooting
69
-
70
- ### Plugin not showing
71
- ```bash
72
- yarn clean
73
- yarn build
74
- yarn pm enable @nocobase/plugin-migration-manager
75
- yarn dev
76
- ```
77
-
78
- ### Build errors
79
- ```bash
80
- rm -rf packages/plugins/@nocobase/plugin-migration-manager/{lib,es,dist}
81
- yarn build packages/plugins/@nocobase/plugin-migration-manager
82
- ```
83
-
84
- ### Permission denied
85
- - Ensure you're logged in as admin
86
- - Check ACL settings
87
-
88
- ## Uninstall
89
-
90
- ```bash
91
- yarn pm disable @nocobase/plugin-migration-manager
92
- rm -rf packages/plugins/@nocobase/plugin-migration-manager
93
- ```
94
-
95
- ## Support
96
-
97
- For issues and questions, check:
98
- - Server logs
99
- - Browser console
100
- - README.md for usage guide
package/README.md DELETED
@@ -1,30 +0,0 @@
1
- # Migration Manager Plugin
2
-
3
- Migrate **collections**, **workflows**, **UI schemas**, and **desktop routes** between NocoBase instances.
4
-
5
- ## Features
6
-
7
- - **Export** collection structures, workflow definitions, UI schema trees, and menu/navigation routes
8
- - **Import** with preview validation before applying changes
9
- - **Merge** mode for collections (add new fields without deleting existing ones)
10
- - **Overwrite** mode for workflows and UI schemas (full replacement)
11
- - **Admin-only** access control
12
-
13
- ## What Gets Migrated
14
-
15
- | Component | Export Content | Import Mode |
16
- |-----------|---------------|-------------|
17
- | Collections | Schema & fields (no data) | Merge |
18
- | Workflows | Definition + all nodes | Overwrite |
19
- | UI Schemas | Complete schema tree | Overwrite |
20
- | Desktop Routes | Menu/navigation tree | Create (skip duplicates) |
21
-
22
- ## API Endpoints
23
-
24
- | Endpoint | Method | Description |
25
- |----------|--------|-------------|
26
- | `migration:list` | GET | List exportable items |
27
- | `migration:export` | POST | Export selected items to JSON |
28
- | `migration:validate` | POST | Pre-import validation |
29
- | `migration:import` | POST | Import from JSON |
30
- | `migration:apply` | POST | Sync DB schema after import |
@@ -1 +0,0 @@
1
- "use strict";(self.webpackChunkplugin_migration_manager=self.webpackChunkplugin_migration_manager||[]).push([["545"],{797:function(e,t,n){n.r(t),n.d(t,{MigrationPage:function(){return k}});var l=n(156),r=n.n(l),o=n(721),a=n(482),i=n(772);function c(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,l=Array(t);n<t;n++)l[n]=e[n];return l}function u(e,t,n,l,r,o,a){try{var i=e[o](a),c=i.value}catch(e){n(e);return}i.done?t(c):Promise.resolve(c).then(l,r)}function s(e){return function(){var t=this,n=arguments;return new Promise(function(l,r){var o=e.apply(t,n);function a(e){u(o,l,r,a,i,"next",e)}function i(e){u(o,l,r,a,i,"throw",e)}a(void 0)})}}function d(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},l=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(l=l.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),l.forEach(function(t){var l;l=n[t],t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l})}return e}function m(e,t){return t=null!=t?t:{},Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):(function(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);n.push.apply(n,l)}return n})(Object(t)).forEach(function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}),e}function p(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n,l,r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var o=[],a=!0,i=!1;try{for(r=r.call(e);!(a=(n=r.next()).done)&&(o.push(n.value),!t||o.length!==t);a=!0);}catch(e){i=!0,l=e}finally{try{a||null==r.return||r.return()}finally{if(i)throw l}}return o}}(e,t)||g(e,t)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function f(e){return function(e){if(Array.isArray(e))return c(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||g(e)||function(){throw TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function g(e,t){if(e){if("string"==typeof e)return c(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return c(e,t)}}function h(e,t){var n,l,r,o,a={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]};return o={next:i(0),throw:i(1),return:i(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function i(o){return function(i){var c=[o,i];if(n)throw TypeError("Generator is already executing.");for(;a;)try{if(n=1,l&&(r=2&c[0]?l.return:c[0]?l.throw||((r=l.return)&&r.call(l),0):l.next)&&!(r=r.call(l,c[1])).done)return r;switch(l=0,r&&(c=[2&c[0],r.value]),c[0]){case 0:case 1:r=c;break;case 4:return a.label++,{value:c[1],done:!1};case 5:a.label++,l=c[1],c=[0];continue;case 7:c=a.ops.pop(),a.trys.pop();continue;default:if(!(r=(r=a.trys).length>0&&r[r.length-1])&&(6===c[0]||2===c[0])){a=0;continue}if(3===c[0]&&(!r||c[1]>r[0]&&c[1]<r[3])){a.label=c[1];break}if(6===c[0]&&a.label<r[1]){a.label=r[1],r=c;break}if(r&&a.label<r[2]){a.label=r[2],a.ops.push(c);break}r[2]&&a.ops.pop(),a.trys.pop();continue}c=t.call(e,a)}catch(e){c=[6,e],l=0}finally{n=r=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}}}var y=o.Typography.Title,v=o.Typography.Text,w=o.Input.Search;function E(e){var t,n,l;return null!=(l=null!=(n=null==e||null==(t=e.data)?void 0:t.data)?n:null==e?void 0:e.data)?l:e}function S(e){return e?e.replace(/\{\{t\("(.+?)"\)\}\}/g,"$1").replace(/_/g," ").replace(/\b\w/g,function(e){return e.toUpperCase()}):""}var b=function(e){return new Promise(function(t){return setTimeout(t,e)})},k=function(){var e,t,n,c=(0,i.useAPIClient)(),u=p((0,l.useState)("export"),2),g=u[0],k=u[1],C=p((0,l.useState)({collections:[],workflows:[],uiSchemas:[]}),2),x=C[0],O=C[1],I=p((0,l.useState)([]),2),T=I[0],z=I[1],j=p((0,l.useState)([]),2),U=j[0],A=j[1],P=p((0,l.useState)([]),2),M=P[0],R=P[1],D=p((0,l.useState)(!1),2),L=D[0],N=D[1],W=p((0,l.useState)(!1),2),K=W[0],q=W[1],B=p((0,l.useState)(null),2),F=B[0],_=B[1],J=p((0,l.useState)(!1),2),G=J[0],V=J[1],$=p((0,l.useState)(""),2),H=$[0],Y=$[1],Q=p((0,l.useState)(""),2),X=Q[0],Z=Q[1],ee=p((0,l.useState)(""),2),et=ee[0],en=ee[1],el=p((0,l.useState)({current:1,pageSize:10}),2),er=el[0],eo=el[1],ea=p((0,l.useState)({current:1,pageSize:10}),2),ei=ea[0],ec=ea[1],eu=p((0,l.useState)({current:1,pageSize:10}),2),es=eu[0],ed=eu[1];(0,l.useEffect)(function(){var e=function(e){(L||K)&&(e.preventDefault(),e.returnValue="")};return window.addEventListener("beforeunload",e),function(){return window.removeEventListener("beforeunload",e)}},[L,K]);var em=(0,i.useRequest)({url:"migration:list",method:"get"},{manual:!1,onSuccess:function(e){var t,n,l,r=E(e);O({collections:null!=(t=null==r?void 0:r.collections)?t:[],workflows:null!=(n=null==r?void 0:r.workflows)?n:[],uiSchemas:null!=(l=null==r?void 0:r.uiSchemas)?l:[]})},onError:function(){return O({collections:[],workflows:[],uiSchemas:[]})}}),ep=em.run,ef=em.loading,eg=(0,i.useRequest)({url:"migration:export",method:"post"},{manual:!0,onSuccess:function(e){var t,n,l,r,a,i,c,u,s=E(e);if(!((null==s||null==(t=s.collections)?void 0:t.length)>0||(null==s||null==(n=s.workflows)?void 0:n.length)>0||(null==s||null==(l=s.uiSchemas)?void 0:l.length)>0||(null==s||null==(r=s.desktopRoutes)?void 0:r.length)>0))return void o.message.warning("Export succeeded but no data.");var d=new Blob([JSON.stringify(s,null,2)],{type:"application/json"}),m=URL.createObjectURL(d),p=document.createElement("a");p.href=m,p.download="nocobase-migration-".concat(Date.now(),".json"),p.click(),URL.revokeObjectURL(m),o.message.success("Export successful! ".concat((null==(a=s.collections)?void 0:a.length)||0," collections, ").concat((null==(i=s.workflows)?void 0:i.length)||0," workflows, ").concat((null==(c=s.uiSchemas)?void 0:c.length)||0," UI schemas, ").concat((null==(u=s.desktopRoutes)?void 0:u.length)||0," routes"))},onError:function(e){return o.message.error("Export failed: ".concat(e.message))}}),eh=eg.run,ey=eg.loading,ev=(e=s(function(){var e,t,n=arguments;return h(this,function(l){switch(l.label){case 0:e=n.length>0&&void 0!==n[0]?n[0]:1e4,t=n.length>1&&void 0!==n[1]?n[1]:2e3,N(!0),l.label=1;case 1:return l.trys.push([1,,5,6]),[4,c.request({url:"app:restart",method:"post",timeout:6e4})];case 2:return l.sent(),[4,b(e)];case 3:return l.sent(),[4,b(t)];case 4:return l.sent(),[3,6];case 5:return N(!1),[7];case 6:return[2]}})}),function(){return e.apply(this,arguments)}),ew=(t=s(function(e){var t,n,l,r,o,a,i=arguments;return h(this,function(u){switch(u.label){case 0:t=i.length>1&&void 0!==i[1]?i[1]:15,n=i.length>2&&void 0!==i[2]?i[2]:1500,l=null,r=0,u.label=1;case 1:if(!(r<t))return[3,8];u.label=2;case 2:return u.trys.push([2,4,,7]),[4,c.request({url:"migration:apply",method:"post",data:{data:{collections:e}},headers:{"Content-Type":"application/json"},timeout:6e5})];case 3:return[2,E(u.sent())];case 4:if(l=o=u.sent(),!((null==o||null==(a=o.response)?void 0:a.status)===503||String((null==o?void 0:o.message)||"").includes("APP_COMMANDING")))return[3,6];return[4,b(n)];case 5:return u.sent(),[3,7];case 6:throw o;case 7:return r++,[3,1];case 8:throw l||Error("Apply failed after several attempts.")}})}),function(e){return t.apply(this,arguments)}),eE=(0,i.useRequest)(function(e){return c.request({url:"migration:import",method:"post",data:{data:e},headers:{"Content-Type":"application/json"},timeout:6e5})},{manual:!0,onSuccess:(n=s(function(e){var t,n,l,i,c,u,p,g,y,v,w,S,b,k,C,x,O,I,T,z,j;return h(this,function(U){return(O=(x=E(e)||{}).needsConfirmation,I=x.results,O)?(z=(null==I||null==(T=I.collections)?void 0:T.conflicts)||[],o.Modal.confirm({title:"Confirm Potentially Data-Altering Changes",icon:r().createElement(a.ExclamationCircleOutlined,null),width:760,okText:"Proceed & Override",cancelText:"Cancel",content:r().createElement("div",null,r().createElement(o.Alert,{type:"warning",showIcon:!0,message:"Conflicts were found on existing fields.",style:{marginBottom:12}}),r().createElement("div",{style:{maxHeight:360,overflow:"auto"}},r().createElement(o.Table,{size:"small",pagination:!1,rowKey:function(e){return"".concat(e.collection,".").concat(e.field)},dataSource:z,columns:[{title:"Collection",dataIndex:"collection"},{title:"Field",dataIndex:"field"},{title:"Current",render:function(e,t){return"type=".concat(t.current.type,", interface=").concat(t.current.interface,", unique=").concat(String(t.current.unique),", allowNull=").concat(String(t.current.allowNull),", pk=").concat(String(t.current.primaryKey))}},{title:"Incoming",render:function(e,t){return"type=".concat(t.incoming.type,", interface=").concat(t.incoming.interface,", unique=").concat(String(t.incoming.unique),", allowNull=").concat(String(t.incoming.allowNull),", pk=").concat(String(t.incoming.primaryKey))}}]}))),onOk:function(){F&&(V(!1),eS(m(d({},F),{options:{forceOverride:!0}})))}})):G&&F?(V(!1),eS(F)):(j=I||{},o.Modal.success({title:"Import Successful",content:r().createElement("div",null,r().createElement("p",null,"Collections: ",(null==(t=j.collections)?void 0:t.success)||0," succeeded, ",(null==(n=j.collections)?void 0:n.failed)||0," failed"),r().createElement("p",null,"Workflows: ",(null==(l=j.workflows)?void 0:l.success)||0," succeeded, ",(null==(i=j.workflows)?void 0:i.failed)||0," failed"),r().createElement("p",null,"UI Schemas: ",(null==(c=j.uiSchemas)?void 0:c.success)||0," succeeded, ",(null==(u=j.uiSchemas)?void 0:u.failed)||0," failed"),((null==(g=j.collections)||null==(p=g.errors)?void 0:p.length)>0||(null==(v=j.workflows)||null==(y=v.errors)?void 0:y.length)>0||(null==(S=j.uiSchemas)||null==(w=S.errors)?void 0:w.length)>0)&&r().createElement(o.Alert,{message:"Some errors occurred",description:r().createElement("ul",null,f((null==(b=j.collections)?void 0:b.errors)||[]).concat(f((null==(k=j.workflows)?void 0:k.errors)||[]),f((null==(C=j.uiSchemas)?void 0:C.errors)||[])).map(function(e,t){return r().createElement("li",{key:t},e.error||String(e))})),type:"warning",style:{marginTop:10}})),okText:"Continue",onOk:s(function(){var e,t,n,l,a;return h(this,function(i){switch(i.label){case 0:return i.trys.push([0,3,4,5]),q(!0),[4,ev(12e3,2e3)];case 1:return i.sent(),[4,ew(((null==F?void 0:F.collections)||[]).map(function(e){return"string"==typeof e?{name:e}:e}),15,1500)];case 2:return l=i.sent(),o.Modal.success({title:"Apply Complete",content:r().createElement("div",null,r().createElement("p",null,"The changes have been successfully applied. Click ",r().createElement("strong",null,"Continue")," to refresh the page for the changes to take effect."),(null==l||null==(t=l.results)||null==(e=t.errors)?void 0:e.length)>0&&r().createElement(o.Alert,{type:"warning",message:"Errors occurred during apply",description:r().createElement("ul",{style:{marginBottom:0}},((null==l||null==(n=l.results)?void 0:n.errors)||[]).map(function(e,t){return r().createElement("li",{key:t},e.collection||e.route||e.schema||"item",": ",e.error)}))})),okText:"Continue",onOk:function(){window.location.reload()}}),[3,5];case 3:return a=i.sent(),o.message.error((null==a?void 0:a.message)||"Apply failed"),[3,5];case 4:return q(!1),_(null),ep(),[7];case 5:return[2]}})})}),ep()),[2]})}),function(e){return n.apply(this,arguments)}),onError:function(e){return o.message.error("Import failed: ".concat(e.message))}}),eS=eE.run,eb=eE.loading,ek=(0,l.useMemo)(function(){var e=H.trim().toLowerCase(),t=(x.collections||[]).filter(function(t){return(t.title||t.name||"").toLowerCase().includes(e)});return{total:t.length,data:t}},[x.collections,H]),eC=(0,l.useMemo)(function(){var e=(er.current-1)*er.pageSize;return ek.data.slice(e,e+er.pageSize)},[ek,er]),ex=(0,l.useMemo)(function(){var e=X.trim().toLowerCase(),t=(x.workflows||[]).filter(function(t){return(t.title||"").toLowerCase().includes(e)});return{total:t.length,data:t}},[x.workflows,X]),eO=(0,l.useMemo)(function(){var e=(ei.current-1)*ei.pageSize;return ex.data.slice(e,e+ei.pageSize)},[ex,ei]),eI=(0,l.useMemo)(function(){var e=et.trim().toLowerCase(),t=(x.uiSchemas||[]).filter(function(t){return(t.displayTitle||t.title||t.name||"").toLowerCase().includes(e)});return{total:t.length,data:t}},[x.uiSchemas,et]),eT=(0,l.useMemo)(function(){var e=(es.current-1)*es.pageSize;return eI.data.slice(e,e+es.pageSize)},[eI,es]);return r().createElement("div",{style:{padding:24,position:"relative"}},r().createElement(o.Card,null,r().createElement(y,{level:2},"Migration Manager"),r().createElement(v,{type:"secondary"},"Export and import collections, workflows, and UI schemas across NocoBase instances"),r().createElement(o.Tabs,{activeKey:g,onChange:k,items:[{label:"Export",key:"export",children:r().createElement(o.Space,{direction:"vertical",size:"large",style:{width:"100%"}},r().createElement(o.Card,{title:r().createElement(o.Space,null,r().createElement(a.DatabaseOutlined,null),"Collections"),size:"small"},r().createElement("div",{style:{marginBottom:12}},r().createElement(w,{allowClear:!0,placeholder:"Filter by Title",onSearch:function(e){Y(e),eo(m(d({},er),{current:1}))},onChange:function(e){Y(e.target.value),eo(m(d({},er),{current:1}))},value:H,style:{maxWidth:320}})),r().createElement(o.Table,{rowSelection:{selectedRowKeys:T,onChange:function(e){return z(e)}},columns:[{title:"Name",dataIndex:"name",key:"name"},{title:"Title",dataIndex:"title",key:"title",render:S},{title:"Fields",dataIndex:"fields",key:"fields"}],dataSource:eC,rowKey:"name",loading:ef,pagination:{current:er.current,pageSize:er.pageSize,total:ek.total,showSizeChanger:!0,onChange:function(e,t){return eo({current:e,pageSize:t})}},size:"small"})),r().createElement(o.Card,{title:r().createElement(o.Space,null,r().createElement(a.BranchesOutlined,null),"Workflows"),size:"small"},r().createElement("div",{style:{marginBottom:12}},r().createElement(w,{allowClear:!0,placeholder:"Filter by Title",onSearch:function(e){Z(e),ec(m(d({},ei),{current:1}))},onChange:function(e){Z(e.target.value),ec(m(d({},ei),{current:1}))},value:X,style:{maxWidth:320}})),r().createElement(o.Table,{rowSelection:{selectedRowKeys:U,onChange:function(e){return A(e)}},columns:[{title:"Title",dataIndex:"title",key:"title"},{title:"Key",dataIndex:"key",key:"key"},{title:"Status",dataIndex:"enabled",key:"enabled",render:function(e){return e?"Enabled":"Disabled"}}],dataSource:eO,rowKey:"id",loading:ef,pagination:{current:ei.current,pageSize:ei.pageSize,total:ex.total,showSizeChanger:!0,onChange:function(e,t){return ec({current:e,pageSize:t})}},size:"small"})),r().createElement(o.Card,{title:r().createElement(o.Space,null,r().createElement(a.LayoutOutlined,null),"UI Schemas"),size:"small"},r().createElement("div",{style:{marginBottom:12}},r().createElement(w,{allowClear:!0,placeholder:"Filter by Title",onSearch:function(e){en(e),ed(m(d({},es),{current:1}))},onChange:function(e){en(e.target.value),ed(m(d({},es),{current:1}))},value:et,style:{maxWidth:320}})),r().createElement(o.Table,{rowSelection:{selectedRowKeys:M,onChange:function(e){return R(e)}},columns:[{title:"Menu / Page",dataIndex:"displayTitle",key:"displayTitle",render:function(e,t){return r().createElement(o.Space,null,r().createElement(v,null,(null==t?void 0:t.displayTitle)||(null==t?void 0:t.title)||(null==t?void 0:t.name)||"Untitled"),r().createElement(o.Tag,null,null==t?void 0:t.type))}},{title:"UID",dataIndex:"schemaUid",key:"schemaUid"}],dataSource:eT,rowKey:"schemaUid",loading:ef,pagination:{current:es.current,pageSize:es.pageSize,total:eI.total,showSizeChanger:!0,onChange:function(e,t){return ed({current:e,pageSize:t})}},size:"small"})),r().createElement(o.Button,{type:"primary",icon:r().createElement(a.DownloadOutlined,null),onClick:function(){if(!T.length&&!U.length&&!M.length)return void o.message.warning("Select at least one item to export");o.Modal.confirm({title:"Export Confirmation",icon:r().createElement(a.ExclamationCircleOutlined,null),content:r().createElement("div",null,r().createElement("p",null,"You will export:"),r().createElement("ul",null,r().createElement("li",null,T.length," Collections"),r().createElement("li",null,U.length," Workflows"),r().createElement("li",null,M.length," UI Schemas/Routes")),r().createElement(o.Alert,{message:"Note",description:"Export includes collection structure, workflow config, UI schema subtree, and desktop routes.",type:"info",style:{marginTop:10}})),onOk:function(){eh({data:{collections:T,workflows:U,uiSchemas:[],desktopRoutes:M}})}})},loading:ey,size:"large",disabled:L||K},"Export Selected Items"))},{label:"Import",key:"import",children:r().createElement(o.Space,{direction:"vertical",size:"large",style:{width:"100%"}},r().createElement(o.Alert,{message:"Import from Development to Production",description:r().createElement("div",null,r().createElement("p",null,"Upload the exported JSON file from the development server."),r().createElement("p",null,r().createElement("strong",null,"What will be imported:")),r().createElement("ul",null,r().createElement("li",null,"Collection structure (without data)"),r().createElement("li",null,"Workflow configuration"),r().createElement("li",null,"UI Schema/Page design")),r().createElement("p",null,r().createElement("strong",null,"What will NOT be affected:")),r().createElement("ul",null,r().createElement("li",null,"Data within collections"),r().createElement("li",null,"Collections not present in the import file"))),type:"info"}),r().createElement(o.Upload,{accept:".json",beforeUpload:function(e){var t=new FileReader;return t.onload=function(e){try{var t,n,l,i,c=JSON.parse(null==(t=e.target)?void 0:t.result);_(c),V(!0),o.Modal.confirm({title:"Import Confirmation",icon:r().createElement(a.ExclamationCircleOutlined,null),content:r().createElement("div",null,r().createElement("p",null,"The file will import:"),r().createElement("ul",null,r().createElement("li",null,(null==(n=c.collections)?void 0:n.length)||0," Collections"),r().createElement("li",null,(null==(l=c.workflows)?void 0:l.length)||0," Workflows"),r().createElement("li",null,(null==(i=c.uiSchemas)?void 0:i.length)||0," UI Schemas")),r().createElement(o.Alert,{message:"Warning",description:"The first step will run a PREVIEW. If safe, the process will proceed automatically.",type:"warning",style:{marginTop:10}})),onOk:function(){return eS(m(d({},c),{options:{preview:!0}}))}})}catch(e){o.message.error("Invalid or corrupt file")}},t.readAsText(e),!1},showUploadList:!1,disabled:L||K},r().createElement(o.Button,{type:"primary",icon:r().createElement(a.UploadOutlined,null),loading:eb,size:"large",disabled:L||K},"Upload Migration File (.json)")))}]})),(L||K)&&r().createElement("div",{style:{position:"fixed",inset:0,backgroundColor:"rgba(255,255,255,0.8)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:9999}},r().createElement(o.Spin,{size:"large",tip:L?"Restarting...":"Applying..."})))}}}]);
@@ -1,5 +0,0 @@
1
- import { Plugin } from '@nocobase/client';
2
- export declare class PluginMigrationManagerClient extends Plugin {
3
- load(): Promise<void>;
4
- }
5
- export default PluginMigrationManagerClient;
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare const MigrationPage: React.FC;
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './server';
2
- export { default } from './server';
package/dist/index.js DELETED
@@ -1,39 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
- var src_exports = {};
30
- __export(src_exports, {
31
- default: () => import_server.default
32
- });
33
- module.exports = __toCommonJS(src_exports);
34
- __reExport(src_exports, require("./server"), module.exports);
35
- var import_server = __toESM(require("./server"));
36
- // Annotate the CommonJS export names for ESM import in node:
37
- 0 && (module.exports = {
38
- ...require("./server")
39
- });
@@ -1,27 +0,0 @@
1
- import { Context } from '@nocobase/actions';
2
- type Id = string | number;
3
- export interface ExportBody {
4
- collections?: string[];
5
- workflows?: Id[];
6
- uiSchemas?: string[];
7
- }
8
- export interface FieldRow {
9
- name: string;
10
- type?: string;
11
- interface?: string;
12
- options?: any;
13
- }
14
- export interface CollectionBundle {
15
- name: string;
16
- title?: string;
17
- primaryKey?: string;
18
- fields?: FieldRow[];
19
- }
20
- export declare class MigrationController {
21
- static export(ctx: Context): Promise<void>;
22
- static import(ctx: Context): Promise<void>;
23
- static list(ctx: Context): Promise<void>;
24
- static validate(ctx: Context): Promise<void>;
25
- static apply(ctx: Context): Promise<void>;
26
- }
27
- export {};
@@ -1,12 +0,0 @@
1
- import { Plugin } from '@nocobase/server';
2
- export declare const namespace: string;
3
- export declare class PluginMigrationManagerServer extends Plugin {
4
- afterAdd(): Promise<void>;
5
- beforeLoad(): Promise<void>;
6
- load(): Promise<void>;
7
- install(): Promise<void>;
8
- afterEnable(): Promise<void>;
9
- afterDisable(): Promise<void>;
10
- remove(): Promise<void>;
11
- }
12
- export default PluginMigrationManagerServer;