diff --git a/src/webui/service/link/routes.py b/src/webui/service/link/routes.py index 04c4b1de59283832b17c92c91727fa716a2c0fea..51e903d9ec28c5aaac20cd49e2f97dd7044e12bf 100644 --- a/src/webui/service/link/routes.py +++ b/src/webui/service/link/routes.py @@ -12,10 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -from flask import render_template, Blueprint, flash, session, redirect, url_for -from common.proto.context_pb2 import Empty, LinkList + +from flask import current_app, render_template, Blueprint, flash, session, redirect, url_for +from common.proto.context_pb2 import Empty, Link, LinkEvent, LinkId, LinkIdList, LinkList, DeviceId from context.client.ContextClient import ContextClient + link = Blueprint('link', __name__, url_prefix='/link') context_client = ContextClient() @@ -32,4 +34,13 @@ def home(): return render_template( "link/home.html", links=response.links, - ) \ No newline at end of file + ) + +@link.route('detail/<path:link_uuid>', methods=('GET', 'POST')) +def detail(link_uuid: str): + request = LinkId() + request.link_uuid.uuid = link_uuid + context_client.connect() + response = context_client.GetLink(request) + context_client.close() + return render_template('link/detail.html',link=response) diff --git a/src/webui/service/main/routes.py b/src/webui/service/main/routes.py index 85d3aeeb7c6f23ab4123412173cdfda4d27b23a4..893f0854361081325305289f95b1471279384c7e 100644 --- a/src/webui/service/main/routes.py +++ b/src/webui/service/main/routes.py @@ -11,33 +11,45 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -import json, logging +import copy, json, logging from flask import jsonify, redirect, render_template, Blueprint, flash, session, url_for, request -from common.proto.context_pb2 import Context, Device, Empty, Link, Topology, ContextIdList +from common.proto.context_pb2 import Context, Device, Empty, Link, Service, Topology, ContextIdList +from common.tools.grpc.Tools import grpc_message_to_json_string from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient +from service.client.ServiceClient import ServiceClient from webui.service.main.forms import ContextForm, DescriptorForm - main = Blueprint('main', __name__) - context_client = ContextClient() device_client = DeviceClient() - +service_client = ServiceClient() logger = logging.getLogger(__name__) - -def process_descriptor(item_name_singluar, item_name_plural, grpc_method, grpc_class, items): +ENTITY_TO_TEXT = { + # name => singular, plural + 'context' : ('Context', 'Contexts' ), + 'topology': ('Topology', 'Topologies'), + 'device' : ('Device', 'Devices' ), + 'link' : ('Link', 'Links' ), + 'service' : ('Service', 'Services' ), +} +ACTION_TO_TEXT = { + # action => infinitive, past + 'add' : ('Add', 'Added'), + 'update' : ('Update', 'Updated'), +} +def process_descriptor(entity_name, action_name, grpc_method, grpc_class, entities): + entity_name_singluar,entity_name_plural = ENTITY_TO_TEXT[entity_name] + action_infinitive, action_past = ACTION_TO_TEXT[action_name] num_ok, num_err = 0, 0 - for item in items: + for entity in entities: try: - grpc_method(grpc_class(**item)) + grpc_method(grpc_class(**entity)) num_ok += 1 except Exception as e: # pylint: disable=broad-except - flash(f'Unable to add {item_name_singluar} {str(item)}: {str(e)}', 'error') + flash(f'Unable to {action_infinitive} {entity_name_singluar} {str(entity)}: {str(e)}', 'error') num_err += 1 - if num_ok : flash(f'{str(num_ok)} {item_name_plural} added', 'success') - if num_err: flash(f'{str(num_err)} {item_name_plural} failed', 'danger') - + if num_ok : flash(f'{str(num_ok)} {entity_name_plural} {action_past}', 'success') + if num_err: flash(f'{str(num_err)} {entity_name_plural} failed', 'danger') def process_descriptors(descriptors): logger.warning(str(descriptors.data)) logger.warning(str(descriptors.name)) @@ -52,16 +64,30 @@ def process_descriptors(descriptors): except Exception as e: # pylint: disable=broad-except flash(f'Unable to load descriptor file: {str(e)}', 'danger') return - + contexts = descriptors.get('contexts' , []) + topologies = descriptors.get('topologies', []) + devices = descriptors.get('devices' , []) + links = descriptors.get('links' , []) + services = descriptors.get('services' , []) + services_add = [] + for service in services: + service_copy = copy.deepcopy(service) + service_copy['service_endpoint_ids'] = [] + service_copy['service_constraints'] = [] + service_copy['service_config'] = {'config_rules': []} + services_add.append(service_copy) context_client.connect() device_client.connect() - process_descriptor('Context', 'Contexts', context_client.SetContext, Context, descriptors['contexts' ]) - process_descriptor('Topology', 'Topologies', context_client.SetTopology, Topology, descriptors['topologies']) - process_descriptor('Device', 'Devices', device_client .AddDevice, Device, descriptors['devices' ]) - process_descriptor('Link', 'Links', context_client.SetLink, Link, descriptors['links' ]) + service_client.connect() + process_descriptor('context', 'add', context_client.SetContext, Context, contexts ) + process_descriptor('topology', 'add', context_client.SetTopology, Topology, topologies ) + process_descriptor('device', 'add', device_client .AddDevice, Device, devices ) + process_descriptor('link', 'add', context_client.SetLink, Link, links ) + process_descriptor('service', 'add', service_client.CreateService, Service, services_add) + process_descriptor('service', 'update', service_client.UpdateService, Service, services ) + service_client.close() device_client.close() context_client.close() - @main.route('/', methods=['GET', 'POST']) def home(): context_client.connect() @@ -89,7 +115,6 @@ def home(): context_client.close() device_client.close() return render_template('main/home.html', context_form=context_form, descriptor_form=descriptor_form) - @main.route('/topology', methods=['GET']) def topology(): context_client.connect() @@ -100,29 +125,30 @@ def topology(): 'name': device.device_id.device_uuid.uuid, 'type': device.device_type, } for device in response.devices] - response = context_client.ListLinks(Empty()) - links = [{ - 'id': link.link_id.link_uuid.uuid, - 'source': link.link_endpoint_ids[0].device_id.device_uuid.uuid, - 'target': link.link_endpoint_ids[1].device_id.device_uuid.uuid, - } for link in response.links] - + links = [] + for link in response.links: + if len(link.link_endpoint_ids) != 2: + str_link = grpc_message_to_json_string(link) + logger.warning('Unexpected link with len(endpoints) != 2: {:s}'.format(str_link)) + continue + links.append({ + 'id': link.link_id.link_uuid.uuid, + 'source': link.link_endpoint_ids[0].device_id.device_uuid.uuid, + 'target': link.link_endpoint_ids[1].device_id.device_uuid.uuid, + }) return jsonify({'devices': devices, 'links': links}) except: logger.exception('Error retrieving topology') finally: context_client.close() - @main.get('/about') def about(): return render_template('main/about.html') - @main.get('/debug') def debug(): return render_template('main/debug.html') - @main.get('/resetsession') def reset_session(): session.clear() - return redirect(url_for("main.home")) + return redirect(url_for("main.home")) \ No newline at end of file diff --git a/src/webui/service/service/routes.py b/src/webui/service/service/routes.py index 81031490ef840ff63262444a5487932a4e72c111..d62e28ca16246934e715086b9091ce965e18ff5b 100644 --- a/src/webui/service/service/routes.py +++ b/src/webui/service/service/routes.py @@ -14,7 +14,7 @@ import grpc from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for -from common.proto.context_pb2 import ContextId, Service, ServiceId, ServiceList, ServiceTypeEnum, ServiceStatusEnum +from common.proto.context_pb2 import ContextId, Service, ServiceId, ServiceList, ServiceTypeEnum, ServiceStatusEnum, Connection from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient @@ -73,12 +73,13 @@ def detail(service_uuid: str): try: context_client.connect() response: Service = context_client.GetService(request) + connections: Connection = context_client.ListConnections(request) context_client.close() except Exception as e: flash('The system encountered an error and cannot show the details of this service.', 'warning') current_app.logger.exception(e) return redirect(url_for('service.home')) - return render_template('service/detail.html', service=response) + return render_template('service/detail.html', service=response, connections=connections) @service.get('<path:service_uuid>/delete') @@ -100,4 +101,4 @@ def delete(service_uuid: str): except Exception as e: flash('Problem deleting service "{:s}": {:s}'.format(service_uuid, str(e.details())), 'danger') current_app.logger.exception(e) - return redirect(url_for('service.home')) + return redirect(url_for('service.home')) \ No newline at end of file diff --git a/src/webui/service/templates/device/detail.html b/src/webui/service/templates/device/detail.html index b4cf6b715250d3e96b5026c3e19758a2be9a9607..f2cdc581553bbd8d45f237fd99d2b746ab0ad61b 100644 --- a/src/webui/service/templates/device/detail.html +++ b/src/webui/service/templates/device/detail.html @@ -1,111 +1,129 @@ <!-- - Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) + Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + + {% extends 'base.html' %} + + {% block content %} + <h1>Device {{ device.device_id.device_uuid.uuid }}</h1> + + <div class="row mb-3"> + <div class="col-sm-3"> + <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('device.home') }}'"> + <i class="bi bi-box-arrow-in-left"></i> + Back to device list + </button> + </div> + <div class="col-sm-3"> + <a id="update" class="btn btn-secondary" href="#"> + <i class="bi bi-pencil-square"></i> + Update + </a> + </div> + <div class="col-sm-3"> + <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete device</button> --> + <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal"> + <i class="bi bi-x-square"></i>Delete device + </button> + </div> + </div> - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -{% extends 'base.html' %} - -{% block content %} - <h1>Device {{ device.device_id.device_uuid.uuid }}</h1> - - <div class="row mb-3"> - <div class="col-sm-3"> - <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('device.home') }}'"> - <i class="bi bi-box-arrow-in-left"></i> - Back to device list - </button> + <br> + <div class="row mb-3"> + <div class="col-sm-4"> + <b>UUID: </b>{{ device.device_id.device_uuid.uuid }}<br><br> + <b>Type: </b>{{ device.device_type }}<br><br> + <b>Drivers: </b> + <ul> + {% for driver in device.device_drivers %} + <li>{{ dde.Name(driver).replace('DEVICEDRIVER_', '').replace('UNDEFINED', 'EMULATED') }}</li> + {% endfor %} + </ul> + </div> + <div class="col-sm-8"> + <table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">Endpoints</th> + <th scope="col">Type</th> + </tr> + </thead> + <tbody> + {% for endpoint in device.device_endpoints %} + <tr> + <td> + {{ endpoint.endpoint_id.endpoint_uuid.uuid }} + </td> + <td> + {{ endpoint.endpoint_type }} + </td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> </div> - <div class="col-sm-3"> - <a id="update" class="btn btn-secondary" href="#"> - <i class="bi bi-pencil-square"></i> - Update - </a> - </div> - <div class="col-sm-3"> - <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete device</button> --> - <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal"> - <i class="bi bi-x-square"></i>Delete device - </button> - </div> - </div> - <div class="row mb-3"> - <div class="col-sm-1"><b>UUID:</b></div> - <div class="col-sm-5"> - {{ device.device_id.device_uuid.uuid }} - </div> - <div class="col-sm-1"><b>Type:</b></div> - <div class="col-sm-5"> - {{ device.device_type }} - </div> - </div> - <div class="row mb-3"> - <div class="col-sm-1"><b>Drivers:</b></div> - <div class="col-sm-11"> - <ul> - {% for driver in device.device_drivers %} - <li>{{ dde.Name(driver).replace('DEVICEDRIVER_', '').replace('UNDEFINED', 'EMULATED') }}</li> - {% endfor %} - </ul> - </div> - </div> - <div class="row mb-3"> - <b>Endpoints:</b> - <div class="col-sm-10"> - <ul> - {% for endpoint in device.device_endpoints %} - <li>{{ endpoint.endpoint_id.endpoint_uuid.uuid }}: {{ endpoint.endpoint_type }}</li> - {% endfor %} - </ul> - </div> - </div> - <div class="row mb-3"> <b>Configurations:</b> - <div class="col-sm-10"> - <ul> - {% for config in device.device_config.config_rules %} + <table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">Key</th> + <th scope="col">Value</th> + </tr> + </thead> + <tbody> + {% for config in device.device_config.config_rules %} {% if config.WhichOneof('config_rule') == 'custom' %} - <li>{{ config.custom.resource_key }}: - <ul> - {% for key, value in (config.custom.resource_value | from_json).items() %} - <li><b>{{ key }}:</b> {{ value }}</li> - {% endfor %} - </ul> - </li> + <tr> + <td> + {{ config.custom.resource_key }} + </td> + <td> + <ul> + {% for key, value in (config.custom.resource_value | from_json).items() %} + <li><b>{{ key }}:</b> {{ value }}</li> + {% endfor %} + </ul> + </td> + </tr> {% endif %} - {% endfor %} - </ul> - </div> - </div> + {% endfor %} + </tbody> + </table> - <!-- Modal --> -<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <h5 class="modal-title" id="staticBackdropLabel">Delete device?</h5> - <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> - </div> - <div class="modal-body"> - Are you sure you want to delete the device "{{ device.device_id.device_uuid.uuid }}"? - </div> - <div class="modal-footer"> - <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button> - <a type="button" class="btn btn-danger" href="{{ url_for('device.delete', device_uuid=device.device_id.device_uuid.uuid) }}"><i class="bi bi-exclamation-diamond"></i>Yes</a> - </div> - </div> - </div> - </div> -{% endblock %} \ No newline at end of file + <!-- Modal --> + <div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="staticBackdropLabel">Delete device?</h5> + <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> + </div> + <div class="modal-body"> + Are you sure you want to delete the device "{{ device.device_id.device_uuid.uuid }}"? + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button> + <a type="button" class="btn btn-danger" href="{{ url_for('device.delete', device_uuid=device.device_id.device_uuid.uuid) }}"><i class="bi bi-exclamation-diamond"></i>Yes</a> + </div> + </div> + </div> + </div> + + {% endblock %} + \ No newline at end of file diff --git a/src/webui/service/templates/link/detail.html b/src/webui/service/templates/link/detail.html new file mode 100644 index 0000000000000000000000000000000000000000..8b49a65eb4b61edaf4d286f691d41c73e6d1c676 --- /dev/null +++ b/src/webui/service/templates/link/detail.html @@ -0,0 +1,59 @@ +<!-- + Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + {% extends 'base.html' %} + + {% block content %} + <h1>Link {{ link.link_id.link_uuid.uuid }}</h1> + <div class="row mb-3"> + <div class="col-sm-3"> + <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('link.home') }}'"> + <i class="bi bi-box-arrow-in-left"></i> + Back to link list + </button> + </div> + </div> + + <br> + <div class="row mb-3"> + <div class="col-sm-4"> + <b>UUID: </b>{{ link.link_id.link_uuid.uuid }}<br><br> + </div> + <div class="col-sm-8"> + <table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">Endpoints</th> + <th scope="col">Type</th> + </tr> + </thead> + <tbody> + {% for end_point in link.link_endpoint_ids %} + <tr> + <td> + {{ end_point.endpoint_uuid.uuid }} + </td> + <td> + {{ end_point.endpoint_uuid.uuid }} + </td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> + + {% endblock %} + \ No newline at end of file diff --git a/src/webui/service/templates/link/home.html b/src/webui/service/templates/link/home.html index d0c122f6aafd0de8e2937be056d1c2e787c91710..77d00d34185ac45ada0ed6d8e9915c0b2f3ad9c0 100644 --- a/src/webui/service/templates/link/home.html +++ b/src/webui/service/templates/link/home.html @@ -1,96 +1,96 @@ <!-- - Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -{% extends 'base.html' %} - -{% block content %} - <h1>Links</h1> - - <div class="row"> - <div class="col"> - <!-- <a href="#" class="btn btn-primary" style="margin-bottom: 10px;"> - <i class="bi bi-plus"></i> - Add New Link - </a> --> - </div> - <div class="col"> - {{ links | length }} links found</i> - </div> - <!-- <div class="col"> - <form> - <div class="input-group"> - <input type="text" aria-label="Search" placeholder="Search..." class="form-control"/> - <button type="submit" class="btn btn-primary">Search</button> - </div> - </form> - </div> --> - </div> - - <table class="table table-striped table-hover"> - <thead> - <tr> - <th scope="col">#</th> - <th scope="col">Endpoints</th> - <th scope="col"></th> - </tr> - </thead> - <tbody> - {% if links %} - {% for link in links %} - <tr> - <td> - <!-- <a href="#"> --> - {{ link.link_id.link_uuid.uuid }} - <!-- </a> --> - </td> - - <td> - <ul> - {% for end_point in link.link_endpoint_ids %} - <li> - {{ end_point.endpoint_uuid.uuid }} / - Device: - <a href="{{ url_for('device.detail', device_uuid=end_point.device_id.device_uuid.uuid) }}"> - {{ end_point.device_id.device_uuid.uuid }} - <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> - <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> - <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> - </svg> - </a> - </li> - {% endfor %} - </ul> - </td> - - <td> - <!-- <a href="#"> - <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> - <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> - <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> - </svg> - </a> --> - </td> - </tr> - {% endfor %} - {% else %} - <tr> - <td colspan="7">No links found</td> - </tr> - {% endif %} - </tbody> - </table> - -{% endblock %} \ No newline at end of file + Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + + {% extends 'base.html' %} + + {% block content %} + <h1>Links</h1> + + <div class="row"> + <div class="col"> + <!-- <a href="#" class="btn btn-primary" style="margin-bottom: 10px;"> + <i class="bi bi-plus"></i> + Add New Link + </a> --> + </div> + <div class="col"> + {{ links | length }} links found</i> + </div> + <!-- <div class="col"> + <form> + <div class="input-group"> + <input type="text" aria-label="Search" placeholder="Search..." class="form-control"/> + <button type="submit" class="btn btn-primary">Search</button> + </div> + </form> + </div> --> + </div> + + <table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">#</th> + <th scope="col">Endpoints</th> + <th scope="col"></th> + </tr> + </thead> + <tbody> + {% if links %} + {% for link in links %} + <tr> + <td> + <!-- <a href="#"> --> + {{ link.link_id.link_uuid.uuid }} + <!-- </a> --> + </td> + + <td> + <ul> + {% for end_point in link.link_endpoint_ids %} + <li> + {{ end_point.endpoint_uuid.uuid }} / + Device: + <a href="{{ url_for('device.detail', device_uuid=end_point.device_id.device_uuid.uuid) }}"> + {{ end_point.device_id.device_uuid.uuid }} + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> + <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> + <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> + </svg> + </a> + </li> + {% endfor %} + </ul> + </td> + + <td> + <a href="{{ url_for('link.detail', link_uuid=link.link_id.link_uuid.uuid) }}"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16"> + <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/> + <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/> + </svg> + </a> + </td> + </tr> + {% endfor %} + {% else %} + <tr> + <td colspan="7">No links found</td> + </tr> + {% endif %} + </tbody> + </table> + + {% endblock %} \ No newline at end of file diff --git a/src/webui/service/templates/service/detail.html b/src/webui/service/templates/service/detail.html index 1e58b9eaad3155524808f60b49840edab7f17739..3a0f0f7d0c3e8b2e4130c967b45568ce2a96fc8d 100644 --- a/src/webui/service/templates/service/detail.html +++ b/src/webui/service/templates/service/detail.html @@ -98,4 +98,39 @@ </div> </div> -{% endblock %} \ No newline at end of file + + <table class="table table-striped table-hover"> + <thead> + <tr> + <th scope="col">Connection Id</th> + <th scope="col">Sub-service</th> + <th scope="col">Path</th> + </tr> + </thead> + <tbody> + {% for connections in connections.connections %} + <tr> + <td> + {{ connections.connection_id.connection_uuid.uuid }} + </td> + <td> + {{ connections.sub_service_ids|map(attribute='service_uuid')|map(attribute='uuid')|join(', ') }} + </td> + + {% for i in range(connections.path_hops_endpoint_ids|length) %} +<td> + {{ connections.path_hops_endpoint_ids[i].device_id.device_uuid.uuid }} / {{ connections.path_hops_endpoint_ids[i].endpoint_uuid.uuid }} +</td> +{% endfor %} + + + </tr> + {% endfor %} + </tbody> + </table> + + + + + +{% endblock %} diff --git a/src/webui/service/templates/service/home.html b/src/webui/service/templates/service/home.html index 0e152006c149df35d477ecfb81bb4fcc0b562d9a..8d231cf17e553f879bd8314514c078054a5a17d5 100644 --- a/src/webui/service/templates/service/home.html +++ b/src/webui/service/templates/service/home.html @@ -73,7 +73,7 @@ <td> <ul> {% for constraint in service.service_constraints %} - <li>{{ constraint.constraint_type }}: {{ constraint.constraint_value }}</li> + <li>{{ constraint.custom.constraint_type }}: {{ constraint.custom.constraint_value }}</li> {% endfor %} </ul> </td>