staticdash 2025.18__py3-none-any.whl → 2025.20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- staticdash/dashboard.py +164 -161
- {staticdash-2025.18.dist-info → staticdash-2025.20.dist-info}/METADATA +1 -1
- staticdash-2025.20.dist-info/RECORD +8 -0
- staticdash-2025.18.dist-info/RECORD +0 -8
- {staticdash-2025.18.dist-info → staticdash-2025.20.dist-info}/WHEEL +0 -0
- {staticdash-2025.18.dist-info → staticdash-2025.20.dist-info}/top_level.txt +0 -0
staticdash/dashboard.py
CHANGED
|
@@ -22,6 +22,7 @@ class AbstractPage:
|
|
|
22
22
|
def __init__(self):
|
|
23
23
|
self.elements = []
|
|
24
24
|
|
|
25
|
+
|
|
25
26
|
def add_header(self, text, level=1, width=None):
|
|
26
27
|
if level not in (1, 2, 3, 4):
|
|
27
28
|
raise ValueError("Header level must be 1, 2, 3, or 4")
|
|
@@ -48,11 +49,12 @@ class AbstractPage:
|
|
|
48
49
|
self.elements.append(("syntax", (code, language), width))
|
|
49
50
|
|
|
50
51
|
class Page(AbstractPage):
|
|
51
|
-
def __init__(self, slug, title, page_width=None):
|
|
52
|
+
def __init__(self, slug, title, page_width=None, marking=None):
|
|
52
53
|
super().__init__()
|
|
53
54
|
self.slug = slug
|
|
54
55
|
self.title = title
|
|
55
56
|
self.page_width = page_width
|
|
57
|
+
self.marking = marking # Page-specific marking
|
|
56
58
|
self.children = []
|
|
57
59
|
self.add_header(title, level=1)
|
|
58
60
|
|
|
@@ -62,6 +64,20 @@ class Page(AbstractPage):
|
|
|
62
64
|
def render(self, index, downloads_dir=None, relative_prefix="", inherited_width=None):
|
|
63
65
|
effective_width = self.page_width or inherited_width
|
|
64
66
|
elements = []
|
|
67
|
+
|
|
68
|
+
# Add floating header and footer for marking
|
|
69
|
+
marking = self.marking or "Default Marking"
|
|
70
|
+
elements.append(div(
|
|
71
|
+
marking,
|
|
72
|
+
cls="floating-header",
|
|
73
|
+
style="position: fixed; top: 0; left: 50%; transform: translateX(-50%); width: auto; background-color: #f8f9fa; text-align: center; padding: 10px; z-index: 1000; font-weight: normal;"
|
|
74
|
+
))
|
|
75
|
+
elements.append(div(
|
|
76
|
+
marking,
|
|
77
|
+
cls="floating-footer",
|
|
78
|
+
style="position: fixed; bottom: 0; left: 50%; transform: translateX(-50%); width: auto; background-color: #f8f9fa; text-align: center; padding: 10px; z-index: 1000; font-weight: normal;"
|
|
79
|
+
))
|
|
80
|
+
|
|
65
81
|
for kind, content, el_width in self.elements:
|
|
66
82
|
style = ""
|
|
67
83
|
outer_style = ""
|
|
@@ -77,10 +93,8 @@ class Page(AbstractPage):
|
|
|
77
93
|
elem = header_tag(text)
|
|
78
94
|
elif kind == "plot":
|
|
79
95
|
fig = content
|
|
80
|
-
# Plotly support (existing)
|
|
81
96
|
if hasattr(fig, "to_html"):
|
|
82
97
|
elem = div(raw_util(fig.to_html(full_html=False, include_plotlyjs='cdn', config={'responsive': True})))
|
|
83
|
-
# Matplotlib support
|
|
84
98
|
else:
|
|
85
99
|
try:
|
|
86
100
|
buf = io.BytesIO()
|
|
@@ -88,7 +102,6 @@ class Page(AbstractPage):
|
|
|
88
102
|
buf.seek(0)
|
|
89
103
|
img_base64 = base64.b64encode(buf.read()).decode("utf-8")
|
|
90
104
|
buf.close()
|
|
91
|
-
# Center the image using a div with inline styles
|
|
92
105
|
elem = div(
|
|
93
106
|
raw_util(f'<img src="data:image/png;base64,{img_base64}" style="max-width:100%;">'),
|
|
94
107
|
style="display: flex; justify-content: center; align-items: center;"
|
|
@@ -97,8 +110,11 @@ class Page(AbstractPage):
|
|
|
97
110
|
elem = div(f"Matplotlib figure could not be rendered: {e}")
|
|
98
111
|
elif kind == "table":
|
|
99
112
|
df = content
|
|
100
|
-
|
|
101
|
-
|
|
113
|
+
try:
|
|
114
|
+
html_table = df.to_html(classes="table-hover table-striped", index=False, border=0, table_id=f"table-{index}", escape=False)
|
|
115
|
+
elem = div(raw_util(html_table))
|
|
116
|
+
except Exception as e:
|
|
117
|
+
elem = div(f"Table could not be rendered: {e}")
|
|
102
118
|
elif kind == "download":
|
|
103
119
|
file_path, label = content
|
|
104
120
|
btn = a(label or os.path.basename(file_path), href=file_path, cls="download-button", download=True)
|
|
@@ -117,7 +133,9 @@ class Page(AbstractPage):
|
|
|
117
133
|
elem = div(elem, style=style)
|
|
118
134
|
elem = div(elem, style=outer_style)
|
|
119
135
|
elements.append(elem)
|
|
120
|
-
|
|
136
|
+
|
|
137
|
+
# Add padding to avoid overlap with header and footer
|
|
138
|
+
wrapper = div(*elements, style=f"max-width: {effective_width}px; margin: 0 auto; width: 100%; padding-top: 80px; padding-bottom: 80px;")
|
|
121
139
|
return [wrapper]
|
|
122
140
|
|
|
123
141
|
class MiniPage(AbstractPage):
|
|
@@ -187,13 +205,42 @@ class MiniPage(AbstractPage):
|
|
|
187
205
|
return row_div
|
|
188
206
|
|
|
189
207
|
class Dashboard:
|
|
190
|
-
def __init__(self, title="Dashboard", page_width=900):
|
|
208
|
+
def __init__(self, title="Dashboard", page_width=900, marking=None):
|
|
191
209
|
self.title = title
|
|
192
210
|
self.pages = []
|
|
193
211
|
self.page_width = page_width
|
|
212
|
+
self.marking = marking # Dashboard-wide marking
|
|
194
213
|
|
|
195
214
|
def add_page(self, page):
|
|
196
215
|
self.pages.append(page)
|
|
216
|
+
|
|
217
|
+
# def _track_outline(self, flowable):
|
|
218
|
+
# """
|
|
219
|
+
# Hook for collecting TOC entries and setting bookmarks.
|
|
220
|
+
# """
|
|
221
|
+
# from reportlab.platypus import Paragraph
|
|
222
|
+
# if isinstance(flowable, Paragraph):
|
|
223
|
+
# text = flowable.getPlainText()
|
|
224
|
+
# style_name = flowable.style.name
|
|
225
|
+
# if style_name.startswith("Heading"):
|
|
226
|
+
# try:
|
|
227
|
+
# level = int(style_name.replace("Heading", ""))
|
|
228
|
+
# except ValueError:
|
|
229
|
+
# return
|
|
230
|
+
# key = f"bookmark_{uuid.uuid4().hex}"
|
|
231
|
+
# flowable.canv.bookmarkPage(key)
|
|
232
|
+
# flowable.canv.addOutlineEntry(text, key, level=level - 1, closed=False)
|
|
233
|
+
# flowable._bookmarkName = key
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _track_outline(self, canvas, doc):
|
|
237
|
+
if hasattr(doc, '_last_heading'):
|
|
238
|
+
level, text = doc._last_heading
|
|
239
|
+
key = f"bookmark_{uuid.uuid4().hex}"
|
|
240
|
+
canvas.bookmarkPage(key)
|
|
241
|
+
canvas.addOutlineEntry(text, key, level=level - 1, closed=False)
|
|
242
|
+
del doc._last_heading
|
|
243
|
+
|
|
197
244
|
|
|
198
245
|
def _render_sidebar(self, pages, prefix="", current_slug=None):
|
|
199
246
|
for page in pages:
|
|
@@ -298,77 +345,75 @@ class Dashboard:
|
|
|
298
345
|
with open(os.path.join(output_dir, "index.html"), "w") as f:
|
|
299
346
|
f.write(str(index_doc))
|
|
300
347
|
|
|
301
|
-
def publish_pdf(self, output_path="dashboard_report.pdf", pagesize="A4",
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
else:
|
|
350
|
-
sec_prefix[level] += 1
|
|
351
|
-
sec_prefix = sec_prefix[:level+1]
|
|
352
|
-
section_num = ".".join(str(n) for n in sec_prefix)
|
|
353
|
-
section_title = f"{section_num} {page.title}"
|
|
354
|
-
outline_entries.append((section_title, level, section_num))
|
|
355
|
-
style = styles['Heading1'] if level == 0 else styles['Heading2']
|
|
356
|
-
bookmark_name = f"section_{section_num.replace('.', '_')}"
|
|
357
|
-
para = Paragraph(f'<a name="{bookmark_name}"/>{section_title}', style)
|
|
358
|
-
heading_paragraphs.append(para)
|
|
359
|
-
story.append(para)
|
|
360
|
-
story.append(Spacer(1, 12))
|
|
361
|
-
|
|
362
|
-
def render_elements(elements):
|
|
363
|
-
for kind, content, _ in elements:
|
|
348
|
+
def publish_pdf(self, output_path="dashboard_report.pdf", pagesize="A4", include_title_page=False, title_page_marking=None, author=None, affiliation=None):
|
|
349
|
+
from reportlab.platypus import SimpleDocTemplate, Spacer, Paragraph, PageBreak, Image
|
|
350
|
+
from reportlab.lib.pagesizes import letter, A4
|
|
351
|
+
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
352
|
+
from datetime import datetime
|
|
353
|
+
import io
|
|
354
|
+
|
|
355
|
+
page_size = A4 if pagesize == "A4" else letter
|
|
356
|
+
styles = getSampleStyleSheet()
|
|
357
|
+
story = []
|
|
358
|
+
|
|
359
|
+
# Add title page
|
|
360
|
+
if include_title_page:
|
|
361
|
+
story.append(Spacer(1, 120))
|
|
362
|
+
story.append(Paragraph(f"<b>{self.title}</b>", styles['Title']))
|
|
363
|
+
story.append(Spacer(1, 48))
|
|
364
|
+
if author:
|
|
365
|
+
story.append(Paragraph(f"<para align='center'>{author}</para>", styles['Normal']))
|
|
366
|
+
if affiliation:
|
|
367
|
+
story.append(Paragraph(f"<para align='center'>{affiliation}</para>", styles['Normal']))
|
|
368
|
+
current_date = datetime.now().strftime("%B %d, %Y")
|
|
369
|
+
story.append(Paragraph(f"<para align='center'>{current_date}</para>", styles['Normal']))
|
|
370
|
+
story.append(PageBreak())
|
|
371
|
+
|
|
372
|
+
# Add Table of Contents
|
|
373
|
+
toc = TableOfContents()
|
|
374
|
+
toc.levelStyles = [
|
|
375
|
+
ParagraphStyle(name='TOCHeading1', fontSize=14, leftIndent=20, firstLineIndent=-20, spaceBefore=10, leading=16),
|
|
376
|
+
ParagraphStyle(name='TOCHeading2', fontSize=12, leftIndent=40, firstLineIndent=-20, spaceBefore=5, leading=12),
|
|
377
|
+
ParagraphStyle(name='TOCHeading3', fontSize=10, leftIndent=60, firstLineIndent=-20, spaceBefore=5, leading=10),
|
|
378
|
+
]
|
|
379
|
+
story.append(Paragraph("Table of Contents", styles["Title"]))
|
|
380
|
+
story.append(toc)
|
|
381
|
+
story.append(PageBreak())
|
|
382
|
+
|
|
383
|
+
def add_marking(canvas, doc, marking):
|
|
384
|
+
if marking:
|
|
385
|
+
canvas.saveState()
|
|
386
|
+
canvas.setFont("Helvetica", 10)
|
|
387
|
+
page_width = doc.pagesize[0]
|
|
388
|
+
text_width = canvas.stringWidth(marking, "Helvetica", 10)
|
|
389
|
+
x_position = (page_width - text_width) / 2
|
|
390
|
+
canvas.drawString(x_position, doc.pagesize[1] - 36, marking)
|
|
391
|
+
canvas.drawString(x_position, 36, marking)
|
|
392
|
+
canvas.restoreState()
|
|
393
|
+
|
|
394
|
+
def render_page(page):
|
|
395
|
+
for kind, content, _ in page.elements:
|
|
364
396
|
if kind == "text":
|
|
365
|
-
story.append(Paragraph(content,
|
|
397
|
+
story.append(Paragraph(content, styles['Normal']))
|
|
366
398
|
story.append(Spacer(1, 8))
|
|
399
|
+
|
|
367
400
|
elif kind == "header":
|
|
368
|
-
text,
|
|
369
|
-
|
|
370
|
-
|
|
401
|
+
text, level = content
|
|
402
|
+
style_key = f'Heading{min(level + 1, 4)}'
|
|
403
|
+
header_style = styles[style_key]
|
|
404
|
+
para = Paragraph(text, header_style)
|
|
405
|
+
story.append(para)
|
|
371
406
|
story.append(Spacer(1, 8))
|
|
407
|
+
|
|
408
|
+
# Capture this heading for TOC/outline
|
|
409
|
+
def capture_heading(canvas, doc, level=level, text=text):
|
|
410
|
+
doc._last_heading = (level, text)
|
|
411
|
+
|
|
412
|
+
# Hack: attach postRender callback to dummy flowable
|
|
413
|
+
spacer = Spacer(0, 0)
|
|
414
|
+
spacer.__dict__["postRender"] = capture_heading
|
|
415
|
+
story.append(spacer)
|
|
416
|
+
|
|
372
417
|
elif kind == "table":
|
|
373
418
|
df = content
|
|
374
419
|
try:
|
|
@@ -394,106 +439,64 @@ class Dashboard:
|
|
|
394
439
|
story.append(t)
|
|
395
440
|
story.append(Spacer(1, 12))
|
|
396
441
|
except Exception:
|
|
397
|
-
story.append(Paragraph("Table could not be rendered.",
|
|
442
|
+
story.append(Paragraph("Table could not be rendered.", styles['Normal']))
|
|
398
443
|
elif kind == "plot":
|
|
399
444
|
fig = content
|
|
400
445
|
try:
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
# Plotly support
|
|
407
|
-
if isinstance(fig, go.Figure):
|
|
408
|
-
# Configure the figure layout for PDF rendering
|
|
409
|
-
fig.update_layout(
|
|
410
|
-
margin=dict(l=10, r=10, t=30, b=30),
|
|
411
|
-
width=900,
|
|
412
|
-
height=540
|
|
413
|
-
)
|
|
414
|
-
|
|
415
|
-
# Use kaleido to export the figure as a PNG
|
|
416
|
-
png_bytes = fig.to_image(format="png", width=900, height=540, engine="kaleido")
|
|
417
|
-
|
|
418
|
-
# Wrap the PNG bytes in a BytesIO buffer
|
|
419
|
-
img_buf = io.BytesIO(png_bytes)
|
|
420
|
-
|
|
421
|
-
# Add the image to the PDF story
|
|
422
|
-
story.append(Spacer(1, 8))
|
|
423
|
-
story.append(Image(img_buf, width=6 * inch, height=3.6 * inch))
|
|
446
|
+
if hasattr(fig, "to_image"):
|
|
447
|
+
img_bytes = fig.to_image(format="png", width=800, height=600, scale=2)
|
|
448
|
+
img_buffer = io.BytesIO(img_bytes)
|
|
449
|
+
img = Image(img_buffer, width=6 * inch, height=4.5 * inch)
|
|
450
|
+
story.append(img)
|
|
424
451
|
story.append(Spacer(1, 12))
|
|
425
|
-
|
|
426
|
-
# Matplotlib support
|
|
427
|
-
elif isinstance(fig, matplotlib.figure.Figure):
|
|
452
|
+
elif hasattr(fig, "savefig"):
|
|
428
453
|
buf = io.BytesIO()
|
|
429
|
-
# Save the figure with higher DPI for better quality
|
|
430
454
|
fig.savefig(buf, format="png", bbox_inches="tight", dpi=300)
|
|
431
455
|
buf.seek(0)
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
fig_width, fig_height = fig.get_size_inches()
|
|
435
|
-
aspect_ratio = fig_height / fig_width
|
|
436
|
-
|
|
437
|
-
# Set width and calculate height based on aspect ratio
|
|
438
|
-
pdf_width = 6 * inch
|
|
439
|
-
pdf_height = pdf_width * aspect_ratio
|
|
440
|
-
|
|
441
|
-
# Add the image to the PDF story
|
|
442
|
-
story.append(Spacer(1, 8))
|
|
443
|
-
story.append(Image(buf, width=pdf_width, height=pdf_height))
|
|
456
|
+
img = Image(buf, width=6 * inch, height=4.5 * inch)
|
|
457
|
+
story.append(img)
|
|
444
458
|
story.append(Spacer(1, 12))
|
|
445
|
-
|
|
446
|
-
else:
|
|
447
|
-
raise ValueError("add_plot must be called with a plotly.graph_objects.Figure or matplotlib.figure.Figure")
|
|
448
|
-
|
|
449
459
|
except Exception as e:
|
|
450
|
-
story.append(Paragraph(f"Plot
|
|
460
|
+
story.append(Paragraph(f"Plot could not be rendered: {e}", styles['Normal']))
|
|
461
|
+
elif kind == "syntax":
|
|
462
|
+
pass
|
|
451
463
|
elif kind == "syntax":
|
|
452
464
|
code, language = content
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
465
|
+
style = ParagraphStyle(
|
|
466
|
+
name='CodeBlock',
|
|
467
|
+
fontName='Courier',
|
|
468
|
+
fontSize=8,
|
|
469
|
+
leading=10,
|
|
470
|
+
leftIndent=12,
|
|
471
|
+
rightIndent=12,
|
|
472
|
+
spaceBefore=6,
|
|
473
|
+
spaceAfter=6,
|
|
474
|
+
borderPadding=6,
|
|
475
|
+
backColor=colors.whitesmoke
|
|
476
|
+
)
|
|
477
|
+
# Escape special characters for XML
|
|
478
|
+
from xml.sax.saxutils import escape
|
|
479
|
+
code_escaped = escape(code)
|
|
480
|
+
para = Paragraph(f"<pre>{code_escaped}</pre>", style)
|
|
481
|
+
story.append(para)
|
|
460
482
|
|
|
461
|
-
|
|
483
|
+
elif kind == "minipage":
|
|
484
|
+
pass
|
|
462
485
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
render_page(child, level=level+1, sec_prefix=child_sec_prefix)
|
|
486
|
+
for child in getattr(page, "children", []):
|
|
487
|
+
story.append(PageBreak())
|
|
488
|
+
render_page(child)
|
|
467
489
|
|
|
468
|
-
|
|
490
|
+
for page in self.pages:
|
|
491
|
+
render_page(page)
|
|
469
492
|
story.append(PageBreak())
|
|
470
493
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
story.append(Paragraph(f"<b>{self.title}</b>", styles['Title']))
|
|
475
|
-
story.append(Spacer(1, 48))
|
|
476
|
-
# Centered info block (no labels)
|
|
477
|
-
info_lines = []
|
|
478
|
-
if author:
|
|
479
|
-
info_lines.append(str(author))
|
|
480
|
-
if affiliation:
|
|
481
|
-
info_lines.append(str(affiliation))
|
|
482
|
-
info_lines.append(pd.Timestamp.now().strftime('%B %d, %Y'))
|
|
483
|
-
info_html = "<br/>".join(info_lines)
|
|
484
|
-
story.append(Paragraph(f'<para align="center">{info_html}</para>', styles['Normal']))
|
|
485
|
-
story.append(PageBreak())
|
|
486
|
-
|
|
487
|
-
for page in self.pages:
|
|
488
|
-
render_page(page)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
doc = MyDocTemplate(
|
|
492
|
-
output_path,
|
|
493
|
-
pagesize=page_size,
|
|
494
|
-
rightMargin=72, leftMargin=72, topMargin=72, bottomMargin=72,
|
|
495
|
-
outline_entries=outline_entries,
|
|
496
|
-
headings=heading_paragraphs
|
|
497
|
-
)
|
|
494
|
+
doc = SimpleDocTemplate(output_path, pagesize=page_size)
|
|
495
|
+
# doc.afterFlowable = self._track_outline
|
|
496
|
+
doc.afterFlowable = lambda flowable: getattr(flowable, "postRender", lambda c, d: None)(doc.canv, doc) or self._track_outline(doc.canv, doc)
|
|
498
497
|
|
|
499
|
-
|
|
498
|
+
doc.build(
|
|
499
|
+
story,
|
|
500
|
+
onFirstPage=lambda canvas, doc: add_marking(canvas, doc, title_page_marking),
|
|
501
|
+
onLaterPages=lambda canvas, doc: add_marking(canvas, doc, self.marking)
|
|
502
|
+
)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
staticdash/__init__.py,sha256=UN_-h8wFGfTPHYjnEb7N9CsxqXo-DQVo0cmREOtvRXE,244
|
|
2
|
+
staticdash/dashboard.py,sha256=YkP5ZXQQupIh5S0PuKXihoAtCitJRBTaUvD58bZuNSo,25190
|
|
3
|
+
staticdash/assets/css/style.css,sha256=RVqNdwBsaDv8izdOQjGmUZ4NROWF8uZhiq8DTNvUB1M,5962
|
|
4
|
+
staticdash/assets/js/script.js,sha256=7xBRlz_19wybbNVwAcfuKNXtDEojGB4EB0Yj4klsoTA,6998
|
|
5
|
+
staticdash-2025.20.dist-info/METADATA,sha256=FYxpbdPmwurhbyawG79E2jj9K4csiRcjadusnoDLH44,1960
|
|
6
|
+
staticdash-2025.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
staticdash-2025.20.dist-info/top_level.txt,sha256=3MzZU6SptkUkjcHV1cvPji0H4aRzPphLHnpStgGEcxM,11
|
|
8
|
+
staticdash-2025.20.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
staticdash/__init__.py,sha256=UN_-h8wFGfTPHYjnEb7N9CsxqXo-DQVo0cmREOtvRXE,244
|
|
2
|
-
staticdash/dashboard.py,sha256=6d3TbXVN0ZdWD5awsqWH9H6tH64fpOanTAiVWG_q-Eo,25056
|
|
3
|
-
staticdash/assets/css/style.css,sha256=RVqNdwBsaDv8izdOQjGmUZ4NROWF8uZhiq8DTNvUB1M,5962
|
|
4
|
-
staticdash/assets/js/script.js,sha256=7xBRlz_19wybbNVwAcfuKNXtDEojGB4EB0Yj4klsoTA,6998
|
|
5
|
-
staticdash-2025.18.dist-info/METADATA,sha256=_Zrirh0NBbV36fcXJQ4oqGQ_lr-UPhYSwLr6Vy3ur3U,1960
|
|
6
|
-
staticdash-2025.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
staticdash-2025.18.dist-info/top_level.txt,sha256=3MzZU6SptkUkjcHV1cvPji0H4aRzPphLHnpStgGEcxM,11
|
|
8
|
-
staticdash-2025.18.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|