rsdeps

Cargo.lock visualizer (mirror)
Log | Files | Refs | README | LICENSE

commit 66e0cd2b6dc1540d4b7debbf25806df193d2c9df
parent 88bdabe314c95eba30bf74c8647cd52c28d0c24c
Author: Andy Khramtsov <>
Date:   Sat, 30 May 2026 02:39:52 +0300

feat: make one single upload box

Diffstat:
Msrc/deps/assets/styles.css | 5+++++
Msrc/deps/pages/home.py | 166+++++++++++++++++++++++++++++++++++++++++++------------------------------------
2 files changed, 95 insertions(+), 76 deletions(-)

diff --git a/src/deps/assets/styles.css b/src/deps/assets/styles.css @@ -190,6 +190,11 @@ p { color: var(--c-font); background-color: var(--c-bg-contrast); border-color: var(--c-border); + padding: 0.25em 0.5em; + border-radius: 0.25em; + border: 1px solid var(--c-border); + text-align: center; + cursor: pointer; } .button:hover { diff --git a/src/deps/pages/home.py b/src/deps/pages/home.py @@ -17,13 +17,10 @@ dash.register_page(__name__, path="/", order=1) class ids: + cargo_toml_textarea: str = "cargo-toml-textarea" cargo_lock_textarea: str = "cargo-lock-textarea" - upload_cargo_lock: str = "upload-cargo-lock" - cargo_lock_filename_display: str = "cargo-lock-filename-display" - cargo_toml_textarea: str = "cargo-toml-textarea" - upload_cargo_toml: str = "upload-cargo-toml" - cargo_toml_filename_display: str = "cargo-toml-filename-display" + upload_files: str = "upload-files" collapse_tables: str = "collapse-tables" cargo_lock_table: str = "cargo-lock-table" @@ -83,47 +80,40 @@ def layout(): html.H2("Cargo dependency visualisation"), dcc.Store(id=ids.cache_store, storage_type="memory"), html.Div( - [ - html.H3("Cargo toml"), + className="vertical-content", + children=[ + dcc.Upload( + className="button", + id=ids.upload_files, + children=[ + "Upload Cargo.toml and Cargo.lock", + ], + multiple=True, + ), + html.Div("Cargo toml:"), dcc.Textarea( id=ids.cargo_toml_textarea, placeholder="Cargo.toml contents", persistence=True, ), - dcc.Upload( - id=ids.upload_cargo_toml, - children=[ - dcc.Button("Upload Cargo.toml"), - ], - ), - html.Div("Uploaded file name:"), - html.Div(id=ids.cargo_toml_filename_display, children="Empty"), - ] - ), - html.Div( - [ - html.H3("Cargo lock"), + html.Div("Cargo lock:"), dcc.Textarea( id=ids.cargo_lock_textarea, placeholder="Cargo.lock contents", persistence=True, ), - dcc.Upload( - id=ids.upload_cargo_lock, - children=[ - dcc.Button("Upload Cargo.lock"), - ], - ), - html.Div("Uploaded file name:"), - html.Div(id=ids.cargo_lock_filename_display, children="Empty"), - ] + ], ), CollapseAIO( aio_id=ids.collapse_tables, label="Table view", default_hidden=True, content=[ - dcc.Button(id=ids.recalculate_button, children="Recalculate"), + html.Button( + className="button", + id=ids.recalculate_button, + children="Recalculate", + ), html.H3("Cargo toml dependencies"), TableAIO( aio_id=ids.cargo_toml_table, @@ -142,6 +132,7 @@ def layout(): for i in [ "name", "version", + "source", "checksum", "dependencies", ] @@ -150,13 +141,21 @@ def layout(): ], ), html.H3("Dependency graph"), - dcc.Button(id=ids.generate_button, children="Generate"), + html.Button( + className="button", + id=ids.generate_button, + children="Generate", + ), dcc.Graph( id=ids.dependency_graph, figure={}, style={"height": 1000}, ), - dcc.Button(id=ids.reset_highlight_button, children="Reset highlight"), + html.Button( + className="button", + id=ids.reset_highlight_button, + children="Reset highlight", + ), html.Div(id=ids.selected_node_details), ], ) @@ -171,15 +170,39 @@ def parse_node_details(details: dict) -> str: def parse_cargo_toml(contents: str) -> pl.DataFrame: toml = tomllib.loads(contents) dependencies = toml.get("dependencies", {}) - return pl.DataFrame(list(dict(name=name) for name in dependencies)) + return pl.DataFrame(list(dict(name=name) for name in dependencies)).match_to_schema( + pl.Schema( + dict( + name=pl.String, + ) + ), + missing_columns="insert", + extra_columns="ignore", + ) def parse_cargo_lock(contents: str) -> pl.DataFrame: toml = tomllib.loads(contents) - return pl.DataFrame(toml.get("package", [])) + return pl.DataFrame(toml.get("package", [])).match_to_schema( + pl.Schema( + dict( + name=pl.String, + version=pl.String, + source=pl.String, + checksum=pl.String, + dependencies=pl.List(pl.String), + ) + ), + missing_columns=dict( + checksum=pl.lit(""), + dependencies=pl.lit([], dtype=pl.List(pl.String)), + ), + extra_columns="ignore", + ) def files_into_graph(cargo_toml: pl.DataFrame, cargo_lock: pl.DataFrame) -> DfGraph: + print(cargo_toml, cargo_lock) arcs = ( ( cargo_lock.select( @@ -396,7 +419,7 @@ def draw_graph_figure( text=node.label, hovertext=node.hover_text, customdata=node.custom_data, - marker=go.Marker( + marker=go.scatter.Marker( showscale=False, color=node.color, size=16, @@ -445,49 +468,44 @@ def draw_graph_figure( @callback( dict( - textarea=Output(ids.cargo_toml_textarea, "value"), - filename=Output(ids.cargo_toml_filename_display, "children"), - ), - dict( - upload_contents=Input(ids.upload_cargo_toml, "contents"), + cargo_toml_textarea=Output(ids.cargo_toml_textarea, "value"), + cargo_lock_textarea=Output(ids.cargo_lock_textarea, "value"), ), dict( - upload_filename=State(ids.upload_cargo_toml, "filename"), + contents=Input(ids.upload_files, "contents"), + filename=Input(ids.upload_files, "filename"), ), + dict(), ) -def upload_cargo_toml(inputs, state): - contents = inputs["upload_contents"] - if not contents: +def upload_files(inputs, state): + contents: list[str] = inputs["contents"] + filename: list[str] = inputs["filename"] + + if not contents or not filename: raise PreventUpdate - content_type, content_string = contents.split(",") - decoded = base64.b64decode(content_string) - return dict( - textarea=decoded.decode("utf-8"), - filename=state["upload_filename"], - ) + try: + cargo_toml_index = filename.index("Cargo.toml") + _, cargo_toml_content_string = contents[cargo_toml_index].split(",") + except ValueError: + cargo_toml_content_string = None + + try: + cargo_lock_index = filename.index("Cargo.lock") + _, cargo_lock_content_string = contents[cargo_lock_index].split(",") + except ValueError: + cargo_lock_content_string = None + + cargo_toml_decoded = ( + base64.b64decode(cargo_toml_content_string).decode("utf-8") if cargo_toml_content_string else dash.no_update + ) + cargo_lock_decoded = ( + base64.b64decode(cargo_lock_content_string).decode("utf-8") if cargo_lock_content_string else dash.no_update + ) -@callback( - dict( - textarea=Output(ids.cargo_lock_textarea, "value"), - filename=Output(ids.cargo_lock_filename_display, "children"), - ), - dict( - upload_contents=Input(ids.upload_cargo_lock, "contents"), - ), - dict( - upload_filename=State(ids.upload_cargo_lock, "filename"), - ), -) -def upload_cargo_lock(inputs, state): - contents = inputs["upload_contents"] - if not contents: - raise PreventUpdate - content_type, content_string = contents.split(",") - decoded = base64.b64decode(content_string) return dict( - textarea=decoded.decode("utf-8"), - filename=state["upload_filename"], + cargo_toml_textarea=cargo_toml_decoded, + cargo_lock_textarea=cargo_lock_decoded, ) @@ -499,9 +517,7 @@ def upload_cargo_lock(inputs, state): textarea=Input(ids.cargo_toml_textarea, "value"), recalculate=Input(ids.recalculate_button, "n_clicks"), ), - dict( - upload_filename=State(ids.upload_cargo_toml, "filename"), - ), + dict(), ) def display_cargo_toml_packages(inputs, state): try: @@ -521,9 +537,7 @@ def display_cargo_toml_packages(inputs, state): textarea=Input(ids.cargo_lock_textarea, "value"), recalculate=Input(ids.recalculate_button, "n_clicks"), ), - dict( - upload_filename=State(ids.upload_cargo_lock, "filename"), - ), + dict(), ) def display_cargo_lock_packages(inputs, state): try: