cli: add support for create/destroy object editor with single type master
authorFelix Fietkau <nbd@nbd.name>
Tue, 25 Feb 2025 15:25:16 +0000 (16:25 +0100)
committerFelix Fietkau <nbd@nbd.name>
Tue, 25 Feb 2025 15:25:17 +0000 (16:25 +0100)
Allows hooking create/destroy in a separate menu without having the user
specify a type argument.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
package/utils/cli/files/usr/share/ucode/cli/object-editor.uc

index c55bf40010502a652d8c2fb7f9bec579bf59d6fc..a49925cf221ad331d5ab7ba8bbf01bba17909403 100644 (file)
@@ -306,34 +306,42 @@ export function new(info, node)
 
 export function object_destroy_call(ctx, argv, named)
 {
-       let type_name = argv[0];
-       if (!type_name)
-               return ctx.invalid_argument();
-
+       let type_info, type_name;
        let info = this.object_info;
-       let type_info = info.types[type_name];
+       if (info.types) {
+               type_name = shift(argv);
+               if (!type_name)
+                       return ctx.invalid_argument();
+
+               type_info = info.types[type_name];
+       } else {
+               type_info = info.type;
+               type_name = type_info.name;
+       }
        if (!type_info)
                return ctx.invalid_argument();
 
        let obj_name = type_info.object ?? type_name;
 
-       let name = argv[1];
-       if (type_info.delete)
-               return call(type_info.delete, info, ctx.model.scope, ctx, type, name);
-
-       let obj = ctx.data.object_edit[obj_name];
-       if (!obj)
-               return ctx.unknown_error();
+       let name = shift(argv);
+       if (type_info.delete) {
+               if (!call(type_info.delete, info, ctx.model.scope, ctx, type, name))
+                       return;
+       } else {
+               let obj = ctx.data.object_edit[obj_name];
+               if (!obj)
+                       return ctx.unknown_error();
 
-       if (!obj[name])
-               return ctx.not_found();
+               if (!obj[name])
+                       return ctx.not_found();
 
-       delete obj[name];
+               delete obj[name];
+       }
 
        if (info.change_cb)
                call(info.change_cb, info, ctx.model.scope, ctx, argv);
 
-       return ctx.ok(`Deleted ${argv[0]} '${name}'`);
+       return ctx.ok(`Deleted ${type_name} '${name}'`);
 };
 
 const create_edit_param = {
@@ -361,34 +369,38 @@ export function object_create_params(node)
 
 export function object_create_call(ctx, argv, named)
 {
-       let type_name = argv[0];
-       if (!type_name)
-               return ctx.invalid_argument();
-
+       let type_info, type_name;
        let info = this.object_info;
-       let type_info = info.types[type_name];
+       if (info.types) {
+               type_name = shift(argv);
+               if (!type_name)
+                       return ctx.invalid_argument();
+
+               type_info = info.types[type_name];
+       } else {
+               type_info = info.type;
+               type_name = type_info.name;
+       }
        if (!type_info)
                return ctx.invalid_argument();
 
        let obj_name = type_info.object ?? type_name;
 
-       let name = argv[1];
+       let name = shift(argv);
        let obj, data;
        if (type_info.add) {
-               data = call(type_info.add, info, ctx.model.scope, ctx, type, name);
+               data = call(type_info.add, info, ctx.model.scope, ctx, type_name, name, named);
                if (!data)
                        return;
        } else {
                data = {};
        }
 
-       ctx.data.object_edit[obj_name] ??= {};
-       obj = ctx.data.object_edit[obj_name];
-
        let entry = type_info.node.set;
        if (entry) {
                ctx.apply_defaults();
                let subctx = ctx.clone();
+               subctx.data.name = name;
                subctx.data.edit = data;
 
                try {
@@ -404,10 +416,17 @@ export function object_create_call(ctx, argv, named)
                }
        }
 
-       obj[name] = data;
+       if (type_info.insert) {
+               if (!call(type_info.insert, info, ctx.model.scope, ctx, type_name, name, data, named))
+                       return;
+       } else {
+               ctx.data.object_edit[obj_name] ??= {};
+               obj = ctx.data.object_edit[obj_name];
+               obj[name] = data;
+       }
 
        if (named.edit)
-               ctx.select(type_name, name);
+               ctx.select(info.type ? "edit" : type_name, name);
 
        return ctx.ok(`Added ${type_name} '${name}'`);
 };
@@ -415,11 +434,19 @@ export function object_create_call(ctx, argv, named)
 function object_lookup(ctx, entry, type_name)
 {
        let info = entry.object_info;
-       let type_info = info.types[type_name];
+       let type_info = info.types ? info.types[type_name] : info.type;
        if (!type_info)
-               return [];
+               return {};
 
-       let obj_name = type_info.object ?? type_name;
+       if (type_info.get_object) {
+               let objs = call(type_info.get_object, info, ctx.model.scope, ctx, type_name);
+               if (type(objs) != "object")
+                       objs = {};
+
+               return objs;
+       }
+
+       let obj_name = type_info.object ?? (info.types ? type_name : type_info.name);
 
        return ctx.data.object_edit[obj_name];
 }
@@ -435,18 +462,23 @@ function object_values(ctx, entry, type_name)
 
 export function object_list_call(ctx, argv, named)
 {
-       return ctx.list(argv[0] + " list", object_values(ctx, this, argv[0]));
+       let info = this.object_info;
+       let type_name = info.types ? argv[0] : info.type.name;
+       return ctx.list(type_name + " list", object_values(ctx, this, type_name));
 };
 
 export function edit_create_destroy(info, node)
 {
-       let type_arg = {
-               name: "type",
-               help: "Type",
-               type: "enum",
-               required: true,
-               value: keys(info.types),
-       };
+       let type_arg = [];
+       if (info.types)
+               type_arg = [{
+                       name: "type",
+                       help: "Type",
+                       type: "enum",
+                       required: true,
+                       value: keys(info.types),
+               }];
+
        let name_arg = {
                name: "name",
                help: "Name",
@@ -462,29 +494,35 @@ export function edit_create_destroy(info, node)
        };
 
        let create_params = {};
-       for (let name, val in info.types)
-               create_params[name] = object_create_params(val.node);
+       if (info.types) {
+               for (let name, val in info.types)
+                       create_params[name] = object_create_params(val.node);
+       } else {
+               create_params = object_create_params(info.type.node);
+       }
 
-       let types_info = " (" + join(", ", keys(info.types)) + ")";
+       let types_info = info.types ? "(" + join(", ", keys(info.types)) + ")" : info.type.name;
        let cmds = {
                destroy: {
                        object_info: info,
-                       help: "Delete object" + types_info,
-                       args: [ type_arg, delete_name_arg ],
+                       help: "Delete " + types_info,
+                       args: [ ...type_arg, delete_name_arg ],
                        call: object_destroy_call,
                },
                list: {
                        object_info: info,
-                       help: "List objects" + types_info,
-                       args: [ type_arg ],
+                       help: "List " + types_info,
+                       args: [ ...type_arg ],
                        call: object_list_call,
                },
                create: {
                        object_info: info,
-                       help: "Create object" + types_info,
-                       args: [ type_arg, name_arg ],
+                       help: "Create " + types_info,
+                       args: [ ...type_arg, name_arg ],
                        type_params: create_params,
                        named_args: function(ctx, argv) {
+                               if (!this.object_info.types)
+                                       return this.type_params;
                                if (!argv[0])
                                        return;
                                return this.type_params[argv[0]];
@@ -493,8 +531,16 @@ export function edit_create_destroy(info, node)
                },
        };
 
-       for (let name, val in info.types) {
-               cmds[name] = {
+
+       let info_types = info.types;
+       if (!info_types) {
+               info_types = {};
+               info_types[info.type.name] = info.type;
+       }
+
+       for (let name, val in info_types) {
+               let cmd_name = info.types ? name : "edit";
+               cmds[cmd_name] = {
                        object_name: name,
                        object_info: info,
                        help: "Edit " + name,
@@ -528,7 +574,7 @@ export function edit_create_destroy(info, node)
                                }
 
                                let info = this.object_info;
-                               let type_info = info.types[this.object_name];
+                               let type_info = info.types ? info.types[this.object_name] : info.type;
                                return ctx.set(`${this.object_name} "${name}"`, {
                                        name,
                                        edit: entry,