Skip to content

Commit 363e82b

Browse files
authored
Merge pull request #264 from nyu-mlab/patch
UI/UX Patches
2 parents d2d2efe + d732b47 commit 363e82b

File tree

8 files changed

+172
-136
lines changed

8 files changed

+172
-136
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Ignore packet dumps
2+
*.pcap
3+
*.pcapng
4+
15
*~
26
.*
37
!.gitattributes

src/libinspector/common.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,16 @@ def show_warning():
6161
else:
6262
# ID is missing or invalid -> BLOCK and show input form
6363
st.subheader("Prolific ID Required")
64-
st.warning("Please enter your Prolific ID to proceed. This ID is essential for data labeling.")
64+
st.warning("Please enter your Prolific ID to proceed. This ID is essential for data labeling and your payment.")
6565

6666
with st.form("prolific_id_form"):
6767
input_id = st.text_input(
68-
"Enter your Prolific ID (1-50 Alphanumeric Characters):",
68+
"Enter your Prolific ID:",
6969
value="",
7070
key="prolific_id_input"
7171
).strip()
7272

7373
submitted = st.form_submit_button("Submit ID")
74-
7574
if submitted:
7675
if is_prolific_id_valid(input_id):
7776
config_set("prolific_id", input_id)
@@ -141,7 +140,8 @@ def bar_graph_data_frame(mac_address: str, now: int):
141140

142141
def plot_traffic_volume(df: pd.DataFrame, now: int, chart_title: str):
143142
"""
144-
Plots the traffic volume over time.
143+
Plots the traffic volume over time. The bar goes from right to left,
144+
like Task Manager in Windows.
145145
146146
Args:
147147
df (pd.DataFrame): DataFrame containing 'Time' and 'Bits' columns.
@@ -153,9 +153,9 @@ def plot_traffic_volume(df: pd.DataFrame, now: int, chart_title: str):
153153
else:
154154
st.markdown(f"#### {chart_title}")
155155
df['seconds_ago'] = now - df['timestamp'].astype(int)
156-
df = df.set_index('seconds_ago').reindex(range(0, 60), fill_value=0).reset_index()
157-
st.bar_chart(df.set_index('seconds_ago')['Bits'], width='content')
158-
156+
df_reindexed = df.set_index('seconds_ago').reindex(range(0, 60), fill_value=0).reset_index()
157+
df_reindexed = df_reindexed.sort_values(by='seconds_ago', ascending=False)
158+
st.bar_chart(df_reindexed.set_index('seconds_ago')['Bits'], width='content')
159159

160160
def get_device_metadata(mac_address: str) -> dict:
161161
"""

src/libinspector/device_detail_page.py

Lines changed: 101 additions & 108 deletions
Large diffs are not rendered by default.

src/libinspector/device_list_page.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ def worker_thread():
5454
custom_name = api_output["Vendor"]
5555
if api_output["Vendor"] != "":
5656
common.config_set(custom_name_key, custom_name)
57+
else:
58+
# If API is down, just try using OUI vendor
59+
common.config_set(custom_name_key, meta_data.get('oui_vendor', 'Unknown Device, likely a Mobile Phone'))
5760
except Exception as e:
5861
logger.info("[Device ID API] Exception when calling API: %s", str(e))
5962
continue
@@ -214,8 +217,13 @@ def show_device_card(device_dict: dict):
214217
# --- Add bar charts for upload/download ---
215218
now = int(time.time())
216219
df_upload_bar_graph, df_download_bar_graph = common.bar_graph_data_frame(device_dict['mac_address'], now)
217-
common.plot_traffic_volume(df_upload_bar_graph, now, "Upload Traffic (sent by device) in the last 60 seconds")
218-
common.plot_traffic_volume(df_download_bar_graph, now,"Download Traffic (received by device) in the last 60 seconds")
220+
chart_col_upload, chart_col_download = st.columns(2)
221+
with chart_col_upload:
222+
common.plot_traffic_volume(df_upload_bar_graph, now,
223+
"Upload Traffic (sent by device) in the last 60 seconds")
224+
with chart_col_download:
225+
common.plot_traffic_volume(df_download_bar_graph, now,
226+
"Download Traffic (received by device) in the last 60 seconds")
219227

220228
# Set whether a device is to be inspected, favorite, or blocked
221229
with c2:

src/libinspector/page_manager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def start_inspector_once():
7575
# Same with the general warning
7676
common.config_set("suppress_warning", False)
7777
common.config_set("labeling_in_progress", False)
78+
common.config_set("api_message", "")
7879
libinspector.core.start_threads()
7980
api_thread = threading.Thread(
8081
name="Device API Thread",

src/libinspector/server/packet_collector.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,20 +173,26 @@ def label_packets():
173173

174174
def make_pcap_filename(start_time: int, end_time: int) -> str:
175175
"""
176-
Generates a pcap filename using the start and end epoch timestamps.
176+
Generates a pcap filename that is both human-readable and informative.
177+
The format is: 'Mon-DD-YYYY_HHMMSSAM/PM_DurationSeconds.pcap'
178+
179+
Example: 'Oct-31-2025_11:31:00AM_6s.pcap'
177180
178181
Args:
179182
start_time (int): Start time in seconds since the epoch.
180183
end_time (int): End time in seconds since the epoch.
181184
182185
Returns:
183-
str: Filename in the format 'YYYYMMDD_HHMMSS-YYYYMMDD_HHMMSS.pcap'.
186+
str: Human-readable filename.
184187
"""
185188
start_dt = datetime.datetime.fromtimestamp(start_time)
186-
end_dt = datetime.datetime.fromtimestamp(end_time)
187-
safe_start = start_dt.strftime("%Y%m%d_%H%M%S")
188-
safe_end = end_dt.strftime("%Y%m%d_%H%M%S")
189-
filename = f"{safe_start}-{safe_end}.pcap"
189+
duration_seconds = end_time - start_time
190+
191+
# Format the start time: e.g., 'Oct-31-2025_113100AM'
192+
safe_start = start_dt.strftime("%b-%d-%Y_%I:%M:%S%p")
193+
194+
# Generate the filename with duration
195+
filename = f"{safe_start}_{duration_seconds}s.pcap"
190196
return filename
191197

192198

src/libinspector/sidebar.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@
44

55
def show():
66
"""
7-
This page shows a toggle to connect to IoT Inspector cloud.
87
This will generate a list of all favorite devices found in IoT Inspector derived from config.json
98
"""
10-
with st.container(border=True):
11-
st.toggle(
12-
"Connect to the IoT Inspector Cloud for enhanced features (Recommended)",
13-
key='connect_to_nyu_inspector_cloud',
14-
value=common.config_get('connect_to_nyu_inspector_cloud', False),
15-
help="Toggle ON if you need help with identifying devices and detecting anonymous devices and activities, but provided that you are okay with IoT Inspector sharing anonymous data with New York University researchers.",
16-
on_change=lambda: common.config_set('connect_to_nyu_inspector_cloud', st.session_state['connect_to_nyu_inspector_cloud'])
17-
)
9+
#with st.container(border=True):
10+
# st.toggle(
11+
# "Connect to the IoT Inspector Cloud for enhanced features (Recommended)",
12+
# key='connect_to_nyu_inspector_cloud',
13+
# value=common.config_get('connect_to_nyu_inspector_cloud', False),
14+
# help="Toggle ON if you need help with identifying devices and detecting anonymous devices and activities, but provided that you are okay with IoT Inspector sharing anonymous data with New York University researchers.",
15+
# on_change=lambda: common.config_set('connect_to_nyu_inspector_cloud', st.session_state['connect_to_nyu_inspector_cloud'])
16+
#)
1817
show_favorite_device_list()
1918

2019

start.ps1

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,40 @@ $streamlitAppPath = "$PSScriptRoot\src\libinspector\dashboard.py"
8888
# The entire argument list is passed to uv.
8989
$StreamlitArgs = @("run", "streamlit", "run", "`"$streamlitAppPath`"")
9090

91-
Start-Process -FilePath "uv" `
91+
$streamlitProcess = Start-Process -FilePath "uv" `
9292
-ArgumentList $StreamlitArgs `
9393
-PassThru `
9494
-NoNewWindow
95-
# Wait for a few seconds to let the server start
96-
Start-Sleep -Seconds 3
9795

96+
97+
$isReady = $false
98+
$pollingDelaySeconds = 3
99+
$appUrl = "http://localhost:33721/"
100+
# Loop indefinitely until $isReady becomes $true
101+
while (-not $isReady) {
102+
try {
103+
# Use Invoke-WebRequest to check for a successful connection (Status Code 200).
104+
# We set a short TimeoutSec on the request itself to prevent hanging.
105+
$request = Invoke-WebRequest -Uri $appUrl -TimeoutSec 5 -ErrorAction Stop
106+
if ($request.StatusCode -eq 200) {
107+
$isReady = $true
108+
Write-Host "✅ Server is ready. Launching browser."
109+
}
110+
} catch {
111+
# Server is not ready yet, or connection failed. Ignore the error.
112+
Write-Host "Still waiting for Streamlit server..."
113+
}
114+
115+
if (-not $isReady) {
116+
Start-Sleep -Seconds $pollingDelaySeconds
117+
}
118+
}
98119
# Open the browser to the application URL
99-
Start-Process -FilePath "http://localhost:33721/"
120+
Start-Process -FilePath $appUrl
100121

101122
# Wait for the Streamlit process to finish or for the user to close this window
102123
Write-Host "IoT Inspector is running. Close this window to stop the application."
124+
if ($streamlitProcess) {
125+
$streamlitProcess.WaitForExit()
126+
}
127+
Write-Host "IoT Inspector has been closed. Exiting setup script."

0 commit comments

Comments
 (0)