solidstats 0.0.4 → 1.0.0

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.
@@ -1,11 +1,10 @@
1
- <div id="audit-details" class="details-panel hidden">
1
+ <div id="audit-details">
2
2
  <%= render partial: 'solidstats/dashboard/audit/audit_summary' %>
3
3
 
4
4
  <% results = @audit_output.dig("results") || [] %>
5
5
  <% if results.empty? %>
6
6
  <%= render partial: 'solidstats/dashboard/audit/no_vulnerabilities' %>
7
7
  <% else %>
8
- <%= render partial: 'solidstats/dashboard/audit/audit_filters' %>
9
8
  <%= render partial: 'solidstats/dashboard/audit/vulnerabilities_table', locals: { results: results } %>
10
9
  <%= render partial: 'solidstats/dashboard/audit/vulnerability_details', locals: { results: results } %>
11
10
  <% end %>
@@ -159,12 +158,6 @@
159
158
  border-left: 4px solid #dc3545;
160
159
  }
161
160
 
162
- .vulnerability-title {
163
- margin-top: 0;
164
- margin-bottom: 0.75rem;
165
- font-size: 1.1rem;
166
- font-weight: 600;
167
- }
168
161
 
169
162
  .vulnerability-meta {
170
163
  display: flex;
@@ -224,6 +217,7 @@
224
217
  border-bottom: 1px solid #e1e4e8;
225
218
  padding: 24px;
226
219
  background-color: #ffffff;
220
+ transition: background-color 0.3s ease;
227
221
  }
228
222
 
229
223
  .md-entry:last-child {
@@ -234,6 +228,10 @@
234
228
  border-left: 4px solid #d73a49;
235
229
  }
236
230
 
231
+ .md-entry.highlight-detail {
232
+ background-color: #fffbe6;
233
+ }
234
+
237
235
  /* Markdown heading style */
238
236
  .md-heading {
239
237
  font-size: 1.5rem;
@@ -416,12 +414,12 @@
416
414
  const toggleBtn = document.querySelector('.toggle-details-btn');
417
415
  if (toggleBtn) {
418
416
  toggleBtn.addEventListener('click', function() {
419
- const detailsSection = document.querySelector('.vulnerabilities-details-section');
420
- const isHidden = detailsSection.classList.contains('hidden');
417
+ const detailsSection = document.querySelector('.md-container');
418
+ const isHidden = detailsSection.style.display === 'none';
421
419
 
422
420
  if (isHidden) {
423
421
  // Show the details
424
- detailsSection.classList.remove('hidden');
422
+ detailsSection.style.display = '';
425
423
  this.textContent = 'Hide Details';
426
424
  this.setAttribute('aria-expanded', 'true');
427
425
 
@@ -432,7 +430,7 @@
432
430
  });
433
431
  } else {
434
432
  // Hide the details
435
- detailsSection.classList.add('hidden');
433
+ detailsSection.style.display = 'none';
436
434
  this.textContent = 'Show Details';
437
435
  this.setAttribute('aria-expanded', 'false');
438
436
  }
@@ -440,66 +438,57 @@
440
438
  }
441
439
 
442
440
  // View details link functionality - simplified to avoid duplication
443
- document.querySelectorAll('.view-details-link').forEach(function(link) {
441
+ document.querySelectorAll('.view-details-link, .scroll-to-details').forEach(function(link) {
444
442
  link.addEventListener('click', function(e) {
445
443
  e.preventDefault();
446
444
  const target = this.getAttribute('href');
447
- const detailsSection = document.querySelector('.vulnerabilities-details-section');
445
+ const mdContainer = document.querySelector('.md-container');
448
446
 
449
447
  // Show the details section if it's hidden
450
- if (detailsSection.classList.contains('hidden')) {
451
- detailsSection.classList.remove('hidden');
448
+ if (mdContainer.style.display === 'none') {
449
+ mdContainer.style.display = '';
452
450
  const toggleBtn = document.querySelector('.toggle-details-btn');
453
- toggleBtn.textContent = 'Hide Details';
454
- toggleBtn.setAttribute('aria-expanded', 'true');
451
+ if (toggleBtn) {
452
+ toggleBtn.textContent = 'Hide Details';
453
+ toggleBtn.setAttribute('aria-expanded', 'true');
454
+ }
455
455
  }
456
456
 
457
457
  // Scroll to the specific vulnerability
458
458
  setTimeout(() => {
459
- document.querySelector(target).scrollIntoView({
460
- behavior: 'smooth',
461
- block: 'start'
462
- });
459
+ const targetElement = document.querySelector(target);
460
+ if (targetElement) {
461
+ const headerOffset = 70;
462
+ const elementPosition = targetElement.getBoundingClientRect().top;
463
+ const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
464
+
465
+ window.scrollTo({
466
+ top: offsetPosition,
467
+ behavior: "smooth"
468
+ });
469
+
470
+ // Highlight the target element briefly
471
+ targetElement.classList.add('highlight-detail');
472
+ setTimeout(() => {
473
+ targetElement.classList.remove('highlight-detail');
474
+ }, 1500);
475
+ }
463
476
  }, 100);
464
477
  });
465
478
  });
466
479
 
467
- // Filter functionality
468
- document.querySelectorAll('.filter-btn').forEach(function(button) {
469
- button.addEventListener('click', function() {
470
- const filter = this.getAttribute('data-filter');
471
-
472
- // Update active button
473
- document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
474
- this.classList.add('active');
475
-
476
- // Handle special case for copy-solutions
477
- if (filter === 'copy-solutions') {
478
- const solutions = [];
479
- document.querySelectorAll('.vulnerability-row').forEach(function(row) {
480
- const gem = row.cells[0].textContent.trim();
481
- const solution = row.querySelector('.solution code')?.textContent.trim() || "No patch available";
482
- solutions.push(`${gem}: ${solution}`);
483
- });
484
-
485
- // Copy all solutions to clipboard
486
- navigator.clipboard.writeText(solutions.join('\n')).then(() => {
487
- alert('All solutions copied to clipboard!');
488
- });
489
-
490
- return;
491
- }
492
-
493
- // Filter the vulnerability rows
494
- document.querySelectorAll('.vulnerability-row').forEach(function(row) {
495
- const isHigh = row.classList.contains('high-severity');
496
-
497
- if (filter === 'all') {
498
- row.style.display = '';
499
- } else if (filter === 'high') {
500
- row.style.display = isHigh ? '' : 'none';
501
- }
502
- });
480
+ // Special case handler for copy-solutions button (if it exists)
481
+ document.querySelector('.filter-btn[data-filter="copy-solutions"]')?.addEventListener('click', function() {
482
+ const solutions = [];
483
+ document.querySelectorAll('.vulnerability-row').forEach(function(row) {
484
+ const gem = row.cells[0].textContent.trim();
485
+ const solution = row.querySelector('.solution code')?.textContent.trim() || "No patch available";
486
+ solutions.push(`${gem}: ${solution}`);
487
+ });
488
+
489
+ // Copy all solutions to clipboard
490
+ navigator.clipboard.writeText(solutions.join('\n')).then(() => {
491
+ alert('All solutions copied to clipboard!');
503
492
  });
504
493
  });
505
494
  });
@@ -1,7 +1,7 @@
1
1
  <%# filepath: /Users/mezbah/microstartup/infolily_organizer/gems/solidstats/app/views/solidstats/dashboard/_audit_summary.html.erb %>
2
2
  <div class="audit-summary">
3
3
  <div class="audit-summary-header">
4
- <h3>Security Audit Summary</h3>
4
+ <h2><span class="icon">🔒</span>Security Audit Summary</h2>
5
5
  <% created_at = @audit_output.dig("created_at") %>
6
6
  <span class="audit-date">Last updated: <%= created_at ? DateTime.parse(created_at).strftime("%B %d, %Y at %H:%M") : Time.now.strftime("%B %d, %Y at %H:%M") %></span>
7
7
  </div>
@@ -1,27 +1,4 @@
1
1
  <div class="stat-card audit-card">
2
- <h2><span class="icon">🔒</span> Security Audit</h2>
3
- <div class="card-content">
4
- <% results = @audit_output.dig("results") || [] %>
5
- <% vulnerabilities_count = results.size %>
6
- <% if vulnerabilities_count == 0 %>
7
- <div class="status-badge success">All Clear</div>
8
- <% else %>
9
- <div class="status-badge warning"><%= vulnerabilities_count %> <%= "Vulnerability".pluralize(vulnerabilities_count) %> Found</div>
10
- <% end %>
11
-
12
- <div class="metrics-group">
13
- <div class="metric">
14
- <span class="metric-label">Affected Gems:</span>
15
- <span class="metric-value"><%= results.map { |r| r.dig("gem", "name") }.uniq.size %></span>
16
- </div>
17
- <div class="metric">
18
- <span class="metric-label">High Severity:</span>
19
- <span class="metric-value"><%= results.count { |r| %w[high critical].include?(r.dig("advisory", "criticality").to_s.downcase) } %></span>
20
- </div>
21
- </div>
22
-
23
- <a href="#" class="toggle-details" data-target="audit-details">Show Details</a>
24
- </div>
25
2
  <%= render 'solidstats/dashboard/audit/audit_details' %>
26
3
  </div>
27
4