|
223 | 223 | .integration-table th:not(:first-child) { |
224 | 224 | text-align: center; |
225 | 225 | } |
| 226 | + .content-table { |
| 227 | + width: 100%; |
| 228 | + border-collapse: collapse; |
| 229 | + font-size: 14px; |
| 230 | + } |
| 231 | + .content-table thead { |
| 232 | + border-bottom: 2px solid rgba(55, 53, 47, 0.09); |
| 233 | + } |
| 234 | + .content-table th { |
| 235 | + color: #787774; |
| 236 | + font-weight: 600; |
| 237 | + padding: 12px 8px; |
| 238 | + text-align: left; |
| 239 | + font-size: 12px; |
| 240 | + text-transform: uppercase; |
| 241 | + letter-spacing: 0.5px; |
| 242 | + } |
| 243 | + .content-table th:last-child { |
| 244 | + text-align: right; |
| 245 | + } |
| 246 | + .content-table td { |
| 247 | + padding: 10px 8px; |
| 248 | + color: #37352f; |
| 249 | + border-bottom: 1px solid rgba(55, 53, 47, 0.06); |
| 250 | + } |
| 251 | + .content-table td:first-child { |
| 252 | + font-weight: 500; |
| 253 | + } |
| 254 | + .content-table td:last-child { |
| 255 | + text-align: right; |
| 256 | + font-weight: 600; |
| 257 | + color: #2383e2; |
| 258 | + } |
| 259 | + .content-table tbody tr:hover { |
| 260 | + background-color: #f7f6f3; |
| 261 | + } |
226 | 262 | """ |
227 | 263 |
|
228 | 264 | def fetch_all_prometheus_metrics(url: str) -> Dict[str, List[Tuple[Dict[str, str], float]]]: |
@@ -534,45 +570,96 @@ def content_stats_grid(): |
534 | 570 | class_="content-card" |
535 | 571 | ) |
536 | 572 |
|
537 | | - type_items = [] |
538 | 573 | sorted_types = sorted(stats["by_type"].items(), key=lambda x: x[1], reverse=True) |
539 | | - for content_type, count in sorted_types: |
540 | | - type_items.append( |
541 | | - ui.div( |
542 | | - ui.span(f"{content_type} :: ", style="color: #787774;"), |
543 | | - ui.span(str(count), style="font-weight: 500;"), |
544 | | - class_="content-type-item" |
545 | | - ) |
| 574 | + type_rows = [ |
| 575 | + ui.tags.tr( |
| 576 | + ui.tags.td(content_type), |
| 577 | + ui.tags.td(str(count)) |
546 | 578 | ) |
| 579 | + for content_type, count in sorted_types |
| 580 | + ] |
547 | 581 |
|
548 | 582 | col2 = ui.div( |
549 | | - ui.div("Content by Type", class_="card-title"), |
550 | | - ui.div(*type_items, class_="section-content"), |
| 583 | + ui.div( |
| 584 | + ui.tags.table( |
| 585 | + ui.tags.thead( |
| 586 | + ui.tags.tr( |
| 587 | + ui.tags.th("Type"), |
| 588 | + ui.tags.th("Count") |
| 589 | + ) |
| 590 | + ), |
| 591 | + ui.tags.tbody(*type_rows), |
| 592 | + class_="content-table" |
| 593 | + ), |
| 594 | + class_="section-content" |
| 595 | + ), |
551 | 596 | class_="content-card" |
552 | 597 | ) |
553 | 598 |
|
554 | | - runtime_items = [] |
555 | | - sorted_runtimes = sorted(stats["runtime_versions"].items(), key=lambda x: x[1], reverse=True) |
556 | | - for runtime, count in sorted_runtimes: |
557 | | - runtime_items.append( |
558 | | - ui.div( |
559 | | - ui.span(f"{runtime} :: ", style="color: #787774;"), |
560 | | - ui.span(str(count), style="font-weight: 500;"), |
561 | | - class_="content-type-item" |
562 | | - ) |
| 599 | + # Define runtime priority order |
| 600 | + runtime_order = {"R": 0, "Python": 1, "Quarto": 2} |
| 601 | + |
| 602 | + # Custom sorting: first by runtime type, then by count (descending) within each type |
| 603 | + def sort_key(item): |
| 604 | + runtime, count = item |
| 605 | + # Extract the runtime language (first word) |
| 606 | + runtime_lang = runtime.split()[0] if runtime else "" |
| 607 | + # Get priority (default to 999 for unknown runtimes) |
| 608 | + priority = runtime_order.get(runtime_lang, 999) |
| 609 | + # Return tuple: (priority, -count) to sort by priority first, then count descending |
| 610 | + return (priority, -count) |
| 611 | + |
| 612 | + sorted_runtimes = sorted(stats["runtime_versions"].items(), key=sort_key) |
| 613 | + runtime_rows = [ |
| 614 | + ui.tags.tr( |
| 615 | + ui.tags.td(runtime), |
| 616 | + ui.tags.td(str(count)) |
563 | 617 | ) |
| 618 | + for runtime, count in sorted_runtimes |
| 619 | + ] |
564 | 620 |
|
565 | 621 | col3 = ui.div( |
566 | | - ui.div("Content by Runtime Version", class_="card-title"), |
567 | | - ui.div(*runtime_items, class_="section-content"), |
| 622 | + ui.div( |
| 623 | + ui.tags.table( |
| 624 | + ui.tags.thead( |
| 625 | + ui.tags.tr( |
| 626 | + ui.tags.th("Runtime Version"), |
| 627 | + ui.tags.th("Count") |
| 628 | + ) |
| 629 | + ), |
| 630 | + ui.tags.tbody(*runtime_rows), |
| 631 | + class_="content-table" |
| 632 | + ), |
| 633 | + class_="section-content" |
| 634 | + ), |
568 | 635 | class_="content-card" |
569 | 636 | ) |
570 | 637 |
|
571 | 638 | access_stats = get_access_control_stats(metrics) |
572 | | - sorted_access_stats = dict(sorted(access_stats.items(), key=lambda x: x[1], reverse=True)) |
573 | | - col4 = create_content_card( |
574 | | - "Content by Access Control", |
575 | | - ui.div(*create_key_value_list(sorted_access_stats), class_="section-content") |
| 639 | + sorted_access_stats = sorted(access_stats.items(), key=lambda x: x[1], reverse=True) |
| 640 | + access_rows = [ |
| 641 | + ui.tags.tr( |
| 642 | + ui.tags.td(access_type), |
| 643 | + ui.tags.td(str(count)) |
| 644 | + ) |
| 645 | + for access_type, count in sorted_access_stats |
| 646 | + ] |
| 647 | + |
| 648 | + col4 = ui.div( |
| 649 | + ui.div( |
| 650 | + ui.tags.table( |
| 651 | + ui.tags.thead( |
| 652 | + ui.tags.tr( |
| 653 | + ui.tags.th("Access Type"), |
| 654 | + ui.tags.th("Count") |
| 655 | + ) |
| 656 | + ), |
| 657 | + ui.tags.tbody(*access_rows), |
| 658 | + class_="content-table" |
| 659 | + ), |
| 660 | + class_="section-content" |
| 661 | + ), |
| 662 | + class_="content-card" |
576 | 663 | ) |
577 | 664 |
|
578 | 665 | return [col1, col2, col3, col4] |
|
0 commit comments