# P1935 UI
## Code Structure
* efo
* static
* network_topology.js
有call到listServices()
- request.js
listServices() call /api/services
* efo
* api.py
call efo.get_service_status()
* efo.py
get_service_status(cluster, namespace)
call adapter2.py裡的get_service_status
Problem
* Service function chain: check if only show default cluster?
## Tasks


1. operator/operator.html字改成Service Topology

2. 在api.py裡把list_services()多加registry_svcs
```javacript=
# list services (network topology)
@bp.route('/services', methods=["GET"])
@login_required
def list_services():
svcs, status_code = efo.get_service_status(current_user.id)
return make_response(jsonify(svcs), status_code)
```
3. 在/static/request.js 連結list_appstores, list_branchstores
```javascript=
// new function
function listStores() {
const branch_httpRequest = new XMLHttpRequest();
var branchs = [];
branch_httpRequest.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE) {
branch_resp = JSON.parse(this.response);
for (var i = 0; i < branch_resp.length; i++){
branchs.push(branch_resp[i]["name"]);
branchs.push(branch_resp[i]["machine_name"]);
branchs.push(branch_resp[i]["cluster_name"]);
branchs.push(branch_resp[i]["role"]);
branchs.push(branch_resp[i]["ip"]);
branchs.push(branch_resp[i]["port"]);
branchs.push(branch_resp[i]["image_list"]);
branchs.push(branch_resp[i]["total_package_size"]);
branchs.push(branch_resp[i]["available_size"]);
}
}
}
branch_httpRequest.open('GET', `/api/branchstores`, false);
branch_httpRequest.send();
const httpRequest = new XMLHttpRequest();
var apps = [];
app_httpRequest.onreadystatechange = function() {
if (this.readyState === XMLHttpRequest.DONE) {
app_resp = JSON.parse(this.response);
for (var i = 0; i < app_resp.length; i++){
apps.push(app_resp[i]["name"]);
apps.push(app_resp[i]["machine_name"]);
apps.push(app_resp[i]["cluster_name"]);
apps.push(app_resp[i]["role"]);
apps.push(app_resp[i]["ip"]);
apps.push(app_resp[i]["port"]);
apps.push(app_resp[i]["image_list"]);
apps.push(app_resp[i]["total_package_size"]);
apps.push(app_resp[i]["available_size"]);
}
}
}
httpRequest.open('GET', `/api/appstores`, false);
httpRequest.send();
const merge = [...httpRequest.response, ...branch_httpRequest.response]
if ( branch_httpRequest.status === 200 && httpRequest.status === 200){
return merge;
/*
return:
[{
'name': ,
'machine_name': ,
'cluster_name': ,
'role:' ,
'image_list': ,
'total_package_size': ,
'available_size':
}, {}]
*/
}
}
```
4. 在draw_network_topology():
* 確保其他有用到listServices()的都有改到
* services -> app_svcs
* add registry_svcs
```javascript=
function draw_network_topology(){
response = listServices();
var services = JSON.parse(response);
store_response = listStores();
var nodes = [];
var edges = [];
prefixes = [];
var branchs = [];
for ( var i = 0; i < services.length; i++){
// check ip prefix
prefix = services[i].ip.split('.')[0];
if (!( prefixes.includes(prefix) )){
prefixes.push(prefix);
nodes.push({
id: prefix+".",
label: prefix+".",
image: "https://i.ibb.co/WB3M1Cc/Edgemaster.png",
shape: "image"
});
}
// add service to topology
nodes.push({
id: services[i].ip,
label: services[i].ip,
image: "https://i.ibb.co/zszT32D/node.png",
shape: "image"
});
edges.push({
from: prefix+".",
to: services[i].ip
});
}
for ( i = 0 ; i < store_response.length ; i++){
prefix = services[i].ip.split('.')[0];
if ( store_response[i] == branch_resp[i] ) {
branchs.push({
id: store_response[i].ip,
label: store_response[i].ip,
image: "https://i.ibb.co/9WCtqkd/branch.png",
shape: "image"
});
edges.push({
from: prefix+".",
to: store_response[i].ip
});
}
}
var data = {
nodes: nodes,
edges: edges,
branchs: branchs,
};
var options = {};
var container = document.querySelector('.network');
network = new vis.Network(container, data, options);
network.on('click',(obj)=>{
document.querySelector('.report').innerHTML = obj.nodes[0];
selectnode=obj.nodes[0];
var list=""
var listbranch=""
for(i = 0; i < services.length; i++){
if(selectnode==services[i].ip){
list=services[i];
break;
}else{
list=""
}
}
for(i = 0; i < store_response.length; i++){
if(selectnode==store_response[i].ip){
listbranch=store_response[i];
break;
}else{
listbranch=""
}
}
const manis = getManifest(list.name);
console.log(manis);
list.description = "";
manis.forEach(mani => {
data = JSON.parse(mani.data);
if ("annotations" in data.metadata) {
list.description = data.metadata.annotations.description;
}
})
const manis_b = getManifest(listbranch.name);
console.log(manis_b);
listbranch.description = "";
manis_b.forEach(mani => {
data = JSON.parse(mani.data);
if ("annotations" in data.metadata) {
listbranch.description = data.metadata.annotations.description;
}
})
if (list==services[i]){
var content='<img src="https://i.ibb.co/zszT32D/node.png" width="100">'
content+=['<center><table class=topo_table>',
'<tr>',
'<td colspan="2" height="60"><span style="border-bottom: 2px #6C6C6C solid;font-size: x-large;">'+list.name+'</td>',
'</tr>',
'<tr>',
'<td>IP</td>',
'<td>'+list.ip+'</td>',
'</tr>',
'<tr>',
'<td>port</td>',
'<td>'+list.port+'</td>',
'</tr>',
'<tr>',
'<td colspan="2" height="50"><span style="border-bottom: 2px #6C6C6C solid;">description</td>',
'</tr>',
'<tr>',
'<td colspan="2">'+list.description+'</td>',
'</tr>'
].join("\n");
}else{
var content = "";
}
if (listbranch==store_response[i]){
var content='<img src="https://i.ibb.co/9WCtqkd/branch.png" width="100">'
content+=['<center><table class=topo_table>',
'<tr>',
'<td colspan="2" height="60"><span style="border-bottom: 2px #6C6C6C solid;font-size: x-large;">'+list.name+'</td>',
'</tr>',
'<tr>',
'<td>IP</td>',
'<td>'+listbranch.ip+'</td>',
'</tr>',
'<tr>',
'<td>port</td>',
'<td>'+listbranch.port+'</td>',
'</tr>',
'<tr>',
'<td colspan="2" height="50"><span style="border-bottom: 2px #6C6C6C solid;">description</td>',
'</tr>',
'<tr>',
'<td colspan="2">'+listbranch.description+'</td>',
'</tr>',
'<button onclick="showpopup();" class=learn_more>more</button>'
].join("\n");
}else{
var content = "";
}
document.querySelector('.report').innerHTML = content;
document.querySelector('.branch_name').innerHTML = listbranch.name;
document.querySelector('.branch_ip').innerHTML = listbranch.ip;
document.querySelector('.branch_port').innerHTML = listbranch.port;
document.querySelector('.branch_image_list').innerHTML = listbranch.image_list;
document.querySelector('.branch_total').innerHTML = listbranch.total_package_size;
document.querySelector('.branch_available').innerHTML = listbranch.available_size;
});
}
````
* 參考node_topology.js
5. operator/simple.html
```javacript=
<div class="report"></div>
<div id=popup_box class=popup_box>
<a onclick="closepopup();" class="popup_close" href="#">x</a>
<h1 style="border-bottom:1px solid lightgray;display: flex;align-items: flex-end;margin-left: 10px;">Owner Node</h1>
<div class="node_content">
<img src="https://i.ibb.co/9WCtqkd/branch.png" width="250">
<center><div class="node_name"></div></center>
</div>
<div class="node_list">
<table class="node_table" text-align="center">
<h2>Basic Information :</h2>
<tr>
<td>IP</td>
<td><div class="branch_ip"></div></td>
</tr>
<tr>
<td>Port</td>
<td><div class="branch_port"></div></td>
</tr>
<tr>
<td>Image list</td>
<td><div class="branch_image_list"></div></td>
</tr>
<tr>
<td>Total package size</td>
<td><div class="branch_total"></div></td>
</tr>
<tr>
<td>Available size</td>
<td><div class="branch_available"></div></td>
</tr>
</table>
</div>
</div>
</div>
```
6. UI介面
* description部分印出private registry: role
e.g. private registry: branchstore
* Branchstore/Appstore圖示用不同顏色
* 加more botton
* Basic Information:
表格:
* ip
* port
* image_list
* total_package_size
* available_size
# Git操作
* 複製到自己的directory
複製到自己的/home/sherrylee
git clone https://github.com/dingyiyi0226/standard-p1935.git
* 若要用branch:
開branch並切到branch: git checkout -b sherrylee
每次改時確認一下是否在branch: git status
* 有人更新: git pull
* 改完想要push到github
git config --global user.name "xxxxx"
git config --global user.email xxxxx@example.com
git add .
git commit -m "xxxxx"
到branch: git push origin sherrylee
到master: git push origin master