diff --git a/pkg/api/http/controller/groups/plugins.py b/pkg/api/http/controller/groups/plugins.py
index 22a3e944..26133c29 100644
--- a/pkg/api/http/controller/groups/plugins.py
+++ b/pkg/api/http/controller/groups/plugins.py
@@ -29,3 +29,9 @@ class PluginsRouterGroup(group.RouterGroup):
target_enabled = data.get('target_enabled')
await self.ap.plugin_mgr.update_plugin_status(plugin_name, target_enabled)
return self.success()
+
+ @self.route('/reorder', methods=['PUT'])
+ async def _() -> str:
+ data = await quart.request.json
+ await self.ap.plugin_mgr.reorder_plugins(data.get('plugins'))
+ return self.success()
diff --git a/pkg/plugin/manager.py b/pkg/plugin/manager.py
index bc8f7817..0295ac44 100644
--- a/pkg/plugin/manager.py
+++ b/pkg/plugin/manager.py
@@ -203,3 +203,18 @@ class PluginManager:
return True
else:
return False
+
+ async def reorder_plugins(self, plugins: list[dict]):
+
+ for plugin in plugins:
+ plugin_name = plugin.get('name')
+ plugin_priority = plugin.get('priority')
+
+ for plugin in self.plugins:
+ if plugin.plugin_name == plugin_name:
+ plugin.priority = plugin_priority
+ break
+
+ self.plugins.sort(key=lambda x: x.priority, reverse=True)
+
+ await self.setting.dump_container_setting(self.plugins)
diff --git a/web/package-lock.json b/web/package-lock.json
index b099d1a2..205a2956 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -20,6 +20,7 @@
"core-js": "^3.37.1",
"roboto-fontface": "*",
"vue": "^3.4.31",
+ "vuedraggable": "^4.1.0",
"vuetify": "^3.6.11",
"vuex": "^4.0.2"
},
@@ -4627,6 +4628,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/sortablejs": {
+ "version": "1.14.0",
+ "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
+ "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==",
+ "license": "MIT"
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -5256,6 +5263,18 @@
"vue": "^3.2.0"
}
},
+ "node_modules/vuedraggable": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
+ "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
+ "license": "MIT",
+ "dependencies": {
+ "sortablejs": "1.14.0"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.1"
+ }
+ },
"node_modules/vuetify": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.2.tgz",
diff --git a/web/package.json b/web/package.json
index 71ca5ba8..c02f2737 100644
--- a/web/package.json
+++ b/web/package.json
@@ -20,6 +20,7 @@
"core-js": "^3.37.1",
"roboto-fontface": "*",
"vue": "^3.4.31",
+ "vuedraggable": "^4.1.0",
"vuetify": "^3.6.11",
"vuex": "^4.0.2"
},
diff --git a/web/src/pages/Plugins.vue b/web/src/pages/Plugins.vue
index 984cefb7..798d9ad2 100644
--- a/web/src/pages/Plugins.vue
+++ b/web/src/pages/Plugins.vue
@@ -8,6 +8,40 @@