├── .editorconfig ├── README.md ├── luci2-app-base ├── .vscode │ └── settings.json ├── Makefile └── root │ ├── usr │ └── share │ │ └── rpcd │ │ ├── acl.d │ │ ├── luci2.json │ │ └── superuser.json │ │ └── luci2 │ │ ├── routes │ │ ├── 10_status.json │ │ ├── 20_recipies.json │ │ ├── 30_system.json │ │ ├── 40_network.json │ │ ├── 50_apps.json │ │ └── 99_development.json │ │ ├── uci │ │ ├── dhcp.json │ │ ├── dropbear.json │ │ ├── firewall.json │ │ ├── network.json │ │ ├── network │ │ │ └── proto │ │ │ │ ├── dhcp.json │ │ │ │ ├── none.json │ │ │ │ └── static.json │ │ ├── system.json │ │ ├── system │ │ │ └── led │ │ │ │ ├── gpio.json │ │ │ │ ├── morse.json │ │ │ │ ├── netdev.json │ │ │ │ ├── timer.json │ │ │ │ └── usbdev.json │ │ └── wireless.json │ │ └── views │ │ ├── apps │ │ ├── apps.view.json │ │ ├── install.upload.content.json │ │ ├── install.view.json │ │ └── software.view.json │ │ ├── development │ │ ├── browser.view.json │ │ ├── ubus.view.json │ │ └── uci.view.json │ │ ├── network │ │ ├── diagnostics.view.json │ │ ├── hosts.view.json │ │ ├── interfaces.view.json │ │ ├── network.view.json │ │ ├── radio.view.json │ │ ├── routes.view.json │ │ ├── switch.view.json │ │ └── wireless.view.json │ │ ├── recipies │ │ └── recipies.view.json │ │ ├── status │ │ ├── dmesg.content.json │ │ ├── firewall.content.json │ │ ├── firewall.view.json │ │ ├── logs.view.json │ │ ├── overview.view.json │ │ ├── overview │ │ │ ├── 01_board.content.json │ │ │ ├── 02_resources.content.json │ │ │ ├── 03_network.content.json │ │ │ ├── 04_dhcp.content.json │ │ │ ├── 05_dsl.content.json │ │ │ └── 06_wifi.content.json │ │ ├── processes.view.json │ │ ├── routes.view.json │ │ ├── syslog.content.json │ │ └── syslog2.content.json │ │ └── system │ │ ├── backup.view.json │ │ ├── startup.view.json │ │ ├── system.administration.content.json │ │ ├── system.backup.content.json │ │ ├── system.dropbear.content.json │ │ ├── system.firmware.content.json │ │ ├── system.flash.restore.content.json │ │ ├── system.led.content.json │ │ ├── system.logging.content.json │ │ ├── system.psw.content.json │ │ ├── system.restore.content.json │ │ ├── system.time.content.json │ │ ├── system.view.json │ │ └── tz.json │ └── www │ └── luci2 │ └── modules │ └── ssh.js ├── luci2-app-dsl ├── Makefile ├── rpcd │ └── status.dsl ├── share │ ├── acl.d │ │ └── status_dsl.json │ └── menu.d │ │ └── status_dsl.json └── www │ ├── controller │ └── status │ │ └── dsl.js │ └── view │ └── status │ └── dsl.html ├── luci2-io-helper ├── Makefile └── src │ ├── CMakeLists.txt │ ├── main.c │ ├── multipart_parser.c │ └── multipart_parser.h ├── luci2-rpc-base ├── Makefile └── src │ ├── CMakeLists.txt │ └── luci2.c ├── luci2-rpc-bwmon ├── Makefile └── src │ ├── CMakeLists.txt │ └── bwmon.c ├── luci2-rpc-rrdns ├── Makefile └── src │ ├── CMakeLists.txt │ ├── rrdns.c │ └── rrdns.h ├── luci2-ui-base ├── Makefile ├── docs │ ├── BUILD.md │ └── CBI.md ├── share │ └── rpcd │ │ ├── acl.d │ │ └── luci-ng.json │ │ └── menu.d │ │ ├── network.json │ │ ├── status.json │ │ ├── system.json │ │ └── tabs.json └── src │ ├── .editorconfig │ ├── .eslintrc │ ├── .gitignore │ ├── Makefile │ ├── bower.json │ ├── gulp │ ├── browsersync.js │ ├── code.js │ ├── conf.js │ ├── general.js │ ├── html.js │ ├── mdIcons.js │ ├── ngMaterial.js │ ├── style.js │ └── translate.js │ ├── gulpfile.js │ ├── package-lock.json │ ├── package.json │ └── www │ ├── amFramework │ ├── components │ │ ├── breadcrumbs.css │ │ ├── breadcrumbs.js │ │ ├── breadcrumbs.tmpl.html │ │ ├── httpProgress.css │ │ ├── httpProgress.js │ │ ├── navTabs.js │ │ ├── navTabs.tmpl.html │ │ ├── panel.js │ │ ├── panel.tmpl.html │ │ ├── sideMenu.css │ │ ├── sideMenu.js │ │ ├── sideMenu.tmpl.html │ │ ├── sideMenuItem.js │ │ ├── sideMenuItem.tmpl.html │ │ ├── slide.css │ │ ├── slide.js │ │ ├── toolbarButtons.js │ │ └── toolbarButtons.tmpl.html │ ├── containers │ │ ├── App.css │ │ ├── App.js │ │ └── App.tmpl.html │ ├── index.js │ ├── resources │ │ └── images │ │ │ └── mdi.svg │ ├── services │ │ ├── loginDialog.css │ │ ├── loginDialog.js │ │ └── loginDialog.tmpl.html │ └── theme.json │ ├── luci-ng.html │ └── luci-ng │ ├── _polyfill.js │ ├── cbi │ ├── cbiDeviceList.js │ ├── cbiDeviceList.tmpl.html │ ├── cbiFlag.js │ ├── cbiFlag.tmpl.html │ ├── cbiInput.js │ ├── cbiInput.tmpl.html │ ├── cbiMap.js │ ├── cbiMap.tmpl.html │ ├── cbiNetworkList.js │ ├── cbiNetworkList.tmpl.html │ ├── cbiOption.js │ ├── cbiOption.tmpl.html │ ├── cbiSection.js │ ├── cbiSection.tmpl.html │ ├── cbiSelect.js │ ├── cbiSelect.tmpl.html │ └── l2.validation.js │ ├── controller │ ├── network │ │ ├── diagnostics.js │ │ ├── interfaces.js │ │ ├── routes.js │ │ └── wireless.js │ ├── status │ │ ├── dmesg.js │ │ ├── overview.js │ │ ├── processes.js │ │ ├── routes.js │ │ └── syslog.js │ └── system │ │ ├── admin.js │ │ ├── backup.js │ │ ├── software.js │ │ ├── startup.js │ │ ├── system.js │ │ └── upgrade.js │ ├── css │ ├── luci-ng.css │ └── material.css │ ├── filters │ └── format.js │ ├── icons │ ├── bridge.png │ ├── bridge_disabled.png │ ├── cbi │ │ ├── add.gif │ │ ├── apply.gif │ │ ├── arrow.gif │ │ ├── down.gif │ │ ├── download.gif │ │ ├── edit.gif │ │ ├── fieldadd.gif │ │ ├── file.gif │ │ ├── find.gif │ │ ├── folder.gif │ │ ├── help.gif │ │ ├── key.gif │ │ ├── link.gif │ │ ├── reload.gif │ │ ├── remove.gif │ │ ├── reset.gif │ │ ├── save.gif │ │ ├── up.gif │ │ └── user.gif │ ├── encryption.png │ ├── encryption_disabled.png │ ├── ethernet.png │ ├── ethernet_disabled.png │ ├── loading.gif │ ├── port_down.png │ ├── port_up.png │ ├── progress.gif │ ├── signal-0-25.png │ ├── signal-0.png │ ├── signal-25-50.png │ ├── signal-50-75.png │ ├── signal-75-100.png │ ├── signal-none.png │ ├── switch.png │ ├── switch_disabled.png │ ├── tunnel.png │ ├── tunnel_disabled.png │ ├── vlan.png │ ├── vlan_disabled.png │ ├── wifi.png │ ├── wifi_big.png │ ├── wifi_big_disabled.png │ └── wifi_disabled.png │ ├── l2.base.js │ ├── proto │ ├── 6in4.js │ ├── 6rd.js │ ├── 6to4.js │ ├── dhcp.js │ ├── dhcpv6.js │ ├── dslite.js │ ├── none.js │ └── static.js │ ├── services │ ├── l2.cgi.js │ ├── l2.class.js │ ├── l2.httpRetry.js │ ├── l2.oui.js │ └── l2.use.js │ ├── ubus │ ├── l2.network.js │ ├── l2.rpc.js │ ├── l2.session.js │ ├── l2.system.js │ ├── l2.uci.js │ └── l2.wireless.js │ ├── ui │ ├── l2.appController.js │ ├── l2.menu.js │ └── l2.spin.js │ └── view │ ├── index.html │ ├── login.html │ ├── network │ ├── diagnostics.html │ ├── interfaces.html │ ├── routes.html │ └── wireless.html │ ├── status │ ├── dmesg.html │ ├── overview.html │ ├── processes.html │ ├── routes.html │ └── syslog.html │ └── system │ ├── admin.html │ ├── backup.html │ ├── software.html │ ├── startup.html │ ├── system.html │ └── upgrade.html ├── luci2-ui-core ├── Makefile ├── root │ └── etc │ │ └── uhttpd │ │ └── luci2.json └── src │ ├── .browserslistrc │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc.json │ ├── .vscode │ ├── launch.json │ ├── settings.json │ └── tasks.json │ ├── JOW.md │ ├── Makefile │ ├── README.md │ ├── TODO.md │ ├── angular.json │ ├── doc │ ├── SCHEMA.UCI.md │ ├── SCHEMA.UI.md │ └── SCHEMA.md │ ├── package-lock.json │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── app.service.ts │ │ ├── shared │ │ │ ├── cgi.service.ts │ │ │ ├── jsonrpc.interface.ts │ │ │ ├── jsonrpc.service.ts │ │ │ ├── observable.debug.ts │ │ │ ├── reconnect.service.ts │ │ │ ├── store.ts │ │ │ ├── ubus.service.ts │ │ │ └── viewsresolver.service.ts │ │ ├── shell │ │ │ ├── login │ │ │ │ ├── ILogin.interface.ts │ │ │ │ ├── login.component.html │ │ │ │ ├── login.component.scss │ │ │ │ ├── login.component.ts │ │ │ │ └── ubus.interface.ts │ │ │ ├── menu │ │ │ │ ├── menu.interface.ts │ │ │ │ ├── menu.service.ts │ │ │ │ └── menuguard.service.ts │ │ │ ├── nav-menu │ │ │ │ ├── _nav-menu.theming.scss │ │ │ │ ├── nav-item.component.html │ │ │ │ ├── nav-item.component.ts │ │ │ │ ├── nav-menu.component.scss │ │ │ │ └── nav-menu.component.ts │ │ │ ├── shell.interface.ts │ │ │ ├── shell.module.ts │ │ │ └── shell │ │ │ │ ├── shell.component.html │ │ │ │ ├── shell.component.scss │ │ │ │ └── shell.component.ts │ │ ├── uci │ │ │ ├── backend │ │ │ │ ├── actions.interface.ts │ │ │ │ ├── config.interface.ts │ │ │ │ ├── option.interface.ts │ │ │ │ ├── section.interface.ts │ │ │ │ └── uci.service.ts │ │ │ └── uci.ts │ │ └── widgets │ │ │ ├── charts │ │ │ ├── charts.module.ts │ │ │ └── set-chart │ │ │ │ ├── setChart.component.html │ │ │ │ ├── setChart.component.scss │ │ │ │ └── setChart.component.ts │ │ │ ├── index.ts │ │ │ ├── popup │ │ │ ├── popup.component.html │ │ │ ├── popup.component.scss │ │ │ └── popup.component.ts │ │ │ ├── popup_file │ │ │ ├── popup_file.component.html │ │ │ ├── popup_file.component.scss │ │ │ └── popup_file.component.ts │ │ │ ├── rootContext.ts │ │ │ └── widgets.module.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── icons.yaml │ ├── icons │ │ ├── logo.svg │ │ └── wordmark.svg │ ├── index.html │ ├── legacy.js │ ├── main.ts │ ├── polyfills.ts │ ├── schema.import.json │ ├── styles.scss │ ├── styles │ │ ├── _components.scss │ │ ├── _constants.scss │ │ ├── _mixins.scss │ │ ├── app-theme.scss │ │ └── main.scss │ ├── tsconfig.app.json │ └── uci.schema.json │ ├── tsconfig.json │ └── tslint.json └── rpcd-mod-iptables ├── .vscode ├── c_cpp_properties.json ├── settings.json └── tasks.json ├── Makefile └── src ├── .clang-format ├── CMakeLists.txt ├── iptables.c ├── iptables6.c ├── main.c ├── shared.c └── shared.h /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | end_of_line = lf 11 | 12 | 13 | [*.md] 14 | max_line_length = off 15 | trim_trailing_whitespace = false 16 | 17 | [Makefile] 18 | indent_style = tab 19 | indent_size = 4 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## WARNING 2 | 3 | This project is stalled as the original LuCI framework has been rewritten to use client side rendering via JavaScript. 4 | 5 | Please see [the documentation](https://openwrt.github.io/luci/) on how to develop get started with the new implementation. 6 | 7 | ~LuCI/Angular JS WIP~ 8 | -------------------------------------------------------------------------------- /luci2-app-base/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "editor.tabSize": 2, 4 | "json.schemas": [ 5 | { 6 | "fileMatch": ["/root/usr/share/rpcd/luci2/views/*.view.json"], 7 | "url": "../luci2-ui-core/src/out/widgetschema/widgets.json" 8 | }, 9 | { 10 | "fileMatch": ["/root/usr/share/rpcd/luci2/views/*.content.json"], 11 | "url": "../luci2-ui-core/src/out/widgetschema/widgets.content.json" 12 | }, 13 | { 14 | "fileMatch": ["/root/usr/share/rpcd/luci2/uci/*/*.json"], 15 | "url": "../luci2-ui-core/src/src/schema.import.json" 16 | }, 17 | { 18 | "fileMatch": [ 19 | "/root/usr/share/rpcd/luci2/uci/*.json", 20 | "!/root/usr/share/rpcd/luci2/uci/*/*.json" 21 | ], 22 | "url": "../luci2-ui-core/src/src/uci.schema.json" 23 | } 24 | ], 25 | "files.exclude": { 26 | "**/.DS_Store": true, 27 | "**/.git": true, 28 | "**/.hg": true, 29 | "**/.svn": true, 30 | "**/CVS": true, 31 | "src/rx-json-ui": true 32 | }, 33 | "spellright.language": ["en"], 34 | "spellright.documentTypes": ["markdown", "latex", "typescript"], 35 | "editor.formatOnSave": true 36 | } 37 | -------------------------------------------------------------------------------- /luci2-app-base/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2020 Adrian Panella 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=luci2-app-base 10 | PKG_VERSION:=20200227 11 | PKG_MAINTAINER:=Adrian Panella 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | include $(INCLUDE_DIR)/package.mk 19 | 20 | define Package/luci2-app-base 21 | SECTION:=luci2 22 | CATEGORY:=LuCI2 23 | TITLE:=LuCI2 Base Application 24 | DEPENDS:=+luci2-ui-core +rpcd-mod-iwinfo +rpcd-mod-rpcsys +luci2-rpc-bwmon +luci2-io-helper +rpcd-mod-iptables 25 | endef 26 | 27 | define Package/luci2-app-base/description 28 | Provides the base applications width standard functionality for the LuCI2 web interface. 29 | endef 30 | 31 | define Build/Compile/Default 32 | 33 | endef 34 | Build/Compile = $(Build/Compile/Default) 35 | 36 | define Package/luci2-app-base/install 37 | $(INSTALL_DIR) $(1)/usr/share 38 | $(CP) ./root/usr/share/* $(1)/usr/share/ 39 | 40 | $(INSTALL_DIR) $(1)/www/luci2/assets/modules 41 | $(CP) ./root/www/luci2/modules/* $(1)/www/luci2/assets/modules/ 42 | endef 43 | 44 | $(eval $(call BuildPackage,luci2-app-base)) 45 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/acl.d/superuser.json: -------------------------------------------------------------------------------- 1 | { 2 | "superuser": { 3 | "description": "Super user access role", 4 | "read": { 5 | "ubus": { "*": ["*"] }, 6 | "uci": ["*"], 7 | "file": { 8 | "/": ["read"], 9 | "/*": ["read"] 10 | } 11 | }, 12 | "write": { 13 | "ubus": { "*": ["*"] }, 14 | "uci": ["*"], 15 | "file": { 16 | "/": ["write"], 17 | "/*": ["write"] 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/routes/10_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": { 3 | "title": "Status", 4 | "index": 10, 5 | "acls": ["status"], 6 | "view": "status/overview", 7 | "hideChilds": true 8 | }, 9 | "status/overview": { 10 | "title": "Status", 11 | "index": 10, 12 | "acls": ["status"], 13 | "view": "status/overview" 14 | }, 15 | 16 | "status/routes": { 17 | "title": "Routes", 18 | "acls": ["status"], 19 | "view": "status/routes", 20 | "index": 20 21 | }, 22 | 23 | "status/processes": { 24 | "title": "Processes", 25 | "acls": ["status"], 26 | "view": "status/processes", 27 | "index": 50 28 | }, 29 | "status/firewall": { 30 | "title": "Firewall", 31 | "acls": ["status"], 32 | "view": "status/firewall", 33 | "index": 60 34 | }, 35 | "logs": { 36 | "title": "Logs", 37 | "acls": ["status"], 38 | "view": "status/logs", 39 | "index": 12 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/routes/20_recipies.json: -------------------------------------------------------------------------------- 1 | { 2 | "recipies": { 3 | "title": "Recipies", 4 | "index": 20, 5 | "acls": ["status"], 6 | "hideChilds": true, 7 | "view": "recipies/recipies" 8 | }, 9 | "recipies/recipies": { 10 | "title": "Recipies", 11 | "index": 10, 12 | "acls": ["status"], 13 | "view": "recipies/recipies" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/routes/30_system.json: -------------------------------------------------------------------------------- 1 | { 2 | "system": { 3 | "title": "System", 4 | "index": 30, 5 | "hideChilds": true, 6 | "view": "system/system" 7 | }, 8 | "system/system": { 9 | "title": "System", 10 | "acls": ["system"], 11 | "view": "system/system", 12 | "module": "ssh", 13 | "index": 10 14 | }, 15 | "system/admin": { 16 | "title": "Administration", 17 | "acls": ["admin"], 18 | "view": "system/admin", 19 | "index": 20 20 | }, 21 | "system/users": { 22 | "title": "Guest Logins", 23 | "acls": ["users"], 24 | "view": "system/users", 25 | "index": 30 26 | }, 27 | 28 | "system/backup": { 29 | "title": "Backup", 30 | "acls": ["backup"], 31 | "view": "system/backup", 32 | "index": 50 33 | }, 34 | "system/upgrade": { 35 | "title": "Upgrade", 36 | "acls": ["upgrade"], 37 | "view": "system/upgrade", 38 | "index": 55 39 | }, 40 | "system/startup": { 41 | "title": "Startup", 42 | "acls": ["startup"], 43 | "view": "system/startup", 44 | "index": 60 45 | }, 46 | "system/cron": { 47 | "title": "Scheduled Tasks", 48 | "acls": ["cron"], 49 | "view": "system/cron", 50 | "index": 70 51 | }, 52 | "system/leds": { 53 | "title": "LED Configuration", 54 | "acls": ["leds"], 55 | "files": ["/etc/init.d/led"], 56 | "view": "system/leds", 57 | "index": 80 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/routes/40_network.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "title": "Network", 4 | "index": 40, 5 | "hideChilds": true, 6 | "view": "network/network" 7 | }, 8 | "network/network": { 9 | "title": "Network", 10 | "acls": ["network"], 11 | "view": "network/network", 12 | "index": 1 13 | }, 14 | "network/interfaces": { 15 | "title": "Interfaces", 16 | "acls": ["network"], 17 | "view": "network/interfaces", 18 | "param": "id", 19 | "index": 10 20 | }, 21 | "network/wireless": { 22 | "title": "Wireless", 23 | "acls": ["network"], 24 | "view": "network/wireless", 25 | "param": "id", 26 | "index": 20 27 | }, 28 | "network/radio": { 29 | "title": "Wireless Radio", 30 | "acls": ["network"], 31 | "view": "network/radio", 32 | "param": "id", 33 | "index": 22 34 | }, 35 | "network/switch": { 36 | "title": "Switch", 37 | "acls": ["network"], 38 | "files": ["/sbin/swconfig"], 39 | "view": "network/switch", 40 | "index": 30 41 | }, 42 | "network/diagnostics": { 43 | "title": "Diagnostics", 44 | "acls": ["diagnostics"], 45 | "view": "network/diagnostics", 46 | "index": 80 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/routes/50_apps.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps": { 3 | "title": "Apps", 4 | "index": 50, 5 | "hideChilds": true, 6 | "view": "apps/apps" 7 | }, 8 | "apps/apps": { 9 | "title": "Apps", 10 | "index": 10, 11 | "hideChilds": true, 12 | "view": "apps/apps" 13 | }, 14 | "apps/software": { 15 | "title": "Software", 16 | "acls": ["software"], 17 | "files": ["/bin/opkg"], 18 | "view": "apps/software", 19 | "index": 40 20 | }, 21 | "apps/install": { 22 | "title": "Install", 23 | "acls": ["software"], 24 | "files": ["/bin/opkg"], 25 | "view": "apps/install", 26 | "index": 40 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/routes/99_development.json: -------------------------------------------------------------------------------- 1 | { 2 | "development": { 3 | "title": "Development", 4 | "index": 900, 5 | "view": "development/ubus" 6 | }, 7 | "development/ubus": { 8 | "title": "UBUS", 9 | "index": 10, 10 | "view": "development/ubus" 11 | }, 12 | "development/uci": { 13 | "title": "UCI", 14 | "index": 20, 15 | "view": "development/uci" 16 | }, 17 | "development/browser": { 18 | "title": "Browser", 19 | "index": 30, 20 | "view": "development/browser" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/uci/network/proto/none.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "description": "Unmanaged", 4 | 5 | "depends=": "$.proto==='none'", 6 | "$onLoad": "store.set('proto', 'none', 'Unmanaged'), console.log('register dhcp')" 7 | } 8 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/uci/system/led/gpio.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | 4 | "depends=": "$.trigger==='gpio'", 5 | 6 | "properties": { 7 | "gpio": { 8 | "title": "GPIO", 9 | "type": "integer", 10 | "default": 0 11 | }, 12 | "inverted": { 13 | "title": "Inverted", 14 | "type": "boolean" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/uci/system/led/morse.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | 4 | "depends=": "$.trigger==='morse'", 5 | 6 | "properties": { 7 | "dev": { 8 | "title": "Device", 9 | "description": "Name of the network/usb device which status should be reflected", 10 | "type": "string", 11 | "required": true, 12 | "enum=": "ubus('luci2.network', 'device_list', '$.devices[*].device')" 13 | }, 14 | "delay": { 15 | "title": "Delay", 16 | "description": "Dit length in milliseconds", 17 | "type": "integer", 18 | "minimum": 0, 19 | "default": 150 20 | }, 21 | "message": { 22 | "title": "Message", 23 | "description": "The message to signal", 24 | "type": "string" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/uci/system/led/netdev.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | 4 | "depends=": "$.trigger==='netdev'", 5 | 6 | "properties": { 7 | "dev": { 8 | "title": "Device", 9 | "description": "Name of the network device which status should be reflected", 10 | "type": "string", 11 | "required": true, 12 | "enum=": "ubus('luci2.network', 'device_list', '$.devices[*].device')" 13 | }, 14 | "mode": { 15 | "title": "Mode", 16 | "description": "One or more of link, tx, or rx, seperated by spaces", 17 | "type": "string", 18 | "required": true, 19 | "enum": ["link", "tx", "rx"], 20 | "default": "link" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/uci/system/led/timer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | 4 | "depends=": "$.trigger==='timer'", 5 | 6 | "properties": { 7 | "delayon": { 8 | "title": "Delay ON", 9 | "description": "How long (ms) the LED should be on", 10 | "type": "integer", 11 | "required": true, 12 | "minimum": 0 13 | }, 14 | "delayoff": { 15 | "title": "Delay OFF", 16 | "description": "How long (ms) the LED should be off", 17 | "type": "integer", 18 | "required": true, 19 | "minimum": 0 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/uci/system/led/usbdev.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | 4 | "depends=": "$.trigger==='usbdev'", 5 | 6 | "properties": { 7 | "dev": { 8 | "title": "Device", 9 | "description": "Name of the usb device which status should be reflected", 10 | "type": "string", 11 | "required": true, 12 | "enum=": "ubus('luci2.network', 'device_list', '$.devices[*].device')" 13 | }, 14 | "interval": { 15 | "title": "Interval", 16 | "description": "Interval in ms when device is active", 17 | "type": "integer", 18 | "required": true, 19 | "minimum": 0, 20 | "default": 50 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/apps/install.upload.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-popup", 3 | "options": { 4 | "title": "Upload package", 5 | "description": "Install package from local computer", 6 | "popupTitle": "Upload Package" 7 | }, 8 | "events": { 9 | "onClose": "$result || ubus('file', 'remove', {path: '/tmp/upload.ipk'}, { all: '' })" 10 | }, 11 | "content": { 12 | "main": [ 13 | { 14 | "widget": "set-file", 15 | "bind": "$.files", 16 | "options": { 17 | "title": "Select app file to upload", 18 | "buttonTitle": "Browse" 19 | }, 20 | "events": { 21 | "onSetup": "$.result = null", 22 | "onAdded": "$.result = cgi.upload('/tmp/upload.ipk', '0400', $.files[0])" 23 | } 24 | }, 25 | { 26 | "widget": "set-text", 27 | "if": "$.files?.length && $.result", 28 | "options": { 29 | "title": "File:", 30 | "subtitle=": "$.files[0].name", 31 | "description=": "`Checksum: ${$.result.checksum}`", 32 | "value=": "formatHuman($.result.size, '1.1-1')" 33 | } 34 | } 35 | ], 36 | "actions": [ 37 | { 38 | "widget": "button", 39 | "options": { "title": "Cancel" }, 40 | "events": { "onClick": "$dlg.close()" } 41 | }, 42 | { 43 | "widget": "button", 44 | "options": { 45 | "title": "Upload", 46 | "disabled=": "!$.files?.length" 47 | }, 48 | "events": { 49 | "onClick": " $dlg.close(true) && snackbar(`TODO: Install package`) " 50 | } 51 | } 52 | ] 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/apps/install.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-subpage", 3 | 4 | "events": { 5 | "onSetup": "$.trigger = 1, $self.list = $.trigger && ubus('luci2.opkg', 'list') || {}" 6 | }, 7 | 8 | "options": { "title": "Install Apps" }, 9 | "content": [ 10 | "loadView('apps/install.upload.content.json')", 11 | { 12 | "widget": "set-button", 13 | "options": { 14 | "title": "Update feeds", 15 | "description": "Download updated list of packages", 16 | "buttonTitle": "Update", 17 | "spinner": "auto" 18 | }, 19 | "events": { 20 | "onClick": "(ubus('luci2.opkg', 'update').code === 0) && $.trigger++ && snackbar('List updated successfully')" 21 | } 22 | }, 23 | { 24 | "widget": "set-expansion", 25 | "options": { 26 | "title": "Install from feeds", 27 | "expanded": true, 28 | "noExpand": true, 29 | "value=": "console.log('list', list) , `${list?.total ?? 0} packages`" 30 | }, 31 | "content": [ 32 | { 33 | "widget": "table", 34 | "options": { 35 | "columns": ["0", "1", "2", "3"], 36 | "headers": { 37 | "0": "Package", 38 | "1": "Version", 39 | "2": "Size", 40 | "3": "Description" 41 | }, 42 | "dataSource=": "list?.packages || []", 43 | "colFormat": ["", "", "HUMAN:'1.1-1'"], 44 | "filter": true, 45 | "pageSizes": [25, 50, 100, 200], 46 | "actions": [{ "icon": "plus-box", "label": "Install" }] 47 | }, 48 | "events": { 49 | "onAction": "ubus('luci2.opkg','install', { package: $row[0]})" 50 | } 51 | } 52 | ] 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/apps/software.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-subpage", 3 | 4 | "options": { "title": "Installed Programs" }, 5 | "content": [ 6 | { 7 | "widget": "table", 8 | "if": "data = ubus('luci2.opkg', 'list_installed')", 9 | "options": { 10 | "columns": ["0", "1"], 11 | "headers": { "0": "Package", "1": "Version" }, 12 | "dataSource=": "data.packages", 13 | "filter": true, 14 | "actions": [{ "icon": "delete", "label": "Uninstall" }] 15 | }, 16 | "events": { 17 | "onAction": "ubus('luci2.opkg','remove', { package: $row[0]})" 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/development/uci.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-page", 3 | "if": "configs = ubus('uci', 'configs').configs", 4 | "content": [ 5 | { 6 | "widget": "set-section", 7 | "bind": "$", 8 | "options": { "title": "UCI autogenerated" }, 9 | "content": [ 10 | { 11 | "widget": "set-select", 12 | "bind": "$.config", 13 | "options": { "title": "Configuration", "enum=": "configs" } 14 | } 15 | ] 16 | }, 17 | 18 | { 19 | "widget": "set-section", 20 | "bind": "$", 21 | "options": { "title": "Generated View" }, 22 | "if": "configs.indexOf($.config)>=0", 23 | "content": ["uciUI($.config)"] 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/network/hosts.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-page", 3 | 4 | "content": [ 5 | { 6 | "widget": "set-section", 7 | "options": { "title": "DNS Server" }, 8 | "content": ["uciUI('dhcp', '@dnsmasq', 0)"] 9 | }, 10 | { 11 | "widget": "set-section", 12 | "options": { "title": "DHCP Interfaces" }, 13 | "content": ["uciUI('dhcp','@dhcp')"] 14 | }, 15 | { 16 | "widget": "set-section", 17 | "options": { "title": "Hostnames" }, 18 | "content": ["uciUI('dhcp','@host')"] 19 | }, 20 | { 21 | "widget": "set-section", 22 | "options": { "title": "Custom Domains" }, 23 | "content": ["uciUI('dhcp','@domain')"] 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/network/interfaces.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "container", 3 | "if": "uciLoad('network')", 4 | "content": [ 5 | "uciUI('network','@interface', parseInt($routeParam.id), {level: 0, widgets: {objectLevel: ['set-subpage','set-section','set-expansion']}})" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/network/radio.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "container", 3 | "if": "uciLoad('wireless')", 4 | "content": [ 5 | "uciUI('wireless','@wifi-device', parseInt($routeParam.id), {level: 0, widgets: {objectLevel: ['set-subpage','set-section','set-expansion']}})" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/network/routes.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-page", 3 | 4 | "content": [ 5 | { 6 | "widget": "set-section", 7 | "options": { "title": "IPv4" }, 8 | "content": ["uciUI('network','@route')"] 9 | }, 10 | { 11 | "widget": "set-section", 12 | "options": { "title": "IPv6" }, 13 | "content": ["uciUI('network','@route6')"] 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/network/switch.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-page", 3 | 4 | "content": [ 5 | { 6 | "widget": "set-section", 7 | "options": { "title": "Switch" }, 8 | "content": ["uciUI('network','@switch', 0, ['!enable_vlan', '!.name'])"] 9 | }, 10 | { 11 | "widget": "set-section", 12 | "options": { "title": "Vlan" }, 13 | "content": [ 14 | "uciUI('network', '@switch', 0, ['enable_vlan'])", 15 | { 16 | "widget": "set-container", 17 | "if": "uci.network['@switch'][0].enable_vlan", 18 | "content": ["uciUI('network','@switch_vlan')"] 19 | } 20 | ] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/network/wireless.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "container", 3 | "if": "uciLoad('wireless')", 4 | "content": [ 5 | "uciUI('wireless','@wifi-iface', parseInt($routeParam.id), {level: 0, widgets: {objectLevel: ['set-subpage','set-section','set-expansion']}})" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/recipies/recipies.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-page", 3 | "content": [ 4 | { 5 | "widget": "set-section", 6 | "options": { "title": "Recipies" }, 7 | "content": [ 8 | { 9 | "widget": "set-autocomplete", 10 | "bind": "$.topic", 11 | "options": { 12 | "title": "Topic", 13 | "description": "Imagine a stepper configured from json", 14 | "enum": ["s"] 15 | } 16 | } 17 | ] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/dmesg.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "table", 3 | "events": { 4 | "onSetup": [ 5 | "$self.re=/^(?:\\[([ .0-9]*)\\])?\\s*(.*)$/i ,", 6 | "$self.log=ubus('luci2.system', 'dmesg').log.split('\\n')" 7 | ] 8 | }, 9 | "options": { 10 | "dataSource=": [ 11 | "log.map( (log, row) => (", 12 | " m=re.exec(log) , m ? ", 13 | " {log, row, time: parseFloat(m[1]), msg: m[2]} :", 14 | " {log, row, msg: log }))" 15 | ], 16 | "columns": ["row", "time", "msg"], 17 | "headers": { "row": "Row", "time": "Time", "msg": "Message" }, 18 | "colFormat": ["", "number:'1.6-6'"], 19 | "pageSizes": [10, 20, 50], 20 | "filter": true, 21 | "disableSort": ["msg"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/firewall.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-subpage", 3 | "options": { "title": "Firewall Status" }, 4 | "content": [ 5 | { 6 | "widget": "tabs", 7 | 8 | "options": { 9 | "tabLabels": ["IPv4", "IPv6"] 10 | }, 11 | "content": [ 12 | { 13 | "widget": "set-container", 14 | "if": "fw = ubus('iptables', 'list', 10000), tables = Object.keys(fw)", 15 | "events": { "onSetup": "$self.command = '/usr/sbin/iptables'" }, 16 | "content": ["loadView('status/firewall.content.json')"] 17 | }, 18 | { 19 | "widget": "set-container", 20 | "if": "fw = ubus('iptables', 'list6', 10000), tables = Object.keys(fw)", 21 | "events": { "onSetup": "$self.command = '/usr/sbin/ip6tables'" }, 22 | "content": ["loadView('status/firewall.content.json')"] 23 | } 24 | ] 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/logs.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-page", 3 | "content": [ 4 | { 5 | "widget": "set-section", 6 | "options": { "title": "Logs" }, 7 | "content": [ 8 | { 9 | "widget": "tabs", 10 | 11 | "options": { 12 | "tabLabels": ["System", "Kernel"] 13 | }, 14 | "content": [ 15 | "loadView('status/syslog.content.json')", 16 | "loadView('status/dmesg.content.json')" 17 | ] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/overview.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-page", 3 | "options": { "class": "status-overview" }, 4 | "events": { 5 | "onSetup": "$self.system_info = ubus('system','info', 2000)" 6 | }, 7 | "content": ["loadView('status/overview/*.json')"] 8 | } 9 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/overview/01_board.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-section", 3 | "options": { "title": "Device" }, 4 | "content": [ 5 | { 6 | "widget": "set-expansion", 7 | "if": "board = ubus('system','board')", 8 | "options": { 9 | "title=": "board.model", 10 | "description=": "board.release.description", 11 | "icon": "information-variant" 12 | }, 13 | "content": [ 14 | { 15 | "widget": "set-text", 16 | "options": { 17 | "title": "Hostname", 18 | "value=": "board.hostname" 19 | } 20 | }, 21 | { 22 | "widget": "set-text", 23 | "options": { "title": "Kernel", "value=": "board.kernel" } 24 | }, 25 | { 26 | "widget": "set-text", 27 | "options": { "title": "Architecture", "value=": "board.system" } 28 | }, 29 | { 30 | "widget": "set-text", 31 | "options": { "title": "Target", "value=": "board.release.target" } 32 | } 33 | ] 34 | }, 35 | { 36 | "widget": "set-text", 37 | "options": { 38 | "description": "Local Time", 39 | "icon": "clock", 40 | "title=": "formatDate(system_info.localtime * 1000, 'MMM d y, HH:mm:ss', 'UTC')", 41 | "subtitle=": "system_info.tzone" 42 | } 43 | }, 44 | { 45 | "widget": "set-text", 46 | "options": { 47 | "description": "Up Time", 48 | "icon": "clock-fast", 49 | "title=": "formatDuration(system_info.uptime * 1000, 'd h:mm:ss')", 50 | "subtitle": "d h:m:s" 51 | } 52 | }, 53 | "loadView('status/overview/include/board.*.json')" 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/routes.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-subpage", 3 | "options": { "title": "Known Routes" }, 4 | "content": [ 5 | { 6 | "widget": "tabs", 7 | 8 | "options": { 9 | "tabLabels": ["IPv4 Routes", "IPv6 Routes", "ARP Table"] 10 | }, 11 | "content": [ 12 | { 13 | "widget": "table", 14 | "if": "data = ubus('luci2.network', 'routes')", 15 | "options": { 16 | "columns": ["target", "nexthop", "metric", "device"], 17 | "headers": { 18 | "target": "Target", 19 | "nexthop": "Gateway", 20 | "metric": "Metric", 21 | "device": "Interface" 22 | }, 23 | "dataSource=": "data.routes" 24 | } 25 | }, 26 | { 27 | "widget": "table", 28 | "if": "data = ubus('luci2.network', 'routes6')", 29 | "options": { 30 | "columns": ["target", "source", "nexthop", "metric", "device"], 31 | "headers": { 32 | "target": "Target", 33 | "source": "Source", 34 | "nexthop": "Gateway", 35 | "metric": "Metric", 36 | "device": "Interface" 37 | }, 38 | "dataSource=": "data.routes" 39 | } 40 | }, 41 | { 42 | "widget": "table", 43 | "if": "data = ubus('luci2.network', 'arp_table')", 44 | "options": { 45 | "columns": ["ipaddr", "macaddr", "device"], 46 | "headers": { 47 | "ipaddr": "IP Address", 48 | "macaddr": "MAC Address", 49 | "device": "Device" 50 | }, 51 | "dataSource=": "data.entries" 52 | } 53 | } 54 | ] 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/syslog.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "table", 3 | "events": { 4 | "onSetup": [ 5 | "$self.log = ubus('luci2.system', 'syslog',10000).log.split('\\n').reverse(), ", 6 | "$self.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" 7 | ] 8 | }, 9 | "options": { 10 | "dataSource=": "log.map( $value => (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], level: m[7]?.split('.')[1]} : {log:$value, msg: $value}))", 11 | "columns": ["date", "type", "pid", "process", "msg"], 12 | "columns_sm": ["date", "level", "process", "msg"], 13 | "headers": { 14 | "date": "Date", 15 | "type": "Type", 16 | "level": "Type", 17 | "pid": "PID", 18 | "process": "Process", 19 | "msg": "Message" 20 | }, 21 | "colFormat": ["date:'MMM-dd HH:mm:ss'"], 22 | "pageSizes": [10, 20, 50], 23 | "filter": true, 24 | "disableSort": ["msg"] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/status/syslog2.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "table", 3 | "events": { 4 | "onSetup": [ 5 | "$self.re = /^([^:[]*)(?:\\[([0-9]+)\\])?:\\s*(.*)$/i ,", 6 | "$self.log = ubus('log', 'read', {stream:false, oneshot:false}, 10000).log.reverse().map( r => (", 7 | " m=re.exec(r.msg),", 8 | " m ? { ...r, msg: m[3], pid: m[2], process: m[1] } : r", 9 | "))" 10 | ] 11 | }, 12 | "options": { 13 | "dataSource=": "log", 14 | "columns": ["time", "priority", "pid", "process", "msg"], 15 | "columns_sm": ["time", "process", "msg"], 16 | "headers": { 17 | "time": "Date", 18 | "type": "Type", 19 | "pid": "PID", 20 | "process": "Process", 21 | "msg": "Message" 22 | }, 23 | "colFormat": ["date:'MMM-dd HH:mm:ss':'UTC'"], 24 | "pageSizes": [10, 20, 50], 25 | "filter": true, 26 | "disableSort": ["msg"] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/backup.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-subpage", 3 | "options": { 4 | "title": "Backup Configuration" 5 | }, 6 | "content": [ 7 | { 8 | "widget": "set-popup-file", 9 | "options": { 10 | "title": "Files to include", 11 | "popupTitle": "Files to include", 12 | "path": "/etc/sysupgrade.conf" 13 | } 14 | }, 15 | { 16 | "widget": "set-expansion", 17 | "options": { 18 | "title": "Generated list", 19 | "description": "Detail of files to backup (changed configuration files, essential base files and user defined)", 20 | "expanded": true, 21 | "noExpand": true 22 | }, 23 | "content": [ 24 | { 25 | "widget": "table", 26 | "if": "data = ubus('luci2.system', 'backup_list').files", 27 | "options": { 28 | "columns": ["File"], 29 | "dataSource=": "data.map( File => {File})", 30 | "filter": true 31 | } 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/startup.view.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-subpage", 3 | 4 | "options": { "title": "Init Scripts" }, 5 | "content": [ 6 | { 7 | "widget": "set-popup-file", 8 | "options": { 9 | "title": "Local Startup", 10 | "description": "Commands to execute them at the end of the boot process", 11 | "path": "/etc/rc.local" 12 | } 13 | }, 14 | { 15 | "widget": "set-expansion", 16 | "options": { 17 | "title": "Init Scripts", 18 | "expanded": true, 19 | "noExpand": true 20 | }, 21 | "content": [ 22 | { 23 | "widget": "table", 24 | "if": "data = ubus('luci2.system', 'init_list')", 25 | "options": { 26 | "columns": ["start", "stop", "name"], 27 | "headers": { 28 | "start": "Start Priority", 29 | "stop": "Stop Priority", 30 | "name": "Name" 31 | }, 32 | "dataSource=": "data.initscripts", 33 | "disableSort": false, 34 | "filter": true, 35 | "actions": [ 36 | { 37 | "icon": "reload", 38 | "label": "Restart", 39 | "data": "restart" 40 | }, 41 | { 42 | "icon": "play", 43 | "label": "Start", 44 | "data": "start" 45 | }, 46 | { 47 | "icon": "stop", 48 | "label": "Stop", 49 | "data": "stop" 50 | } 51 | ] 52 | }, 53 | "events": { 54 | "onAction": "ubus('luci2.system','init_action', { name: $row.name, action: $action.data})" 55 | } 56 | } 57 | ] 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.administration.content.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "widget": "set-popup", 4 | "if": "$user", 5 | "options": { 6 | "title": "Password", 7 | "description=": "`Changes password for current user (${$user})`", 8 | "popupTitle=": "`Change Password for '${$user}'`" 9 | }, 10 | "content": ["loadView('system/system.psw.content.json')"] 11 | }, 12 | { 13 | "widget": "set-expansion", 14 | "if": "ubus('file', 'stat', {path:'/etc/config/dropbear'}, { all: null } ) && uciLoad('dropbear')", 15 | "options": { 16 | "title": "SSH Access", 17 | "value=": [ 18 | "uci.dropbear['@dropbear'].length ? ", 19 | "`${uci.dropbear['@dropbear'][0].Interface || 'all'}:${uci.dropbear['@dropbear'][0].Port}${", 20 | "uci.dropbear['@dropbear'].length > 1 ? ` (+${uci.dropbear['@dropbear'].length-1})` : ''}`", 21 | " : 'Disabled'" 22 | ] 23 | }, 24 | "content": ["loadView('system/system.dropbear.content.json')"] 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.backup.content.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "widget": "set-button", 4 | "options": { 5 | "title": "Backup", 6 | "description": "Download a tar archive of the current configuration files", 7 | "buttonTitle": "Generate", 8 | "spinner": "auto" 9 | }, 10 | "events": { 11 | "onClick": "cgi.backup()" 12 | } 13 | }, 14 | { 15 | "widget": "set-link", 16 | "options": { 17 | "title": "Configure", 18 | "description": "List files/folder to keep & backup", 19 | "link": "system/backup" 20 | } 21 | }, 22 | "loadView('system/system.firmware.content.json')", 23 | { 24 | "widget": "set-expansion", 25 | "options": { 26 | "title": "Restore" 27 | }, 28 | "content": [ 29 | "loadView('system/system.flash.restore.content.json')", 30 | { 31 | "widget": "set-button", 32 | "if": "ubus('luci2.system', 'reset_test' ).supported", 33 | "options": { 34 | "title": "Restore defaults", 35 | "description": "Revert to default configuration", 36 | "buttonTitle": "Reset" 37 | }, 38 | "events": { 39 | "onClick": "popupMsg('This will erase all current configuration.\\nAre you sure?') && ubus('luci2.system', 'reset_start' ) && reconnect()" 40 | } 41 | }, 42 | { 43 | "widget": "set-button", 44 | "options": { 45 | "title": "Restore to previous", 46 | "description": "Revert to previous firmware", 47 | "buttonTitle": "Rollback" 48 | } 49 | } 50 | ] 51 | } 52 | ] 53 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.firmware.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "set-popup", 3 | "options": { 4 | "title": "Firmware", 5 | "description": "Flash new firmware image", 6 | "popupTitle": "Flash" 7 | }, 8 | "content": { 9 | "main": [ 10 | { 11 | "widget": "set-file", 12 | "bind": "$.files", 13 | "options": { 14 | "title": "Select image file", 15 | "description=": "JSON.stringify($.result)", 16 | "buttonTitle": "Select" 17 | }, 18 | "events": { 19 | "onSetup": "$.result = null", 20 | "onAdded": "$.result = cgi.upload('/tmp/backup.tar.gz','0400', $.files[0])" 21 | } 22 | }, 23 | { 24 | "widget": "set-toggle", 25 | "bind": "$.keep", 26 | "options": { 27 | "title": "Keep settings", 28 | "default": true 29 | } 30 | } 31 | ], 32 | "actions": [ 33 | { 34 | "widget": "button", 35 | "options": { "title": "Cancel" }, 36 | "events": { "onClick": "$dlg.close()" } 37 | }, 38 | { 39 | "widget": "button", 40 | "options": { 41 | "title": "Upload", 42 | "disabled=": "!$.files || !$.files.length" 43 | }, 44 | "events": { 45 | "onClick": " $dlg.close() && snackbar(`flashing device`) " 46 | } 47 | } 48 | ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.led.content.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "widget": "set-rowarray", 4 | "bind": "uci.system['@led']", 5 | "events": { 6 | "onNewRow": "{}", 7 | "onDeleteRow": "popupMsg('Are you sure you want to delete this Led?', true)" 8 | }, 9 | 10 | "content": [ 11 | { 12 | "widget": "set-expansion", 13 | "options": { 14 | "title=": "$row.data.name ?? ''", 15 | "description=": "$row.data.sysfs ?? ''", 16 | "value=": "$row.data.trigger ?? ''" 17 | }, 18 | 19 | "content": ["uciUI('system', '@led', $row.index)"] 20 | } 21 | ] 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.logging.content.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "widget": "set-expansion", 4 | "options": { 5 | "title": "System Log" 6 | }, 7 | "content": [ 8 | "uciUI('system', '@system', 0, ['log_buffer_size', '#/file_log'])", 9 | { 10 | "widget": "set-toggle", 11 | "bind": "$.log_remote", 12 | "options": { 13 | "title": "Remote Logging", 14 | "description": "Log to server in addition to the local destination." 15 | }, 16 | "content": [ 17 | "uciUI('system', '@system', 0, ['#/remote_log/*', '!log_remote'])" 18 | ] 19 | } 20 | ] 21 | }, 22 | "uciUI('system', '@system', 0, '#/kernel_log')", 23 | { 24 | "widget": "set-expansion", 25 | "options": { 26 | "title": "Cron Log" 27 | }, 28 | "events": { "onSetup": "$self.system0= uci.system['@system'][0]" }, 29 | "content": [ 30 | { 31 | "widget": "set-toggle", 32 | "for": "['Log Job Start', 'Log Job End', 'Log Failed Jobs', 'Log PID for all Jobs']", 33 | "bind": "$[$for.index]", 34 | "events": { 35 | "onInit": "$[$for.index] = system0.cronloglevel & (2 ** $for.index)", 36 | "onValueChange": "$value ? system0.cronloglevel |= (2 ** $for.index) : system0.cronloglevel &= ~(2 ** $for.index)" 37 | }, 38 | "options": { "title=": "$for.data" } 39 | } 40 | ] 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.psw.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "form", 3 | "content": [ 4 | { 5 | "widget": "input", 6 | "bind": "$.psw1", 7 | "options": { 8 | "title": "New password", 9 | "type": "string", 10 | "inputType": "password", 11 | "minLength": 5, 12 | "required": true, 13 | "autocomplete": "new-password" 14 | } 15 | }, 16 | { 17 | "widget": "input", 18 | "bind": "$.psw2", 19 | "options": { 20 | "title": "Retype password", 21 | "inputType": "password", 22 | "const=": "$.psw1", 23 | "required": true, 24 | "autocomplete": "new-password" 25 | } 26 | }, 27 | { 28 | "widget": "button", 29 | "options": { "title": "Cancel" }, 30 | "events": { "onClick": "$dlg.close()" } 31 | }, 32 | { 33 | "widget": "button", 34 | "options": { 35 | "title": "Change", 36 | "disabled=": "!$form.valid" 37 | }, 38 | "events": { 39 | "onClick": [ 40 | "ubus('rpc-sys', 'password_set', {user:$user, password: $.psw1, extra: 'test'}, e => ", 41 | " snackbar(`Failed to change the system password: ${e.message}`) ) === null && ", 42 | " $dlg.close() && snackbar('Password successfully changed') " 43 | ] 44 | } 45 | } 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.restore.content.json: -------------------------------------------------------------------------------- 1 | { 2 | "widget": "form", 3 | "content": [ 4 | { 5 | "widget": "span", 6 | "options": { 7 | "text=": "$.files?.[0].name || 'Select file'" 8 | } 9 | }, 10 | { 11 | "widget": "file-button", 12 | "bind": "$.files", 13 | "options": { "title": "Select" } 14 | }, 15 | { 16 | "widget": "button", 17 | "options": { "title": "Cancel" }, 18 | "events": { "onClick": "$dlg.close()" } 19 | }, 20 | { 21 | "widget": "button", 22 | "options": { 23 | "title": "Upload", 24 | "disabled=": "!$.files || !$.files.length" 25 | }, 26 | "events": { 27 | "onClick": [ 28 | "cgi.upload('/tmp/backup.tar.gz','666', $.files[0]) && ", 29 | "$dlg.close() && snackbar(`uploading ${$.files[0].name}`) " 30 | ] 31 | } 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /luci2-app-base/root/usr/share/rpcd/luci2/views/system/system.time.content.json: -------------------------------------------------------------------------------- 1 | [ 2 | "uciUI('system', '@system', 0, 'zonename')", 3 | { 4 | "widget": "set-button", 5 | 6 | "options": { 7 | "title": "Local Time", 8 | "description=": "$tmp.localtime ? formatDate( $tmp.localtime * 1000, 'MMM d y, HH:mm:ss', 'UTC') : ''", 9 | "buttonTitle": "Sync with Browser", 10 | "spinner": "auto" 11 | }, 12 | "events": { 13 | "onSetup": "$tmp.localtime = ubus('system', 'info').localtime", 14 | "onClick": [ 15 | "ubus('luci', 'setLocaltime', {localtime: Math.floor(Date.now() / 1000)}).result &&", 16 | " ($tmp.localtime = ubus('system', 'info').localtime) && ", 17 | "snackbar('Time changed')" 18 | ] 19 | } 20 | }, 21 | 22 | { 23 | "widget": "set-expansion", 24 | "bind": "uci.system['@timeserver'][0]", 25 | "if": "ubus('file','stat', {path: '/usr/sbin/ntpd'}, { all: null })", 26 | "options": { 27 | "title": "Time Synchronization", 28 | "value=": "$.enabled && $?.server.length ? $.server[0] + ($.server.length >1 ? ` (+${$.server.length-1})` : '') : 'disabled'", 29 | "description": "Use NTP server" 30 | }, 31 | "content": [ 32 | { 33 | "widget": "set-button", 34 | "if": "ubus('luci', 'getInitList', {name: 'sysntpd'}).sysntpd.enabled", 35 | "options": { 36 | "title": "Service is running", 37 | "buttonTitle": "Sync with NTP", 38 | "spinner": "auto" 39 | }, 40 | "events": { 41 | "onClick": [ 42 | "ubus('luci2.system', 'init_action', {name: 'sysntpd', action: 'restart'}, e => snackbar(`Error restarting service: ${e.message}`)) === null &&", 43 | "snackbar('Synced with NTP server')" 44 | ] 45 | } 46 | }, 47 | "uciUI('system', '@timeserver', 0, ['enabled','use_dhcp','server', 'enable_server'])" 48 | ] 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /luci2-app-dsl/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016 Florian Eckert 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=luci2-app-dsl 10 | PKG_VERSION:=2016-03-01 11 | PKG_MAINTAINER:=Florian Eckert 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | include $(INCLUDE_DIR)/package.mk 19 | 20 | define Build/Compile 21 | endef 22 | 23 | define Package/luci2-app-dsl 24 | SECTION:=luci2 25 | CATEGORY:=LuCI2 26 | TITLE:=LuCI2 support for DSL status 27 | MAINTAINER:=Eckert.Florian@googlemail.com 28 | DEPENDS:=+luci2-ui-base @TARGET_lantiq @TARGET_lantiq_xrx200 29 | endef 30 | 31 | define Package/luci2-app-dsl/description 32 | Provides the LuCI2 web interface with lantiq dsl status informations. 33 | endef 34 | 35 | define Package/luci2-app-dsl/postinst 36 | #!/bin/sh 37 | /etc/init.d/rpcd restart 38 | exit 0 39 | endef 40 | 41 | define Package/luci2-app-dsl/postrm 42 | #!/bin/sh 43 | /etc/init.d/rpcd restart 44 | exit 0 45 | endef 46 | 47 | define Package/luci2-app-dsl/install 48 | $(INSTALL_DIR) $(1)/usr/libexec/rpcd 49 | $(INSTALL_BIN) ./rpcd/status.dsl $(1)/usr/libexec/rpcd/status.dsl 50 | 51 | $(INSTALL_DIR) $(1)/usr/share/rpcd 52 | $(CP) ./share/* $(1)/usr/share/rpcd/ 53 | 54 | $(INSTALL_DIR) $(1)/www/luci-ng 55 | $(CP) ./www/* $(1)/www/luci-ng/ 56 | endef 57 | 58 | $(eval $(call BuildPackage,luci2-app-dsl)) 59 | -------------------------------------------------------------------------------- /luci2-app-dsl/rpcd/status.dsl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2016 OpenWrt.org 3 | 4 | . /lib/functions.sh 5 | . /usr/share/libubox/jshn.sh 6 | 7 | case "$1" in 8 | list) 9 | json_init 10 | 11 | json_add_object "getDslStatus" 12 | json_close_object 13 | 14 | json_dump 15 | ;; 16 | call) 17 | case "$2" in 18 | getDslStatus) 19 | IFS=$'\n' 20 | dsl_status=$(/etc/init.d/dsl_control lucistat) 21 | json_init 22 | json_add_object "dsl" 23 | for dsl in $dsl_status; do 24 | if [ "${dsl/dsl.}" != "${dsl}" ] ; then 25 | status=${dsl:4} 26 | param=${status#*=} 27 | param=${param/nil/} 28 | param=${param//\"/} 29 | value=${status%=*} 30 | json_add_string "${value}" "${param}" 31 | fi 32 | done 33 | json_close_object 34 | json_dump 35 | ;; 36 | esac 37 | ;; 38 | esac 39 | -------------------------------------------------------------------------------- /luci2-app-dsl/share/acl.d/status_dsl.json: -------------------------------------------------------------------------------- 1 | { 2 | "status_dsl": { 3 | "description": "Status information xdsl", 4 | "read": { 5 | "ubus": { 6 | "status.dsl": [ 7 | "getDslStatus" 8 | ] 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /luci2-app-dsl/share/menu.d/status_dsl.json: -------------------------------------------------------------------------------- 1 | { 2 | "status/dsl": { 3 | "title": "xDSL Status", 4 | "acls": [ "status_dsl" ], 5 | "view": "status/dsl", 6 | "index": 60 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /luci2-app-dsl/www/controller/status/dsl.js: -------------------------------------------------------------------------------- 1 | L2.registerController('StatusDslController', 2 | ['$q', '$scope', 'l2rpc', '$timeout', 'l2spin', function($q, $scope, l2rpc, $timeout, l2spin) { 3 | angular.extend($scope, { 4 | getDslStatus: l2rpc.declare({ 5 | object: 'status.dsl', 6 | method: 'getDslStatus' 7 | }), 8 | 9 | loadDslStatus: function() { 10 | return $scope.getDslStatus().then(function(status) { 11 | $scope.dsl = status; 12 | $scope.$timeout = $timeout($scope.loadDslStatus, 5000); 13 | }); 14 | } 15 | }); 16 | 17 | l2spin.open(); 18 | $scope.loadDslStatus().then(l2spin.close); 19 | 20 | $scope.$on('$destroy', function() { 21 | $timeout.cancel($scope.$timeout); 22 | }); 23 | }]); 24 | -------------------------------------------------------------------------------- /luci2-io-helper/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2013-2015 Jo-Philipp Wich 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=luci2-io-helper 10 | PKG_VERSION:=20141219 11 | PKG_MAINTAINER:=Jo-Philipp Wich 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | include $(INCLUDE_DIR)/package.mk 19 | include $(INCLUDE_DIR)/cmake.mk 20 | 21 | define Build/Prepare 22 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 23 | $(CP) ./src/* $(PKG_BUILD_DIR)/ 24 | endef 25 | 26 | define Package/luci2-io-helper 27 | SECTION:=luci2 28 | CATEGORY:=LuCI2 29 | TITLE:=LuCI2 IO Helper 30 | DEPENDS:=+libubox +libubus 31 | endef 32 | 33 | define Package/luci2-io-helper/description 34 | Provides a CGI multicall executable to handle large binary up/download tasks. 35 | endef 36 | 37 | define Package/luci2-io-helper/install 38 | $(INSTALL_DIR) $(1)/usr/libexec $(1)/www/cgi-bin 39 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/luci2-io $(1)/usr/libexec/ 40 | $(LN) /usr/libexec/luci2-io $(1)/www/cgi-bin/luci-upload 41 | $(LN) /usr/libexec/luci2-io $(1)/www/cgi-bin/luci-backup 42 | endef 43 | 44 | $(eval $(call BuildPackage,luci2-io-helper)) 45 | -------------------------------------------------------------------------------- /luci2-io-helper/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(luci2-io C) 4 | 5 | INCLUDE(CheckFunctionExists) 6 | 7 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) 8 | 9 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 10 | 11 | IF(APPLE) 12 | INCLUDE_DIRECTORIES(/opt/local/include) 13 | LINK_DIRECTORIES(/opt/local/lib) 14 | ENDIF() 15 | 16 | ADD_EXECUTABLE(luci2-io main.c multipart_parser.c) 17 | TARGET_LINK_LIBRARIES(luci2-io ubox ubus) 18 | 19 | INSTALL(TARGETS luci2-io RUNTIME DESTINATION sbin) 20 | -------------------------------------------------------------------------------- /luci2-io-helper/src/multipart_parser.h: -------------------------------------------------------------------------------- 1 | /* Based on node-formidable by Felix Geisendörfer 2 | * Igor Afonov - afonov@gmail.com - 2012 3 | * MIT License - http://www.opensource.org/licenses/mit-license.php 4 | */ 5 | #ifndef _multipart_parser_h 6 | #define _multipart_parser_h 7 | 8 | #ifdef __cplusplus 9 | extern "C" 10 | { 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | typedef struct multipart_parser multipart_parser; 17 | typedef struct multipart_parser_settings multipart_parser_settings; 18 | typedef struct multipart_parser_state multipart_parser_state; 19 | 20 | typedef int (*multipart_data_cb) (multipart_parser*, const char *at, size_t length); 21 | typedef int (*multipart_notify_cb) (multipart_parser*); 22 | 23 | struct multipart_parser_settings { 24 | multipart_data_cb on_header_field; 25 | multipart_data_cb on_header_value; 26 | multipart_data_cb on_part_data; 27 | 28 | multipart_notify_cb on_part_data_begin; 29 | multipart_notify_cb on_headers_complete; 30 | multipart_notify_cb on_part_data_end; 31 | multipart_notify_cb on_body_end; 32 | }; 33 | 34 | multipart_parser* multipart_parser_init 35 | (const char *boundary, const multipart_parser_settings* settings); 36 | 37 | void multipart_parser_free(multipart_parser* p); 38 | 39 | size_t multipart_parser_execute(multipart_parser* p, const char *buf, size_t len); 40 | 41 | void multipart_parser_set_data(multipart_parser* p, void* data); 42 | void * multipart_parser_get_data(multipart_parser* p); 43 | 44 | #ifdef __cplusplus 45 | } /* extern "C" */ 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /luci2-rpc-base/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015-2016 Jo-Philipp Wich 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=luci2-rpc-base 10 | PKG_VERSION:=20200325 11 | PKG_MAINTAINER:=Jo-Philipp Wich 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | include $(INCLUDE_DIR)/package.mk 19 | include $(INCLUDE_DIR)/cmake.mk 20 | 21 | define Build/Prepare 22 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 23 | $(CP) ./src/* $(PKG_BUILD_DIR)/ 24 | endef 25 | 26 | define Package/luci2-rpc-base 27 | SECTION:=luci2 28 | CATEGORY:=LuCI2 29 | TITLE:=Base LuCI2 RPC calls 30 | DEPENDS:=+rpcd +libubox +libubus +libuci +libjson-c +libblobmsg-json 31 | endef 32 | 33 | 34 | 35 | define Package/luci2-rpc-base/description 36 | Provides the basic RPC infrastructure to run LuCI2. 37 | endef 38 | 39 | define Package/luci2-rpc-base/install 40 | $(INSTALL_DIR) $(1)/usr/lib/rpcd 41 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/luci2.so $(1)/usr/lib/rpcd/ 42 | endef 43 | 44 | define Package/luci2-rpc-base/postinst 45 | #!/bin/sh 46 | /etc/init.d/rpcd restart 47 | exit 0 48 | endef 49 | 50 | $(eval $(call BuildPackage,luci2-rpc-base)) 51 | -------------------------------------------------------------------------------- /luci2-rpc-base/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(luci2-rpc-base C) 4 | 5 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) 6 | 7 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 8 | 9 | IF(APPLE) 10 | INCLUDE_DIRECTORIES(/opt/local/include) 11 | LINK_DIRECTORIES(/opt/local/lib) 12 | ENDIF() 13 | 14 | FIND_LIBRARY(crypt NAMES crypt) 15 | IF(crypt STREQUAL "LIBS-NOTFOUND") 16 | SET(crypt "") 17 | ENDIF() 18 | 19 | find_library(json NAMES json-c) 20 | 21 | ADD_LIBRARY(luci2-rpc-base MODULE luci2.c) 22 | TARGET_LINK_LIBRARIES(luci2-rpc-base ubox ubus uci blobmsg_json ${json} ${crypt}) 23 | SET_TARGET_PROPERTIES(luci2-rpc-base PROPERTIES OUTPUT_NAME luci2 PREFIX "") 24 | 25 | INSTALL(TARGETS luci2-rpc-base LIBRARY DESTINATION lib) 26 | -------------------------------------------------------------------------------- /luci2-rpc-bwmon/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2015-2016 Jo-Philipp Wich 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=luci2-rpc-bwmon 10 | PKG_VERSION:=20150125 11 | PKG_MAINTAINER:=Jo-Philipp Wich 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | include $(INCLUDE_DIR)/package.mk 19 | include $(INCLUDE_DIR)/cmake.mk 20 | 21 | define Build/Prepare 22 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 23 | $(CP) ./src/* $(PKG_BUILD_DIR)/ 24 | endef 25 | 26 | define Package/luci2-rpc-bwmon 27 | SECTION:=luci2 28 | CATEGORY:=LuCI2 29 | TITLE:=Bandwidth monitoring stats for RPC server 30 | DEPENDS:=+rpcd +libubox +libubus 31 | endef 32 | 33 | define Package/luci2-rpc-bwmon/description 34 | Provides bandwidth monitoring data via the RPC server. 35 | endef 36 | 37 | define Package/luci2-rpc-bwmon/install 38 | $(INSTALL_DIR) $(1)/usr/lib/rpcd 39 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/bwmon.so $(1)/usr/lib/rpcd/ 40 | endef 41 | 42 | define Package/luci2-rpc-bwmon/postinst 43 | #!/bin/sh 44 | killall -HUP rpcd 2>/dev/null 45 | exit 0 46 | endef 47 | 48 | $(eval $(call BuildPackage,luci2-rpc-bwmon)) 49 | -------------------------------------------------------------------------------- /luci2-rpc-bwmon/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(luci2-rpc-bwmon C) 4 | 5 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) 6 | 7 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 8 | 9 | IF(APPLE) 10 | INCLUDE_DIRECTORIES(/opt/local/include) 11 | LINK_DIRECTORIES(/opt/local/lib) 12 | ENDIF() 13 | 14 | ADD_LIBRARY(luci2-rpc-bwmon MODULE bwmon.c) 15 | TARGET_LINK_LIBRARIES(luci2-rpc-bwmon ubox ubus) 16 | SET_TARGET_PROPERTIES(luci2-rpc-bwmon PROPERTIES OUTPUT_NAME bwmon PREFIX "") 17 | 18 | INSTALL(TARGETS luci2-rpc-bwmon LIBRARY DESTINATION lib) 19 | -------------------------------------------------------------------------------- /luci2-rpc-rrdns/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016 Jo-Philipp Wich 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=luci2-rpc-rrdns 10 | PKG_VERSION:=20160218 11 | PKG_MAINTAINER:=Jo-Philipp Wich 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | include $(INCLUDE_DIR)/package.mk 19 | include $(INCLUDE_DIR)/cmake.mk 20 | 21 | define Build/Prepare 22 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 23 | $(CP) ./src/* $(PKG_BUILD_DIR)/ 24 | endef 25 | 26 | define Package/luci2-rpc-rrdns 27 | SECTION:=luci2 28 | CATEGORY:=LuCI2 29 | TITLE:=Rapid reverse DNS for RPC server 30 | DEPENDS:=+rpcd +libubox +libubus 31 | endef 32 | 33 | define Package/luci2-rpc-rrdns/description 34 | Provides rapid mass reverse DNS lookup functionality. 35 | endef 36 | 37 | define Package/luci2-rpc-rrdns/install 38 | $(INSTALL_DIR) $(1)/usr/lib/rpcd 39 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/rrdns.so $(1)/usr/lib/rpcd/ 40 | endef 41 | 42 | define Package/luci2-rpc-rrdns/postinst 43 | #!/bin/sh 44 | killall -HUP rpcd 2>/dev/null 45 | exit 0 46 | endef 47 | 48 | $(eval $(call BuildPackage,luci2-rpc-rrdns)) 49 | -------------------------------------------------------------------------------- /luci2-rpc-rrdns/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(rpcd-mod-rrdns C) 4 | 5 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) 6 | 7 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 8 | 9 | IF(APPLE) 10 | INCLUDE_DIRECTORIES(/opt/local/include) 11 | LINK_DIRECTORIES(/opt/local/lib) 12 | ENDIF() 13 | 14 | FIND_LIBRARY(resolv NAMES resolv) 15 | IF(resolv STREQUAL "LIBS-NOTFOUND") 16 | SET(resolv "") 17 | ENDIF() 18 | 19 | ADD_LIBRARY(rpcd-mod-rrdns MODULE rrdns.c) 20 | TARGET_LINK_LIBRARIES(rpcd-mod-rrdns ubox ubus ${resolv}) 21 | SET_TARGET_PROPERTIES(rpcd-mod-rrdns PROPERTIES OUTPUT_NAME rrdns PREFIX "") 22 | 23 | INSTALL(TARGETS rpcd-mod-rrdns LIBRARY DESTINATION lib) 24 | -------------------------------------------------------------------------------- /luci2-rpc-rrdns/src/rrdns.h: -------------------------------------------------------------------------------- 1 | /* 2 | * rrdns - Rapid Reverse DNS lookup plugin for the UBUS RPC server 3 | * 4 | * Copyright (C) 2016 Jo-Philipp Wich 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define RRDNS_MAX_TIMEOUT 5000 24 | #define RRDNS_DEF_TIMEOUT 250 25 | 26 | #define RRDNS_MAX_LIMIT 1000 27 | #define RRDNS_DEF_LIMIT 10 28 | 29 | 30 | struct rrdns_request { 31 | struct avl_node by_id; 32 | struct avl_node by_addr; 33 | uint16_t id; 34 | uint16_t family; 35 | union { 36 | struct in_addr in; 37 | struct in6_addr in6; 38 | } addr; 39 | }; 40 | 41 | struct rrdns_context { 42 | struct ubus_context *context; 43 | struct ubus_request_data request; 44 | struct uloop_timeout timeout; 45 | struct blob_attr *addr_cur; 46 | int addr_rem; 47 | struct uloop_fd socket; 48 | struct blob_buf blob; 49 | struct avl_tree request_ids; 50 | struct avl_tree request_addrs; 51 | }; 52 | -------------------------------------------------------------------------------- /luci2-ui-base/share/rpcd/menu.d/network.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": { 3 | "title": "Network", 4 | "index": 30 5 | }, 6 | "network/interfaces": { 7 | "title": "Interfaces", 8 | "acls": [ "network" ], 9 | "view": "network/interfaces", 10 | "index": 10 11 | }, 12 | "network/wireless": { 13 | "title": "Wireless", 14 | "acls": [ "network" ], 15 | "view": "network/wireless", 16 | "index": 20 17 | }, 18 | "network/switch": { 19 | "title": "Switch", 20 | "acls": [ "network" ], 21 | "files": [ "/sbin/swconfig" ], 22 | "view": "network/switch", 23 | "index": 30 24 | }, 25 | "network/hosts": { 26 | "title": "Hostnames", 27 | "acls": [ "hostnames" ], 28 | "files": [ "/etc/config/dhcp" ], 29 | "view": "network/hosts", 30 | "index": 50 31 | }, 32 | "network/routes": { 33 | "title": "Routes", 34 | "acls": [ "routes" ], 35 | "view": "network/routes", 36 | "index": 70 37 | }, 38 | "network/diagnostics": { 39 | "title": "Diagnostics", 40 | "acls": [ "diagnostics" ], 41 | "view": "network/diagnostics", 42 | "index": 80 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /luci2-ui-base/share/rpcd/menu.d/status.json: -------------------------------------------------------------------------------- 1 | { 2 | "status": { 3 | "title": "Status", 4 | "index": 10 5 | }, 6 | "status/overview": { 7 | "title": "Overview", 8 | "acls": [ "status" ], 9 | "view": "status/overview", 10 | "index": 10 11 | }, 12 | "status/routes": { 13 | "title": "Routes", 14 | "acls": [ "status" ], 15 | "view": "status/routes", 16 | "index": 20 17 | }, 18 | "status/syslog": { 19 | "title": "System Log", 20 | "acls": [ "status" ], 21 | "view": "status/syslog", 22 | "index": 30 23 | }, 24 | "status/dmesg": { 25 | "title": "Kernel Log", 26 | "acls": [ "status" ], 27 | "view": "status/dmesg", 28 | "index": 40 29 | }, 30 | "status/processes": { 31 | "title": "Processes", 32 | "acls": [ "status" ], 33 | "view": "status/processes", 34 | "index": 50 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /luci2-ui-base/share/rpcd/menu.d/system.json: -------------------------------------------------------------------------------- 1 | { 2 | "system": { 3 | "title": "System", 4 | "index": 20 5 | }, 6 | "system/system": { 7 | "title": "System", 8 | "acls": [ "system" ], 9 | "view": "system/system", 10 | "index": 10 11 | }, 12 | "system/admin": { 13 | "title": "Administration", 14 | "acls": [ "admin" ], 15 | "view": "system/admin", 16 | "index": 20 17 | }, 18 | "system/users": { 19 | "title": "Guest Logins", 20 | "acls": [ "users" ], 21 | "view": "system/users", 22 | "index": 30 23 | }, 24 | "system/software": { 25 | "title": "Software", 26 | "acls": [ "software" ], 27 | "files": [ "/bin/opkg" ], 28 | "view": "system/software", 29 | "index": 40 30 | }, 31 | "system/backup": { 32 | "title": "Backup", 33 | "acls": [ "backup" ], 34 | "view": "system/backup", 35 | "index": 50 36 | }, 37 | "system/upgrade": { 38 | "title": "Upgrade", 39 | "acls": [ "upgrade" ], 40 | "view": "system/upgrade", 41 | "index": 55 42 | }, 43 | "system/startup": { 44 | "title": "Startup", 45 | "acls": [ "startup" ], 46 | "view": "system/startup", 47 | "index": 60 48 | }, 49 | "system/cron": { 50 | "title": "Scheduled Tasks", 51 | "acls": [ "cron" ], 52 | "view": "system/cron", 53 | "index": 70 54 | }, 55 | "system/leds": { 56 | "title": "LED Configuration", 57 | "acls": [ "leds" ], 58 | "files": [ "/etc/init.d/led" ], 59 | "view": "system/leds", 60 | "index": 80 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /luci2-ui-base/share/rpcd/menu.d/tabs.json: -------------------------------------------------------------------------------- 1 | { 2 | "tabs": { 3 | "title": "Tabbed", 4 | "index": 50 5 | }, 6 | "tabs/network": { 7 | "title": "Network", 8 | "tabbed": true, 9 | "index": 10 10 | }, 11 | 12 | "tabs/network/status": { 13 | "title": "Status", 14 | "acls": [ "status" ], 15 | "view": "status/routes", 16 | "index": 10 17 | }, 18 | 19 | "tabs/network/basic": { 20 | "title": "Basic", 21 | "acls": [ "routes" ], 22 | "view": "network/routes", 23 | "index": 20 24 | }, 25 | 26 | "tabs/network/advanced": { 27 | "title": "Advanced", 28 | "acls": [ "routes" ], 29 | "view": "network/routes", 30 | "index": 30 31 | } 32 | } -------------------------------------------------------------------------------- /luci2-ui-base/src/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "angular": true, 4 | "L2": true 5 | 6 | }, 7 | "root": true, 8 | "env": { 9 | "browser": true 10 | }, 11 | "extends": ["eslint:recommended", "google", "angular"], 12 | 13 | "plugins": ["json"], 14 | "rules": { 15 | /* google overrides */ 16 | "no-console": 0, 17 | "require-jsdoc": 0, 18 | "max-len": [2, { 19 | "code": 110, 20 | "tabWidth": 4, 21 | "ignoreUrls": true 22 | }], 23 | "keyword-spacing": "error", 24 | "one-var": 0, 25 | "guard-for-in": 0, 26 | "comma-dangle": [2, "never"], 27 | "object-curly-spacing": [2, "always"], 28 | 29 | /* disable Google ES6 */ 30 | "no-var": 0, 31 | "prefer-rest-params": 0, 32 | "prefer-spread": 0, 33 | 34 | /* temporary disabled */ 35 | 36 | "key-spacing": 0, 37 | "no-mixed-spaces-and-tabs": [2, "smart-tabs"], 38 | "no-multi-spaces": 0, 39 | "camelcase": 0, 40 | 41 | "indent": [2, "tab", { 42 | "SwitchCase": 1, 43 | "VariableDeclarator": 1, 44 | "outerIIFEBody": 0, 45 | "MemberExpression": 1, 46 | "FunctionDeclaration": { 47 | "parameters": "first", 48 | "body": 1 49 | }, 50 | "FunctionExpression": { 51 | "parameters": "first", 52 | "body": 1 53 | }, 54 | "CallExpression": { 55 | "arguments": "first" 56 | }, 57 | "ArrayExpression": 1, 58 | "ObjectExpression": 1 59 | }], 60 | 61 | /* custom extras */ 62 | "object-curly-newline": ["error", { 63 | "multiline": true 64 | }], 65 | "lines-around-directive": 2, 66 | /* Angular overrides */ 67 | "angular/definedundefined": 0, 68 | "angular/typecheck-array": 0, 69 | "angular/typecheck-date": 0, 70 | "angular/typecheck-function": 0, 71 | "angular/typecheck-number": 0, 72 | "angular/typecheck-object": 0, 73 | "angular/typecheck-string": 0, 74 | "angular/document-service": 0, 75 | "angular/window-service": 0, 76 | // "angular/no-directive-replace": 2, 77 | "angular/no-http-callback": 1, 78 | "angular/log": 0, 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /luci2-ui-base/src/.gitignore: -------------------------------------------------------------------------------- 1 | .tmp/ 2 | .maps/ 3 | dist/ 4 | node_modules/ 5 | bower_components/ 6 | -------------------------------------------------------------------------------- /luci2-ui-base/src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2017 Adrian Panella 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | GULP:=node ./node_modules/.bin/gulp 8 | BOWER:=node ./node_modules/.bin/bower 9 | 10 | all: build 11 | 12 | .tmp/.npm_stamp: package.json 13 | npm install 14 | mkdir -p .tmp 15 | touch .tmp/.npm_stamp 16 | 17 | .tmp/.bower_stamp: bower.json 18 | $(BOWER) install --config.interactive=false 19 | mkdir -p .tmp 20 | touch .tmp/.bower_stamp 21 | 22 | .tmp/.download_stamp: ./gulp/conf.js 23 | $(GULP) download 24 | mkdir -p .tmp 25 | touch .tmp/.download_stamp 26 | 27 | prepare: .tmp/.npm_stamp .tmp/.bower_stamp .tmp/.download_stamp 28 | 29 | build: prepare 30 | $(GULP) dist 31 | 32 | clean: 33 | $(GULP) clean 34 | 35 | distclean: clean 36 | rm -rf bower_components 37 | rm -rf node_modules 38 | 39 | -------------------------------------------------------------------------------- /luci2-ui-base/src/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "luci-ng", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "angular": "~1.6.1", 6 | "angular-aria": "~1.6.1", 7 | "angular-animate": "~1.6.1", 8 | "angular-messages": "~1.6.1", 9 | "angular-gettext": "~2.3.8", 10 | "angular-bootstrap": "~2.1.0", 11 | "bootstrap-css-only": "~3.0.0", 12 | "angular-cookies": "~1.6.1", 13 | "angular-ui-router": "~1.0.0" 14 | }, 15 | "devDependencies": {}, 16 | "overrides": {} 17 | } 18 | -------------------------------------------------------------------------------- /luci2-ui-base/src/gulp/browsersync.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | 'use strict'; 4 | 5 | const gulp = require('gulp'); 6 | const browserSync = require('browser-sync').create('server1'); 7 | const proxy = require('http-proxy-middleware'); 8 | 9 | // load configuration files 10 | const conf = require('./conf.js'); 11 | 12 | 13 | // export Gulp tasks 14 | 15 | exports.tasks = { 16 | serveDev: gulp.parallel(watch, serve()), 17 | serveDist: serve('dist') 18 | }; 19 | 20 | exports.browserSync = browserSync; 21 | 22 | function serve(mode) { 23 | return function serveDev(done) { 24 | browserSync.init({ 25 | server: { 26 | baseDir: mode == 'dist' ? [conf.paths.dist] : [conf.paths.tmp, conf.paths.src], 27 | index: conf.paths.mainHtml, 28 | routes: { 29 | '/bower_components': 'bower_components', 30 | '/node_modules': 'node_modules', 31 | '/.tmp': '.tmp', 32 | '/.maps': '.maps' 33 | }, 34 | middleware: conf.proxy ? proxy(conf.proxy) : undefined 35 | }, 36 | open: false 37 | }); 38 | done(); 39 | }; 40 | } 41 | 42 | function watch(done) { 43 | gulp.watch([conf.path.mainHtml('src', ''), 44 | 'bower.json', 45 | conf.path.src('**/*.js')], gulp.series('inject', reloadBrowserSync)); 46 | gulp.watch(conf.path.src('**/*.html'), reloadBrowserSync); 47 | gulp.watch(conf.path.src('**/*.css'), gulp.series('autoprefixCss')); 48 | 49 | done(); 50 | } 51 | 52 | function reloadBrowserSync(done) { 53 | browserSync.reload(); 54 | done(); 55 | } 56 | 57 | -------------------------------------------------------------------------------- /luci2-ui-base/src/gulp/general.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | 'use strict'; 4 | 5 | const gulp = require('gulp'); 6 | const path = require('path'); 7 | const del = require('del'); 8 | const $ = require('gulp-load-plugins')(); // load all gulp-* modules 9 | const lazypipe = require('lazypipe'); 10 | 11 | // load configuration files 12 | const conf = require('./conf.js'); 13 | 14 | // export Gulp tasks 15 | 16 | exports.tasks = { 17 | clean: clean, 18 | download: downloadFiles, 19 | copyAssets: copyAssets, 20 | build: build 21 | }; 22 | 23 | 24 | function clean(done) { 25 | del([conf.paths.dist, conf.paths.tmp, conf.paths.maps]); 26 | done(); 27 | } 28 | 29 | 30 | function downloadFiles() { 31 | var urls = (conf.downloads && conf.downloads.length) ? conf.downloads : []; 32 | 33 | return $.download(urls) 34 | .pipe($.flatmap((stream, file)=> { 35 | var output = path.parse(file.history[file.history.length-1]).name; 36 | 37 | return stream.pipe($.decompress()) 38 | .pipe($.rename((fileN) => { 39 | fileN.dirname = path.join(output, fileN.dirname); 40 | })); 41 | })) 42 | .pipe(gulp.dest(conf.wiredep.directory)); 43 | } 44 | 45 | function copyAssets() { 46 | return gulp.src(conf.path.assets('src', ''), { base: conf.paths.src }) 47 | .pipe(gulp.dest(conf.paths.dist)); 48 | } 49 | 50 | function build() { 51 | return gulp.src(conf.path.mainHtml('tmp', '')) 52 | .pipe($.useref({}, lazypipe().pipe($.sourcemaps.init, { loadMaps: true }))) 53 | .pipe($.if('*.js', $.uglify({ preserveComments: 'license' }))) 54 | .pipe($.if('*.css', $.cssnano())) 55 | .pipe($.if('*.html', $.htmlmin())) 56 | .pipe($.sourcemaps.write(conf.path.maps('..', ''))) 57 | .pipe(gulp.dest(conf.paths.dist)); 58 | } 59 | -------------------------------------------------------------------------------- /luci2-ui-base/src/gulp/html.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | 'use strict'; 4 | 5 | const gulp = require('gulp'); 6 | const $ = require('gulp-load-plugins')(); // load all gulp-* modules 7 | const series = require('stream-series'); 8 | 9 | // load configuration files 10 | const conf = require('./conf.js'); 11 | 12 | 13 | // export Gulp tasks 14 | 15 | exports.tasks = { 16 | copyHtml: copyHtml, 17 | partials: partials, 18 | injectPartials: gulp.series(partials, injectPartials) 19 | }; 20 | 21 | 22 | function copyHtml() { 23 | return gulp.src(conf.path.mainHtml('src', '')) 24 | .pipe(gulp.dest(conf.paths.tmp)); 25 | } 26 | 27 | 28 | function partials() { 29 | var streams = []; 30 | 31 | for (var mod in conf.ngModules) { 32 | streams.push(gulp.src([conf.path.module[mod]('src', '**/*.tmpl.html')] 33 | .concat(conf.path.assets('!'))) 34 | .pipe($.htmlmin({ collapseWhitespace: true })) 35 | .pipe($.angularTemplatecache(mod + '.tmpl.js', { 36 | module: mod, 37 | root: conf.ngModules[mod].path 38 | }))); 39 | } 40 | 41 | return series(streams) 42 | .pipe($.insert.wrap(conf.closure.pre, conf.closure.post)) 43 | .pipe(gulp.dest(conf.paths.tmp)); 44 | } 45 | 46 | function injectPartials() { 47 | var tmpl = gulp.src(conf.path.tmp('*.tmpl.js'), { read: false }); 48 | 49 | return gulp.src(conf.path.mainHtml('tmp', '')) 50 | .pipe($.inject(tmpl, { name: 'partials', relative: true })) 51 | .pipe(gulp.dest(conf.paths.tmp)); 52 | } 53 | -------------------------------------------------------------------------------- /luci2-ui-base/src/gulp/mdIcons.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | 'use strict'; 4 | 5 | const gulp = require('gulp'); 6 | const path = require('path'); 7 | const del = require('del'); 8 | const $ = require('gulp-load-plugins')(); // load all gulp-* modules 9 | 10 | // load configuration files 11 | const conf = require('./conf.js'); 12 | 13 | 14 | // export Gulp tasks 15 | 16 | exports.tasks = { 17 | svg: gulp.series(svgExtractIcons, svgIconset), 18 | svgExtract: svgExtractIcons 19 | }; 20 | 21 | 22 | function svgIconset() { 23 | var icons = require(conf.path.tmp('..', 'svgIcons.json')); 24 | var paths = []; 25 | for (var icon in icons) { 26 | if (icons[icon]) 27 | paths.push(path.join(conf.wiredep.directory, 'MaterialDesignIconsDesign/svg/', icon + '.svg')); 28 | } 29 | return gulp.src(paths) 30 | .pipe($.svgmin()) 31 | .pipe($.cheerio({ 32 | run: function(sel) { 33 | sel('[fill]').removeAttr('fill'); 34 | }, 35 | parserOptions: { xmlMode: true } 36 | })) 37 | .pipe($.svgNgmaterial({ filename : 'iconset.svg', contentTransform: '' })) 38 | .pipe(gulp.dest(conf.path.iconset('tmp', ''))) 39 | .pipe(gulp.dest(conf.path.iconset('dist', ''))); 40 | } 41 | 42 | function svgExtractIcons() { 43 | del(conf.path.tmp('svgIcons.json')); 44 | 45 | return gulp.src([conf.path.src('**/*.html'), conf.path.src('**/*.js')]) 46 | .pipe($.search(/md-svg-icon\s*=\s*["']([^"'{]*)["']/g, function(item) { 47 | var group=item.match(/md-svg-icon\s*=\s*["']([^"']*)["']/); 48 | var res = {}; 49 | res[group.length > 1 ? group[1] : item] = true; 50 | return res; 51 | }, { 52 | path: conf.paths.tmp, 53 | filename: 'svgIcons.json' 54 | })) 55 | .pipe($.search(/svgIcon\s*[:=]\s*["']([^"'{]*)["']/g, function(item) { 56 | var group=item.match(/svgIcon\s*[:=]\s*["']([^"']*)["']/); 57 | var res = {}; 58 | res[group.length > 1 ? group[1] : item] = true; 59 | return res; 60 | }, { 61 | path: conf.paths.tmp, 62 | filename: 'svgIcons.json' 63 | })); 64 | } 65 | -------------------------------------------------------------------------------- /luci2-ui-base/src/gulp/style.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | 'use strict'; 4 | 5 | const gulp = require('gulp'); 6 | const $ = require('gulp-load-plugins')(); // load all gulp-* modules 7 | const browserSync = require('./browsersync.js').browserSync; 8 | 9 | // load configuration files 10 | const conf = require('./conf.js'); 11 | 12 | 13 | // export Gulp tasks 14 | 15 | exports.tasks = { 16 | injectCss: gulp.series(autoprefixCss, injectCss), 17 | autoprefixCss: autoprefixCss 18 | }; 19 | 20 | 21 | function autoprefixCss() { 22 | return gulp.src([conf.path.src('**/*.css')].concat(conf.path.assets('!'))) 23 | .pipe($.autoprefixer()) 24 | .pipe(gulp.dest(conf.paths.tmp)) 25 | .pipe(browserSync.stream()); 26 | } 27 | 28 | function injectCss() { 29 | var css = gulp.src([conf.path.tmp('**/*.css')].concat(conf.path.assets('!')), 30 | { read: false }); 31 | 32 | return gulp.src(conf.path.mainHtml('tmp', '')) 33 | .pipe($.inject(css, { relative: true })) 34 | .pipe(gulp.dest(conf.paths.tmp)); 35 | } 36 | -------------------------------------------------------------------------------- /luci2-ui-base/src/gulp/translate.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | 'use strict'; 4 | 5 | const gulp = require('gulp'); 6 | const path = require('path'); 7 | const $ = require('gulp-load-plugins')(); // load all gulp-* modules 8 | 9 | // load configuration files 10 | const conf = require('./conf.js'); 11 | 12 | 13 | // export Gulp tasks 14 | 15 | exports.tasks = { 16 | translatePot: translatePot, 17 | translateJson: translateJson 18 | }; 19 | 20 | 21 | function translatePot() { 22 | return gulp.src([path.join(conf.paths.src, '**/*.html'), path.join(conf.paths.src, '**/*.js')]) 23 | .pipe($.angularGettext.extract('template.pot', {})) 24 | .pipe(gulp.dest(path.join(conf.paths.tmp, 'po'))); 25 | } 26 | 27 | function translateJson() { 28 | return gulp.src(path.join(conf.paths.src, 'po/**/*.po')) 29 | .pipe($.angularGettext.compile({ format: 'json' })) 30 | .pipe(gulp.dest(path.join(conf.paths.dist, 'translations/'))); 31 | } 32 | -------------------------------------------------------------------------------- /luci2-ui-base/src/gulpfile.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, es6 */ 2 | 3 | 'use strict'; 4 | 5 | const gulp = require('gulp'); 6 | 7 | // load tasks from subfolder and register them 8 | const gtask = require('require-dir')('./gulp'); 9 | 10 | for (var f in gtask) 11 | if (gtask[f].tasks) 12 | for (var t in gtask[f].tasks) 13 | gulp.task(t, gtask[f].tasks[t]); 14 | 15 | /** Add combined task declarations **/ 16 | 17 | gulp.task('clean', gulp.series('clean')); // remove output & tmp directory 18 | gulp.task('lint:fix', gulp.series('lintFix')); // fix linting errors in place 19 | 20 | gulp.task('inject', gulp.series('copyHtml', 'injectCss', 'injectJs', 'injectMaterial')); 21 | 22 | gulp.task('dist', gulp.parallel('svg', 'copyAssets', 23 | gulp.series('lintErr', 'inject', 'injectPartials', 'build'))); 24 | 25 | gulp.task('serve', gulp.series('svg', 'inject', 'serveDev')); 26 | gulp.task('serve:dist', gulp.series('dist', 'serveDist')); 27 | -------------------------------------------------------------------------------- /luci2-ui-base/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "luci-ng", 3 | "version": "0.1.0", 4 | "description": "Provides the LuCI2 web interface with standard functionality", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "luci", 11 | "lede" 12 | ], 13 | "author": "", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "angular-material": "~1.1.3", 17 | "autoprefixer": "~6.6.1", 18 | "bower": "~1.8.8", 19 | "browser-sync": "^2.26.7", 20 | "del": "^5.1.0", 21 | "eslint-config-angular": "~0.5.0", 22 | "eslint-config-google": "~0.7.1", 23 | "eslint-plugin-angular": "~1.6.3", 24 | "eslint-plugin-json": "~1.2.0", 25 | "gulp": "~4.0.0", 26 | "gulp-angular-gettext": "~2.2.0", 27 | "gulp-angular-templatecache": "~2.0.0", 28 | "gulp-autoprefixer": "~3.1.1", 29 | "gulp-changed": "~1.3.2", 30 | "gulp-cheerio": "~0.6.2", 31 | "gulp-cssnano": "~2.1.2", 32 | "gulp-debug": "~3.0.0", 33 | "gulp-decompress": "~2.0.1", 34 | "gulp-download": "0.0.1", 35 | "gulp-eslint": "~3.0.0", 36 | "gulp-filter": "~4.0.0", 37 | "gulp-flatmap": "~1.0.0", 38 | "gulp-foreach": "~0.1.0", 39 | "gulp-htmlmin": "~3.0.0", 40 | "gulp-if": "~2.0.2", 41 | "gulp-inject": "~3.0.0", 42 | "gulp-insert": "~0.5.0", 43 | "gulp-load-plugins": "~1.4.0", 44 | "gulp-ng-annotate": "~1.1.0", 45 | "gulp-rename": "~1.2.2", 46 | "gulp-search": "~1.0.0", 47 | "gulp-sourcemaps": "~1.9.1", 48 | "gulp-svg-ngmaterial": "~2.0.2", 49 | "gulp-svgmin": "~1.2.3", 50 | "gulp-tap": "~0.1.3", 51 | "gulp-uglify": "~1.5.4", 52 | "gulp-useref": "~3.1.2", 53 | "gulp-util": "~3.0.8", 54 | "http-proxy-middleware": "^0.20.0", 55 | "lazypipe": "~1.0.1", 56 | "require-dir": "~0.3.2", 57 | "stream-series": "~0.1.1", 58 | "through2": "~2.0.3", 59 | "wiredep": "~4.0.0" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/breadcrumbs.css: -------------------------------------------------------------------------------- 1 | /* amfBreadcrumbs classes */ 2 | 3 | .amf-breadcrumbs { 4 | text-transform: capitalize; 5 | margin-left: 0.7em; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/breadcrumbs.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | {{$eval('state.' + $ctrl.labelProperty) || state.name}} 5 | {{$eval('state.' + $ctrl.labelProperty) || state.name}} 6 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/httpProgress.css: -------------------------------------------------------------------------------- 1 | /* amfHttpProgress classes */ 2 | 3 | .amf-http-progress { 4 | margin: 0px; 5 | border: none; 6 | padding: 0px; 7 | width: 100%; 8 | position: fixed; 9 | top: 0px; 10 | left: 0px; 11 | z-index: 90; 12 | } 13 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/navTabs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc directive 3 | * @name amfNavTabs 4 | * @module amFramework 5 | * 6 | * @restrict E 7 | * 8 | * @description 9 | * `` Combines a Tabbed navigation with an ui-view routing. 10 | * It provides sync of url/tabs and and embeded view content, integrated with ui-router. 11 | * It is intended to be used directly in the 'component' attribute of a parent state. 12 | * In a way it's similar to mdNavBar but it provides the bar pagination needed for scrolling in small devices, 13 | * but only allows dynamic creation from an object data, and no explicit markup definition of tabs. 14 | * 15 | * @param tabs {!Array=} Array of tabs with title and sref data 16 | * following properties: 17 | * - `title` - `{string=}`: String to show on the tab 18 | * - `sref` - `{string=}`: State name to link this tab to 19 | * - `disabled` - `{bool=}`: True if the tab is disabled (not clickable) 20 | * 21 | */ 22 | 23 | angular.module('amFramework') 24 | .component('amfNavTabs', { 25 | transclude: false, 26 | bindings: { tabs: '<' }, 27 | templateUrl: 'amFramework/components/navTabs.tmpl.html', 28 | controller: NavTabsCtrl 29 | }); 30 | 31 | 32 | function NavTabsCtrl($transitions, $state) { 33 | var self = this; 34 | // Private data 35 | self.selectedIndex = 0; 36 | 37 | self.$onDestroy = $transitions.onSuccess({ to: $state.$current.name + '.**' }, transHook); 38 | 39 | self.syncSref = function(tab) { 40 | $state.go(tab.sref); 41 | }; 42 | 43 | function transHook(transition) { 44 | var toSref = transition.$to().name; 45 | for (var i=0; i 2 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/panel.js: -------------------------------------------------------------------------------- 1 | angular.module('amFramework') 2 | .directive('amfPanel', function() { 3 | return { 4 | restrict: 'E', 5 | transclude: true, 6 | scope: { 7 | title: '@', 8 | template: '@', 9 | options: '@', 10 | icon: '@', 11 | data: '=' 12 | }, 13 | templateUrl: 'amFramework/components/panel.tmpl.html' 14 | }; 15 | }); 16 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/panel.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 | 6 |

{{title}}

7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/sideMenu.css: -------------------------------------------------------------------------------- 1 | /* amfSideMenu classes */ 2 | 3 | .amf-button-toggle .amf-toggle-icon { 4 | display: block; 5 | margin-left: auto; 6 | speak: none; 7 | vertical-align: middle; 8 | transform: rotate(0deg); 9 | -webkit-transform: rotate(0deg); 10 | transition: transform 0.3s ease-in-out; 11 | -webkit-transition: -webkit-transform 0.3s ease-in-out; 12 | } 13 | .amf-button-toggle .amf-toggle-icon.toggled { 14 | transform: rotate(180deg); 15 | -webkit-transform: rotate(180deg); 16 | } 17 | 18 | amf-side-menu ul { 19 | margin: 0px; 20 | padding: 0px; 21 | overflow-x: hidden; 22 | max-width: 100%; 23 | list-style: none; 24 | } 25 | 26 | amf-side-menu li { 27 | margin: 0; 28 | overflow: hidden; 29 | } 30 | 31 | amf-side-menu ul ul { 32 | padding: 5px; 33 | } 34 | 35 | amf-side-menu-item { 36 | 37 | } 38 | 39 | amf-side-menu-item .md-button { 40 | margin: 0px; 41 | width: 100%; 42 | overflow: hidden; 43 | 44 | } 45 | 46 | .amf-menu-item-00 { 47 | text-transform: uppercase; 48 | } 49 | 50 | .amf-menu-item-01 { 51 | text-transform: capitalize; 52 | } 53 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/sideMenu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc directive 3 | * @name amfSideMenu 4 | * @module amFramework 5 | * 6 | * @restrict E 7 | * 8 | * @description 9 | * `` Generates a navigation menu with unlimited nested items. 10 | * If it is inside a mdSidenav, it will automatically close on click. 11 | * 12 | * Style can be customized by level using the `.amf-menu-item-` class. Where root items 13 | * have a level of `00`. 14 | * 15 | * @param nodes {!Array=} Array of nodes with menu data that have the 16 | * following properties: 17 | * - `title` - `{string=}`: Label to display on the menu 18 | * - `sref` - `{string=}`: State to activate when clicked. Ignored if the node has children. 19 | * If a node doesn't have children and sref is empty, the item will be shown as disabled. 20 | * - `isOpen` - `{boolean=}`: Get/sets if a node with children is currently open. 21 | * - `childs` - `{!Array=}`: Array of children nodes, with the same structure 22 | * @param onClick {function(!node)=} Function that is called when an item is clicked. 23 | * It recives the current node object as a parameter. 24 | * 25 | */ 26 | angular.module('amFramework') 27 | .component('amfSideMenu', { 28 | transclude: false, 29 | bindings: { 30 | nodes: '<', 31 | onClick: '&' 32 | }, 33 | templateUrl: 'amFramework/components/sideMenu.tmpl.html' 34 | }); 35 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/sideMenu.tmpl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 |
  • 5 | 6 |
  • 7 |
8 | 9 |
10 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/sideMenuItem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc directive 3 | * @name amfSideMenuItem 4 | * @module amFramework 5 | * 6 | * @restrict E 7 | * 8 | * @description 9 | * `` Internal directive representing a specific item of a amfSideMenu. 10 | * It is not intended to be used directly 11 | * 12 | * @param nodes {!Array=} Array of nodes with menu data that have the 13 | * following properties: 14 | * - `node` - `{!Object=}`: Object with node information 15 | * - `level` - `{integer=}`: Level of the node in the tree. Root elements have `0` level 16 | * and each child level increases by one. It will set a class `.amf-menu-item-` 17 | * that can be used to customize specific level appearence. 18 | * 19 | */ 20 | angular.module('amFramework') 21 | .component('amfSideMenuItem', { 22 | transclude: false, 23 | bindings: { 24 | level: '@', 25 | node: '<' 26 | }, 27 | templateUrl: 'amFramework/components/sideMenuItem.tmpl.html', 28 | require: { 29 | menu: '^^amfSideMenu', 30 | sidenav: '?^^mdSidenav' 31 | }, 32 | controller: SideMenuItemCtrl 33 | }); 34 | 35 | 36 | function SideMenuItemCtrl() { 37 | // Private data 38 | var self = this; 39 | 40 | // Public Methods & Event Handlers 41 | this.click = click; 42 | 43 | // Construction 44 | 45 | // Implementation 46 | function click() { 47 | self.node.isOpen = !self.node.isOpen; 48 | if ((!self.node.childs || !self.node.childs.length) && self.node.sref && self.sidenav) 49 | self.sidenav.close(); 50 | 51 | if (typeof self.menu.onClick == 'function') 52 | self.menu.onClick(self.node); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/sideMenuItem.tmpl.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | {{$ctrl.node.title}} 4 | 5 | 6 | 7 | 8 |
9 |
10 | 11 |
12 | {{$ctrl.node.title}} 13 |
14 |
15 | 16 |
17 | {{$ctrl.node.title}} 18 |
19 |
20 | 21 | 22 | 23 |
24 |
    25 |
  • 26 | 27 |
  • 28 |
29 |
30 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/slide.css: -------------------------------------------------------------------------------- 1 | /* amfSlide classes */ 2 | 3 | 4 | .amf-slide-wrapper { 5 | overflow: hidden; 6 | transition-delay: 0s; 7 | transition-duration: 0.5s; 8 | transition-property: height; 9 | transition-timing-function: ease-in-out; 10 | height: 0px; 11 | margin: 0 !important; 12 | padding: 0 !important; 13 | border: none; 14 | } 15 | 16 | .amf-slide-content { 17 | margin: 0 !important; 18 | padding: 0 !important; 19 | border: none; 20 | } -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/slide.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc directive 3 | * @name amfSlide 4 | * @module amFramework 5 | * 6 | * @restrict A 7 | * 8 | * @description 9 | * `amf-slide` Helper directive to give the element a slide animation to show or hide 10 | * 11 | * @param amfSlide {!bool=} change it to animate and show/hide 12 | * 13 | */ 14 | 15 | angular.module('amFramework') 16 | .directive('amfSlide', function() { 17 | return { 18 | restrict: 'A', 19 | transclude: true, 20 | template: '
', 21 | scope: { amfSlide: '<' }, 22 | 23 | controller: function() {}, 24 | controllerAs: '$ctrl', 25 | link: postLink 26 | }; 27 | }); 28 | 29 | function postLink(scope, element, attr, $ctrl) { 30 | $ctrl.element = element; 31 | element.addClass('amf-slide-wrapper'); 32 | $ctrl.content = element.children('.amf-slide-content'); 33 | 34 | scope.$watch('amfSlide', function amfSlideWatchAction(value) { 35 | if (value) { 36 | $ctrl.element.css({ height: $ctrl.content[0].clientHeight + 'px' }); 37 | } else { 38 | $ctrl.element.css({ height: '0px' }); 39 | } 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/toolbarButtons.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ngdoc directive 3 | * @name amfToolbarButtons 4 | * @module amFramework 5 | * 6 | * @restrict E 7 | * 8 | * @description 9 | * `` Generates a toolbar icon menu which opens popup menues with actions 10 | * 11 | * @param buttons {!Array=} Array of button definition with the following properties: 12 | * - `icon` - `{string=}`: Icon to display on the menu. It must be a named SVG already loaded. 13 | * - `lagel` - `{string=}`: Label to display on the menu. 14 | * - `badge` - `{string=}`: Badge to display over the icon button. 15 | * - `onClick` - `{function()=}`: Function that is called when an item is clicked. 16 | * - `menu` - `{!Array=}`: Array of children nodes, with the same structure 17 | * 18 | */ 19 | angular.module('amFramework') 20 | .component('amfToolbarButtons', { 21 | replace: false, 22 | transclude: false, 23 | bindings: { buttons: '<' }, 24 | templateUrl: 'amFramework/components/toolbarButtons.tmpl.html' 25 | }); 26 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/components/toolbarButtons.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 8 | 9 | 10 | {{btn.badge}} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {{item.label}} 22 | 23 | {{item.badge}} 24 | 25 | 26 | 27 | 28 |
29 | 30 |
-------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/containers/App.css: -------------------------------------------------------------------------------- 1 | md-sidenav.md-locked-open.md-sidenav-left { 2 | width: 200px; 3 | min-width: 110px; 4 | max-width: 300px; 5 | } 6 | 7 | .amf-notifications-label { 8 | height: 16px; 9 | min-width: 16px; 10 | line-height: 16px; 11 | text-align: center; 12 | border-radius: 8px; 13 | position: absolute; 14 | font-size: 10px; 15 | top: 2px; 16 | right: 2px; 17 | background-color: #E75753; 18 | padding-left: 4px; 19 | padding-right: 4px; 20 | } 21 | 22 | .md-icon { 23 | height: auto; 24 | } -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/containers/App.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('amFramework') 5 | .component('amfApp', { 6 | templateUrl: 'amFramework/containers/App.tmpl.html', 7 | controller: AppController, 8 | bindings: { 9 | sideMenu: '<', 10 | toolbar: '<', 11 | onClick: '&' 12 | }, 13 | transclude: { 14 | title: '?amfAppTitle', 15 | content: '?amfAppContent', 16 | footer: '?amfAppFooter' 17 | } 18 | }); 19 | 20 | function AppController($mdSidenav, $timeout) { 21 | this.openMenu = function() { 22 | $timeout(function() { 23 | $mdSidenav('left').open(); 24 | }); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/containers/App.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | 8 |
9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 |
36 |
37 | 38 |
39 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('amFramework', ['ngMaterial', 'ngAnimate', 'ui.router', 'ngMessages']) 5 | .config(function($mdThemingProvider) { 6 | 'ngInject'; 7 | 8 | $mdThemingProvider.theme('default') 9 | .primaryPalette('blue-grey', { default: '600' }) 10 | .accentPalette('teal', { default: '500' }) 11 | .warnPalette('defaultPrimary') 12 | .backgroundPalette('grey', { 13 | 'default': '50', 14 | 'hue-1': '300' 15 | }); 16 | 17 | $mdThemingProvider.definePalette('defaultPrimary', { 18 | '50': '#FFFFFF', 19 | '100': 'rgb(255, 198, 197)', 20 | '200': '#E75753', 21 | '300': '#E75753', 22 | '400': '#E75753', 23 | '500': '#E75753', 24 | '600': '#E75753', 25 | '700': '#E75753', 26 | '800': '#E75753', 27 | '900': '#E75753', 28 | 'A100': '#E75753', 29 | 'A200': '#E75753', 30 | 'A400': '#E75753', 31 | 'A700': '#E75753' 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/services/loginDialog.css: -------------------------------------------------------------------------------- 1 | /* amfLoginDialog classes */ 2 | 3 | .amf-login-dialog { 4 | min-width: 50%; 5 | padding: 20px; 6 | } 7 | 8 | .amf-login-dialog-header { 9 | text-align: center; 10 | } 11 | 12 | .amf-login-dialog-header md-icon { 13 | width: 96px; 14 | height: 96px; 15 | } 16 | 17 | .amf-login-dialog-header h2 { 18 | font-size: 24px; 19 | font-weight: bold; 20 | } 21 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/services/loginDialog.tmpl.html: -------------------------------------------------------------------------------- 1 | 34 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/amFramework/theme.json: -------------------------------------------------------------------------------- 1 | { 2 | "themes": { 3 | "default": { 4 | "primaryPalette": ["blue-grey", { 5 | "default": "600" 6 | }], 7 | "accentPalette": ["teal", { 8 | "default": "500" 9 | }], 10 | "warnPalette": "defaultPrimary", 11 | "backgroundPalette": ["grey", { 12 | "default": "50", 13 | "hue-1": "300" 14 | }] 15 | } 16 | }, 17 | "palettes": { 18 | "defaultPrimary": { 19 | "50": "#FFFFFF", 20 | "100": "rgb(255, 198, 197)", 21 | "200": "#E75753", 22 | "300": "#E75753", 23 | "400": "#E75753", 24 | "500": "#E75753", 25 | "600": "#E75753", 26 | "700": "#E75753", 27 | "800": "#E75753", 28 | "900": "#E75753", 29 | "A100": "#E75753", 30 | "A200": "#E75753", 31 | "A400": "#E75753", 32 | "A700": "#E75753" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiDeviceList.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 13 | 30 |
31 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiFlag.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('LuCI2').directive('cbiFlag', function() { 4 | return { 5 | restrict: 'AE', 6 | scope: true, 7 | 8 | controllerAs: 'Flag', 9 | controller: function(gettext) { 10 | var self = angular.extend(this, { 11 | checked: function(set) { 12 | var val; 13 | 14 | if (arguments.length) { 15 | if (set) 16 | val = self.defaultOn ? undefined : self.onValue; 17 | else 18 | val = self.defaultOn ? self.offValue : undefined; 19 | 20 | self.cbiOwnerOption.formValue(val); 21 | } else { 22 | val = self.cbiOwnerOption.formValue(); 23 | } 24 | 25 | return ((val === undefined && self.defaultOn) || 26 | (val === self.onValue)); 27 | }, 28 | 29 | textValue: function() { 30 | return self.checked() ? gettext('yes') : gettext('no'); 31 | } 32 | }); 33 | }, 34 | 35 | replace: true, 36 | templateUrl: 'luci-ng/cbi/cbiFlag.tmpl.html', 37 | 38 | require: ['cbiFlag', '^cbiOption'], 39 | link: function($scope, iElem, iAttr, ctrls) { 40 | var cbiFlagCtrl = ctrls[0], 41 | cbiOptionCtrl = ctrls[1]; 42 | 43 | cbiOptionCtrl.cbiWidget = angular.extend(cbiFlagCtrl, { 44 | onValue: iAttr.hasOwnProperty('on') ? iAttr.on : '1', 45 | offValue: iAttr.hasOwnProperty('off') ? iAttr.off : '0', 46 | defaultOn: iAttr.hasOwnProperty('defaultOn'), 47 | cbiOwnerOption: cbiOptionCtrl 48 | }); 49 | } 50 | }; 51 | }); 52 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiFlag.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiInput.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('LuCI2').directive('cbiInput', function() { 4 | return { 5 | restrict: 'AE', 6 | replace: true, 7 | templateUrl: 'luci-ng/cbi/cbiInput.tmpl.html' 8 | }; 9 | }); 10 | 11 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiInput.tmpl.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiMap.tmpl.html: -------------------------------------------------------------------------------- 1 |
+ 2 |

{{Map.title}}

3 |

{{Map.description}}

4 |

Loading configuration data…

5 |
6 | 7 |
8 |
9 |
10 | 11 | 12 | 13 |
14 |
15 |
-------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiNetworkList.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 13 | 21 |
22 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiOption.tmpl.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
{{Option.errorMsg}}
6 |
7 |
{{Option.description}}
8 |
9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiSelect.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('LuCI2').directive('cbiSelect', function($parse) { 4 | return { 5 | restrict: 'AE', 6 | scope: true, 7 | 8 | controllerAs: 'Select', 9 | controller: function() { 10 | var self = angular.extend(this, { 11 | textValue: function() { 12 | var o = self.selectElem.options, 13 | i = self.selectElem.selectedIndex; 14 | 15 | return o[i].text; 16 | } 17 | }); 18 | }, 19 | 20 | replace: true, 21 | templateUrl: 'luci-ng/cbi/cbiSelect.tmpl.html', 22 | 23 | require: ['cbiSelect', '^cbiOption'], 24 | link: function($scope, iElem, iAttr, ctrls) { 25 | var cbiSelectCtrl = ctrls[0], 26 | cbiOptionCtrl = ctrls[1]; 27 | 28 | cbiOptionCtrl.cbiWidget = angular.extend(cbiSelectCtrl, { 29 | selectElem: iElem[0], 30 | cbiOwnerOption: cbiOptionCtrl 31 | }); 32 | } 33 | }; 34 | }); 35 | 36 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/cbi/cbiSelect.tmpl.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/controller/network/interfaces.js: -------------------------------------------------------------------------------- 1 | L2.registerController('NetworkInterfacesController', function($scope, l2uci) { 2 | l2uci.load('wireless').then(function() { 3 | angular.element('[ng-view]').html(angular.toJson(l2uci.get('wireless', 'radio0'), true)); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/controller/network/routes.js: -------------------------------------------------------------------------------- 1 | L2.registerController('NetworkRoutesController', function() { 2 | }); 3 | 4 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/controller/status/dmesg.js: -------------------------------------------------------------------------------- 1 | L2.registerController('StatusDmesgController', function($scope, l2rpc, $timeout, l2spin) { 2 | angular.extend($scope, { 3 | getKernelLog: l2rpc.declare({ 4 | object: 'luci2.system', 5 | method: 'dmesg', 6 | expect: { log: '' } 7 | }), 8 | 9 | getLog: function() { 10 | return $scope.getKernelLog().then(function(log) { 11 | var lines = log.split(/\n/); 12 | 13 | lines.pop(); 14 | 15 | $scope.log = lines.reverse().join('\n'); 16 | $scope.lines = lines.length; 17 | 18 | $timeout($scope.getLog, 5000); 19 | }); 20 | } 21 | }); 22 | 23 | l2spin.open(); 24 | $scope.getLog().then(l2spin.close); 25 | }); 26 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/controller/status/processes.js: -------------------------------------------------------------------------------- 1 | L2.registerController('StatusProcessesController', function($q, $scope, l2rpc, l2system, 2 | $timeout, l2spin, gettext) { 3 | angular.extend($scope, { 4 | getProcessList: l2rpc.declare({ 5 | object: 'luci2.system', 6 | method: 'process_list', 7 | expect: { processes: [] } 8 | }), 9 | 10 | sendSignal: l2rpc.declare({ 11 | object: 'luci2.system', 12 | method: 'process_signal', 13 | params: ['pid', 'signal'], 14 | filter: function(data) { 15 | return (data == 0); 16 | } 17 | }), 18 | 19 | getStatus: function() { 20 | return $scope.getProcessList().then(function(processes) { 21 | $scope.processes = processes; 22 | $scope.$timeout = $timeout($scope.getStatus, 5000); 23 | }); 24 | } 25 | }); 26 | 27 | l2spin.open(); 28 | $scope.getStatus().then(l2spin.close); 29 | 30 | $scope.$on('$destroy', function() { 31 | $timeout.cancel($scope.$timeout); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/controller/status/routes.js: -------------------------------------------------------------------------------- 1 | L2.registerController('StatusRoutesController', function($q, $scope, l2rpc, l2oui, gettext) { 2 | angular.extend($scope, { 3 | getRoutes: l2rpc.declare({ 4 | object: 'luci2.network', 5 | method: 'routes', 6 | expect: { routes: [] } 7 | }), 8 | 9 | getIPv6Routes: l2rpc.declare({ 10 | object: 'luci2.network', 11 | method: 'routes6', 12 | expect: { routes: [] } 13 | }), 14 | 15 | getARPTable: l2rpc.declare({ 16 | object: 'luci2.network', 17 | method: 'arp_table', 18 | expect: { entries: [] } 19 | }), 20 | 21 | getStatus: function() { 22 | return $q.all([ 23 | $scope.getRoutes().then(function(routes) { 24 | $scope.routes = routes; 25 | }), 26 | $scope.getIPv6Routes().then(function(routes6) { 27 | $scope.routes6 = routes6; 28 | }), 29 | $scope.getARPTable().then(function(arptable) { 30 | $scope.arptable = { }; 31 | 32 | arptable.sort(function(a, b) { 33 | var ip1 = a.ipaddr.split('.'); 34 | var ip2 = b.ipaddr.split('.'); 35 | a.id = '%02x%02x%02x%02x'.format(ip1[0], ip1[1], ip1[2], ip1[3]); 36 | b.id = '%02x%02x%02x%02x'.format(ip2[0], ip2[1], ip2[2], ip2[3]); 37 | 38 | if (a.id < b.id) 39 | return -1; 40 | else if (a.id > b.id) 41 | return 1; 42 | 43 | return 0; 44 | }); 45 | 46 | for (var i = 0, e; e = arptable[i]; i++) { 47 | if (e.macaddr === '00:00:00:00:00:00') 48 | continue; 49 | 50 | var entries = $scope.arptable[e.macaddr] || 51 | ($scope.arptable[e.macaddr] = []); 52 | 53 | entries.push(e); 54 | } 55 | }) 56 | ]); 57 | }, 58 | 59 | getVendor: function(mac) { 60 | var info = { vendor: gettext('Loading…') }; 61 | 62 | l2oui.lookup(mac).then(function(vendor) { 63 | info.vendor = vendor; 64 | }); 65 | 66 | return info; 67 | } 68 | }); 69 | 70 | $scope.getStatus(); 71 | }); 72 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/controller/status/syslog.js: -------------------------------------------------------------------------------- 1 | L2.registerController('StatusSyslogController', function($scope, l2rpc, $timeout, l2spin) { 2 | angular.extend($scope, { 3 | getSystemLog: l2rpc.declare({ 4 | object: 'luci2.system', 5 | method: 'syslog', 6 | expect: { log: '' } 7 | }), 8 | 9 | getLog: function() { 10 | return $scope.getSystemLog().then(function(log) { 11 | var lines = log.split(/\n/); 12 | 13 | if (!/\n$/.test(log)) 14 | lines.pop(); 15 | 16 | $scope.log = lines.reverse().join('\n'); 17 | $scope.lines = lines.length; 18 | 19 | $timeout($scope.getLog, 5000); 20 | }); 21 | } 22 | }); 23 | 24 | l2spin.open(); 25 | $scope.getLog().then(l2spin.close); 26 | }); 27 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/css/material.css: -------------------------------------------------------------------------------- 1 | /* Angular Material overrides */ 2 | 3 | .md-chips md-chip { 4 | height: 26px; 5 | line-height: 26px; 6 | border-radius: 13px; 7 | 8 | } 9 | 10 | .md-chips md-chip .md-chip-remove { 11 | height: 26px; 12 | width: 26px; 13 | } 14 | 15 | .md-chips md-chip .md-chip-remove md-icon { 16 | height: 16px; 17 | width: 16px; 18 | min-height: 16px; 19 | min-width: 16px; 20 | } 21 | 22 | .md-chips md-chip .md-chip-remove-container { 23 | line-height: 26px; 24 | } 25 | 26 | md-input-container .md-chips { 27 | font-size: 100%; 28 | padding: 0 0 0px 2px; 29 | 30 | } 31 | md-input-container .md-chips .md-chip-input-container { 32 | margin: 0px; 33 | } 34 | 35 | md-input-container .md-chips .md-chip-input-container input.md-input { 36 | line-height: 26px; 37 | height: 30px; 38 | } 39 | 40 | md-input-container .md-chips .md-chip-input-container .md-errors-spacer { 41 | display: none; 42 | } -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/filters/format.js: -------------------------------------------------------------------------------- 1 | angular.module('LuCI2') 2 | .filter('format', function() { 3 | return function(input, template, ifnull) { 4 | if (input === null || input === undefined) { 5 | if (ifnull !== null && ifnull !== undefined) 6 | return ifnull; 7 | 8 | return ''; 9 | } 10 | 11 | if (angular.isString(template)) 12 | return template.format(input); 13 | 14 | return input; 15 | }; 16 | }); 17 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/bridge.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/bridge_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/bridge_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/add.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/add.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/apply.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/apply.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/arrow.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/down.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/download.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/download.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/edit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/edit.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/fieldadd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/fieldadd.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/file.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/file.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/find.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/find.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/folder.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/folder.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/help.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/help.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/key.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/key.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/link.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/link.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/reload.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/reload.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/remove.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/remove.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/reset.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/reset.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/save.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/save.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/up.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/cbi/user.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/cbi/user.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/encryption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/encryption.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/encryption_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/encryption_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/ethernet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/ethernet.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/ethernet_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/ethernet_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/loading.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/port_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/port_down.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/port_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/port_up.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/progress.gif -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/signal-0-25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/signal-0-25.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/signal-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/signal-0.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/signal-25-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/signal-25-50.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/signal-50-75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/signal-50-75.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/signal-75-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/signal-75-100.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/signal-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/signal-none.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/switch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/switch.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/switch_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/switch_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/tunnel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/tunnel.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/tunnel_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/tunnel_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/vlan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/vlan.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/vlan_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/vlan_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/wifi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/wifi.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/wifi_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/wifi_big.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/wifi_big_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/wifi_big_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/icons/wifi_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-base/src/www/luci-ng/icons/wifi_disabled.png -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/l2.base.js: -------------------------------------------------------------------------------- 1 | /* eslint angular/module-setter: 0 */ 2 | 3 | window.L2 = angular.module('LuCI2', [ 4 | 'gettext', 5 | 'ui.router', 6 | 'ngAnimate', 7 | 'ui.bootstrap', 8 | 'ngCookies', 9 | 'ngMaterial', 10 | 'amFramework' 11 | ]); 12 | 13 | angular.module('LuCI2') 14 | .config(function($controllerProvider, $compileProvider, $filterProvider, 15 | $httpProvider, $provide, amfLoginDialogProvider, $urlRouterProvider) { 16 | angular.extend(L2, { 17 | registerController: $controllerProvider.register, 18 | registerDirective: $compileProvider.directive, 19 | registerFilter: $filterProvider.register, 20 | registerFactory: $provide.factory, 21 | registerService: $provide.service 22 | }); 23 | 24 | $httpProvider.interceptors.push('l2httpRetry'); 25 | 26 | amfLoginDialogProvider.configure({ 27 | loginFactory: function(l2session) { 28 | 'ngInject'; 29 | 30 | return l2session.loginCB; 31 | }, 32 | retryFilter: function(req, token) { 33 | if (req.data && angular.isArray(req.data.params) && req.data.params.length) 34 | req.data.params[0]=token; 35 | } 36 | }); 37 | 38 | $urlRouterProvider.otherwise('/menu/status/overview'); 39 | }) 40 | .config(function($mdIconProvider) { 41 | $mdIconProvider.defaultIconSet('luci-ng/icons/svg/iconset.svg'); 42 | }) 43 | .run(function($injector, l2session, gettextCatalog) { 44 | angular.extend(L2, { 45 | invoke: $injector.invoke, 46 | getService: angular.bind($injector, $injector.get) 47 | }); 48 | 49 | gettextCatalog.setCurrentLanguage('de'); 50 | // gettextCatalog.debug = true; 51 | 52 | // dummy rpc call to immidiatly trigger the login interceptor 53 | l2session.data(); 54 | }); 55 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/6in4.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: '6in4', 4 | description: gettext('IPv6-in-IPv4 (RFC4213)'), 5 | tunnel: true, 6 | virtual: true 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/6rd.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: '6rd', 4 | description: gettext('IPv6-over-IPv4 (6rd)'), 5 | tunnel: true, 6 | virtual: true 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/6to4.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: '6to4', 4 | description: gettext('IPv6-over-IPv4 (6to4)'), 5 | tunnel: true, 6 | virtual: true 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/dhcp.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: 'dhcp', 4 | description: gettext('DHCP client'), 5 | tunnel: false, 6 | virtual: false 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/dhcpv6.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: 'dhcpv6', 4 | description: gettext('DHCPv6 client / IPv6 autoconfig'), 5 | tunnel: false, 6 | virtual: false 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/dslite.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: 'dslite', 4 | description: gettext('Dual-Stack Lite (RFC6333)'), 5 | tunnel: true, 6 | virtual: true 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/none.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: 'none', 4 | description: gettext('Unmanaged'), 5 | tunnel: false, 6 | virtual: false 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/proto/static.js: -------------------------------------------------------------------------------- 1 | L2.invoke(['l2network', 'gettext', function(l2network, gettext) { 2 | l2network.registerProtocolHandler({ 3 | protocol: 'static', 4 | description: gettext('Static address'), 5 | tunnel: false, 6 | virtual: false 7 | }); 8 | }]); 9 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/services/l2.cgi.js: -------------------------------------------------------------------------------- 1 | angular.module('LuCI2').factory('l2cgi', function($q, $http, l2rpc) { 2 | var _cgi = { }; 3 | return angular.extend(_cgi, { 4 | 5 | _upload: function(fd) { 6 | var def=$q.defer(); 7 | $http.post('/cgi-bin/luci-upload', fd, { 8 | transformRequest: angular.identity, 9 | headers: { 10 | 'Accept': '*/*', 11 | 'Content-Type': undefined 12 | } 13 | }).then(function(response) { 14 | def.resolve(response.data); 15 | }, function(response) { 16 | def.reject(response); 17 | }); 18 | return def.promise; 19 | }, 20 | 21 | uploadBackup: function(file) { 22 | var fd =new FormData(); 23 | fd.append('sessionid', l2rpc.getToken()); 24 | fd.append('filename', '/tmp/backup.tar.gz'); 25 | fd.append('filemode', '0400'); 26 | fd.append('filedata', file); 27 | return _cgi._upload(fd); 28 | }, 29 | 30 | uploadUpgrade: function(file) { 31 | var fd =new FormData(); 32 | fd.append('sessionid', l2rpc.getToken()); 33 | fd.append('filename', '/tmp/firmware.bin'); 34 | fd.append('filemode', '0400'); 35 | fd.append('filedata', file); 36 | return _cgi._upload(fd); 37 | }, 38 | 39 | _download: function() { 40 | var fileName = 'backup.tar.gz'; 41 | var a = document.createElement('a'); 42 | document.body.appendChild(a); 43 | a.style = 'display: none'; 44 | return $http({ 45 | url: '/cgi-bin/luci-backup', 46 | data: 'sessionid=' + l2rpc.getToken(), 47 | method: 'POST', 48 | headers: { 49 | 'Accept': '*/*', 50 | 'Content-Type': 'application/x-www-form-urlencoded' 51 | }, 52 | responseType: 'arraybuffer', 53 | cache: false 54 | }).then(function(response) { 55 | console.log('success'); 56 | var file = new Blob([response.data], { type: 'application/x-gzip' }); 57 | var fileURL = window.URL.createObjectURL(file); 58 | a.href = fileURL; 59 | a.download = fileName; 60 | a.click(); 61 | }, function(response) { 62 | console.log('failed'); 63 | }); 64 | } 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/services/l2.class.js: -------------------------------------------------------------------------------- 1 | angular.module('LuCI2') 2 | .factory('l2class', function() { 3 | var _class = function() { }; 4 | return angular.extend(_class, { 5 | extend: function(properties) { 6 | var prototype; 7 | 8 | _class.__init__ = true; 9 | prototype = new _class(); 10 | delete _class.__init__; 11 | 12 | angular.extend(prototype, properties, { 13 | __super__: this.prototype, 14 | callSuper: function() { 15 | var args = []; 16 | var func = arguments[0]; 17 | var ctx = this.__super__; 18 | var ret; 19 | 20 | if (typeof(ctx) != 'object' || typeof(ctx[func]) != 'function') 21 | return undefined; 22 | 23 | for (var i = 1; i < arguments.length; i++) 24 | args.push(arguments[i]); 25 | 26 | _class.__scope__ = ctx; 27 | ret = ctx[func].apply(this, args); 28 | delete _class.__scope__; 29 | 30 | return ret; 31 | } 32 | }); 33 | 34 | function Subclass() { 35 | this.options = arguments[0] || { }; 36 | 37 | if (!_class.__init__ && typeof(this.init) == 'function') 38 | this.init.apply(this, arguments); 39 | } 40 | 41 | Subclass.prototype = prototype; 42 | Subclass.prototype.constructor = Subclass; 43 | Subclass.extend = _class.extend; 44 | 45 | return Subclass; 46 | } 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/services/l2.httpRetry.js: -------------------------------------------------------------------------------- 1 | angular.module('LuCI2') 2 | .factory('l2httpRetry', function($q, $timeout, $injector) { 3 | return { 4 | 'responseError': function(response) { 5 | var $http = $injector.get('$http'); 6 | var retry = response.config._retry || 0; 7 | 8 | if (response.status <= 0 && retry++ < 3) { 9 | response.config._retry = retry; 10 | return $timeout(function() { 11 | return $http(response.config); 12 | }, 2500); 13 | } 14 | 15 | return $q.reject(response); 16 | } 17 | }; 18 | }); 19 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/services/l2.oui.js: -------------------------------------------------------------------------------- 1 | angular.module('LuCI2').factory('l2oui', function($http, $q) { 2 | var _oui = { }; 3 | return angular.extend(_oui, { 4 | _load: function(res) { 5 | if (angular.isObject(res) && angular.isArray(res.data) && 6 | (res.data.length % 3) === 0 && res.data.length > 0) 7 | _oui._database = res.data; 8 | else 9 | _oui._database = []; 10 | }, 11 | 12 | load: function() { 13 | if (!_oui._database) 14 | return $http.get('https://raw.githubusercontent.com/jow-/oui-database/master/oui.json') 15 | .then(_oui._load, _oui._load); 16 | 17 | return $q.resolve(); 18 | }, 19 | 20 | _lookup: function(mac) { 21 | var m, l = 0, r = _oui._database.length / 3 - 1; 22 | var mac1 = parseInt(mac.replace(/[^a-fA-F0-9]/g, ''), 16); 23 | 24 | while (l <= r) { 25 | m = l + Math.floor((r - l) / 2); 26 | 27 | var mask = (0xffffffffffff - 28 | (Math.pow(2, 48 - _oui._database[m * 3 + 1]) - 1)); 29 | 30 | var mac1_hi = ((mac1 / 0x10000) & (mask / 0x10000)) >>> 0; 31 | var mac1_lo = ((mac1 & 0xffff) & (mask & 0xffff)) >>> 0; 32 | 33 | var mac2 = parseInt(_oui._database[m * 3], 16); 34 | var mac2_hi = (mac2 / 0x10000) >>> 0; 35 | var mac2_lo = (mac2 & 0xffff) >>> 0; 36 | 37 | if (mac1_hi === mac2_hi && mac1_lo === mac2_lo) 38 | return _oui._database[m * 3 + 2]; 39 | 40 | if (mac2_hi > mac1_hi || 41 | (mac2_hi === mac1_hi && mac2_lo > mac1_lo)) 42 | r = m - 1; 43 | else 44 | l = m + 1; 45 | } 46 | 47 | return undefined; 48 | }, 49 | 50 | lookup: function(mac) { 51 | return _oui.load().then(function() { 52 | return _oui._lookup(mac); 53 | }, function() { 54 | return undefined; 55 | }); 56 | } 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/services/l2.use.js: -------------------------------------------------------------------------------- 1 | angular.module('LuCI2').factory('l2use', function($q, l2spin) { 2 | var _use = { 3 | _head: document.getElementsByTagName('head')[0], 4 | _registry: { }, 5 | 6 | load: function(path) { 7 | var deferred = $q.defer(); 8 | 9 | if (!/^(\/|https?:\/\/)/.test(path)) 10 | path = this._base + path; 11 | 12 | if (this._registry[path]) { 13 | deferred.resolve(false); 14 | } else { 15 | l2spin.open(); 16 | 17 | var el = document.createElement('script'), loaded = false; 18 | 19 | el.onload = el.onreadystatechange = function() { 20 | if ((el.readyState && el.readyState !== 'complete' && 21 | el.readyState !== 'loaded') || loaded) 22 | return; 23 | 24 | el.onload = el.onreadystatechange = null; 25 | loaded = true; 26 | 27 | deferred.resolve(true); 28 | 29 | l2spin.close(); 30 | }; 31 | 32 | el.onerror = function() { 33 | el.onerror = null; 34 | loaded = true; 35 | 36 | deferred.reject(false); 37 | }; 38 | 39 | el.async = true; 40 | el.src = path; 41 | 42 | this._head.insertBefore(el, this._head.firstChild); 43 | this._registry[path] = true; 44 | } 45 | 46 | return deferred.promise; 47 | } 48 | }; 49 | 50 | var scripts = document.getElementsByTagName('script'); 51 | 52 | for (var i = 0; i < scripts.length; i++) { 53 | if (/^(.*\/)?angular\.min\.js\b/.test(scripts[i].src)) { 54 | _use._base = RegExp.$1; 55 | break; 56 | } 57 | } 58 | 59 | return _use; 60 | }); 61 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/ui/l2.appController.js: -------------------------------------------------------------------------------- 1 | /* eslint angular/controller-as-vm: 0 */ 2 | 3 | angular.module('LuCI2') 4 | .controller('AppController', function(l2menu, l2session, $scope) { 5 | var self = this; 6 | self.logout = l2session.destroy; 7 | self.thisYear = new Date().getFullYear(); 8 | 9 | $scope.$on('session.setup', function(event, session) { 10 | l2menu.update().then(function(menu) { 11 | self.sideMenuItems = menu.childs; 12 | l2menu.registerStates(); 13 | }); 14 | }); 15 | 16 | self.toolbar = [ 17 | { 18 | svgIcon: 'border-color', 19 | badge: '0', 20 | menu: [ 21 | { svgIcon: 'content-save', label: 'Commit' }, 22 | { svgIcon: 'undo', label: 'Reset' }] 23 | }, 24 | { 25 | svgIcon: 'account-circle', 26 | menu: [ 27 | { label: 'root', svgIcon: 'account-check' }, 28 | { label: 'Expert Mode', svgIcon: 'tune' }, 29 | { svgIcon: 'lock-outline', label: 'Change Password' }, 30 | { svgIcon: 'logout-variant', label: 'Logout' }] 31 | }, 32 | { 33 | svgIcon: 'power-settings', 34 | menu: [ 35 | { 36 | svgIcon: 'reload', 37 | label: 'Reboot', 38 | onClick: function() { 39 | alert('are you shure?'); 40 | } 41 | }, 42 | { svgIcon: 'translate', label: 'Languaje' }, 43 | { svgIcon: 'palette', label: 'Theme' }] 44 | }]; 45 | }); 46 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/ui/l2.spin.js: -------------------------------------------------------------------------------- 1 | /* eslint no-unreachable:0 */ 2 | 3 | angular.module('LuCI2') 4 | .factory('l2spin', function($uibModal, gettext) { 5 | var template = ''; 10 | 11 | var _loading = { }; 12 | return angular.extend(_loading, { 13 | open: function() { 14 | return; 15 | if (_loading.$modal) 16 | return; 17 | 18 | _loading.$modal = $uibModal.open({ 19 | backdrop: 'static', 20 | template: template, 21 | windowClass: 'no-animation-modal' 22 | }); 23 | }, 24 | 25 | close: function() { 26 | return; 27 | if (!_loading.$modal) 28 | return; 29 | 30 | _loading.$modal.close(); 31 | delete _loading.$modal; 32 | } 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/view/index.html: -------------------------------------------------------------------------------- 1 |

Index

2 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/view/login.html: -------------------------------------------------------------------------------- 1 |
3 | 4 | 5 | 7 | 8 | 9 | 11 | 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/view/network/interfaces.html: -------------------------------------------------------------------------------- 1 |

Interfaces

2 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/view/status/dmesg.html: -------------------------------------------------------------------------------- 1 |

Kernel Log

2 | 3 | 4 | -------------------------------------------------------------------------------- /luci2-ui-base/src/www/luci-ng/view/status/syslog.html: -------------------------------------------------------------------------------- 1 |

System Log

2 | 3 | 4 | -------------------------------------------------------------------------------- /luci2-ui-core/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2020 Adrian Panella 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=luci2-ui-core 10 | PKG_VERSION:=20200227 11 | PKG_MAINTAINER:=Adrian Panella 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | PKG_BUILD_DEPENDS:=!LUCI2_USE_HOST_NODE:node/host 19 | PKG_CONFIG_DEPENDS:=CONFIG_LUCI2_USE_HOST_NODE 20 | 21 | include $(INCLUDE_DIR)/package.mk 22 | 23 | define Package/luci2-ui-core 24 | SECTION:=luci2 25 | CATEGORY:=LuCI2 26 | TITLE:=Luci2 UI Core 27 | DEPENDS:=+rpcd +uhttpd +uhttpd-mod-ubus +luci2-rpc-base +rpcd-mod-file 28 | endef 29 | 30 | define Package/luci2-ui-core/description 31 | Provides the LuCI2 web interface with standard functionality. 32 | endef 33 | 34 | define Package/luci2-ui-core/config 35 | config LUCI2_USE_HOST_NODE 36 | bool "Use existing nodejs installation on the host system" 37 | default y 38 | help 39 | This disables the build dependency on the node package from 40 | the OpenWrt packages feed, allowing for faster development 41 | builds. 42 | endef 43 | 44 | define Build/Prepare 45 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 46 | find ./src -maxdepth 1 -type f -exec cp -f {} $(PKG_BUILD_DIR) \; 47 | $(CP) ./src/src $(PKG_BUILD_DIR)/src 48 | $(MAKE) -C $(PKG_BUILD_DIR) prepare 49 | endef 50 | 51 | define Package/luci2-ui-core/install 52 | $(INSTALL_DIR) $(1)/www/luci2 53 | $(CP) $(PKG_BUILD_DIR)/dist/* $(1)/www/luci2 54 | $(INSTALL_DIR) $(1)/etc/uhttpd 55 | $(CP) ./root/etc/uhttpd/* $(1)/etc/uhttpd/ 56 | endef 57 | 58 | define Package/luci2-ui-core/postinst 59 | #!/bin/sh 60 | 61 | if [ "$$(uci -q get uhttpd.main.ubus_prefix)" != "/ubus" ]; then 62 | uci set uhttpd.main.ubus_prefix="/ubus" 63 | uci commit uhttpd 64 | fi 65 | 66 | exit 0 67 | endef 68 | 69 | $(eval $(call BuildPackage,luci2-ui-core)) 70 | -------------------------------------------------------------------------------- /luci2-ui-core/root/etc/uhttpd/luci2.json: -------------------------------------------------------------------------------- 1 | { 2 | "request": [ 3 | [ 4 | "if", 5 | ["or", ["eq", "REQUEST_URI", "/luci2/index.html"], ["eq", "REQUEST_URI", "/"]], 6 | ["redirect", "/luci2/"] 7 | ] 8 | ], 9 | "fallback": [ 10 | [ 11 | "if", 12 | ["regex", "REQUEST_URI", "^/luci2/.+"], 13 | ["rewrite", "/luci2/"] 14 | ] 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /luci2-ui-core/src/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 1% and last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 # For IE 9-11 support, remove 'not'. 12 | not op_mini all 13 | not and_uc >=10 14 | -------------------------------------------------------------------------------- /luci2-ui-core/src/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | indent_size = 4 18 | -------------------------------------------------------------------------------- /luci2-ui-core/src/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /out 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | # IDEs and editors 13 | /.idea 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | *.sublime-workspace 20 | 21 | # IDE - VSCode 22 | .vscode/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | 28 | # misc 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /libpeerconnection.log 33 | npm-debug.log 34 | testem.log 35 | /typings 36 | 37 | # e2e 38 | /e2e/*.js 39 | /e2e/*.map 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | -------------------------------------------------------------------------------- /luci2-ui-core/src/.prettierignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /out 3 | /src/rx-json-ui -------------------------------------------------------------------------------- /luci2-ui-core/src/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "printWidth": 90, 4 | "trailingComma": "es5", 5 | "bracketSpacing": true, 6 | "endOfLine": "auto" 7 | } 8 | -------------------------------------------------------------------------------- /luci2-ui-core/src/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "CLI", 8 | "program": "${workspaceFolder}/node_modules/rx-json-ui-cli/bin/cli.js", 9 | "sourceMaps": false, 10 | "args": [ 11 | "g", 12 | "-m", 13 | "app/app.module", 14 | "-p", 15 | "./src/tsconfig.app.json", 16 | "dist/widgetschema" 17 | ], 18 | "stopOnEntry": true, 19 | "skipFiles": ["/**"], 20 | "console": "integratedTerminal" 21 | }, 22 | { 23 | "type": "chrome", 24 | "request": "launch", 25 | "name": "Launch Chrome against localhost", 26 | "url": "http://localhost:4200", 27 | "webRoot": "${workspaceRoot}", 28 | "sourceMaps": true 29 | }, 30 | { 31 | "type": "chrome", 32 | "request": "attach", 33 | "name": "Attach to Chrome", 34 | "port": 9222, 35 | "webRoot": "${workspaceRoot}", 36 | "sourceMaps": true, 37 | "sourceMapPathOverrides": { 38 | "webpack:///.+/~/*": "${webRoot}/node_modules/*", 39 | "webpack:///.+/src/*": "${webRoot}/src/*" 40 | } 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /luci2-ui-core/src/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "tslint.rulesDirectory": "./node_modules/tslint-eslint-rules/dist/rules", 4 | "editor.tabSize": 2, 5 | "stylelint.enable": true, 6 | "css.validate": false, 7 | "scss.validate": false, 8 | "typescript.tsc.autoDetect": "off", 9 | "typescript.referencesCodeLens.enabled": true, 10 | "typescript.implementationsCodeLens.enabled": true, 11 | "files.associations": { 12 | ".stylelintrc": "json" 13 | }, 14 | "json.schemas": [ 15 | { 16 | "fileMatch": ["/.stylelintrc"], 17 | "url": "http://json.schemastore.org/stylelintrc" 18 | } 19 | ], 20 | 21 | "terminal.integrated.shellArgs.linux": ["--rcfile", ".vscode/bashrc"], 22 | "tslint.exclude": "**/node_modules/**", 23 | "files.exclude": { 24 | "**/.DS_Store": true, 25 | "**/.git": true, 26 | "**/.hg": true, 27 | "**/.svn": true, 28 | "**/CVS": true, 29 | "src/rx-json-ui": true 30 | }, 31 | "spellright.language": ["en"], 32 | "spellright.documentTypes": ["markdown", "latex", "typescript"], 33 | "editor.formatOnSave": true, 34 | "typescript.tsdk": "node_modules\\typescript\\lib" 35 | } 36 | -------------------------------------------------------------------------------- /luci2-ui-core/src/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "lint", 7 | "problemMatcher": [ 8 | { 9 | "owner": "ng", 10 | "source": "tslint", 11 | "applyTo": "allDocuments", 12 | "fileLocation": "absolute", 13 | "severity": "warning", 14 | "pattern": { 15 | "regexp": "^(WARNING|ERROR):(\\s+\\(\\S*\\))?\\s+(\\S.*):(\\d+):(\\d+)\\s+-\\s+(.*)$", 16 | "severity": 1, 17 | "file": 3, 18 | "line": 4, 19 | "column": 5, 20 | "message": 6 21 | } 22 | } 23 | ] 24 | }, 25 | { 26 | "type": "npm", 27 | "script": "start", 28 | "isBackground": true, 29 | "group": { 30 | "kind": "build", 31 | "isDefault": true 32 | }, 33 | "problemMatcher": "$tsc-watch" 34 | }, 35 | { 36 | "type": "npm", 37 | "script": "build", 38 | "problemMatcher": "$tsc" 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /luci2-ui-core/src/JOW.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # System 4 | 5 | * why does luci save hostname via Lua, instead of default uci behaviour via procd? 6 | `fs.writefile( "/proc/sys/kernel/hostname", newname )` 7 | 8 | * why does Luci save timezone via Lua, instead of default uci behaviour via procd? 9 | `fs.writefile("/etc/TZ", timezone .. "\n")` 10 | 11 | * check for `/usr/sbin/ntpd` to enable ntpd settings? 12 | 13 | * why Luci doesn't allow modifying `zonename`, it is valid in init scripts? 14 | * what is `luci.sys.zoneinfo.tzoffset` used for? 15 | 16 | * best place to store `tz_data` to be dynamic with current year data? 17 | 18 | * why does Luci change ntpd status directly and not via uci/procd? 19 | `sys.call("env -i /etc/init.d/sysntpd start >/dev/null")` 20 | if it was disabled, the init script is not registered and no trigger will reload the config!? 21 | 22 | * who is responsible for enabling/disabling startup scripts to sync with uci `enabled` status? 23 | Luci called `/etc/init.d/sysntpd enable` (or disable) on change 24 | 25 | * why are `use_dhcp` and `dhcp_interface` not configurable via Luci? 26 | they are also not documented in [](https://openwrt.org/docs/guide-user/advanced/ntp_configuration) 27 | 28 | * UCI method to set device time -------------------------------------------------------------------------------- /luci2-ui-core/src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2020 Adrian Panella 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | all: build 8 | 9 | node_modules: package-lock.json 10 | npm ci 11 | 12 | out/icons: node_modules src/icons.yaml 13 | npm run svg 14 | 15 | prepare: node_modules out/icons 16 | 17 | build: prepare 18 | npm run gen-schema 19 | npm run build 20 | 21 | compile: build 22 | 23 | clean: 24 | rm -rf dist 25 | rm -rf out 26 | rm .icons 27 | 28 | distclean: clean 29 | rm -rf node_modules 30 | 31 | -------------------------------------------------------------------------------- /luci2-ui-core/src/README.md: -------------------------------------------------------------------------------- 1 | # LuciNg2 2 | 3 | Luci-NG implementation using Angular 4 + Material 2. 4 | 5 | ## Install 6 | You need `Node` and `Npm` installed in the development machine. 7 | 8 | Run `npm install` to install all dependencies. 9 | 10 | ## Development server 11 | 12 | Run `npm start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 13 | 14 | All `Ubus` calls are forwarded to the LEDE box using the settings in `proxy.conf.json`. 15 | 16 | ## Build 17 | 18 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. 19 | 20 | Building of the ipk package is not yet implemented. 21 | -------------------------------------------------------------------------------- /luci2-ui-core/src/doc/SCHEMA.UI.md: -------------------------------------------------------------------------------- 1 | 2 | ### Example 3 | ``` 4 | { 5 | "type": "", 6 | "binding": ???, 7 | "status": hidden | readonly | default 8 | "options": { element's specifc options} 9 | 10 | "enum": [ list values] 11 | 12 | "elements": [ 13 | { 14 | "type": 15 | } 16 | ] 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /luci2-ui-core/src/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/ubus": { 3 | "target": "http://localhost:9080", 4 | "secure": false 5 | }, 6 | "/cgi-bin": { 7 | "target": "http://localhost:9080", 8 | "secure": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | @import '../styles/_components.scss'; 2 | 3 | app-root { 4 | position: absolute; 5 | top: 0; 6 | bottom: 0; 7 | left: 0; 8 | right: 0; 9 | 10 | @include flex-container(column, stretch); 11 | } 12 | 13 | wdg-widget { 14 | flex: 1 1 auto; 15 | } 16 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { 7 | ChangeDetectionStrategy, 8 | ChangeDetectorRef, 9 | Component, 10 | OnInit, 11 | ViewEncapsulation, 12 | } from '@angular/core'; 13 | 14 | import { IMenuItemArr } from './shell/menu/menu.interface'; 15 | import { MenuService } from './shell/menu/menu.service'; 16 | 17 | @Component({ 18 | selector: 'app-root', 19 | templateUrl: './app.component.html', 20 | styleUrls: ['./app.component.scss'], 21 | encapsulation: ViewEncapsulation.None, 22 | changeDetection: ChangeDetectionStrategy.OnPush, 23 | }) 24 | export class AppComponent implements OnInit { 25 | menu: IMenuItemArr | undefined; 26 | 27 | constructor(private _menuService: MenuService, private _cdr: ChangeDetectorRef) {} 28 | 29 | ngOnInit(): void { 30 | this._menuService.loadMenu().subscribe((m) => { 31 | this.menu = m; 32 | this._cdr.markForCheck(); 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { HttpClientModule } from '@angular/common/http'; 7 | import { NgModule } from '@angular/core'; 8 | import { FormsModule } from '@angular/forms'; 9 | import { BrowserModule } from '@angular/platform-browser'; 10 | import { RouterModule } from '@angular/router'; 11 | import { RxObject } from 'espression-rx'; 12 | import { RoutedWidgetComponent } from 'rx-json-ui'; 13 | 14 | import { AppComponent } from './app.component'; 15 | import { APP_STATE } from './app.service'; 16 | import { ViewsResolverService } from './shared/viewsresolver.service'; 17 | import { MenuGuardService } from './shell/menu/menuguard.service'; 18 | import { ShellModule } from './shell/shell.module'; 19 | import { WidgetsModule } from './widgets'; 20 | 21 | const appState = RxObject({}); 22 | 23 | @NgModule({ 24 | declarations: [AppComponent], 25 | imports: [ 26 | BrowserModule, 27 | FormsModule, 28 | HttpClientModule, 29 | ShellModule, 30 | RouterModule.forRoot( 31 | [ 32 | { 33 | path: '**', // initial wildcard route, will be replaced on menu load 34 | component: RoutedWidgetComponent, 35 | resolve: ViewsResolverService, 36 | canActivate: [MenuGuardService], 37 | }, 38 | ], 39 | { enableTracing: false, useHash: false } 40 | ), 41 | WidgetsModule, 42 | ], 43 | providers: [ 44 | { 45 | provide: APP_STATE, 46 | useValue: appState, 47 | }, 48 | ], 49 | entryComponents: [RoutedWidgetComponent], 50 | bootstrap: [AppComponent], 51 | }) 52 | export class AppModule {} 53 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/app.service.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { InjectionToken } from '@angular/core'; 7 | import { IRxProperties } from 'espression-rx'; 8 | 9 | export interface AppState extends IRxProperties { 10 | pollState: boolean; 11 | userName: string; 12 | } 13 | export const APP_STATE = new InjectionToken('AppSate'); 14 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shared/jsonrpc.interface.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | export interface IJsonrpcRequest { 7 | jsonrpc: string; 8 | method: string; 9 | params?: any[] | object; 10 | id?: string | number | null; 11 | } 12 | 13 | export interface IJsonrpcError { 14 | layer: 'http' | 'jsonrpc' | 'ubus'; 15 | code: number; 16 | message: string; 17 | data: any; 18 | } 19 | 20 | export interface IJsonrpcResponse { 21 | jsonrpc: string; 22 | result?: any; 23 | error?: IJsonrpcError; 24 | id: string | number | null; 25 | } 26 | 27 | /* eslint-disable @typescript-eslint/naming-convention */ 28 | export enum JsonrpcErrorCodes { 29 | ParseError = -32700, 30 | InvalidRequest = -32600, 31 | NotFound = -32601, 32 | InvalidParams = -32602, 33 | InternalError = -32603, 34 | AccessDenied = -32002, 35 | ServerErrorStart = -32099, 36 | ServerErrorEnd = -32000, 37 | } 38 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shared/observable.debug.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { Observable } from 'rxjs'; 7 | import { tap } from 'rxjs/operators'; 8 | 9 | import { environment } from '../../environments/environment'; 10 | 11 | /* Observable Debugger extension */ 12 | 13 | export function debug(title: string): (source: Observable) => Observable { 14 | return (source: Observable) => 15 | environment.production 16 | ? source 17 | : source.pipe( 18 | tap( 19 | // don't log in production 20 | (d) => console.log(title, 'next', d), 21 | (e) => console.log(title, 'error', e), 22 | () => console.log(title, 'complete') 23 | ) 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shared/store.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import { RxObject } from 'espression-rx'; 9 | 10 | export class RxStore { 11 | _store = new Map(); 12 | 13 | set(store: string, key: string, value: any): void { 14 | if (!this._store.has(store)) this._store.set(store, RxObject({})); 15 | this._store.get(store)[key] = value; 16 | } 17 | 18 | get(store: string, key: string): any { 19 | return this._store.get(store)[key]; 20 | } 21 | 22 | has(store: string, key: string): boolean { 23 | return this._store.has(store) && key in this._store.get(store); 24 | } 25 | 26 | keys(store: string): string[] { 27 | return Object.keys(this._store.get(store)); 28 | } 29 | 30 | values(store: string): string[] { 31 | return Object.values(this._store.get(store)); 32 | } 33 | 34 | entries(store: string): Array<[string, any]> { 35 | return Object.entries(this._store.get(store)); 36 | } 37 | 38 | delete(store: string): void { 39 | this._store.delete(store); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shared/viewsresolver.service.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import { LocationStrategy } from '@angular/common'; 9 | import { Inject, Injectable } from '@angular/core'; 10 | import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; 11 | import { AbstractWidgetDef, Context, ROOT_EXPR_CONTEXT } from 'rx-json-ui'; 12 | import { forkJoin, from, Observable, of } from 'rxjs'; 13 | import { map } from 'rxjs/operators'; 14 | 15 | import { UbusService } from './ubus.service'; 16 | 17 | @Injectable({ 18 | providedIn: 'root', 19 | }) 20 | export class ViewsResolverService implements Resolve { 21 | constructor( 22 | private ubus: UbusService, 23 | private location: LocationStrategy, 24 | @Inject(ROOT_EXPR_CONTEXT) private rootContext: Context 25 | ) {} 26 | 27 | resolve( 28 | route: ActivatedRouteSnapshot, 29 | _state: RouterStateSnapshot 30 | ): Observable { 31 | // wait for view and module, but only pass on the view 32 | return forkJoin([ 33 | this.ubus.loadView(`${route.data.view}.view.json`), 34 | this.loadModule(route.data.module), 35 | ]).pipe(map(([v]: [AbstractWidgetDef[], boolean]) => v[0])); 36 | } 37 | 38 | /** Dynamically loads a module and stores it in the `rootContext.modules` */ 39 | loadModule(moduleName: string): Observable { 40 | if (!moduleName) return of(false); 41 | // don't reload the same module 42 | if (this.rootContext.modules[moduleName]) return of(true); 43 | const baseHref = this.location.getBaseHref(); 44 | return from( 45 | import(/* webpackIgnore: true */ `${baseHref}assets/modules/${moduleName}.js`) 46 | ).pipe( 47 | map((module) => { 48 | if (module) this.rootContext.modules[moduleName] = module; 49 | return true; 50 | }) 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/login/ILogin.interface.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { Observable } from 'rxjs'; 7 | 8 | export interface ILogin { 9 | login(username: string, password: string): Observable; 10 | } 11 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/login/login.component.html: -------------------------------------------------------------------------------- 1 |
Login
2 | 3 |
4 |
5 | 6 | 14 | 15 | 16 | 25 | 26 | 27 |
{{ errorMessage }}
28 |
29 |
30 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/login/login.component.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/_components.scss'; 2 | 3 | app-login { 4 | display: block; 5 | padding-left: 12px; 6 | padding-right: 12px; 7 | 8 | .mat-dialog-title { 9 | display: flex; 10 | flex-direction: row; 11 | align-items: center; 12 | color: $mediumgray; 13 | } 14 | .mat-dialog-title mat-icon { 15 | height: 60px; 16 | width: 60px; 17 | flex: 0 0 auto; 18 | } 19 | .mat-dialog-title span { 20 | flex: 0 0 auto; 21 | } 22 | .mat-dialog-content { 23 | display: flex; 24 | flex-direction: column; 25 | min-width: 240px; 26 | } 27 | 28 | .mat-dialog-actions { 29 | justify-content: flex-end; 30 | } 31 | } 32 | 33 | .cdk-overlay-pane.login-dialog { 34 | @include media-query(sm) { 35 | margin-top: 112px; 36 | height: 100%; 37 | width: 100%; 38 | mat-dialog-container { 39 | border-radius: 0px; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/login/login.component.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { Component, Inject, ViewEncapsulation } from '@angular/core'; 7 | import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; 8 | 9 | import { IJsonrpcError } from '../../shared/jsonrpc.interface'; 10 | 11 | import { ILogin } from './ILogin.interface'; 12 | 13 | @Component({ 14 | selector: 'app-login', 15 | templateUrl: './login.component.html', 16 | styleUrls: ['./login.component.scss'], 17 | encapsulation: ViewEncapsulation.None, 18 | }) 19 | export class LoginComponent { 20 | user = ''; 21 | password = ''; 22 | errorMessage: string | undefined; 23 | 24 | constructor( 25 | private _dialogRef: MatDialogRef, 26 | @Inject(MAT_DIALOG_DATA) private _loginService: ILogin 27 | ) {} 28 | 29 | login(): void { 30 | this._loginService.login(this.user, this.password).subscribe( 31 | (s) => this._dialogRef.close(s), 32 | (e: IJsonrpcError) => { 33 | this.errorMessage = 34 | e.layer === 'ubus' && e.code === 6 35 | ? 'Invalid username/password' 36 | : `${e.layer} error ${e.code}: ${e.message}`; 37 | } 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/login/ubus.interface.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | export interface IUbusAcls { 7 | 'access-group': { group: string[] }; 8 | } 9 | 10 | export interface IUbusSession { 11 | acls: IUbusAcls; 12 | data: { username: string }; 13 | expires: number; 14 | timeout: number; 15 | // eslint-disable-next-line @typescript-eslint/naming-convention 16 | ubus_rpc_session: string; 17 | } 18 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/menu/menu.interface.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | export interface IMenuItem { 7 | [extra: string]: any; 8 | index: number; 9 | title: string; 10 | tabbed?: boolean; 11 | view?: string; 12 | link: string; 13 | linkTo?: string; 14 | } 15 | 16 | export interface IMenuItemObj extends IMenuItem { 17 | childs?: { [path: string]: IMenuItemObj }; 18 | } 19 | 20 | export interface IMenuItemArr extends IMenuItem { 21 | childs?: IMenuItemArr[]; 22 | } 23 | export interface IMenu { 24 | [key: string]: IMenuItem; 25 | } 26 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/menu/menuguard.service.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import { Injectable } from '@angular/core'; 9 | import { 10 | ActivatedRouteSnapshot, 11 | CanActivate, 12 | Router, 13 | RouterStateSnapshot, 14 | } from '@angular/router'; 15 | import { Observable } from 'rxjs'; 16 | import { map } from 'rxjs/operators'; 17 | 18 | import { MenuService } from './menu.service'; 19 | 20 | @Injectable({ 21 | providedIn: 'root', 22 | }) 23 | export class MenuGuardService implements CanActivate { 24 | constructor(private _router: Router, private _menuService: MenuService) {} 25 | 26 | canActivate( 27 | _route: ActivatedRouteSnapshot, 28 | _state: RouterStateSnapshot 29 | ): Observable { 30 | // load menu definitions and routes, and renavigate 31 | return this._menuService 32 | .loadMenu() 33 | .pipe(map(() => (this._router.navigateByUrl(_state.url), false))); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/nav-menu/_nav-menu.theming.scss: -------------------------------------------------------------------------------- 1 | @import '~@angular/material/theming'; 2 | 3 | @mixin nav-menu-theme($theme) { 4 | $primary: map-get($theme, primary); 5 | $accent: map-get($theme, accent); 6 | $warn: map-get($theme, warn); 7 | $foreground: map-get($theme, foreground); 8 | $background: map-get($theme, background); 9 | 10 | .nav-menu-item { 11 | color: mat-color($foreground, secondary-text); 12 | 13 | &:hover { 14 | color: mat-color($primary); 15 | background-color: mat-color($background, hover); 16 | } 17 | } 18 | .nav-menu-item.selected { 19 | color: mat-color($primary); 20 | } 21 | button.nav-menu-item { 22 | &:focus { 23 | color: mat-color($foreground, base); 24 | } 25 | } 26 | 27 | .heading { 28 | color: mat-color($foreground, text); 29 | } 30 | .level-2 { 31 | color: mat-color($foreground, hint-text); 32 | } 33 | .level-3 { 34 | color: mat-color($foreground, hint-text); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/nav-menu/nav-item.component.html: -------------------------------------------------------------------------------- 1 | 13 | 14 |
15 | 24 | {{ node.title }} 25 | 26 | 27 | 28 | 40 | 41 |
42 | 48 |
49 |
50 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/nav-menu/nav-item.component.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { 7 | ChangeDetectionStrategy, 8 | Component, 9 | Input, 10 | OnChanges, 11 | ViewEncapsulation, 12 | } from '@angular/core'; 13 | import { MatDrawer } from '@angular/material/sidenav'; 14 | 15 | import { IMenuNode } from '../shell.interface'; 16 | 17 | @Component({ 18 | selector: 'app-nav-item', 19 | templateUrl: 'nav-item.component.html', 20 | encapsulation: ViewEncapsulation.None, 21 | changeDetection: ChangeDetectionStrategy.OnPush, 22 | }) 23 | export class NavItemComponent implements OnChanges { 24 | @Input() 25 | level = 1; 26 | @Input() 27 | node!: IMenuNode; 28 | @Input() 29 | drawer: MatDrawer | undefined; 30 | isExpanded = false; 31 | classes: { [index: string]: boolean } = {}; 32 | nodeChilds: IMenuNode[] = []; 33 | 34 | ngOnChanges(): void { 35 | this.nodeChilds = (this.node && this.node.childs) || []; 36 | 37 | this.setClasses(); 38 | } 39 | 40 | setClasses(): void { 41 | this.classes = { 42 | [`level-${this.level}`]: true, 43 | collapsed: !this.isExpanded, 44 | expanded: this.isExpanded, 45 | }; 46 | } 47 | 48 | headerClicked(): void { 49 | this.isExpanded = !this.isExpanded; 50 | this.setClasses(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/nav-menu/nav-menu.component.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { 7 | ChangeDetectionStrategy, 8 | Component, 9 | Input, 10 | ViewEncapsulation, 11 | } from '@angular/core'; 12 | import { MatDrawer } from '@angular/material/sidenav'; 13 | 14 | import { IMenuNode } from '../shell.interface'; 15 | 16 | @Component({ 17 | selector: 'app-nav-menu', 18 | template: ``, 23 | styleUrls: ['./nav-menu.component.scss'], 24 | encapsulation: ViewEncapsulation.None, 25 | changeDetection: ChangeDetectionStrategy.OnPush, 26 | }) 27 | export class NavMenuComponent { 28 | @Input() 29 | nodes: IMenuNode[] = []; 30 | 31 | @Input() 32 | drawer: MatDrawer | undefined; 33 | } 34 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/shell.interface.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | export interface IMenuNode { 7 | title: string; // Label to display on the menu 8 | tooltip?: string; 9 | svgIcon?: string; // icon to show on the menu ([namespace:]iconName), it must been previously loaded 10 | link: string; // Route to activate when clicked. Ignored if the node has children. 11 | // If empty and childless node, the item will be shown as disabled. 12 | disabled?: boolean; // disable the item 13 | open?: boolean; // default state 14 | 15 | childs?: IMenuNode[]; 16 | hideChilds?: boolean; 17 | } 18 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/shell/shell.module.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { NgModule } from '@angular/core'; 7 | import { FormsModule } from '@angular/forms'; 8 | import { MatBadgeModule } from '@angular/material/badge'; 9 | import { MatSidenavModule } from '@angular/material/sidenav'; 10 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 11 | import { RouterModule } from '@angular/router'; 12 | import { MaterialModule } from 'rx-json-ui'; 13 | 14 | import { WidgetsModule } from '../widgets'; 15 | 16 | import { LoginComponent } from './login/login.component'; 17 | import { MenuService } from './menu/menu.service'; 18 | import { NavItemComponent } from './nav-menu/nav-item.component'; 19 | import { NavMenuComponent } from './nav-menu/nav-menu.component'; 20 | import { ShellComponent } from './shell/shell.component'; 21 | 22 | /** 23 | * ShellModule 24 | * 25 | * This module groups all components and services used to build the application's shell: 26 | * Menu navigation - Breadcrumbs - Top buttons bar - Log in services, etc 27 | * It is intended to be agnostic of a specific application and serve as a generic template 28 | * 29 | */ 30 | @NgModule({ 31 | imports: [ 32 | RouterModule, 33 | BrowserAnimationsModule, 34 | FormsModule, 35 | RouterModule, 36 | WidgetsModule, 37 | MaterialModule, 38 | MatBadgeModule, 39 | MatSidenavModule, 40 | ], 41 | declarations: [ShellComponent, NavMenuComponent, NavItemComponent, LoginComponent], 42 | exports: [ShellComponent], 43 | providers: [MenuService], 44 | entryComponents: [LoginComponent], 45 | }) 46 | export class ShellModule {} 47 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/uci/backend/config.interface.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { IUciSectionData, IUciSectionSchema } from './section.interface'; 7 | 8 | /** 9 | * Config File Schema used by UCI backend 10 | */ 11 | 12 | export interface IUciConfigSchema { 13 | /** Must be `object` */ 14 | type: string; 15 | 16 | /** title of the UCI config */ 17 | title?: string; 18 | /** description of the config */ 19 | description?: string; 20 | 21 | /** Sections of the config file */ 22 | properties: { [sectionType: string]: IUciSectionSchema }; 23 | } 24 | 25 | export interface IUciConfigData { 26 | [section: string]: IUciSectionData; 27 | } 28 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/uci/backend/section.interface.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { IUciOptionSchema } from './option.interface'; 7 | 8 | /** 9 | * Option Schema used by UCI backend 10 | */ 11 | export interface IUciSectionSchema { 12 | /** 13 | * Sections are always `object` jsonschema type 14 | * The actual `uci` section type is defined by the property name holding this object 15 | */ 16 | type: string; 17 | 18 | title?: string; 19 | description?: string; 20 | 21 | // Section Name Rules 22 | 23 | /** Indicates if it has a name */ 24 | anonymous?: boolean; 25 | /** RegEx pattern for name validation on non anonymous sections */ 26 | pattern?: string; 27 | 28 | /** Name template for new section (an ordinal is appended at the end) */ 29 | default?: string; 30 | /** the name cannot be repeated within this section type */ 31 | unique?: boolean; 32 | 33 | // Validations 34 | 35 | /** Number of sections of this type must/can be present */ 36 | minLength?: number; 37 | maxLength?: number; 38 | 39 | /** Sections of this type cannot be added/deleted */ 40 | freezed?: boolean; 41 | // Child Options 42 | 43 | properties: IUciPropertiesSchema; 44 | } 45 | 46 | export interface IUciPropertiesSchema { 47 | [property: string]: IUciOptionSchema; 48 | } 49 | 50 | export interface IUciSectionData { 51 | [options: string]: string | string[] | any; 52 | '.anonymous': boolean; 53 | '.type': string; 54 | '.name': string; 55 | '.index'?: number; 56 | } 57 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/charts/charts.module.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2020 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import { NgModule } from '@angular/core'; 9 | import { BaseSettingsModule, MaterialModule, WidgetsCoreModule } from 'rx-json-ui'; 10 | 11 | import { SetChartWidgetComponent } from './set-chart/setChart.component'; 12 | 13 | export { SetChartWidgetComponent } from './set-chart/setChart.component'; 14 | 15 | @NgModule({ 16 | imports: [ 17 | MaterialModule, 18 | BaseSettingsModule, 19 | 20 | WidgetsCoreModule.forRoot({ 21 | widgets: [{ type: 'set-chart', component: SetChartWidgetComponent }], 22 | }), 23 | ], 24 | declarations: [SetChartWidgetComponent], 25 | exports: [SetChartWidgetComponent], 26 | }) 27 | export class ChartsWidgetsModule {} 28 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/charts/set-chart/setChart.component.html: -------------------------------------------------------------------------------- 1 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/charts/set-chart/setChart.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | .set-row-chart { 9 | display: block; 10 | height: 52px; 11 | padding-top: 8px; 12 | padding-bottom: 8px; 13 | padding-left: 4px; 14 | padding-right: 4px; 15 | } 16 | 17 | .ct-series-a .ct-line { 18 | stroke: #004271; 19 | } 20 | .ct-series-a .ct-area { 21 | fill: #004271; 22 | } 23 | 24 | set-chart > set-base > .set-row-main .set-row-ctrl-container { 25 | flex: 0 2 250px; 26 | } 27 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | export * from './widgets.module'; 9 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/popup/popup.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{ data.message }} 4 | 5 |
6 |
7 | 10 | 13 |
14 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/popup/popup.component.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/_components.scss'; 2 | 3 | app-popup-dialog { 4 | display: block; 5 | 6 | .mat-dialog-content { 7 | display: flex; 8 | flex-direction: row; 9 | align-items: center; 10 | 11 | min-height: 60px; 12 | } 13 | 14 | .app-popup-spinner { 15 | margin-left: 18px; 16 | } 17 | 18 | .app-popup-icon { 19 | width: 60px; 20 | height: 60px; 21 | margin-right: 18px; 22 | color: $mediumgray; 23 | } 24 | 25 | .mat-dialog-actions { 26 | display: flex; 27 | flex-direction: row; 28 | justify-content: flex-end; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/popup/popup.component.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { Component, Inject, ViewEncapsulation } from '@angular/core'; 7 | import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; 8 | 9 | export interface IPopupDialogData { 10 | icon?: string; 11 | message: string; 12 | okLabel?: string; 13 | cancelLabel?: string; 14 | spinner?: boolean; 15 | } 16 | 17 | export const APP_POPUP_OPTS = { 18 | maxWidth: '100vw', 19 | maxHeight: '100vh', 20 | panelClass: 'app-popup-panel', 21 | }; 22 | 23 | @Component({ 24 | selector: 'app-popup-dialog', 25 | templateUrl: 'popup.component.html', 26 | styleUrls: ['popup.component.scss'], 27 | encapsulation: ViewEncapsulation.None, 28 | }) 29 | export class PopupDialogComponent { 30 | constructor( 31 | public dialogRef: MatDialogRef, 32 | @Inject(MAT_DIALOG_DATA) public data: IPopupDialogData 33 | ) {} 34 | 35 | setMessage(message: string): void { 36 | this.data.message = message ?? ''; 37 | } 38 | setSpinner(state: boolean): void { 39 | this.data.spinner = state; 40 | } 41 | setIcon(icon: string): void { 42 | this.data.icon = icon; 43 | } 44 | 45 | setData(data: Partial): void { 46 | this.data = { ...this.data, ...data }; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/popup_file/popup_file.component.html: -------------------------------------------------------------------------------- 1 | 10 |
11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/popup_file/popup_file.component.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/app/widgets/widgets.module.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2017 Adrian Panella , contributors. 3 | * Licensed under the MIT license. 4 | */ 5 | 6 | import { NgModule } from '@angular/core'; 7 | import { 8 | BaseSettingsModule, 9 | CommonWidgetsModule, 10 | ESpression, 11 | Expressions, 12 | FormFieldWidgetsModule, 13 | MaterialModule, 14 | SettingsWidgetsModule, 15 | WidgetsCoreModule, 16 | } from 'rx-json-ui'; 17 | 18 | import { ChartsWidgetsModule } from './charts/charts.module'; 19 | import { PopupDialogComponent } from './popup/popup.component'; 20 | import { SetPopupFileWidgetComponent } from './popup_file/popup_file.component'; 21 | import { rootContextProvider } from './rootContext'; 22 | 23 | export { SetPopupFileWidgetComponent } from './popup_file/popup_file.component'; 24 | 25 | /** Module containing all Widget components */ 26 | @NgModule({ 27 | imports: [ 28 | MaterialModule, 29 | ChartsWidgetsModule, 30 | CommonWidgetsModule, 31 | FormFieldWidgetsModule, 32 | SettingsWidgetsModule, 33 | BaseSettingsModule, 34 | WidgetsCoreModule.forRoot({ 35 | widgets: [{ type: 'set-popup-file', component: SetPopupFileWidgetComponent }], 36 | }), 37 | ], 38 | declarations: [PopupDialogComponent, SetPopupFileWidgetComponent], 39 | exports: [WidgetsCoreModule, MaterialModule, SetPopupFileWidgetComponent], 40 | entryComponents: [PopupDialogComponent], 41 | 42 | providers: [ 43 | { 44 | provide: Expressions, 45 | useClass: ESpression, 46 | }, 47 | rootContextProvider, 48 | ], 49 | }) 50 | export class WidgetsModule {} 51 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-core/src/src/assets/.gitkeep -------------------------------------------------------------------------------- /luci2-ui-core/src/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | // eslint-disable-next-line 9 | export const environment = { 10 | production: true, 11 | }; 12 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | // The file contents for the current environment will overwrite these during build. 9 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 10 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 11 | // The list of which env maps to which file can be found in `.angular-cli.json`. 12 | 13 | // eslint-disable-next-line 14 | export const environment = { 15 | production: false, 16 | }; 17 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jow-/luci-ng/0cec1da63854ba5eb37df7e7a2253e99ee830f6f/luci2-ui-core/src/src/favicon.ico -------------------------------------------------------------------------------- /luci2-ui-core/src/src/icons.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | icons: 3 | # general shell icons 4 | - account 5 | - alert-circle-outline 6 | - alert-outline 7 | - arrow-down-thick 8 | - arrow-left 9 | - arrow-up-thick 10 | - chevron-down 11 | - close 12 | - close-circle 13 | - content-save 14 | - content-save-edit-outline 15 | - delete 16 | - dots-vertical 17 | - help-circle-outline 18 | - information-variant 19 | - information-outline 20 | - flash 21 | - format-list-bulleted 22 | - lock-outline 23 | - lock-reset 24 | - logout-variant 25 | - menu 26 | - menu-right 27 | - minus-circle-outline 28 | - palette 29 | - pencil 30 | - play 31 | - plus-box 32 | - plus-circle-outline 33 | - power-settings 34 | - reload 35 | - refresh 36 | - stop 37 | - sync 38 | - sync-off 39 | - translate 40 | - undo 41 | 42 | # app-base icons 43 | - access-point 44 | - access-point-network 45 | - chip 46 | - clock 47 | - clock-fast 48 | - directions-fork 49 | - ip-network-outline 50 | - link 51 | - memory 52 | - monitor-dashboard 53 | - router-network 54 | - router-wireless 55 | - sd 56 | - security-network 57 | - table 58 | - wan 59 | - wifi-strength-1 60 | - wifi-strength-2 61 | - wifi-strength-3 62 | - wifi-strength-4 63 | - wifi-strength-off-outline 64 | - wifi-strength-outline 65 | --- 66 | namespace: openwrt 67 | keepClassName: true 68 | source: ./src/icons/ 69 | icons: 70 | - logo 71 | - wordmark 72 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Luci2 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | Loading... 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/legacy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file will only be loaded by legacy browsers with no 'module' support 3 | */ 4 | 5 | var app = document.querySelector('#approot'); 6 | if (app) app.style.display = 'none'; 7 | 8 | var legacy = document.querySelector('#legacy'); 9 | if (legacy) legacy.style.display = 'block'; 10 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/main.ts: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2018 Adrian Panella 3 | * 4 | * This software is released under the MIT License. 5 | * https://opensource.org/licenses/MIT 6 | */ 7 | 8 | import { enableProdMode } from '@angular/core'; 9 | import { platformBrowser } from '@angular/platform-browser'; 10 | 11 | import { AppModule } from './app/app.module'; 12 | import { environment } from './environments/environment'; 13 | 14 | if (environment.production) { 15 | enableProdMode(); 16 | } 17 | 18 | // check if the browser supports 'Proxy' 19 | 20 | if (typeof Proxy !== 'function') { 21 | const app = document.querySelector('#approot') as HTMLDivElement; 22 | if (app) app.style.display = 'none'; 23 | 24 | const legacy = document.querySelector('#legacy') as HTMLDivElement; 25 | if (legacy) legacy.style.display = 'block'; 26 | } else { 27 | platformBrowser().bootstrapModule(AppModule); 28 | } 29 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /** HACK: force import of environment.ts/environment.prod.ts to load env specific polyfills */ 3 | import 'zone.js/dist/zone'; 4 | 5 | import './environments/environment'; 6 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/schema.import.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | 4 | "oneOf": [ 5 | { "$ref": "../out/widgetschema/schema.json#/definitions/SchemaPartialObject" }, 6 | { 7 | "type": "array", 8 | "items": { 9 | "$ref": "../out/widgetschema/schema.json#/definitions/SchemaPartialObject" 10 | } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | // Include custom Material theming. 4 | @import './styles/main.scss'; 5 | 6 | @import '~chartist/dist/chartist.min.css'; 7 | 8 | // style for the legacy error message 9 | #legacy { 10 | font-size: 24px; 11 | font-weight: 500; 12 | margin: 24px; 13 | } 14 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/styles/_components.scss: -------------------------------------------------------------------------------- 1 | /* Common includes and mixins for Components */ 2 | 3 | @import './_constants.scss'; 4 | @import './_mixins.scss'; 5 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/styles/_constants.scss: -------------------------------------------------------------------------------- 1 | $unit: 8px; 2 | 3 | // TYPOGRAPHY 4 | $main-font: 'Roboto', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, 5 | 'Lucida Grande', sans-serif; 6 | 7 | $code-font: 'Droid Sans Mono', monospace; 8 | 9 | // BREAKPOINTS for media queries 10 | $bp-xs: 320px; 11 | $bp-sm: 600px; 12 | $bp-md: 800px; 13 | $bp-lg: 1000px; 14 | $bp-xl: 1280px; 15 | 16 | // COLOR PALETTE 17 | $blue: #1976d2; 18 | $accentblue: #1e88e5; 19 | $brightred: #dd0031; 20 | $darkred: #c3002f; 21 | $white: #ffffff; 22 | $offwhite: #fafafa; 23 | $backgroundgray: #f1f1f1; 24 | $lightgray: #dbdbdb; 25 | $mist: #eceff1; 26 | $mediumgray: #6e6e6e; 27 | $darkgray: #333; 28 | $black: #0a1014; 29 | $orange: #ff9800; 30 | $anti-pattern: $brightred; 31 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | // import global themes 2 | @import './app-theme'; 3 | 4 | // import global variables 5 | @import './constants'; 6 | 7 | // import global mixins 8 | @import './mixins'; 9 | 10 | .cdk-overlay-pane.app-popup-panel { 11 | @include media-query(sm) { 12 | //margin-top: 56px; 13 | //align-self: stretch; 14 | width: 100%; 15 | 16 | mat-dialog-container { 17 | border-radius: 0px; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "", 6 | "types": [] 7 | }, 8 | "files": ["main.ts", "polyfills.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /luci2-ui-core/src/src/uci.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "SchemaNumber": {} 5 | }, 6 | 7 | "allOf": [ 8 | { "$ref": "../out/widgetschema/schema.json#/definitions" }, 9 | { 10 | "type": "object", 11 | 12 | "properties": { 13 | "properties": { 14 | "type": "object", 15 | "propertyNames": { 16 | "type": "string", 17 | "pattern": "^@[\\x20-\\x7E]+$" 18 | }, 19 | "additionalProperties": { 20 | "title": "Typed Section", 21 | "$ref": "../out/widgetschema/schema.json#/definitions/SchemaArray" 22 | } 23 | } 24 | }, 25 | "required": ["type", "properties"], 26 | "minProperties": 1 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /luci2-ui-core/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "downlevelIteration": true, 5 | "module": "es2020", 6 | "outDir": "./dist/out-tsc", 7 | "baseUrl": "src", 8 | "sourceMap": true, 9 | "declaration": false, 10 | "moduleResolution": "node", 11 | "emitDecoratorMetadata": true, 12 | "experimentalDecorators": true, 13 | "noUnusedParameters": true, 14 | "noUnusedLocals": true, 15 | "noImplicitReturns": true, 16 | "strict": true, 17 | "preserveSymlinks": true, 18 | "target": "es2015", 19 | "typeRoots": ["node_modules/@types"], 20 | "lib": ["es2017", "dom"] 21 | }, 22 | "angularCompilerOptions": { 23 | "preserveWhitespaces": false, 24 | "strictInjectionParameters": true, 25 | "fullTemplateTypeCheck": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rpcd-mod-iptables/.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "ipq806x", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "/home/ianchi/data/openwrt/sdk_ipq806x/staging_dir/target-arm_cortex-a15+neon-vfpv4_musl_eabi/usr/include/**" 8 | ], 9 | "defines": [], 10 | "compilerPath": "/home/ianchi/data/openwrt/sdk_ipq806x/staging_dir/toolchain-arm_cortex-a15+neon-vfpv4_gcc-7.5.0_musl_eabi/bin/arm-openwrt-linux-muslgnueabi-gcc-7.5.0", 11 | "cStandard": "c11", 12 | "cppStandard": "c++17", 13 | "intelliSenseMode": "gcc-x64" 14 | }, 15 | { 16 | "name": "x86_64", 17 | "includePath": [ 18 | "${workspaceFolder}/**", 19 | "/home/ianchi/data/openwrt/sdk_x86_64/staging_dir/target-x86_64_musl/usr/include/**" 20 | ], 21 | "defines": [], 22 | "compilerPath": "/mnt/data/openwrt/sdk_x86_64/staging_dir/toolchain-x86_64_gcc-7.5.0_musl/bin/x86_64-openwrt-linux-musl-gcc", 23 | "cStandard": "c99", 24 | "cppStandard": "c++17", 25 | "intelliSenseMode": "gcc-x64", 26 | "compilerArgs": [ 27 | "-Os ", 28 | "-Wall ", 29 | "-Werror ", 30 | "--std=gnu99 ", 31 | "-Wmissing-declarations" 32 | ], 33 | "browse": { 34 | "path": [ 35 | "${workspaceFolder}/", 36 | "/home/ianchi/data/openwrt/sdk_x86_64/staging_dir/target-x86_64_musl/usr/include/" 37 | ], 38 | "limitSymbolsToIncludedHeaders": true 39 | } 40 | } 41 | ], 42 | "version": 4 43 | } -------------------------------------------------------------------------------- /rpcd-mod-iptables/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.errorSquiggles": "Enabled", 3 | "files.associations": { 4 | "sstream": "cpp" 5 | }, 6 | } -------------------------------------------------------------------------------- /rpcd-mod-iptables/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "mod-iptables compile x86", 8 | "type": "shell", 9 | "command": "cd ~/data/openwrt/sdk_x86_64 && make package/rpcd-mod-iptables/{clean,compile} && cp ~/data/openwrt/sdk_x86_64/bin/packages/x86_64/luci2/rpcd-mod-iptables*.ipk ~/data/openwrt/openwrt-docker/ipk || tail -n15 ~/data/openwrt/sdk_x86_64/logs/package/feeds/luci2/rpcd-mod-iptables/compile.txt", 10 | "group": "build", 11 | "problemMatcher": [] 12 | }, 13 | { 14 | "label": "mod-iptables compile ipq", 15 | "type": "shell", 16 | "command": "cd ~/data/openwrt/sdk_ipq806x && make package/rpcd-mod-iptables/{clean,compile} || tail -n15 ~/data/openwrt/sdk_ipq806x/logs/package/feeds/luci2/rpcd-mod-iptables/compile.txt", 17 | "group": "build", 18 | "problemMatcher": [] 19 | }, 20 | { 21 | "label": "mod-iptables deploy x86 - docker", 22 | "type": "shell", 23 | "command": "scp ~/data/openwrt/sdk_x86_64/bin/packages/x86_64/luci2/rpcd-mod-iptables*.ipk root@172.17.0.2:/tmp/ && ssh root@172.17.0.2 opkg install --force-reinstall /tmp/rpcd-mod-iptables*.ipk", 24 | "group": "test", 25 | "problemMatcher": [] 26 | }, 27 | { 28 | "label": "mod-iptables deploy ipq - router", 29 | "type": "shell", 30 | "command": "scp ~/data/openwrt/sdk_ipq806x/bin/packages/arm_cortex-a15_neon-vfpv4/luci2/rpcd-mod-iptables*.ipk root@172.25.1.1:/tmp/ && ssh root@172.25.1.1 opkg install --force-reinstall /tmp/rpcd-mod-iptables*.ipk", 31 | "group": "test", 32 | "problemMatcher": [] 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /rpcd-mod-iptables/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2020 Adrian Panella 3 | # 4 | # Licensed under the Apache License, Version 2.0. 5 | # 6 | 7 | include $(TOPDIR)/rules.mk 8 | 9 | PKG_NAME:=rpcd-mod-iptables 10 | PKG_VERSION:=20200328 11 | PKG_MAINTAINER:=Adrian Panella 12 | 13 | PKG_LICENSE:=Apache-2.0 14 | PKG_LICENSE_FILES:= 15 | 16 | PKG_BUILD_PARALLEL:=1 17 | 18 | include $(INCLUDE_DIR)/package.mk 19 | include $(INCLUDE_DIR)/cmake.mk 20 | 21 | define Build/Prepare 22 | $(INSTALL_DIR) $(PKG_BUILD_DIR) 23 | $(CP) ./src/* $(PKG_BUILD_DIR)/ 24 | endef 25 | 26 | define Package/rpcd-mod-iptables 27 | SECTION:=luci2 28 | CATEGORY:=LuCI2 29 | TITLE:=RPC calls to query iptables 30 | DEPENDS:=+rpcd +libubox +libubus +kmod-ipt-core +libip4tc +libip6tc +libxtables 31 | endef 32 | 33 | 34 | 35 | define Package/rpcd-mod-iptables/description 36 | Query iptables thru RPC. 37 | endef 38 | 39 | define Package/rpcd-mod-iptables/install 40 | $(INSTALL_DIR) $(1)/usr/lib/rpcd 41 | $(INSTALL_BIN) $(PKG_BUILD_DIR)/iptables.so $(1)/usr/lib/rpcd/ 42 | endef 43 | 44 | define Package/rpcd-mod-iptables/postinst 45 | #!/bin/sh 46 | /etc/init.d/rpcd restart 47 | exit 0 48 | endef 49 | 50 | $(eval $(call BuildPackage,rpcd-mod-iptables)) 51 | -------------------------------------------------------------------------------- /rpcd-mod-iptables/src/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | UseTab: Always 3 | IndentWidth: 4 4 | TabWidth: 4 5 | 6 | BreakBeforeBraces: Custom 7 | BraceWrapping: 8 | AfterEnum: false 9 | AfterStruct: true 10 | SplitEmptyFunction: false 11 | AfterControlStatement: true 12 | AfterFunction: true 13 | BeforeElse: true 14 | 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortFunctionsOnASingleLine: false 17 | AllowShortLoopsOnASingleLine: false 18 | AlwaysBreakAfterReturnType: AllDefinitions 19 | BinPackArguments: true 20 | BinPackParameters: true 21 | IndentCaseLabels: false 22 | ColumnLimit: 90 23 | AccessModifierOffset: -4 24 | AlignConsecutiveAssignments: true 25 | AlignTrailingComments: true 26 | Cpp11BracedListStyle: false 27 | 28 | -------------------------------------------------------------------------------- /rpcd-mod-iptables/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(rpcd-mod-iptables C) 4 | 5 | ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) 6 | 7 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 8 | 9 | IF(APPLE) 10 | INCLUDE_DIRECTORIES(/opt/local/include) 11 | LINK_DIRECTORIES(/opt/local/lib) 12 | ENDIF() 13 | 14 | 15 | ADD_LIBRARY(rpcd-mod-iptables MODULE main.c shared.c iptables.c iptables6.c) 16 | TARGET_LINK_LIBRARIES(rpcd-mod-iptables ubox ubus xtables ip4tc ip6tc iptext iptext4 iptext6 ) 17 | SET_TARGET_PROPERTIES(rpcd-mod-iptables PROPERTIES OUTPUT_NAME iptables PREFIX "") 18 | 19 | INSTALL(TARGETS rpcd-mod-iptables LIBRARY DESTINATION lib) 20 | -------------------------------------------------------------------------------- /rpcd-mod-iptables/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * iptables - UBUS RPC iptables service 3 | * 4 | * Copyright (C) 2020 Adrian Panella 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "shared.h" 20 | #include 21 | 22 | struct blob_buf buf; 23 | static const struct rpc_daemon_ops *ops; 24 | 25 | static int 26 | rpc_iptables_api_init(const struct rpc_daemon_ops *o, struct ubus_context *ctx) 27 | { 28 | int rv = 0; 29 | 30 | static const struct ubus_method mod_iptables_methods[] = { 31 | UBUS_METHOD_NOARG("list", rpcd_mod_iptables_list), 32 | UBUS_METHOD_NOARG("list6", rpcd_mod_iptables_list6), 33 | }; 34 | 35 | static struct ubus_object_type mod_iptables_type = 36 | UBUS_OBJECT_TYPE("rpcd-mod-iptables", mod_iptables_methods); 37 | 38 | static struct ubus_object mod_iptables_obj = { 39 | .name = "iptables", 40 | .type = &mod_iptables_type, 41 | .methods = mod_iptables_methods, 42 | .n_methods = ARRAY_SIZE(mod_iptables_methods), 43 | }; 44 | 45 | ops = o; 46 | 47 | rv |= ubus_add_object(ctx, &mod_iptables_obj); 48 | 49 | return rv; 50 | } 51 | 52 | struct rpc_plugin rpc_plugin = { .init = rpc_iptables_api_init }; -------------------------------------------------------------------------------- /rpcd-mod-iptables/src/shared.h: -------------------------------------------------------------------------------- 1 | /* 2 | * iptables - UBUS RPC iptables service 3 | * 4 | * Copyright (C) 2020 Adrian Panella 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #undef NDEBUG 27 | 28 | #ifndef NDEBUG 29 | #define DPRINTF(...) fprintf(dbg, __VA_ARGS__) 30 | #else 31 | #define DPRINTF(...) 32 | #endif 33 | 34 | extern struct blob_buf buf; 35 | extern const char unsupported_rev[24]; 36 | extern FILE *dbg; 37 | 38 | void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) 39 | __attribute__((noreturn, format(printf, 2, 3))); 40 | 41 | void capture_stdout(); 42 | void restore_stdout(); 43 | void blobmsg_add_printf_output(struct blob_buf *buffer, char *key); 44 | 45 | int mod_init_xtables(uint8_t nfproto); 46 | void mod_free(); 47 | 48 | int rpcd_mod_iptables_list(struct ubus_context *ctx, struct ubus_object *obj, 49 | struct ubus_request_data *req, const char *method, 50 | struct blob_attr *msg); 51 | 52 | int rpcd_mod_iptables_list6(struct ubus_context *ctx, struct ubus_object *obj, 53 | struct ubus_request_data *req, const char *method, 54 | struct blob_attr *msg); 55 | --------------------------------------------------------------------------------