Skip to content

Commit bc4a764

Browse files
committed
gluon web2 "5 minute edition"
1 parent 4f1e930 commit bc4a764

File tree

10 files changed

+1273
-22
lines changed

10 files changed

+1273
-22
lines changed

package/gluon-web2/.gitignore

+6-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
node_modules
1+
/node_modules
2+
/.parcel-cache
3+
/dist
4+
.DS_Store
5+
yarn-debug.log*
6+
yarn-error.log*

package/gluon-web2/dump-network.lua

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
local interfaces = {}
2+
local uci = require('simple-uci').cursor()
3+
local json = require 'jsonc'
4+
local ethernet = require 'gluon.ethernet'
5+
6+
uci:foreach('gluon', 'interface', function(interface)
7+
table.insert(interfaces, interface)
8+
end)
9+
10+
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- You will need this for encoding/decoding
11+
-- encoding
12+
function enc(data)
13+
return ((data:gsub('.', function(x)
14+
local r,b='',x:byte()
15+
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
16+
return r;
17+
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
18+
if (#x < 6) then return '' end
19+
local c=0
20+
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
21+
return b:sub(c+1,c+1)
22+
end)..({ '', '==', '=' })[#data%3+1])
23+
end
24+
25+
-- decoding
26+
function dec(data)
27+
data = string.gsub(data, '[^'..b..'=]', '')
28+
return (data:gsub('.', function(x)
29+
if (x == '=') then return '' end
30+
local r,f='',(b:find(x)-1)
31+
for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
32+
return r;
33+
end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
34+
if (#x ~= 8) then return '' end
35+
local c=0
36+
for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
37+
return string.char(c)
38+
end))
39+
end
40+
41+
print(enc(json.stringify({
42+
phy_interfaces = ethernet.interfaces(),
43+
uci = interfaces
44+
})))

package/gluon-web2/package.json

+19-2
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,33 @@
22
"name": "gluon-web2",
33
"version": "1.0.0",
44
"description": "Gluon Web rewritten with Preact and Parcel",
5-
"main": "index.js",
65
"author": "Gluon Contributors",
76
"license": "MIT",
87
"dependencies": {
98
"preact": "^10.15.1"
109
},
10+
"scripts": {
11+
"start": "parcel serve --target dev",
12+
"build": "parcel build"
13+
},
14+
"targets": {
15+
"default": {
16+
"source": "src/index.tsx",
17+
"distDir": "bundle"
18+
},
19+
"dev": {
20+
"source": "src/index.html"
21+
}
22+
},
23+
"eslintConfig": {
24+
"extends": "ipfs"
25+
},
1126
"devDependencies": {
12-
"parcel": "^2.9.2",
27+
"@parcel/transformer-sass": "2.9.2",
1328
"@types/jest": "^29.5.2",
29+
"eslint-config-ipfs": "^4.0.3",
1430
"jest": "^29.5.0",
31+
"parcel": "^2.9.2",
1532
"ts-jest": "^29.1.0",
1633
"typescript": "^5.1.3"
1734
}

package/gluon-web2/src/GluonWeb2.tsx

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Fragment, h } from "preact";
2+
import { useState } from 'preact/hooks';
3+
4+
import Components from "./components"
5+
6+
const GluonWeb2 = ({ id, component, data: initialData }: { id: string, component: string, data: any }) => {
7+
const { data, setData } = useState<any>(initialData)
8+
9+
return (
10+
<Fragment>
11+
<input type="text" style="display: none" name={id} value={JSON.stringify(data)} />,
12+
{
13+
h(Components[component], {
14+
data,
15+
setData
16+
})
17+
}
18+
</Fragment>
19+
)
20+
}
21+
22+
export default GluonWeb2;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import VlanUI from "./vlan-ui"
2+
export default {
3+
"vlan-ui": VlanUI
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { h } from "preact";
2+
3+
const ROLES = {
4+
'uplink': 'Uplink',
5+
'mesh': 'Mesh',
6+
'client': 'Client'
7+
}
8+
9+
const VlanUI = ({ data, setData }: { data: any, setData: (data: any) => void }) => {
10+
/* return data.uci.map(intf => {
11+
(
12+
<div>
13+
<label class="gluon-value-title" for="id.1.4.iface_wan_vlan11">{intf.name}</label>
14+
<div class="gluon-value-field">
15+
<div>
16+
17+
<label data-index="1">
18+
{(intf.roles ?? [])}
19+
<input data-update="click change" type="checkbox" id="id.1.4.iface_wan_vlan11.uplink" name="id.1.4.iface_wan_vlan11" value="uplink" data-exclusive-with="[&#34;client&#34;]" data-update="change">
20+
<label for="id.1.4.iface_wan_vlan11.uplink"></label>
21+
<span class="gluon-multi-list-option-descr">Uplink</span>
22+
</label>
23+
&#160;&#160;&#160;
24+
25+
<label data-index="2">
26+
<input data-update="click change" type="checkbox" id="id.1.4.iface_wan_vlan11.mesh" name="id.1.4.iface_wan_vlan11" value="mesh" checked="checked" data-exclusive-with="[&#34;client&#34;]" data-update="change">
27+
<label for="id.1.4.iface_wan_vlan11.mesh"></label>
28+
<span class="gluon-multi-list-option-descr">Mesh</span>
29+
</label>
30+
&#160;&#160;&#160;
31+
32+
<label data-index="3">
33+
<input data-update="click change" type="checkbox" id="id.1.4.iface_wan_vlan11.client" name="id.1.4.iface_wan_vlan11" value="client" data-exclusive-with="[&#34;uplink&#34;,&#34;mesh&#34;]" data-update="change">
34+
<label for="id.1.4.iface_wan_vlan11.client"></label>
35+
<span class="gluon-multi-list-option-descr">Client</span>
36+
</label>
37+
38+
39+
</div>
40+
41+
)
42+
}) */
43+
44+
return <h1>VLANUI {JSON.stringify(data)}</h1>
45+
};
46+
47+
export default VlanUI;

package/gluon-web2/src/index.html

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
name="viewport"
77
content="width=device-width, initial-scale=1, shrink-to-fit=no"
88
/>
9-
<title>Parcel Preact Typescript</title>
9+
<link rel="stylesheet" href="../../gluon-config-mode-theme/sass/gluon.scss">
10+
<link rel="stylesheet" href="./main.scss">
11+
<title>Gluon Web v2 Development Render</title>
1012
</head>
1113
<body>
12-
<div id="root"></div>
13-
<script src="./index.tsx"></script>
14+
<gluon-web2 data-component="vlan-ui" data-component-data="eyJwaHlfaW50ZXJmYWNlcyI6WyJ3YW4iLCJsYW40IiwibGFuMiIsImxhbjMiLCJsYW4xIl0sInVjaSI6W3siLm5hbWUiOiJpZmFjZV93YW4iLCIudHlwZSI6ImludGVyZmFjZSIsIm5hbWUiOiJcL3dhbiIsInJvbGUiOlsibm90aGluZyJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4IjoxfSx7Ii5uYW1lIjoiaWZhY2VfbGFuIiwiLnR5cGUiOiJpbnRlcmZhY2UiLCJuYW1lIjoiXC9sYW4iLCJyb2xlIjpbInVwbGluayJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4IjoyfSx7Ii5uYW1lIjoiaWZhY2Vfd2FuX3ZsYW4xMSIsIi50eXBlIjoiaW50ZXJmYWNlIiwibmFtZSI6Indhbi4xMSIsInJvbGUiOlsibWVzaCJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4Ijo1fSx7Ii5uYW1lIjoiaWZhY2VfbGFuMV92bGFuMjU1IiwiLnR5cGUiOiJpbnRlcmZhY2UiLCJuYW1lIjoibGFuMS4yNTUiLCJyb2xlIjpbIm1lc2giXSwiLmFub255bW91cyI6ZmFsc2UsIi5pbmRleCI6Nn0seyIubmFtZSI6ImlmYWNlX2xhbjJfdmxhbjI1NSIsIi50eXBlIjoiaW50ZXJmYWNlIiwibmFtZSI6ImxhbjIuMjU1Iiwicm9sZSI6WyJtZXNoIl0sIi5hbm9ueW1vdXMiOmZhbHNlLCIuaW5kZXgiOjd9LHsiLm5hbWUiOiJpZmFjZV9sYW4zX3ZsYW4yNTUiLCIudHlwZSI6ImludGVyZmFjZSIsIm5hbWUiOiJsYW4zLjI1NSIsInJvbGUiOlsibWVzaCJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4Ijo4fSx7Ii5uYW1lIjoiaWZhY2VfbGFuNF92bGFuMjU1IiwiLnR5cGUiOiJpbnRlcmZhY2UiLCJuYW1lIjoibGFuNC4yNTUiLCJyb2xlIjpbIm1lc2giXSwiLmFub255bW91cyI6ZmFsc2UsIi5pbmRleCI6OX0seyIubmFtZSI6ImlmYWNlX2xhbjFfdmxhbjMiLCIudHlwZSI6ImludGVyZmFjZSIsIm5hbWUiOiJsYW4xLjMiLCJyb2xlIjpbImNsaWVudCJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4IjoxMH0seyIubmFtZSI6ImlmYWNlX2xhbjJfdmxhbjMiLCIudHlwZSI6ImludGVyZmFjZSIsIm5hbWUiOiJsYW4yLjMiLCJyb2xlIjpbImNsaWVudCJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4IjoxMX0seyIubmFtZSI6ImlmYWNlX2xhbjNfdmxhbjMiLCIudHlwZSI6ImludGVyZmFjZSIsIm5hbWUiOiJsYW4zLjMiLCJyb2xlIjpbImNsaWVudCJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4IjoxMn0seyIubmFtZSI6ImlmYWNlX2xhbjRfdmxhbjMiLCIudHlwZSI6ImludGVyZmFjZSIsIm5hbWUiOiJsYW40LjMiLCJyb2xlIjpbImNsaWVudCJdLCIuYW5vbnltb3VzIjpmYWxzZSwiLmluZGV4IjoxM31dfQ=="></gluon-web2>
15+
<script type="module" src="./index.tsx"></script>
1416
</body>
1517
</html>

package/gluon-web2/src/index.tsx

+63-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,65 @@
11
import { h, render } from "preact";
2-
import App from "./App";
2+
/* import App from "./App";
33
4-
render(<App />, document.getElementById("root")!);
4+
render(<App />, document.getElementById("root")!); */
5+
6+
import GluonWeb2 from "./GluonWeb2";
7+
8+
const INSTANCES: Record<string, GluonWeb2Instance> = {}
9+
10+
class GluonWeb2Instance {
11+
readonly el: HTMLElement;
12+
readonly rendered: any;
13+
14+
constructor(el: HTMLElement) {
15+
this.el = el;
16+
const dataset = this.el.dataset
17+
18+
try {
19+
let parsedData = JSON.parse(atob(dataset.componentData))
20+
21+
this.rendered = render(<GluonWeb2
22+
id={dataset.gluonWeb2}
23+
component={dataset.component}
24+
data={parsedData}
25+
/>, this.el)
26+
} catch (error) {
27+
const errEl = document.createElement('p')
28+
errEl.classList.add('web2-error')
29+
el.appendChild(errEl)
30+
errEl.appendChild(document.createTextNode(
31+
JSON.stringify(dataset, null, 2) + ' ' + String(error)
32+
))
33+
}
34+
}
35+
36+
teardown() {
37+
38+
}
39+
}
40+
41+
function findGluonWeb2() {
42+
const nodes = document.querySelectorAll('gluon-web2')
43+
44+
let seen: Record<string, boolean> = {}
45+
46+
for (let i = 0; i < nodes.length; i++) {
47+
let node = nodes[i] as HTMLElement
48+
49+
if (!node.dataset.gluonWeb2) {
50+
node.dataset.gluonWeb2 = String(Math.random())
51+
INSTANCES[node.dataset.gluonWeb2] = new GluonWeb2Instance(node)
52+
}
53+
54+
seen[node.dataset.gluonWeb2] = true
55+
}
56+
57+
for (const key of Object.keys(INSTANCES).filter(k => !seen[k])) {
58+
INSTANCES[key].teardown()
59+
delete INSTANCES[key]
60+
}
61+
}
62+
63+
window.GluonWeb2Refresh = findGluonWeb2
64+
65+
findGluonWeb2()

package/gluon-web2/src/main.scss

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.web2-error {
2+
background: #ff000080;
3+
color: black;
4+
padding: 1em;
5+
}

0 commit comments

Comments
 (0)