jow- / luci-ng

LuCI on Angular
84 stars 26 forks source link

JSON UI #53

Closed ianchi closed 6 years ago

ianchi commented 6 years ago

This PR continues on the ideas from #45. It is still more in proof of concept state, with much pending work everywhere. My main aim is to settle on how to write the plugins views purely in json. This is a first proposal to expand upon. I still have to better integrate this with the json schema deffinition of UCI config files. @jow- any comments & ideas are welcomed. Not much work was done yet on the design & styling, so look with broad mind.

So far all views in this version are completely defined in JSON (you can take a look here. Here are some screenshots,

Overview

overview

{
  "type": "grid-container",
  "options": {
    "direction": "row"
  },
  "content": [{
      "type": "stat-expand",
      "context": {
        "board=": "ubus('system','board')"
      },
      "options": {
        "gridCol": "span 2",
        "gridRowOpen": "span 3",
        "gridRowClosed": "auto",
        "value=": "board.model",
        "title=": "board.release.description",
        "icon": "information-variant",
        "noGraph": true
      },
      "content": {
        "type": "table",
        "options": {

          "colKeys": ["title", "value"],
          "colHeaders": false,
          "dataSource": [{
              "title": "Hostname",
              "value=": "board.hostname"
            },
            {
              "title": "Kernel",
              "value=": "board.kernel"
            },
            {
              "title": "System",
              "value=": "board.system"
            },
            {
              "title": "Target",
              "value=": "board.release.target"
            }
          ]
        }
      }
    },
    {
      "type": "stat-expand",
      "context": {
        "info=": "ubus('system','info')"
      },
      "options": {
        "title": "Uptime",
        "icon": "clock-fast",
        "value=": "info.uptime * 1000",
        "unit": "d h:m:s",
        "format": "date:'d HH:mm:ss'",
        "noGraph": true
      }
    },

System Log

syslog

{
  "type": "table",
  "context": {
    "log=": "ubus('luci2.system', 'syslog')",
    "re=": "/^(<[0-9]+>)?\\s*(([a-z ]*)\\s+([0-9]{1,2})\\s+([0-9]{2}:[0-9]{2}:[0-9]{2})\\s([0-9]{4}))\\s+([\\w.-]+)?\\s+([\\w\\-().0-9/]+)(?:\\[([a-z0-9-.]+)\\])?:\\s*(.+)$/i"
  },
  "options": {
    "title": "System Log",
    "icon": "sd",
    "dataSource=": "map(log.log.split('\\n').reverse(), 'm=re.exec($value) , m ? {log: $value, priority: m[1], date: new Date(m[2]), month: m[3],day: m[4],hour: m[5],year: m[6],type: m[7],process: m[8],pid: m[9],msg: m[10]} : {log:$value, msg: $value}')",
    "colKeys": ["date", "type", "pid", "process", "msg"],
    "colHeaders": ["Date", "Type", "PID", "Process", "Message"],
    "colFormat": ["date:'MMM-dd HH:mm:ss'"],
    "colTransform": [],
    "pageSizes": [10, 20, 50],
    "filterBy": ["type", "process", "msg"],
    "disableSort": ["msg"]
  }
}

Processes

process

{
  "type": "table",
  "context": {
    "data=": "ubus('luci2.system', 'process_list')"
  },
  "options": {
    "title": "Running Processes",
    "dataSource=": "data.processes",
    "colKeys": ["pid", "user", "command"],
    "colHeaders": ["PID", "Owner", "Command"],
    "filterBy": true,
    "actionsHeader": "Signal",
    "actions": [{
      "icon": "reload",
      "label": "Reload - HUP",
      "action": "ubus('luci2.system','process_signal', { pid: $data.pid, signal: 1})"
    },
    {
      "icon": "close-circle ",
      "label": "Terminate - INT",
      "action": "ubus('luci2.system','process_signal', { pid: $data.pid, signal: 15})"
    },{
      "icon": "flash",
      "label": "Kill - KILL",
      "action": "ubus('luci2.system','process_signal', { pid: $data.pid, signal: 9})"
    }]
  }
}

UCI integration

This is just an example, and is where more work is still needed uci

{
    "type": "tabs",

    "options": {
        "tabLabels": ["Password", "SSH Access", "SSH Keys"]
    },

    "content": [{
            "type": "form",
            "content": [{
                "type": "input",
                "bind": "$model.password",
                "options": {
                    "title": "Password",
                    "required": true
                }
            }, {
                "type": "input",
                "bind": "$model.repassword",
                "validate": "$value === $model.password",
                "options": {
                    "title": "Reenter Password"
                }

            }, {
                "type": "button",
                "bind": "$model.click",
                "options": {
                    "title": "Save",
                    "click": "ubus()"
                }
            }]
        },{
          "type": "uci-section",
          "options": {
            "sectionName": "system.ntp"
          }
        },
        {
            "type": "table",
            "options": {
                "dataSource=": "map(ubus('luci2.system', 'sshkeys_get').keys, 'm=/^([^ ]*) ([^ ]*([^ ]{8})) ([^ ]*)$/.exec($value),{row: $value, key: m[4], type: m[1], hash: m[2], ending: m[3]}')",
                "colKeys": ["key","type", "ending"],
                "colHeaders": ["Remote", "Type", "Hash End"]
            }
        }
    ]

}
danielfdickinson commented 6 years ago

Yeah! I'm glad you still working on this, I was beginning to worry the project was dead; I'm hoping to poke a round and learn how to help, but I'm not a frontend guy so I'm not sure really how much I can help with this. I do hope to see what sort of thing I can do in terms of allow use of this along with old LuCI in a sufficiently integrated way to be useful as bridging measure.

danielfdickinson commented 6 years ago

Will this require nodejs on the router? If so how big are the required components? Or are you using node to generate js, html, and css that is served by uhttpd, in production?

ianchi commented 6 years ago

Hi @cshoredaniel, as you see, albait a bit slowly, but LUCI-NG it’s still moving forward, and any help is welcomed.

Regarding your comments at #44: At the moment the new frame is still evolving and changing, so I think that integrating old LUCI should wait until we have a more clear idea on where/how we need to integrate. But feel free to propose ideas.

ianchi commented 6 years ago

Hi @jow-, when you have a chance, I’d like to know your view on this PR. Thanks!

jow- commented 6 years ago

@ianchi - I love it and really like the fact that it allows moving the heavier logic bits to ubus actions on the remote side. Do you see any reason to not merge it, even if it is wip?

ianchi commented 6 years ago

Hi @jow- , exactly, my idea is that business logic should almost completely reside in backend (Ubus methods) and the view definitions should only handle some minor transformations and mostly deal with pure presentation logic. Probably need for adjustment to some ubus methods will arise.

I sent this as a PR more as an excuse to trigger some discussion. It definitely needs a lot of changes, and no views should actually be made using this API, as it will surely have breaking changes. It also implies changes to the UCI jsonSchema definitions made in the PR #45 (already merged) to make them work together more seamlessly.

Anyway, I'll merge it and continue from here.