@design.estate/dees-catalog 3.35.1 → 3.37.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.
- package/dist_bundle/bundle.js +1391 -247
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-button/dees-button/dees-button.d.ts +6 -0
- package/dist_ts_web/elements/00group-button/dees-button/dees-button.demo.js +69 -29
- package/dist_ts_web/elements/00group-button/dees-button/dees-button.js +75 -6
- package/dist_ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.d.ts +104 -6
- package/dist_ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.demo.js +153 -54
- package/dist_ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.js +716 -153
- package/dist_ts_web/elements/dees-statsgrid/dees-statsgrid.d.ts +22 -1
- package/dist_ts_web/elements/dees-statsgrid/dees-statsgrid.demo.js +130 -2
- package/dist_ts_web/elements/dees-statsgrid/dees-statsgrid.js +322 -1
- package/dist_ts_web/services/DeesServiceLibLoader.d.ts +34 -1
- package/dist_ts_web/services/DeesServiceLibLoader.js +27 -1
- package/dist_ts_web/services/index.d.ts +1 -1
- package/dist_ts_web/services/versions.d.ts +1 -0
- package/dist_ts_web/services/versions.js +2 -1
- package/dist_watch/bundle.js +1389 -245
- package/dist_watch/bundle.js.map +3 -3
- package/package.json +1 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-button/dees-button/dees-button.demo.ts +68 -28
- package/ts_web/elements/00group-button/dees-button/dees-button.ts +78 -6
- package/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.demo.ts +163 -56
- package/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.ts +756 -161
- package/ts_web/elements/dees-statsgrid/dees-statsgrid.demo.ts +130 -2
- package/ts_web/elements/dees-statsgrid/dees-statsgrid.ts +352 -1
- package/ts_web/services/DeesServiceLibLoader.ts +50 -1
- package/ts_web/services/index.ts +1 -1
- package/ts_web/services/versions.ts +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html, css, cssManager } from '@design.estate/dees-element';
|
|
2
2
|
import '@design.estate/dees-wcctools/demotools';
|
|
3
3
|
import '../dees-panel/dees-panel.js';
|
|
4
|
-
import type { IStatsTile, ICpuCore } from '../dees-statsgrid/dees-statsgrid.js';
|
|
4
|
+
import type { IStatsTile, ICpuCore, IPartitionData, IDiskData } from '../dees-statsgrid/dees-statsgrid.js';
|
|
5
5
|
|
|
6
6
|
// Helper function to generate random CPU core data
|
|
7
7
|
const generateCpuCores = (count: number): ICpuCore[] => {
|
|
@@ -601,8 +601,136 @@ html\`
|
|
|
601
601
|
></dees-statsgrid>
|
|
602
602
|
\`;`}</div>
|
|
603
603
|
</dees-panel>
|
|
604
|
+
|
|
605
|
+
<dees-panel .title=${'7. Disk & Storage Tiles'} .subtitle=${'Partition and physical disk visualization tiles'}>
|
|
606
|
+
<dees-statsgrid
|
|
607
|
+
.tiles=${[
|
|
608
|
+
{
|
|
609
|
+
id: 'root-partition',
|
|
610
|
+
title: 'Root Partition',
|
|
611
|
+
value: 0,
|
|
612
|
+
type: 'partition',
|
|
613
|
+
icon: 'lucide:folder-root',
|
|
614
|
+
partitionData: {
|
|
615
|
+
used: 698_341_425_152, // ~650 GB
|
|
616
|
+
total: 1_073_741_824_000, // ~1 TB
|
|
617
|
+
filesystem: 'ext4',
|
|
618
|
+
mountPoint: '/'
|
|
619
|
+
}
|
|
620
|
+
},
|
|
621
|
+
{
|
|
622
|
+
id: 'home-partition',
|
|
623
|
+
title: 'Home Partition',
|
|
624
|
+
value: 0,
|
|
625
|
+
type: 'partition',
|
|
626
|
+
icon: 'lucide:home',
|
|
627
|
+
partitionData: {
|
|
628
|
+
used: 214_748_364_800, // ~200 GB
|
|
629
|
+
total: 536_870_912_000, // ~500 GB
|
|
630
|
+
filesystem: 'ext4',
|
|
631
|
+
mountPoint: '/home'
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
id: 'data-partition',
|
|
636
|
+
title: 'Data Partition',
|
|
637
|
+
value: 0,
|
|
638
|
+
type: 'partition',
|
|
639
|
+
icon: 'lucide:database',
|
|
640
|
+
partitionData: {
|
|
641
|
+
used: 1_932_735_283_200, // ~1.8 TB (90% - critical)
|
|
642
|
+
total: 2_147_483_648_000, // ~2 TB
|
|
643
|
+
filesystem: 'xfs',
|
|
644
|
+
mountPoint: '/data'
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
id: 'nvme-ssd',
|
|
649
|
+
title: 'Primary NVMe',
|
|
650
|
+
value: 0,
|
|
651
|
+
type: 'disk',
|
|
652
|
+
icon: 'lucide:hard-drive',
|
|
653
|
+
columnSpan: 2,
|
|
654
|
+
diskData: {
|
|
655
|
+
capacity: 2_000_000_000_000, // 2 TB
|
|
656
|
+
model: 'Samsung 990 Pro',
|
|
657
|
+
type: 'nvme',
|
|
658
|
+
iops: {
|
|
659
|
+
read: 7450,
|
|
660
|
+
write: 6900
|
|
661
|
+
},
|
|
662
|
+
health: 98
|
|
663
|
+
}
|
|
664
|
+
},
|
|
665
|
+
{
|
|
666
|
+
id: 'sata-ssd',
|
|
667
|
+
title: 'Secondary SSD',
|
|
668
|
+
value: 0,
|
|
669
|
+
type: 'disk',
|
|
670
|
+
icon: 'lucide:hard-drive',
|
|
671
|
+
diskData: {
|
|
672
|
+
capacity: 1_000_000_000_000, // 1 TB
|
|
673
|
+
model: 'Crucial MX500',
|
|
674
|
+
type: 'ssd',
|
|
675
|
+
iops: {
|
|
676
|
+
read: 560,
|
|
677
|
+
write: 510
|
|
678
|
+
},
|
|
679
|
+
health: 85
|
|
680
|
+
}
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
id: 'hdd-storage',
|
|
684
|
+
title: 'Backup HDD',
|
|
685
|
+
value: 0,
|
|
686
|
+
type: 'disk',
|
|
687
|
+
icon: 'lucide:archive',
|
|
688
|
+
diskData: {
|
|
689
|
+
capacity: 8_000_000_000_000, // 8 TB
|
|
690
|
+
model: 'Seagate IronWolf',
|
|
691
|
+
type: 'hdd',
|
|
692
|
+
iops: {
|
|
693
|
+
read: 210,
|
|
694
|
+
write: 195
|
|
695
|
+
},
|
|
696
|
+
health: 42
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
]}
|
|
700
|
+
.minTileWidth=${280}
|
|
701
|
+
.gap=${16}
|
|
702
|
+
></dees-statsgrid>
|
|
703
|
+
|
|
704
|
+
<div class="tile-config">
|
|
705
|
+
<div class="config-section">
|
|
706
|
+
<div class="config-title">Partition Tile Properties</div>
|
|
707
|
+
<div class="config-description">
|
|
708
|
+
<ul style="margin: 8px 0; padding-left: 20px;">
|
|
709
|
+
<li><strong>partitionData.used:</strong> Used space in bytes (auto-formatted)</li>
|
|
710
|
+
<li><strong>partitionData.total:</strong> Total capacity in bytes</li>
|
|
711
|
+
<li><strong>partitionData.filesystem:</strong> Filesystem type (ext4, xfs, ntfs)</li>
|
|
712
|
+
<li><strong>partitionData.mountPoint:</strong> Mount point path (optional)</li>
|
|
713
|
+
</ul>
|
|
714
|
+
Color thresholds: Normal (<75%), Warning (75-90%), Critical (>90%)
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
<div class="config-section">
|
|
718
|
+
<div class="config-title">Disk Tile Properties</div>
|
|
719
|
+
<div class="config-description">
|
|
720
|
+
<ul style="margin: 8px 0; padding-left: 20px;">
|
|
721
|
+
<li><strong>diskData.capacity:</strong> Total capacity in bytes</li>
|
|
722
|
+
<li><strong>diskData.model:</strong> Disk model name (optional)</li>
|
|
723
|
+
<li><strong>diskData.type:</strong> Disk type: 'ssd', 'hdd', or 'nvme'</li>
|
|
724
|
+
<li><strong>diskData.iops:</strong> Read/write IOPS (optional)</li>
|
|
725
|
+
<li><strong>diskData.health:</strong> Health percentage 0-100 (optional)</li>
|
|
726
|
+
</ul>
|
|
727
|
+
Health thresholds: Good (70-100%), Warning (30-70%), Critical (<30%)
|
|
728
|
+
</div>
|
|
729
|
+
</div>
|
|
730
|
+
</div>
|
|
731
|
+
</dees-panel>
|
|
604
732
|
</div>
|
|
605
|
-
|
|
733
|
+
|
|
606
734
|
<script>
|
|
607
735
|
// Cleanup live updates on page unload
|
|
608
736
|
window.addEventListener('beforeunload', () => {
|
|
@@ -30,12 +30,30 @@ export interface ICpuCore {
|
|
|
30
30
|
label?: string;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export interface IPartitionData {
|
|
34
|
+
used: number; // bytes
|
|
35
|
+
total: number; // bytes
|
|
36
|
+
filesystem: string; // e.g., 'ext4', 'NTFS', 'btrfs'
|
|
37
|
+
mountPoint?: string; // e.g., '/', '/home', 'C:'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface IDiskData {
|
|
41
|
+
capacity: number; // bytes
|
|
42
|
+
model?: string; // e.g., 'Samsung 970 EVO Plus'
|
|
43
|
+
type?: 'ssd' | 'hdd' | 'nvme';
|
|
44
|
+
iops?: {
|
|
45
|
+
read: number;
|
|
46
|
+
write: number;
|
|
47
|
+
};
|
|
48
|
+
health?: number; // 0-100 (100 = new, 0 = end of life)
|
|
49
|
+
}
|
|
50
|
+
|
|
33
51
|
export interface IStatsTile {
|
|
34
52
|
id: string;
|
|
35
53
|
title: string;
|
|
36
54
|
value: number | string;
|
|
37
55
|
unit?: string;
|
|
38
|
-
type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text' | 'multiPercentage' | 'cpuCores';
|
|
56
|
+
type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text' | 'multiPercentage' | 'cpuCores' | 'partition' | 'disk';
|
|
39
57
|
|
|
40
58
|
// Layout options
|
|
41
59
|
columnSpan?: number; // Number of columns to span (default: 1)
|
|
@@ -60,6 +78,12 @@ export interface IStatsTile {
|
|
|
60
78
|
// For cpuCores type
|
|
61
79
|
coresData?: ICpuCore[];
|
|
62
80
|
|
|
81
|
+
// For partition type
|
|
82
|
+
partitionData?: IPartitionData;
|
|
83
|
+
|
|
84
|
+
// For disk type
|
|
85
|
+
diskData?: IDiskData;
|
|
86
|
+
|
|
63
87
|
// Visual customization
|
|
64
88
|
color?: string;
|
|
65
89
|
icon?: string;
|
|
@@ -485,6 +509,219 @@ export class DeesStatsGrid extends DeesElement {
|
|
|
485
509
|
max-width: 100%;
|
|
486
510
|
}
|
|
487
511
|
|
|
512
|
+
/* Partition Styles */
|
|
513
|
+
.partition-wrapper {
|
|
514
|
+
width: 100%;
|
|
515
|
+
display: flex;
|
|
516
|
+
flex-direction: column;
|
|
517
|
+
flex: 1;
|
|
518
|
+
gap: 8px;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
.partition-header {
|
|
522
|
+
display: flex;
|
|
523
|
+
align-items: baseline;
|
|
524
|
+
gap: 8px;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.partition-percentage {
|
|
528
|
+
font-size: var(--value-font-size);
|
|
529
|
+
font-weight: 600;
|
|
530
|
+
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
|
531
|
+
line-height: 1.1;
|
|
532
|
+
letter-spacing: -0.025em;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.partition-bar {
|
|
536
|
+
width: 100%;
|
|
537
|
+
height: 6px;
|
|
538
|
+
background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')};
|
|
539
|
+
border-radius: 3px;
|
|
540
|
+
overflow: hidden;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
.partition-bar-fill {
|
|
544
|
+
height: 100%;
|
|
545
|
+
background: ${cssManager.bdTheme('#333333', '#e0e0e0')};
|
|
546
|
+
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
|
547
|
+
border-radius: 3px;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.partition-bar-fill.warning {
|
|
551
|
+
background: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')};
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.partition-bar-fill.critical {
|
|
555
|
+
background: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 84.2% 60.2%)')};
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.partition-stats {
|
|
559
|
+
display: flex;
|
|
560
|
+
justify-content: space-between;
|
|
561
|
+
align-items: center;
|
|
562
|
+
margin-top: auto;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.partition-stat {
|
|
566
|
+
display: flex;
|
|
567
|
+
flex-direction: column;
|
|
568
|
+
gap: 2px;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.partition-stat-label {
|
|
572
|
+
font-size: 10px;
|
|
573
|
+
font-weight: 500;
|
|
574
|
+
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
|
|
575
|
+
text-transform: uppercase;
|
|
576
|
+
letter-spacing: 0.02em;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.partition-stat-value {
|
|
580
|
+
font-size: 13px;
|
|
581
|
+
font-weight: 600;
|
|
582
|
+
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
|
583
|
+
letter-spacing: -0.01em;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.partition-meta {
|
|
587
|
+
display: flex;
|
|
588
|
+
align-items: center;
|
|
589
|
+
gap: 6px;
|
|
590
|
+
margin-top: 4px;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.partition-filesystem {
|
|
594
|
+
font-size: 11px;
|
|
595
|
+
font-weight: 500;
|
|
596
|
+
color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
|
|
597
|
+
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
|
|
598
|
+
padding: 2px 6px;
|
|
599
|
+
border-radius: 3px;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.partition-mountpoint {
|
|
603
|
+
font-size: 11px;
|
|
604
|
+
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/* Disk Styles */
|
|
608
|
+
.disk-wrapper {
|
|
609
|
+
width: 100%;
|
|
610
|
+
display: flex;
|
|
611
|
+
flex-direction: column;
|
|
612
|
+
flex: 1;
|
|
613
|
+
gap: 8px;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.disk-capacity {
|
|
617
|
+
font-size: var(--value-font-size);
|
|
618
|
+
font-weight: 600;
|
|
619
|
+
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
|
620
|
+
line-height: 1.1;
|
|
621
|
+
letter-spacing: -0.025em;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.disk-model {
|
|
625
|
+
font-size: 12px;
|
|
626
|
+
color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
|
|
627
|
+
display: flex;
|
|
628
|
+
align-items: center;
|
|
629
|
+
gap: 6px;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.disk-type-badge {
|
|
633
|
+
font-size: 10px;
|
|
634
|
+
font-weight: 600;
|
|
635
|
+
text-transform: uppercase;
|
|
636
|
+
color: ${cssManager.bdTheme('hsl(215.4 16.3% 46.9%)', 'hsl(215 20.2% 65.1%)')};
|
|
637
|
+
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
|
|
638
|
+
padding: 2px 6px;
|
|
639
|
+
border-radius: 3px;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.disk-metrics {
|
|
643
|
+
display: flex;
|
|
644
|
+
flex-direction: column;
|
|
645
|
+
gap: 8px;
|
|
646
|
+
margin-top: auto;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
.disk-iops {
|
|
650
|
+
display: flex;
|
|
651
|
+
align-items: center;
|
|
652
|
+
gap: 12px;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.disk-iops-item {
|
|
656
|
+
display: flex;
|
|
657
|
+
align-items: baseline;
|
|
658
|
+
gap: 4px;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.disk-iops-label {
|
|
662
|
+
font-size: 10px;
|
|
663
|
+
font-weight: 500;
|
|
664
|
+
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
|
|
665
|
+
text-transform: uppercase;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.disk-iops-value {
|
|
669
|
+
font-size: 13px;
|
|
670
|
+
font-weight: 600;
|
|
671
|
+
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.disk-health {
|
|
675
|
+
display: flex;
|
|
676
|
+
flex-direction: column;
|
|
677
|
+
gap: 4px;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.disk-health-header {
|
|
681
|
+
display: flex;
|
|
682
|
+
justify-content: space-between;
|
|
683
|
+
align-items: baseline;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.disk-health-label {
|
|
687
|
+
font-size: 10px;
|
|
688
|
+
font-weight: 500;
|
|
689
|
+
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
|
|
690
|
+
text-transform: uppercase;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.disk-health-value {
|
|
694
|
+
font-size: 12px;
|
|
695
|
+
font-weight: 600;
|
|
696
|
+
color: ${cssManager.bdTheme('hsl(215.3 25% 8.8%)', 'hsl(210 40% 98%)')};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.disk-health-bar {
|
|
700
|
+
width: 100%;
|
|
701
|
+
height: 4px;
|
|
702
|
+
background: ${cssManager.bdTheme('#e8e8e8', '#1a1a1a')};
|
|
703
|
+
border-radius: 2px;
|
|
704
|
+
overflow: hidden;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.disk-health-fill {
|
|
708
|
+
height: 100%;
|
|
709
|
+
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
|
710
|
+
border-radius: 2px;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.disk-health-fill.good {
|
|
714
|
+
background: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
.disk-health-fill.warning {
|
|
718
|
+
background: ${cssManager.bdTheme('hsl(45.4 93.4% 47.5%)', 'hsl(45.4 93.4% 47.5%)')};
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.disk-health-fill.critical {
|
|
722
|
+
background: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 84.2% 60.2%)')};
|
|
723
|
+
}
|
|
724
|
+
|
|
488
725
|
/* Trend Styles */
|
|
489
726
|
.trend-container {
|
|
490
727
|
width: 100%;
|
|
@@ -659,6 +896,12 @@ export class DeesStatsGrid extends DeesElement {
|
|
|
659
896
|
case 'cpuCores':
|
|
660
897
|
return this.renderCpuCores(tile);
|
|
661
898
|
|
|
899
|
+
case 'partition':
|
|
900
|
+
return this.renderPartition(tile);
|
|
901
|
+
|
|
902
|
+
case 'disk':
|
|
903
|
+
return this.renderDisk(tile);
|
|
904
|
+
|
|
662
905
|
case 'text':
|
|
663
906
|
return html`
|
|
664
907
|
<div class="text-value" style="${tile.color ? `color: ${tile.color}` : ''}">
|
|
@@ -876,6 +1119,114 @@ export class DeesStatsGrid extends DeesElement {
|
|
|
876
1119
|
`;
|
|
877
1120
|
}
|
|
878
1121
|
|
|
1122
|
+
private formatBytes(bytes: number): string {
|
|
1123
|
+
if (bytes === 0) return '0 B';
|
|
1124
|
+
const k = 1024;
|
|
1125
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
1126
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1127
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
private renderPartition(tile: IStatsTile): TemplateResult {
|
|
1131
|
+
if (!tile.partitionData) {
|
|
1132
|
+
return html`<div class="tile-value">${tile.value}</div>`;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
const { used, total, filesystem, mountPoint } = tile.partitionData;
|
|
1136
|
+
const percentage = Math.min(100, Math.max(0, (used / total) * 100));
|
|
1137
|
+
const free = total - used;
|
|
1138
|
+
|
|
1139
|
+
// Determine color class based on usage
|
|
1140
|
+
const getColorClass = (): string => {
|
|
1141
|
+
if (percentage >= 90) return 'critical';
|
|
1142
|
+
if (percentage >= 75) return 'warning';
|
|
1143
|
+
return '';
|
|
1144
|
+
};
|
|
1145
|
+
|
|
1146
|
+
return html`
|
|
1147
|
+
<div class="partition-wrapper">
|
|
1148
|
+
<div class="partition-header">
|
|
1149
|
+
<span class="partition-percentage">${Math.round(percentage)}%</span>
|
|
1150
|
+
</div>
|
|
1151
|
+
<div class="partition-bar">
|
|
1152
|
+
<div
|
|
1153
|
+
class="partition-bar-fill ${getColorClass()}"
|
|
1154
|
+
style="width: ${percentage}%"
|
|
1155
|
+
></div>
|
|
1156
|
+
</div>
|
|
1157
|
+
<div class="partition-stats">
|
|
1158
|
+
<div class="partition-stat">
|
|
1159
|
+
<span class="partition-stat-label">Used</span>
|
|
1160
|
+
<span class="partition-stat-value">${this.formatBytes(used)}</span>
|
|
1161
|
+
</div>
|
|
1162
|
+
<div class="partition-stat">
|
|
1163
|
+
<span class="partition-stat-label">Free</span>
|
|
1164
|
+
<span class="partition-stat-value">${this.formatBytes(free)}</span>
|
|
1165
|
+
</div>
|
|
1166
|
+
</div>
|
|
1167
|
+
<div class="partition-meta">
|
|
1168
|
+
<span class="partition-filesystem">${filesystem}</span>
|
|
1169
|
+
${mountPoint ? html`<span class="partition-mountpoint">${mountPoint}</span>` : ''}
|
|
1170
|
+
</div>
|
|
1171
|
+
</div>
|
|
1172
|
+
`;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
private renderDisk(tile: IStatsTile): TemplateResult {
|
|
1176
|
+
if (!tile.diskData) {
|
|
1177
|
+
return html`<div class="tile-value">${tile.value}</div>`;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
const { capacity, model, type, iops, health } = tile.diskData;
|
|
1181
|
+
|
|
1182
|
+
// Determine health color class (inverted - high is good)
|
|
1183
|
+
const getHealthClass = (value: number): string => {
|
|
1184
|
+
if (value >= 70) return 'good';
|
|
1185
|
+
if (value >= 30) return 'warning';
|
|
1186
|
+
return 'critical';
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
return html`
|
|
1190
|
+
<div class="disk-wrapper">
|
|
1191
|
+
<div class="disk-capacity">${this.formatBytes(capacity)}</div>
|
|
1192
|
+
${model || type ? html`
|
|
1193
|
+
<div class="disk-model">
|
|
1194
|
+
${model ? html`<span>${model}</span>` : ''}
|
|
1195
|
+
${type ? html`<span class="disk-type-badge">${type}</span>` : ''}
|
|
1196
|
+
</div>
|
|
1197
|
+
` : ''}
|
|
1198
|
+
<div class="disk-metrics">
|
|
1199
|
+
${iops ? html`
|
|
1200
|
+
<div class="disk-iops">
|
|
1201
|
+
<div class="disk-iops-item">
|
|
1202
|
+
<span class="disk-iops-label">Read</span>
|
|
1203
|
+
<span class="disk-iops-value">${iops.read.toLocaleString()}</span>
|
|
1204
|
+
</div>
|
|
1205
|
+
<div class="disk-iops-item">
|
|
1206
|
+
<span class="disk-iops-label">Write</span>
|
|
1207
|
+
<span class="disk-iops-value">${iops.write.toLocaleString()}</span>
|
|
1208
|
+
</div>
|
|
1209
|
+
</div>
|
|
1210
|
+
` : ''}
|
|
1211
|
+
${health !== undefined ? html`
|
|
1212
|
+
<div class="disk-health">
|
|
1213
|
+
<div class="disk-health-header">
|
|
1214
|
+
<span class="disk-health-label">Health</span>
|
|
1215
|
+
<span class="disk-health-value">${health}%</span>
|
|
1216
|
+
</div>
|
|
1217
|
+
<div class="disk-health-bar">
|
|
1218
|
+
<div
|
|
1219
|
+
class="disk-health-fill ${getHealthClass(health)}"
|
|
1220
|
+
style="width: ${health}%"
|
|
1221
|
+
></div>
|
|
1222
|
+
</div>
|
|
1223
|
+
</div>
|
|
1224
|
+
` : ''}
|
|
1225
|
+
</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
`;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
879
1230
|
private async handleGridAction(action: plugins.tsclass.website.IMenuItem) {
|
|
880
1231
|
if (action.action) {
|
|
881
1232
|
await action.action();
|
|
@@ -25,6 +25,24 @@ export interface IXtermFitAddonBundle {
|
|
|
25
25
|
FitAddon: typeof FitAddon;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Bundle type for xterm-addon-search
|
|
30
|
+
* SearchAddon is loaded from CDN, so we use a minimal interface
|
|
31
|
+
*/
|
|
32
|
+
export interface IXtermSearchAddonBundle {
|
|
33
|
+
SearchAddon: new () => IXtermSearchAddon;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Minimal interface for xterm SearchAddon
|
|
38
|
+
*/
|
|
39
|
+
export interface IXtermSearchAddon {
|
|
40
|
+
activate(terminal: Terminal): void;
|
|
41
|
+
dispose(): void;
|
|
42
|
+
findNext(term: string, searchOptions?: { regex?: boolean; wholeWord?: boolean; caseSensitive?: boolean; incremental?: boolean }): boolean;
|
|
43
|
+
findPrevious(term: string, searchOptions?: { regex?: boolean; wholeWord?: boolean; caseSensitive?: boolean; incremental?: boolean }): boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
28
46
|
/**
|
|
29
47
|
* Bundle type for Tiptap editor and extensions
|
|
30
48
|
*/
|
|
@@ -56,6 +74,7 @@ export class DeesServiceLibLoader {
|
|
|
56
74
|
// Cached library references
|
|
57
75
|
private xtermLib: IXtermBundle | null = null;
|
|
58
76
|
private xtermFitAddonLib: IXtermFitAddonBundle | null = null;
|
|
77
|
+
private xtermSearchAddonLib: IXtermSearchAddonBundle | null = null;
|
|
59
78
|
private highlightJsLib: HLJSApi | null = null;
|
|
60
79
|
private apexChartsLib: typeof ApexChartsType | null = null;
|
|
61
80
|
private tiptapLib: ITiptapBundle | null = null;
|
|
@@ -63,6 +82,7 @@ export class DeesServiceLibLoader {
|
|
|
63
82
|
// Loading promises to prevent duplicate concurrent loads
|
|
64
83
|
private xtermLoadingPromise: Promise<IXtermBundle> | null = null;
|
|
65
84
|
private xtermFitAddonLoadingPromise: Promise<IXtermFitAddonBundle> | null = null;
|
|
85
|
+
private xtermSearchAddonLoadingPromise: Promise<IXtermSearchAddonBundle> | null = null;
|
|
66
86
|
private highlightJsLoadingPromise: Promise<HLJSApi> | null = null;
|
|
67
87
|
private apexChartsLoadingPromise: Promise<typeof ApexChartsType> | null = null;
|
|
68
88
|
private tiptapLoadingPromise: Promise<ITiptapBundle> | null = null;
|
|
@@ -134,6 +154,32 @@ export class DeesServiceLibLoader {
|
|
|
134
154
|
return this.xtermFitAddonLoadingPromise;
|
|
135
155
|
}
|
|
136
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Load xterm-addon-search from CDN
|
|
159
|
+
* @returns Promise resolving to SearchAddon class
|
|
160
|
+
*/
|
|
161
|
+
public async loadXtermSearchAddon(): Promise<IXtermSearchAddonBundle> {
|
|
162
|
+
if (this.xtermSearchAddonLib) {
|
|
163
|
+
return this.xtermSearchAddonLib;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (this.xtermSearchAddonLoadingPromise) {
|
|
167
|
+
return this.xtermSearchAddonLoadingPromise;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.xtermSearchAddonLoadingPromise = (async () => {
|
|
171
|
+
const url = `${CDN_BASE}/xterm-addon-search@${CDN_VERSIONS.xtermAddonSearch}/+esm`;
|
|
172
|
+
const module = await import(/* @vite-ignore */ url);
|
|
173
|
+
|
|
174
|
+
this.xtermSearchAddonLib = {
|
|
175
|
+
SearchAddon: module.SearchAddon,
|
|
176
|
+
};
|
|
177
|
+
return this.xtermSearchAddonLib;
|
|
178
|
+
})();
|
|
179
|
+
|
|
180
|
+
return this.xtermSearchAddonLoadingPromise;
|
|
181
|
+
}
|
|
182
|
+
|
|
137
183
|
/**
|
|
138
184
|
* Inject xterm CSS styles into the document head
|
|
139
185
|
*/
|
|
@@ -257,6 +303,7 @@ export class DeesServiceLibLoader {
|
|
|
257
303
|
await Promise.all([
|
|
258
304
|
this.loadXterm(),
|
|
259
305
|
this.loadXtermFitAddon(),
|
|
306
|
+
this.loadXtermSearchAddon(),
|
|
260
307
|
this.loadHighlightJs(),
|
|
261
308
|
this.loadApexCharts(),
|
|
262
309
|
this.loadTiptap(),
|
|
@@ -266,12 +313,14 @@ export class DeesServiceLibLoader {
|
|
|
266
313
|
/**
|
|
267
314
|
* Check if a specific library is already loaded
|
|
268
315
|
*/
|
|
269
|
-
public isLoaded(library: 'xterm' | 'xtermFitAddon' | 'highlightJs' | 'apexCharts' | 'tiptap'): boolean {
|
|
316
|
+
public isLoaded(library: 'xterm' | 'xtermFitAddon' | 'xtermSearchAddon' | 'highlightJs' | 'apexCharts' | 'tiptap'): boolean {
|
|
270
317
|
switch (library) {
|
|
271
318
|
case 'xterm':
|
|
272
319
|
return this.xtermLib !== null;
|
|
273
320
|
case 'xtermFitAddon':
|
|
274
321
|
return this.xtermFitAddonLib !== null;
|
|
322
|
+
case 'xtermSearchAddon':
|
|
323
|
+
return this.xtermSearchAddonLib !== null;
|
|
275
324
|
case 'highlightJs':
|
|
276
325
|
return this.highlightJsLib !== null;
|
|
277
326
|
case 'apexCharts':
|
package/ts_web/services/index.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { DeesServiceLibLoader } from './DeesServiceLibLoader.js';
|
|
2
|
-
export type { IXtermBundle, IXtermFitAddonBundle, ITiptapBundle } from './DeesServiceLibLoader.js';
|
|
2
|
+
export type { IXtermBundle, IXtermFitAddonBundle, IXtermSearchAddonBundle, IXtermSearchAddon, ITiptapBundle } from './DeesServiceLibLoader.js';
|
|
3
3
|
export { CDN_BASE, CDN_VERSIONS } from './versions.js';
|