From 35b04e392a38b7189167fd6f39eaf38558054f98 Mon Sep 17 00:00:00 2001 From: Joaquin Matres <4514346+joamatab@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:40:26 -0800 Subject: [PATCH 1/3] remove webapp --- README.md | 1 - gplugins/web/Makefile | 2 - gplugins/web/__init__.py | 1 - gplugins/web/gds_files/C.gds | Bin 212 -> 0 bytes gplugins/web/gds_files/C_width20.gds | Bin 220 -> 0 bytes gplugins/web/gds_files/C_width5.gds | Bin 218 -> 0 bytes gplugins/web/gds_files/coh_rx_dual_pol.gds | Bin 14536 -> 0 bytes gplugins/web/gds_files/coh_rx_single_pol.gds | Bin 13550 -> 0 bytes .../coh_rx_single_pol_pad_d_19b6c499.gds | Bin 13564 -> 0 bytes .../coh_rx_single_pol_pad_d_d4526895.gds | Bin 13564 -> 0 bytes gplugins/web/gds_files/coh_tx_dual_pol.gds | Bin 10292 -> 0 bytes gplugins/web/gds_files/crossing_arm.gds | Bin 1498 -> 0 bytes gplugins/web/gds_files/dbr_cavity.gds | Bin 7406 -> 0 bytes gplugins/web/gds_files/die_bbox_frame.gds | Bin 440 -> 0 bytes .../gds_files/loss_deembedding_ch14_23.gds | Bin 27548 -> 0 bytes .../web/gds_files/pad_array_add_fiducials.gds | Bin 872 -> 0 bytes .../spiral_inner_io_add_gra_f2760628.gds | Bin 39252 -> 0 bytes gplugins/web/gds_files/wg.gds | Bin 182 -> 0 bytes gplugins/web/main.py | 300 ------------- gplugins/web/middleware.py | 55 --- gplugins/web/server.py | 219 ---------- gplugins/web/server_jupyter.py | 28 -- gplugins/web/static/client.css | 109 ----- gplugins/web/static/client.js | 410 ------------------ gplugins/web/templates/client.html.j2 | 32 -- gplugins/web/templates/file_browser.html.j2 | 27 -- gplugins/web/templates/filewatcher.html.j2 | 66 --- gplugins/web/templates/footer.html.j2 | 3 - gplugins/web/templates/gds_history.html.j2 | 10 - gplugins/web/templates/header.html.j2 | 84 ---- gplugins/web/templates/index.html.j2 | 14 - gplugins/web/templates/navbar.html.j2 | 19 - gplugins/web/templates/pdk.html.j2 | 10 - gplugins/web/templates/viewer.html.j2 | 44 -- pyproject.toml | 6 - 35 files changed, 1440 deletions(-) delete mode 100644 gplugins/web/Makefile delete mode 100644 gplugins/web/__init__.py delete mode 100644 gplugins/web/gds_files/C.gds delete mode 100644 gplugins/web/gds_files/C_width20.gds delete mode 100644 gplugins/web/gds_files/C_width5.gds delete mode 100644 gplugins/web/gds_files/coh_rx_dual_pol.gds delete mode 100644 gplugins/web/gds_files/coh_rx_single_pol.gds delete mode 100644 gplugins/web/gds_files/coh_rx_single_pol_pad_d_19b6c499.gds delete mode 100644 gplugins/web/gds_files/coh_rx_single_pol_pad_d_d4526895.gds delete mode 100644 gplugins/web/gds_files/coh_tx_dual_pol.gds delete mode 100644 gplugins/web/gds_files/crossing_arm.gds delete mode 100644 gplugins/web/gds_files/dbr_cavity.gds delete mode 100644 gplugins/web/gds_files/die_bbox_frame.gds delete mode 100644 gplugins/web/gds_files/loss_deembedding_ch14_23.gds delete mode 100644 gplugins/web/gds_files/pad_array_add_fiducials.gds delete mode 100644 gplugins/web/gds_files/spiral_inner_io_add_gra_f2760628.gds delete mode 100644 gplugins/web/gds_files/wg.gds delete mode 100644 gplugins/web/main.py delete mode 100644 gplugins/web/middleware.py delete mode 100755 gplugins/web/server.py delete mode 100755 gplugins/web/server_jupyter.py delete mode 100644 gplugins/web/static/client.css delete mode 100644 gplugins/web/static/client.js delete mode 100644 gplugins/web/templates/client.html.j2 delete mode 100644 gplugins/web/templates/file_browser.html.j2 delete mode 100644 gplugins/web/templates/filewatcher.html.j2 delete mode 100644 gplugins/web/templates/footer.html.j2 delete mode 100644 gplugins/web/templates/gds_history.html.j2 delete mode 100644 gplugins/web/templates/header.html.j2 delete mode 100644 gplugins/web/templates/index.html.j2 delete mode 100644 gplugins/web/templates/navbar.html.j2 delete mode 100644 gplugins/web/templates/pdk.html.j2 delete mode 100644 gplugins/web/templates/viewer.html.j2 diff --git a/README.md b/README.md index 8f9d67e5..aa5cde8f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ gdsfactory plugins: - `mpb` for MPB mode solver. - `elmer` for electrostatic (capacitive) simulations. - `palace` for full-wave driven (S parameter) and electrostatic (capacitive) simulations. -- `web` for gdsfactory webapp. - `vlsir` for parsing GDS-extracted circuit netlists into Spice, Spectre and Xyce Schematic File formats. ## Installation diff --git a/gplugins/web/Makefile b/gplugins/web/Makefile deleted file mode 100644 index 914b8d10..00000000 --- a/gplugins/web/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -run: - uvicorn main:app --reload diff --git a/gplugins/web/__init__.py b/gplugins/web/__init__.py deleted file mode 100644 index b2f01558..00000000 --- a/gplugins/web/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__version__ = "0.0.11" diff --git a/gplugins/web/gds_files/C.gds b/gplugins/web/gds_files/C.gds deleted file mode 100644 index a16a30abb8481f980b6c6356eaa3bc3f6079f5a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212 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%0DcdY-e_e2vYUbJlM` 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 tyMI>u=;XQ3vg){xp69*c diff --git a/gplugins/web/gds_files/crossing_arm.gds b/gplugins/web/gds_files/crossing_arm.gds deleted file mode 100644 index 3ba4be790d0839f2d1e79b89ce1e3b5a22400c5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1498 zcmaLXO-NKx6u|NGK72EN)%1Z783rZPA}ke35V0r>6Cw!7LUalXK~rX;XpswD87hjc zYSBc5;UWI_MhFJ7{CMi^f1I&`sDa0C?tS;Yd(V0IT=B%VuSm9K z2j(SB_DMhv%fUbYONQ+=)L)N;Blku2Iw>Wm+fQEj*cUH4JD3-Ha`m!gr~Lcbkmucq zG)1HJw{O*iBaPw)MZ8Q~Eb(^OB2p1@jEUFsZ_SvEmm;j?*R?aI{USSK#u!igb;|E_zl_xC%t*KQ}) z?mp6YrVl1wn*JPHY2QSH1Zv$8N$bX0WJ0@0B=s(~iv;KK6J8Q=xEJ_fNtwYRY{m)9#5n?fjd8q&8@$(SDxvE7*Ot5}51 z&YIY7XgGs;09=@1un)#M+_HBXN9RCALw0Ki<>%ut4W0HtwyE zll3uOA3oLf;saej)@VFPUe~%YAHQLa#*ZP*2U3gva^hMi_x@MpSe1D4ZCT-~zIC z|7&vZ=pMSJ`NG#2(t5-kY({D+Wd^Aek3GF!qxFmrw7&7F);ltP@Dj3Dg7f6CK+gxf jr{@KZ>iI#=sN3`)cIf#+jx2nRElAAzOS*lwxvu;K)zpE% diff --git a/gplugins/web/gds_files/dbr_cavity.gds b/gplugins/web/gds_files/dbr_cavity.gds deleted file mode 100644 index a386a12e99df41c5d1a947496f50314bfde94795..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7406 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 J4)ik%0{}r0bD;nL diff --git a/gplugins/web/gds_files/loss_deembedding_ch14_23.gds b/gplugins/web/gds_files/loss_deembedding_ch14_23.gds deleted file mode 100644 index 6566a5df1a7411afb7f47703703e9a61035fe439..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27548 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 Y;}-@7bpaR+69>~QfpF diff --git a/gplugins/web/main.py b/gplugins/web/main.py deleted file mode 100644 index cb691d39..00000000 --- a/gplugins/web/main.py +++ /dev/null @@ -1,300 +0,0 @@ -import base64 -import importlib -import os -import pathlib -from glob import glob -from pathlib import Path - -import gdsfactory as gf -from fastapi import FastAPI, Form, HTTPException, Request, status -from fastapi.responses import HTMLResponse, RedirectResponse -from fastapi.staticfiles import StaticFiles -from fastapi.templating import Jinja2Templates -from gdsfactory.cell import Settings -from gdsfactory.config import CONF, GDSDIR_TEMP, pdks -from gdsfactory.watch import FileWatcher -from loguru import logger -from pydantic import BaseModel -from starlette.routing import WebSocketRoute - -from gplugins.common.config import PATH -from gplugins.web.middleware import ProxiedHeadersMiddleware -from gplugins.web.server import LayoutViewServerEndpoint, get_layout_view - -module_path = Path(__file__).parent.absolute() - -app = FastAPI( - routes=[WebSocketRoute("/view/{cell_name}/ws", endpoint=LayoutViewServerEndpoint)] -) -app.add_middleware(ProxiedHeadersMiddleware) -# app = FastAPI() -app.mount("/static", StaticFiles(directory=PATH.web / "static"), name="static") - -# gdsfiles = StaticFiles(directory=home_path) -# app.mount("/gds_files", gdsfiles, name="gds_files") -templates = Jinja2Templates(directory=PATH.web / "templates") - - -def load_pdk(pdk: str | None = None) -> gf.Pdk: - pdk = pdk or os.environ.get("PDK", "generic") - - if pdk == "generic": - active_pdk = gf.get_active_pdk() - else: - active_module = importlib.import_module(pdk) - active_pdk = active_module.PDK - active_pdk.activate() - return active_pdk - - -def get_url(request: Request) -> str: - port_mod = "" - if request.url.port is not None and len(str(request.url).split(".")) < 3: - port_mod = f":{str(request.url.port)}" - - hostname = request.url.hostname - - if "github" in hostname: - port_mod = "" - - url = str( - request.url.scheme - + "://" - + (hostname or "localhost") - + port_mod - + request.url.path - ) - return url - - -@app.get("/", response_class=HTMLResponse) -async def root(request: Request): - return templates.TemplateResponse("index.html.j2", {"request": request}) - - -@app.get("/pdk-list", response_model=list[str]) -async def get_pdk_list() -> list[str]: - pdks_installed = [] - for pdk in pdks: - try: - m = importlib.import_module(pdk) - m.PDK - pdks_installed.append(pdk) - except Exception as e: - logger.error(f"Could not import {pdk} {e}") - return sorted(pdks_installed) - - -class PDKItem(BaseModel): - pdk: str - - -@app.post("/pdk-set") -async def set_pdk(pdk_item: PDKItem): - pdk = pdk_item.pdk - load_pdk(pdk) - return {"message": f"PDK {pdk} set successfully!"} - - -@app.get("/gds_list", response_class=HTMLResponse) -async def gds_list(request: Request): - """List all saved GDS files.""" - files_root = GDSDIR_TEMP - paths_list = glob(str(files_root / "*.gds")) - files_list = sorted(Path(gdsfile).stem for gdsfile in paths_list) - files_metadata = [ - {"name": file_name, "url": f"view/{file_name}"} for file_name in files_list - ] - return templates.TemplateResponse( - "file_browser.html.j2", - { - "request": request, - "message": f"GDS files in {str(files_root)!r}", - "files_root": files_root, - "files_metadata": files_metadata, - }, - ) - - -@app.get("/gds_current", response_class=HTMLResponse) -async def gds_current() -> RedirectResponse: - """List all saved GDS files.""" - if CONF.last_saved_files: - return RedirectResponse(f"/view/{CONF.last_saved_files[-1].stem}") - else: - return RedirectResponse( - "/", - status_code=status.HTTP_302_FOUND, - ) - - -@app.get("/pdk", response_class=HTMLResponse) -async def pdk(request: Request): - if "preview.app.github" in str(request.url): - return RedirectResponse(str(request.url).replace(".preview", "")) - active_pdk = load_pdk() - pdk_name = active_pdk.name - components = list(active_pdk.cells.keys()) - return templates.TemplateResponse( - "pdk.html.j2", - { - "request": request, - "title": "Main", - "pdk_name": pdk_name, - "components": sorted(components), - }, - ) - - -LOADED_COMPONENTS = {} - - -@app.get("/view/{cell_name}", response_class=HTMLResponse) -async def view_cell(request: Request, cell_name: str, variant: str | None = None): - gds_files = GDSDIR_TEMP.glob("*.gds") - gds_names = [gdspath.stem for gdspath in gds_files] - - if "preview.app.github" in str(request.url): - return RedirectResponse(str(request.url).replace(".preview", "")) - - if variant in LOADED_COMPONENTS: - component = LOADED_COMPONENTS[variant] - else: - try: - component = gf.get_component(cell_name) - except Exception as e: - if cell_name not in gds_names: - raise HTTPException( - status_code=400, detail=f"Component not found. {e}" - ) from e - - gdspath = GDSDIR_TEMP / cell_name - component = gf.import_gds(gdspath=gdspath.with_suffix(".gds")) - component.settings = Settings(name=component.name) - layout_view = get_layout_view(component) - pixel_data = layout_view.get_pixels_with_options(800, 400).to_png_data() - b64_data = base64.b64encode(pixel_data).decode("utf-8") - return templates.TemplateResponse( - "viewer.html.j2", - { - "request": request, - "cell_name": cell_name, - "variant": variant, - "title": "Viewer", - "initial_view": b64_data, - "component": component, - "url": get_url(request), - }, - ) - - -@app.post("/update/{cell_name}") -async def update_cell(request: Request, cell_name: str): - """Cell name is the name of the PCell function.""" - data = await request.form() - settings = {k: v for k, v in data.items() if v != ""} - - if not settings: - return RedirectResponse( - f"/view/{cell_name}", - status_code=status.HTTP_302_FOUND, - ) - try: - component = gf.get_component({"component": cell_name, "settings": settings}) - variant = component.name - except Exception as e: - raise HTTPException(status_code=400, detail=f"Component not found. {e}") from e - - LOADED_COMPONENTS[component.name] = component - return RedirectResponse( - f"/view/{cell_name}?variant={variant}", - status_code=status.HTTP_302_FOUND, - ) - - -@app.post("/search", response_class=RedirectResponse) -async def search(name: str = Form(...)): - logger.info(f"Searching for {name}...") - try: - gf.get_component(name) - except ValueError: - return RedirectResponse("/", status_code=status.HTTP_404_NOT_FOUND) - logger.info(f"Successfully found {name}! Redirecting...") - return RedirectResponse(f"/view/{name}", status_code=status.HTTP_302_FOUND) - - -######################### -# filewatcher -####################### - -watched_folder = None -watcher = None -output = "" -component = None - - -@app.get("/filewatcher", response_class=HTMLResponse) -async def filewatcher(request: Request): - global component - - if CONF.last_saved_files: - component = gf.import_gds(gf.CONF.last_saved_files[-1]) - component.settings = Settings(name=component.name) - else: - component = gf.components.straight() - - layout_view = get_layout_view(component) - pixel_data = layout_view.get_pixels_with_options(800, 400).to_png_data() - b64_data = base64.b64encode(pixel_data).decode("utf-8") - - return templates.TemplateResponse( - "filewatcher.html.j2", - { - "request": request, - "output": output, - "cell_name": str(component.name), - "variant": None, - "title": "Viewer", - "initial_view": b64_data, - "component": component, - "url": get_url(request), - }, - ) - - -@app.post("/filewatcher_start") -async def watch_folder(request: Request, folder_path: str = Form(...)): - global component - global output - global watched_folder - global watcher - - if folder_path is None or not folder_path.strip(): - raise HTTPException(status_code=400, detail="Folder path is required.") - if not os.path.exists(folder_path) or not os.path.isdir(folder_path): - raise HTTPException(status_code=400, detail="Folder does not exist.") - - watched_folder = folder_path - watched_folder = pathlib.Path(folder_path) - watcher = FileWatcher(path=folder_path) - watcher.start() - output += f"watching {watched_folder}\n" - return RedirectResponse( - "/filewatcher", - status_code=status.HTTP_302_FOUND, - ) - - -@app.get("/filewatcher_stop") -def stop_watcher(request: Request) -> str: - """Stops filewacher.""" - global watcher - global watched_folder - global output - - if watcher: - watcher.stop() - - message = f"stopped watching {watched_folder}\n" - output += message - return message diff --git a/gplugins/web/middleware.py b/gplugins/web/middleware.py deleted file mode 100644 index 4b9202dd..00000000 --- a/gplugins/web/middleware.py +++ /dev/null @@ -1,55 +0,0 @@ -from starlette.types import ASGIApp, Receive, Scope, Send - -Headers = list[tuple[bytes, bytes]] - -# original developed by researchers at university of cambridge: -# https://pypi.org/project/fastapi-proxiedheadersmiddleware/ - -# modification to resolve Connection: keep-alive vs. upgrade conflict -# conflict described here: https://github.com/orgs/community/discussions/57596 -# doesn't seem to work as intended, as the upgrade decision is made -# before the request goes through the middleware - - -class ProxiedHeadersMiddleware: - """ - A middleware that modifies the request to ensure that FastAPI uses the - X-Forwarded-* headers when creating URLs used to reference this application. - - We are very permissive in allowing all X-Forwarded-* headers to be used, as - we know that this API will be published behind the API Gateway, and is - therefore not prone to redirect hijacking. - - """ - - def __init__(self, app: ASGIApp): - self.app = app - - async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: - scope["headers"] = self.remap_headers(scope.get("headers", {})) - - await self.app(scope, receive, send) - return - - def remap_headers(self, source: Headers) -> Headers: - """ - Map X-Forwarded-Host to host and X-Forwarded-Prefix to prefix. - - """ - upgrade = len( - [q for p, q in source if "connection" in str(p) and "upgrade" in str(q)] - ) - - source = dict(source) - if upgrade: # resolve conflict with priority of upgrade - source[b"connection"] = b"upgrade" - - if b"x-forwarded-host" in source: - source[b"host"] = source[b"x-forwarded-host"] - source.pop(b"x-forwarded-host") - - if b"x-forwarded-prefix" in source: - source[b"host"] = source[b"host"] + source[b"x-forwarded-prefix"] - source.pop(b"x-forwarded-prefix") - - return list(source.items()) diff --git a/gplugins/web/server.py b/gplugins/web/server.py deleted file mode 100755 index 90f83485..00000000 --- a/gplugins/web/server.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python3 -# type: ignore - -import asyncio -import json - -import gdsfactory as gf -import klayout.db as db -import klayout.lay as lay -from fastapi import WebSocket -from gdsfactory.component import GDSDIR_TEMP -from loguru import logger -from starlette.endpoints import WebSocketEndpoint - -host = "localhost" -port = 8765 - - -class LayoutViewServerEndpoint(WebSocketEndpoint): - encoding = "text" - - def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) - logger.info("Initialized websocket") - _params = self.scope["query_string"].decode("utf-8") - _params_splitted = _params.split("&") - params = {} - for _param in _params_splitted: - key, value = _param.split("=") - params[key] = value - - # print("args:", args) - # print("kwargs:", kwargs) - # self.url = params["gds_file"].replace('/', '\\') - # self.layer_props = params.get("layer_props", None) - lyp_path = GDSDIR_TEMP / "layer_props.lyp" - active_pdk = gf.get_active_pdk() - if active_pdk.layer_views: - active_pdk.layer_views.to_lyp(lyp_path) - self.layer_props = lyp_path - # path_params = args[0]['path_params'] - # cell_name = path_params["cell_name"] - cell_name = params["variant"] - # c = gf.get_component(cell_name) - gds_path = GDSDIR_TEMP / f"{cell_name}.gds" - # c.write_gds(gds_path) - self.url = self.gds_path = str(gds_path) - - async def on_connect(self, websocket) -> None: - await websocket.accept() - await self.connection(websocket) - - async def on_receive(self, websocket, data) -> None: - await self.reader(websocket, data) - - async def on_disconnect(self, websocket, close_code) -> None: - pass - - async def send_image(self, websocket, data) -> None: - await websocket.send_text(data) - - def image_updated(self, websocket) -> None: - pixel_buffer = self.layout_view.get_screenshot_pixels() - asyncio.create_task(self.send_image(websocket, pixel_buffer.to_png_data())) - - def mode_dump(self): - return self.layout_view.mode_names() - - def annotation_dump(self): - return [d[1] for d in self.layout_view.annotation_templates()] - - def layer_dump(self): - return [ - { - "dp": layer.eff_dither_pattern(), - "ls": layer.eff_line_style(), - "c": layer.eff_fill_color(), - "fc": layer.eff_frame_color(), - "m": layer.marked, - "s": layer.source, - "t": layer.transparent, - "va": layer.valid, - "v": layer.visible, - "w": layer.width, - "x": layer.xfill, - "name": layer.name, - "id": layer.id(), - } - for layer in self.layout_view.each_layer() - ] - - async def connection(self, websocket: WebSocket, path: str | None = None) -> None: - self.layout_view = lay.LayoutView() - url = self.url - self.layout_view.load_layout(url) - if self.layer_props is not None: - self.layout_view.load_layer_props(str(self.layer_props)) - self.layout_view.max_hier() - - await websocket.send_text( - json.dumps( - { - "msg": "loaded", - "modes": self.mode_dump(), - "annotations": self.annotation_dump(), - "layers": self.layer_dump(), - } - ) - ) - - asyncio.create_task(self.timer(websocket)) - - async def timer(self, websocket) -> None: - self.layout_view.on_image_updated_event = lambda: self.image_updated(websocket) - while True: - self.layout_view.timer() - await asyncio.sleep(0.01) - - def buttons_from_js(self, js): - buttons = 0 - k = js["k"] - b = js["b"] - if (k & 1) != 0: - buttons |= lay.ButtonState.ShiftKey - if (k & 2) != 0: - buttons |= lay.ButtonState.ControlKey - if (k & 4) != 0: - buttons |= lay.ButtonState.AltKey - if (b & 1) != 0: - buttons |= lay.ButtonState.LeftButton - if (b & 2) != 0: - buttons |= lay.ButtonState.RightButton - if (b & 4) != 0: - buttons |= lay.ButtonState.MidButton - return buttons - - def wheel_event(self, function, js) -> None: - delta = 0 - dx = js["dx"] - dy = js["dy"] - if dx != 0: - delta = -dx - horizontal = True - elif dy != 0: - delta = -dy - horizontal = False - if delta != 0: - function( - delta, horizontal, db.Point(js["x"], js["y"]), self.buttons_from_js(js) - ) - - def mouse_event(self, function, js) -> None: - function(db.Point(js["x"], js["y"]), self.buttons_from_js(js)) - - async def reader(self, websocket, data: str) -> None: - js = json.loads(data) - msg = js["msg"] - if msg == "clear-annotations": - self.layout_view.clear_annotations() - elif msg == "initialize": - self.layout_view.resize(js["width"], js["height"]) - await websocket.send_text(json.dumps({"msg": "initialized"})) - elif msg == "layer-v": - layer_id = js["id"] - vis = js["value"] - for layer in self.layout_view.each_layer(): - if layer.id() == layer_id: - layer.visible = vis - elif msg == "layer-v-all": - vis = js["value"] - for layer in self.layout_view.each_layer(): - layer.visible = vis - elif msg == "mode_select": - self.layout_view.switch_mode(js["mode"]) - elif msg == "mouse_dblclick": - self.mouse_event(self.layout_view.send_mouse_double_clicked_event, js) - elif msg == "mouse_enter": - self.layout_view.send_enter_event() - elif msg == "mouse_leave": - self.layout_view.send_leave_event() - elif msg == "mouse_move": - self.mouse_event(self.layout_view.send_mouse_move_event, js) - elif msg == "mouse_pressed": - self.mouse_event(self.layout_view.send_mouse_press_event, js) - elif msg == "mouse_released": - self.mouse_event(self.layout_view.send_mouse_release_event, js) - elif msg == "quit": - return - elif msg == "resize": - self.layout_view.resize(js["width"], js["height"]) - elif msg == "select-mode": - mode = js["value"] - self.layout_view.switch_mode(mode) - elif msg == "select-ruler": - ruler = js["value"] - self.layout_view.set_config("current-ruler-template", str(ruler)) - elif msg == "wheel": - self.wheel_event(self.layout_view.send_wheel_event, js) - - -def get_layer_properties() -> str | None: - lyp_path = GDSDIR_TEMP / "layers.lyp" - active_pdk = gf.get_active_pdk() - if active_pdk.layer_views: - lyp_path = active_pdk.layer_views.to_lyp(lyp_path) - return str(lyp_path) - - -def get_layout_view(component: gf.Component) -> lay.LayoutView: - """Returns klayout layout view for a gdsfactory Component.""" - gds_path = GDSDIR_TEMP / f"{component.name}.gds" - component.write_gds(gdspath=str(gds_path)) - layout_view = lay.LayoutView() - layout_view.load_layout(str(gds_path)) - lyp_path = get_layer_properties() - if lyp_path: - layout_view.load_layer_props(str(lyp_path)) - layout_view.max_hier() - return layout_view diff --git a/gplugins/web/server_jupyter.py b/gplugins/web/server_jupyter.py deleted file mode 100755 index 48346213..00000000 --- a/gplugins/web/server_jupyter.py +++ /dev/null @@ -1,28 +0,0 @@ -import asyncio - -import uvicorn - -from gplugins.web.main import app - -global jupyter_server -jupyter_server = None - - -def _run(port: int = 8000) -> None: - global jupyter_server - - config = uvicorn.Config(app, port=port) - jupyter_server = uvicorn.Server(config) - loop = asyncio.get_event_loop() - loop.create_task(jupyter_server.serve()) - - -def _server_is_running() -> bool: - global jupyter_server - return False if jupyter_server is None else jupyter_server.started - - -def start(port: int = 8000) -> None: - """Start a jupyter_server if it's not already started.""" - if not _server_is_running(): - _run(port=port) diff --git a/gplugins/web/static/client.css b/gplugins/web/static/client.css deleted file mode 100644 index 34f89931..00000000 --- a/gplugins/web/static/client.css +++ /dev/null @@ -1,109 +0,0 @@ -body { - font-family: Helvetica, Arial; - font-size: 12pt; - background-color: #F5F5F5; /* Soft Gray background for body */ - color: #333; /* Dark Gray for default text */ -} - -#layout_canvas { - width: 100%; - height: 100%; -} - -input, select { - background-color: #FAFAFA; /* Slightly off-white for input fields */ - padding: 4pt; - font-size: 12pt; - border: 1px solid #CCC; /* A subtle border */ -} - -.checked { - background-color: #2E86C1; /* Changing from Gray to Blue for a fresh look */ - color: white; -} - -.unchecked { - background-color: #FAFAFA; /* Consistency with other elements */ -} - -div .menu-left-frame, div .menu-right-frame { - background-color: #FAFAFA; /* Blue background for menus */ - padding: 0; - border-radius: 8px; /* A little rounding for modern feel */ -} - -div .menu-left-frame { - position: absolute; - left: 4pt; - top: 4pt; -} - -div .menu-right-frame { - position: absolute; - right: 4pt; - top: 4pt; -} - -.viewer-panel { - overflow: auto; - display: table; - border-spacing: 0.5rem; - padding: 0; -} - -.viewer-panel-sub { - display: table-row; -} - -.viewer-frame-cell, .viewer-layers-cell { - position: relative; - display: table-cell; - vertical-align: top; - border: 1px solid #DDD; /* Softer border color */ - overflow: hidden; -} - -.viewer-frame { - width: 800px; - height: 500px; - resize: both; - overflow: hidden; - padding: 10px; - padding-top: 40pt; - background-color: white; /* Clear background for frames */ - border-radius: 8px; /* Consistency with other rounded elements */ -} - -.viewer-layers { - min-width: 20%; - white-space: nowrap; - overflow-y: scroll; - padding: 0.5rem; - height: 500px; - background-color: white; /* Clear background for layers */ - border-radius: 8px; /* Consistency */ -} - -.layer-name-cell { - padding-left: 0.5rem; -} - -.layer-visible-cell { - padding-right: 0.5rem; -} - -a { - padding: 5px; - margin: 10px; - display: inline-block; - border: 2px solid #2E86C1; /* Matching Blue for link borders */ - color: #2E86C1; /* Matching Blue for link color */ - text-decoration: none; /* Remove default underline */ - border-radius: 8px; /* Consistency with other rounded elements */ - transition: background-color 0.3s, color 0.3s; /* Smooth hover transition */ -} - -a:hover { - background-color: #2E86C1; /* Blue background on hover */ - color: white; -} diff --git a/gplugins/web/static/client.js b/gplugins/web/static/client.js deleted file mode 100644 index ef39ecc2..00000000 --- a/gplugins/web/static/client.js +++ /dev/null @@ -1,410 +0,0 @@ - -// TODO: shouldn't be explicit here .. -// let url = 'ws://localhost:8765/ws'; - -let ws_url = current_url.replace("http://", "ws://"); -ws_url = ws_url.replace("https://", "wss://"); -ws_url += '/ws?' + "variant=" + cell_variant; -let url = ws_url; -console.log(url); - - -var canvas = document.getElementById("layout_canvas"); -var context = canvas.getContext("2d"); - -var message = document.getElementById("message"); - -// HTML5 does not have a resize event, so we need to poll -// to generate events for the canvas resize - -var lastCanvasWidth = 0; -var lastCanvasHeight = 0; - -setInterval(function () { - - var view = document.getElementById('layout-view'); - var w = view.clientWidth; - var h = view.clientHeight; - - if (lastCanvasWidth !== w || lastCanvasHeight !== h) { - - // this avoids flicker: - - var tempCanvas = document.createElement('canvas'); - tempCanvas.width = canvas.width; - tempCanvas.height = canvas.height; - var tempContext = tempCanvas.getContext("2d"); - tempContext.drawImage(context.canvas, 0, 0); - - lastCanvasWidth = w; - lastCanvasHeight = h; - canvas.width = canvas.clientWidth; - canvas.height = canvas.clientHeight; - - context.drawImage(tempContext.canvas, 0, 0); - if (socket.connected) { - socket.send(JSON.stringify({ msg: "resize", width: canvas.width, height: canvas.height })); - } - else { - console.log("Socket is not connected. Loading static image data...") - const img = new Image(); - img.src = initial_image_data; - img.onload = () => { - context.drawImage(img, 0, 0, img.width, img.height, // source rectangle - 0, 0, canvas.width, canvas.height); // destination rectangle - } - - // resizes the layer list: - - let layers = document.getElementById("layers"); - - var padding = 10; // padding in pixels - layers.style.height = (h - 2 * padding) + "px"; - - }; - } - -}, 10) - -let socket = new WebSocket(url); -socket.binaryType = "blob"; -var initialized = false; - -function showHierarchy(hierarchy) { - var hierarchyElement = document.getElementById("hierarchy"); - hierarchyElement.childNodes = new Array(); - - var hierarchyUL = document.createElement("ul"); - hierarchyUL.className = "hierarchy-ul"; - hierarchyElement.appendChild(hierarchyUL) - - function addToUL(hierarchy, ul){ - for (const [key, value] of Object.entries(hierarchy)) { - console.log(`${key}: ${value}`); - var li = document.createElement("li"); - ul.appendChild(li); - if(typeof value === 'object'){ //further hiera - caret = document.createElement("span"); - caret.className = "caret"; - caret.innerText = key; - sub_ul = document.createElement("ul"); - sub_ul.className = "nested" - li.appendChild(caret) - li.appendChild(sub_ul) - addToUL(value, sub_ul) - } else { - li.innerText = key; - } - } - } - - addToUL(hierarchy, hierarchyUL) - - var toggler = document.getElementsByClassName("caret"); - var i; - - for (i = 0; i < toggler.length; i++) { - toggler[i].addEventListener("click", function() { - this.parentElement.querySelector(".nested").classList.toggle("active"); - this.classList.toggle("caret-down"); - }); - } - -} - - -// Installs a handler called when the connection is established -socket.onopen = function (evt) { - - var ev = { msg: "initialize", width: canvas.width, height: canvas.height }; - socket.send(JSON.stringify(ev)); - - // Prevents the context menu to show up over the canvas area - canvas.addEventListener('contextmenu', function (evt) { - evt.preventDefault(); - }); - - canvas.addEventListener('mousemove', function (evt) { - sendMouseEvent(canvas, "mouse_move", evt); - evt.preventDefault(); - }, false); - - canvas.addEventListener('click', function (evt) { - sendMouseEvent(canvas, "mouse_click", evt); - evt.preventDefault(); - }, false); - - canvas.addEventListener('dblclick', function (evt) { - sendMouseEvent(canvas, "mouse_dblclick", evt); - evt.preventDefault(); - }, false); - - canvas.addEventListener('mousedown', function (evt) { - sendMouseEvent(canvas, "mouse_pressed", evt); - evt.preventDefault(); - }, false); - - canvas.addEventListener('mouseup', function (evt) { - sendMouseEvent(canvas, "mouse_released", evt); - evt.preventDefault(); - }, false); - - canvas.addEventListener('mouseenter', function (evt) { - sendMouseEvent(canvas, "mouse_enter", evt); - evt.preventDefault(); - }, false); - - canvas.addEventListener('mouseout', function (evt) { - sendMouseEvent(canvas, "mouse_leave", evt); - evt.preventDefault(); - }, false); - - canvas.addEventListener('wheel', function (evt) { - sendWheelEvent(canvas, "wheel", evt); - evt.preventDefault(); - }, false); -} - -// Installs a handler for the messages delivered by the web socket -socket.onmessage = function (evt) { - - let data = evt.data; - if (typeof (data) === "string") { - - // For debugging: - // message.textContent = data; - - // incoming messages are JSON objects - js = JSON.parse(data); - if (js.msg == "initialized") { - initialized = true; - } else if (js.msg == "loaded") { - showLayers(js.layers); - showMenu(js.modes, js.annotations); - } - - } else if (initialized) { - - // incoming blob messages are paint events - createImageBitmap(data).then(function (image) { - context.drawImage(image, 0, 0) - }); - - } - -}; - -socket.onclose = evt => console.log(`Closed ${evt.code}`); - -function mouseEventToJSON(canvas, type, evt) { - - var rect = canvas.getBoundingClientRect(); - var x = evt.clientX - rect.left; - var y = evt.clientY - rect.top; - var keys = 0; - if (evt.shiftKey) { - keys += 1; - } - if (evt.ctrlKey) { - keys += 2; - } - if (evt.altKey) { - keys += 4; - } - return { msg: type, x: x, y: y, b: evt.buttons, k: keys }; - -} - -function sendMouseEvent(canvas, type, evt) { - - if (socket.readyState == 1 /*OPEN*/) { - var ev = mouseEventToJSON(canvas, type, evt); - socket.send(JSON.stringify(ev)); - } - -} - -function sendWheelEvent(canvas, type, evt) { - - if (socket.readyState == 1 /*OPEN*/) { - var ev = mouseEventToJSON(canvas, type, evt); - ev.dx = evt.deltaX; - ev.dy = evt.deltaY; - ev.dm = evt.deltaMode; - socket.send(JSON.stringify(ev)); - } - -} - - - -// Updates the layer list -function showMenu(modes, annotations) { - - var modeElement = document.getElementById("modes"); - modeElement.childNodes = new Array(); - - var modeTable = document.createElement("table"); - modeTable.className = "modes-table"; - modeElement.appendChild(modeTable) - - var modeRow = document.createElement("tr"); - modeRow.className = "mode-row-header"; - modeRow.id = "mode-row"; - modeTable.appendChild(modeRow) - - var cell; - var inner; - - modes.forEach(function (m) { - - cell = document.createElement("td"); - cell.className = "mode-cell"; - - var inner = document.createElement("input"); - inner.value = m; - inner.type = "button"; - inner.className = "unchecked"; - inner.onclick = function () { - var modeRow = document.getElementById("mode-row"); - modeRow.childNodes.forEach(function (e) { - e.firstChild.className = "unchecked"; - }); - inner.className = "checked"; - socket.send(JSON.stringify({ msg: "select-mode", value: m })); - }; - - cell.appendChild(inner); - modeRow.appendChild(cell); - - }); - - var menuElement = document.getElementById("menu"); - - var menuTable = document.createElement("table"); - menuTable.className = "menu-table"; - menuElement.appendChild(menuTable) - - var menuRow = document.createElement("tr"); - menuRow.className = "menu-row-header"; - menuTable.appendChild(menuRow) - - cell = document.createElement("td"); - cell.className = "menu-cell"; - menuRow.appendChild(cell); - - var rulersSelect = document.createElement("select"); - rulersSelect.onchange = function () { - socket.send(JSON.stringify({ msg: "select-ruler", value: rulersSelect.selectedIndex })); - }; - cell.appendChild(rulersSelect); - - cell = document.createElement("td"); - cell.className = "menu-cell"; - menuRow.appendChild(cell); - - var clearRulers = document.createElement("input"); - clearRulers.value = "Clear Rulers"; - clearRulers.type = "button"; - clearRulers.onclick = function () { - socket.send(JSON.stringify({ msg: "clear-annotations" })); - }; - cell.appendChild(clearRulers); - - var index = 0; - - annotations.forEach(function (a) { - - var option = document.createElement("option"); - option.value = index; - option.text = a; - - rulersSelect.appendChild(option); - - index += 1; - - }); -} - -// Updates the layer list -function showLayers(layers) { - - var layerElement = document.getElementById("layers"); - layerElement.childNodes = new Array(); - - var layerTable = document.createElement("table"); - layerTable.className = "layer-table"; - layerElement.appendChild(layerTable) - - var cell; - var inner; - var s; - var visibilityCheckboxes = []; - - var layerRow = document.createElement("tr"); - layerRow.className = "layer-row-header"; - - // create a top level entry for resetting/setting all visible flags - - cell = document.createElement("td"); - cell.className = "layer-visible-cell"; - - inner = document.createElement("input"); - inner.type = "checkbox"; - inner.checked = true; - inner.onclick = function () { - var checked = this.checked; - visibilityCheckboxes.forEach(function (cb) { - cb.checked = checked; - }); - socket.send(JSON.stringify({ msg: "layer-v-all", value: checked })); - }; - cell.appendChild(inner); - - layerRow.appendChild(cell); - layerTable.appendChild(layerRow); - - // create table rows for each layer - - layers.forEach(function (l) { - - var layerRow = document.createElement("tr"); - layerRow.className = "layer-row"; - - cell = document.createElement("td"); - cell.className = "layer-visible-cell"; - - inner = document.createElement("input"); - visibilityCheckboxes.push(inner); - inner.type = "checkbox"; - inner.checked = l.v; - inner.onclick = function () { - socket.send(JSON.stringify({ msg: "layer-v", id: l.id, value: this.checked })); - }; - cell.appendChild(inner); - - layerRow.appendChild(cell); - - cell = document.createElement("td"); - cell.className = "layer-color-cell"; - s = "border-style: solid; border-width: " + (l.w < 0 ? 1 : l.w) + "px; border-color: #" + (l.fc & 0xffffff).toString(16) + ";"; - cell.style = s; - layerRow.appendChild(cell); - - inner = document.createElement("div"); - s = "width: 2rem; height: 1em;"; - s += "margin: 1px;"; - s += "background: #" + (l.c & 0xffffff).toString(16) + ";"; - inner.style = s; - cell.appendChild(inner); - - cell = document.createElement("td"); - cell.className = "layer-name-cell"; - cell.textContent = (l.name != 0 ? l.name : l.s); - layerRow.appendChild(cell); - - layerTable.appendChild(layerRow); - - }); - -} diff --git a/gplugins/web/templates/client.html.j2 b/gplugins/web/templates/client.html.j2 deleted file mode 100644 index 4ad10d6e..00000000 --- a/gplugins/web/templates/client.html.j2 +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - -
-
-
- - -
- -
-
-
-
-
-
-
- -
-
- - - - - - - diff --git a/gplugins/web/templates/file_browser.html.j2 b/gplugins/web/templates/file_browser.html.j2 deleted file mode 100644 index 3bf1757b..00000000 --- a/gplugins/web/templates/file_browser.html.j2 +++ /dev/null @@ -1,27 +0,0 @@ -{% include 'header.html.j2' %} -{% include 'navbar.html.j2' %} - - - KWeb GDS File Browser - - - - -
-

-{{ message }} -

-
- -
-

Files available:

- -

File root: {{ files_root }}

-
- - - diff --git a/gplugins/web/templates/filewatcher.html.j2 b/gplugins/web/templates/filewatcher.html.j2 deleted file mode 100644 index a4c699dd..00000000 --- a/gplugins/web/templates/filewatcher.html.j2 +++ /dev/null @@ -1,66 +0,0 @@ -{% include 'header.html.j2' %} -{% include 'navbar.html.j2' %} - - - Folder Watcher - - - -

Folder to watch for changing files

-
- - - -
- -
-
{{ output }}
-
- - -
-

{{ cell_name }}

- {% if variant %} -

({{ variant }})

- {% endif %} - -
-
-
- - -
- -
-
-
-
-
-
-
-
- -
-
- - - - - -{% include 'footer.html.j2' %} diff --git a/gplugins/web/templates/footer.html.j2 b/gplugins/web/templates/footer.html.j2 deleted file mode 100644 index fc1b9604..00000000 --- a/gplugins/web/templates/footer.html.j2 +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/gplugins/web/templates/gds_history.html.j2 b/gplugins/web/templates/gds_history.html.j2 deleted file mode 100644 index 6b3731aa..00000000 --- a/gplugins/web/templates/gds_history.html.j2 +++ /dev/null @@ -1,10 +0,0 @@ -{% include 'header.html.j2' %} -{% include 'navbar.html.j2' %} -

gdspaths

-

-{% for component in components %} -{{ component }} -{% endfor %} -

- -{% include 'footer.html.j2' %} diff --git a/gplugins/web/templates/header.html.j2 b/gplugins/web/templates/header.html.j2 deleted file mode 100644 index ad233f9f..00000000 --- a/gplugins/web/templates/header.html.j2 +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - Gdsfactory - {{ title | default("Page") }} - - - - - - - - - - - - - - - diff --git a/gplugins/web/templates/index.html.j2 b/gplugins/web/templates/index.html.j2 deleted file mode 100644 index d2f34f29..00000000 --- a/gplugins/web/templates/index.html.j2 +++ /dev/null @@ -1,14 +0,0 @@ -{% include 'header.html.j2' %} -{% include 'navbar.html.j2' %} - - - Homepage - - -

gdsfactory webapp

-

Pdk explorer

-

Last Component.show()

-

Component.show() list

-

filewatcher

- - diff --git a/gplugins/web/templates/navbar.html.j2 b/gplugins/web/templates/navbar.html.j2 deleted file mode 100644 index 1bdedc42..00000000 --- a/gplugins/web/templates/navbar.html.j2 +++ /dev/null @@ -1,19 +0,0 @@ - diff --git a/gplugins/web/templates/pdk.html.j2 b/gplugins/web/templates/pdk.html.j2 deleted file mode 100644 index 938ccc7d..00000000 --- a/gplugins/web/templates/pdk.html.j2 +++ /dev/null @@ -1,10 +0,0 @@ -{% include 'header.html.j2' %} -{% include 'navbar.html.j2' %} -

{{ pdk_name }} PDK explorer

-

-{% for component in components %} -

  • {{ component }}
  • -{% endfor %} -

    - -{% include 'footer.html.j2' %} diff --git a/gplugins/web/templates/viewer.html.j2 b/gplugins/web/templates/viewer.html.j2 deleted file mode 100644 index 645e637c..00000000 --- a/gplugins/web/templates/viewer.html.j2 +++ /dev/null @@ -1,44 +0,0 @@ -{% include 'header.html.j2' %} -{% include 'navbar.html.j2' %} -
    -

    {{ cell_name }}

    - {% if variant %} -

    ({{ variant }})

    - {% endif %} - -
    -
    -
    - - -
    - -
    -
    -
    -
    -
    -
    -
    -

    Parameters

    -
    - - {% for setting_name, setting_value in component.settings.default.items() %} -
    - - {% if setting_name in component.settings.changed %} - - {% else %} - - {% endif %} -
    - {% endfor %} -
    -
    - - -{% include 'footer.html.j2' %} diff --git a/pyproject.toml b/pyproject.toml index f7c4fb4b..7caa4c2c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,12 +96,6 @@ vlsir = [ "vlsir>=4.0.0,<6.0.0", "vlsirtools>=4.0.0,<6.0.0" ] -web = [ - "jinja2", - "python-multipart", - "fastapi>=0.102.0,<1", - "uvicorn[standard]" -] [tool.black] exclude = ''' # Specify the files/dirs that should be ignored by the black formatter From 643bdfae1516e984bcbb96654883f502c7eb6b0a Mon Sep 17 00:00:00 2001 From: Joaquin Matres <4514346+joamatab@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:43:53 -0800 Subject: [PATCH 2/3] remove web from config --- gplugins/common/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gplugins/common/config.py b/gplugins/common/config.py index a529eb29..aa4d4b24 100644 --- a/gplugins/common/config.py +++ b/gplugins/common/config.py @@ -18,7 +18,6 @@ class Path: module = module_path repo = repo_path - web = module / "web" results_tidy3d = home / ".tidy3d" test_data = repo / "test-data" sparameters_repo = test_data / "sp" From f0ea0a095c9541aaaa7e633a1f41ed02f83b2a41 Mon Sep 17 00:00:00 2001 From: Joaquin Matres <4514346+joamatab@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:44:10 -0800 Subject: [PATCH 3/3] fix makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6c194fea..25159251 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ install: - pip install -e .[dev,docs,devsim,femwell,gmsh,klayout,meow,meshwell,ray,sax,schematic,tidy3d,web,vlsir] + pip install -e .[dev,docs,devsim,femwell,gmsh,klayout,meow,meshwell,ray,sax,schematic,tidy3d,vlsir] pre-commit install dev: test-data gmsh elmer install