nuxt-devtools-observatory 0.1.28 → 0.1.30
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/README.md +30 -7
- package/client/dist/assets/index-BCaKoHBH.js +17 -0
- package/client/dist/assets/index-BmGW_M3W.css +1 -0
- package/client/dist/index.html +2 -2
- package/client/src/composables/useResizablePane.ts +65 -0
- package/client/src/stores/observatory.ts +12 -2
- package/client/src/style.css +203 -28
- package/client/src/views/ComposableTracker.vue +324 -259
- package/client/src/views/FetchDashboard.vue +104 -133
- package/client/src/views/ProvideInjectGraph.vue +99 -109
- package/client/src/views/RenderHeatmap.vue +191 -147
- package/client/src/views/TransitionTimeline.vue +166 -131
- package/client/tsconfig.json +3 -1
- package/client/vite.config.ts +8 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +156 -156
- package/dist/runtime/plugin.js +1 -1
- package/package.json +9 -6
- package/client/dist/assets/index-DXCGQOSF.js +0 -17
- package/client/dist/assets/index-htI4WwBU.css +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, computed, watch } from 'vue'
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import { useResizablePane } from '@observatory-client/composables/useResizablePane'
|
|
4
|
+
import { useObservatoryData, openInEditor as openInEditorFromStore } from '@observatory-client/stores/observatory'
|
|
5
|
+
import type { InjectEntry, ProvideEntry } from '@observatory/types/snapshot'
|
|
5
6
|
|
|
6
7
|
interface TreeNodeData {
|
|
7
8
|
id: string
|
|
@@ -46,6 +47,7 @@ const V_GAP = 72
|
|
|
46
47
|
const H_GAP = 18
|
|
47
48
|
|
|
48
49
|
const { provideInject, connected } = useObservatoryData()
|
|
50
|
+
const { paneWidth: detailWidth, onHandleMouseDown } = useResizablePane(280, 'observatory:provide:detailWidth')
|
|
49
51
|
|
|
50
52
|
function nodeColor(node: TreeNodeData): string {
|
|
51
53
|
if (node.injects.some((entry) => !entry.ok)) {
|
|
@@ -450,20 +452,20 @@ const edges = computed<Edge[]>(() => {
|
|
|
450
452
|
</script>
|
|
451
453
|
|
|
452
454
|
<template>
|
|
453
|
-
<div class="view">
|
|
454
|
-
<div class="toolbar">
|
|
455
|
+
<div class="provide-graph tracker-view">
|
|
456
|
+
<div class="provide-graph__toolbar tracker-toolbar">
|
|
455
457
|
<button :class="{ active: activeFilter === 'all' }" @click="activeFilter = 'all'">all keys</button>
|
|
456
458
|
<button
|
|
457
459
|
v-for="key in allKeys"
|
|
458
460
|
:key="key"
|
|
459
|
-
|
|
461
|
+
class="provide-graph__key-filter mono"
|
|
460
462
|
:class="{ active: activeFilter === key }"
|
|
461
463
|
@click="activeFilter = key"
|
|
462
464
|
>
|
|
463
465
|
{{ key }}
|
|
464
466
|
</button>
|
|
465
467
|
<button
|
|
466
|
-
|
|
468
|
+
class="provide-graph__toolbar-spacer"
|
|
467
469
|
:class="{ 'danger-active': activeFilter === 'shadow' }"
|
|
468
470
|
@click="activeFilter = activeFilter === 'shadow' ? 'all' : 'shadow'"
|
|
469
471
|
>
|
|
@@ -472,37 +474,37 @@ const edges = computed<Edge[]>(() => {
|
|
|
472
474
|
<button :class="{ 'danger-active': activeFilter === 'warn' }" @click="activeFilter = activeFilter === 'warn' ? 'all' : 'warn'">
|
|
473
475
|
warnings
|
|
474
476
|
</button>
|
|
475
|
-
<input v-model="searchQuery" type="search" placeholder="search component or key…"
|
|
477
|
+
<input v-model="searchQuery" type="search" class="provide-graph__search" placeholder="search component or key…" />
|
|
476
478
|
</div>
|
|
477
479
|
|
|
478
|
-
<div class="split">
|
|
479
|
-
<div class="
|
|
480
|
-
<div class="
|
|
481
|
-
<span class="dot
|
|
480
|
+
<div class="provide-graph__split tracker-split">
|
|
481
|
+
<div class="provide-graph__graph-area">
|
|
482
|
+
<div class="provide-graph__legend">
|
|
483
|
+
<span class="provide-graph__legend-dot provide-graph__legend-dot--provides"></span>
|
|
482
484
|
<span>provides</span>
|
|
483
|
-
<span class="dot
|
|
485
|
+
<span class="provide-graph__legend-dot provide-graph__legend-dot--both"></span>
|
|
484
486
|
<span>both</span>
|
|
485
|
-
<span class="dot
|
|
487
|
+
<span class="provide-graph__legend-dot provide-graph__legend-dot--injects"></span>
|
|
486
488
|
<span>injects</span>
|
|
487
|
-
<span class="dot
|
|
489
|
+
<span class="provide-graph__legend-dot provide-graph__legend-dot--missing"></span>
|
|
488
490
|
<span>missing provider</span>
|
|
489
491
|
</div>
|
|
490
|
-
<div v-if="layout.length" class="
|
|
491
|
-
<div class="
|
|
492
|
-
<svg class="
|
|
492
|
+
<div v-if="layout.length" class="provide-graph__canvas-stage">
|
|
493
|
+
<div class="provide-graph__canvas-wrap" :style="{ width: `${canvasW}px`, height: `${canvasH}px` }">
|
|
494
|
+
<svg class="provide-graph__edges-svg" :width="canvasW" :height="canvasH" :viewBox="`0 0 ${canvasW} ${canvasH}`">
|
|
493
495
|
<path
|
|
494
496
|
v-for="edge in edges"
|
|
495
497
|
:key="edge.id"
|
|
496
498
|
:d="`M ${edge.x1},${edge.y1} C ${edge.x1},${(edge.y1 + edge.y2) / 2} ${edge.x2},${(edge.y1 + edge.y2) / 2} ${edge.x2},${edge.y2}`"
|
|
497
|
-
class="
|
|
499
|
+
class="provide-graph__edge"
|
|
498
500
|
fill="none"
|
|
499
501
|
/>
|
|
500
502
|
</svg>
|
|
501
503
|
<div
|
|
502
504
|
v-for="layoutNode in layout"
|
|
503
505
|
:key="layoutNode.data.id"
|
|
504
|
-
class="
|
|
505
|
-
:class="{ '
|
|
506
|
+
class="provide-graph__node"
|
|
507
|
+
:class="{ 'provide-graph__node--selected': selectedNode?.id === layoutNode.data.id }"
|
|
506
508
|
:style="{
|
|
507
509
|
left: `${layoutNode.x - NODE_W / 2}px`,
|
|
508
510
|
top: `${layoutNode.y - NODE_H / 2}px`,
|
|
@@ -511,8 +513,8 @@ const edges = computed<Edge[]>(() => {
|
|
|
511
513
|
}"
|
|
512
514
|
@click="selectedNode = layoutNode.data"
|
|
513
515
|
>
|
|
514
|
-
<span class="
|
|
515
|
-
<span class="mono
|
|
516
|
+
<span class="provide-graph__node-dot" :style="{ background: nodeColor(layoutNode.data) }"></span>
|
|
517
|
+
<span class="mono provide-graph__node-label">{{ layoutNode.data.label }}</span>
|
|
516
518
|
<span v-if="layoutNode.data.provides.length" class="badge badge-ok badge-xs">
|
|
517
519
|
+{{ layoutNode.data.provides.length }}
|
|
518
520
|
</span>
|
|
@@ -520,14 +522,16 @@ const edges = computed<Edge[]>(() => {
|
|
|
520
522
|
</div>
|
|
521
523
|
</div>
|
|
522
524
|
</div>
|
|
523
|
-
<div v-else class="
|
|
525
|
+
<div v-else class="provide-graph__graph-empty">
|
|
524
526
|
{{ connected ? 'No components match the current provide/inject filter.' : 'Waiting for connection to the Nuxt app…' }}
|
|
525
527
|
</div>
|
|
526
528
|
</div>
|
|
527
529
|
|
|
528
|
-
<div v-if="selectedNode" class="
|
|
529
|
-
|
|
530
|
-
|
|
530
|
+
<div v-if="selectedNode" class="tracker-resize-handle" @mousedown="onHandleMouseDown" />
|
|
531
|
+
|
|
532
|
+
<div v-if="selectedNode" class="provide-graph__detail tracker-detail-panel" :style="{ width: detailWidth + 'px' }">
|
|
533
|
+
<div class="provide-graph__detail-header">
|
|
534
|
+
<span class="provide-graph__detail-title mono bold">{{ selectedNode.label }}</span>
|
|
531
535
|
<button
|
|
532
536
|
v-if="selectedNode.componentFile && selectedNode.componentFile !== 'unknown'"
|
|
533
537
|
class="jump-btn"
|
|
@@ -540,7 +544,7 @@ const edges = computed<Edge[]>(() => {
|
|
|
540
544
|
</div>
|
|
541
545
|
|
|
542
546
|
<div v-if="selectedNode.provides.length" class="detail-section">
|
|
543
|
-
<div class="section-label">provides ({{ selectedNode.provides.length }})</div>
|
|
547
|
+
<div class="tracker-section-label provide-graph__section-label">provides ({{ selectedNode.provides.length }})</div>
|
|
544
548
|
<div class="detail-list">
|
|
545
549
|
<div
|
|
546
550
|
v-for="(entry, index) in selectedNode.provides"
|
|
@@ -570,7 +574,7 @@ const edges = computed<Edge[]>(() => {
|
|
|
570
574
|
<span v-for="name in entry.consumerNames" :key="name" class="consumer-chip mono">{{ name }}</span>
|
|
571
575
|
<span v-if="!entry.consumerNames.length" class="muted text-sm">no consumers</span>
|
|
572
576
|
</div>
|
|
573
|
-
<div v-else class="muted text-sm"
|
|
577
|
+
<div v-else class="provide-graph__compact-muted muted text-sm">no consumers detected</div>
|
|
574
578
|
<pre
|
|
575
579
|
v-if="entry.complex && expandedProvideValues.has(provideValueId(selectedNode.id, entry.key, index))"
|
|
576
580
|
class="value-box"
|
|
@@ -585,7 +589,7 @@ const edges = computed<Edge[]>(() => {
|
|
|
585
589
|
class="detail-section"
|
|
586
590
|
:style="{ marginTop: selectedNode.provides.length ? '10px' : '0' }"
|
|
587
591
|
>
|
|
588
|
-
<div class="section-label">injects ({{ selectedNode.injects.length }})</div>
|
|
592
|
+
<div class="tracker-section-label provide-graph__section-label">injects ({{ selectedNode.injects.length }})</div>
|
|
589
593
|
<div class="detail-list">
|
|
590
594
|
<div
|
|
591
595
|
v-for="entry in selectedNode.injects"
|
|
@@ -603,11 +607,11 @@ const edges = computed<Edge[]>(() => {
|
|
|
603
607
|
</div>
|
|
604
608
|
</div>
|
|
605
609
|
|
|
606
|
-
<div v-if="!selectedNode.provides.length && !selectedNode.injects.length" class="muted text-sm"
|
|
610
|
+
<div v-if="!selectedNode.provides.length && !selectedNode.injects.length" class="provide-graph__empty-detail muted text-sm">
|
|
607
611
|
no provide/inject in this component
|
|
608
612
|
</div>
|
|
609
613
|
</div>
|
|
610
|
-
<div v-else class="detail-empty">
|
|
614
|
+
<div v-else class="tracker-detail-empty">
|
|
611
615
|
{{ connected ? 'Click a node to inspect.' : 'Waiting for connection to the Nuxt app…' }}
|
|
612
616
|
</div>
|
|
613
617
|
</div>
|
|
@@ -615,57 +619,40 @@ const edges = computed<Edge[]>(() => {
|
|
|
615
619
|
</template>
|
|
616
620
|
|
|
617
621
|
<style scoped>
|
|
618
|
-
.
|
|
619
|
-
|
|
620
|
-
flex-direction: column;
|
|
621
|
-
height: 100%;
|
|
622
|
-
overflow: hidden;
|
|
623
|
-
padding: 12px;
|
|
624
|
-
gap: 10px;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
.toolbar {
|
|
628
|
-
display: flex;
|
|
629
|
-
align-items: center;
|
|
630
|
-
gap: 6px;
|
|
631
|
-
flex-shrink: 0;
|
|
632
|
-
flex-wrap: wrap;
|
|
622
|
+
.provide-graph__toolbar-spacer {
|
|
623
|
+
margin-left: auto;
|
|
633
624
|
}
|
|
634
625
|
|
|
635
|
-
.
|
|
636
|
-
|
|
637
|
-
gap: 12px;
|
|
638
|
-
flex: 1;
|
|
639
|
-
overflow: hidden;
|
|
640
|
-
min-height: 0;
|
|
626
|
+
.provide-graph__search {
|
|
627
|
+
max-width: 200px;
|
|
641
628
|
}
|
|
642
629
|
|
|
643
|
-
.
|
|
630
|
+
.provide-graph__graph-area {
|
|
644
631
|
flex: 1;
|
|
645
632
|
overflow: auto;
|
|
646
|
-
border:
|
|
633
|
+
border: var(--tracker-border-width) solid var(--border);
|
|
647
634
|
border-radius: var(--radius-lg);
|
|
648
|
-
padding:
|
|
635
|
+
padding: var(--tracker-space-3);
|
|
649
636
|
background: var(--bg3);
|
|
650
637
|
}
|
|
651
638
|
|
|
652
|
-
.
|
|
639
|
+
.provide-graph__legend {
|
|
653
640
|
display: flex;
|
|
654
641
|
align-items: center;
|
|
655
|
-
gap:
|
|
656
|
-
font-size:
|
|
642
|
+
gap: var(--tracker-space-3);
|
|
643
|
+
font-size: var(--tracker-font-size-sm);
|
|
657
644
|
color: var(--text2);
|
|
658
|
-
margin-bottom:
|
|
645
|
+
margin-bottom: var(--tracker-space-3);
|
|
659
646
|
}
|
|
660
647
|
|
|
661
|
-
.
|
|
648
|
+
.provide-graph__canvas-stage {
|
|
662
649
|
display: flex;
|
|
663
650
|
justify-content: center;
|
|
664
651
|
align-items: flex-start;
|
|
665
652
|
min-width: 100%;
|
|
666
653
|
}
|
|
667
654
|
|
|
668
|
-
.dot {
|
|
655
|
+
.provide-graph__legend-dot {
|
|
669
656
|
width: 8px;
|
|
670
657
|
height: 8px;
|
|
671
658
|
border-radius: 50%;
|
|
@@ -673,23 +660,39 @@ const edges = computed<Edge[]>(() => {
|
|
|
673
660
|
margin-right: 2px;
|
|
674
661
|
}
|
|
675
662
|
|
|
676
|
-
.
|
|
663
|
+
.provide-graph__legend-dot--provides {
|
|
664
|
+
background: var(--teal);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.provide-graph__legend-dot--both {
|
|
668
|
+
background: var(--blue);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.provide-graph__legend-dot--injects {
|
|
672
|
+
background: var(--text3);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.provide-graph__legend-dot--missing {
|
|
676
|
+
background: var(--red);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.provide-graph__canvas-wrap {
|
|
677
680
|
position: relative;
|
|
678
681
|
}
|
|
679
682
|
|
|
680
|
-
.
|
|
683
|
+
.provide-graph__edges-svg {
|
|
681
684
|
position: absolute;
|
|
682
685
|
top: 0;
|
|
683
686
|
left: 0;
|
|
684
687
|
pointer-events: none;
|
|
685
688
|
}
|
|
686
689
|
|
|
687
|
-
.
|
|
690
|
+
.provide-graph__edge {
|
|
688
691
|
stroke: var(--border);
|
|
689
692
|
stroke-width: 1.5;
|
|
690
693
|
}
|
|
691
694
|
|
|
692
|
-
.
|
|
695
|
+
.provide-graph__node {
|
|
693
696
|
position: absolute;
|
|
694
697
|
display: flex;
|
|
695
698
|
align-items: center;
|
|
@@ -697,35 +700,35 @@ const edges = computed<Edge[]>(() => {
|
|
|
697
700
|
padding: 0 10px;
|
|
698
701
|
height: 32px;
|
|
699
702
|
border-radius: var(--radius);
|
|
700
|
-
border:
|
|
703
|
+
border: var(--tracker-border-width) solid var(--border);
|
|
701
704
|
background: var(--bg3);
|
|
702
705
|
cursor: pointer;
|
|
703
706
|
transition:
|
|
704
|
-
border-color
|
|
705
|
-
background
|
|
707
|
+
border-color var(--tracker-transition-fast),
|
|
708
|
+
background var(--tracker-transition-fast);
|
|
706
709
|
overflow: hidden;
|
|
707
710
|
box-sizing: border-box;
|
|
708
711
|
white-space: nowrap;
|
|
709
712
|
}
|
|
710
713
|
|
|
711
|
-
.
|
|
714
|
+
.provide-graph__node:hover {
|
|
712
715
|
border-color: var(--text3);
|
|
713
716
|
}
|
|
714
717
|
|
|
715
|
-
.
|
|
718
|
+
.provide-graph__node--selected {
|
|
716
719
|
border-color: var(--node-color);
|
|
717
720
|
background: color-mix(in srgb, var(--node-color) 8%, transparent);
|
|
718
721
|
}
|
|
719
722
|
|
|
720
|
-
.
|
|
723
|
+
.provide-graph__node-dot {
|
|
721
724
|
width: 7px;
|
|
722
725
|
height: 7px;
|
|
723
726
|
border-radius: 50%;
|
|
724
727
|
flex-shrink: 0;
|
|
725
728
|
}
|
|
726
729
|
|
|
727
|
-
.
|
|
728
|
-
font-size:
|
|
730
|
+
.provide-graph__node-label {
|
|
731
|
+
font-size: var(--tracker-font-size-sm);
|
|
729
732
|
flex: 1;
|
|
730
733
|
overflow: hidden;
|
|
731
734
|
text-overflow: ellipsis;
|
|
@@ -736,54 +739,32 @@ const edges = computed<Edge[]>(() => {
|
|
|
736
739
|
padding: 1px 4px;
|
|
737
740
|
}
|
|
738
741
|
|
|
739
|
-
.
|
|
740
|
-
width: 280px;
|
|
741
|
-
flex-shrink: 0;
|
|
742
|
-
overflow: auto;
|
|
743
|
-
border: 0.5px solid var(--border);
|
|
744
|
-
border-radius: var(--radius-lg);
|
|
745
|
-
padding: 12px;
|
|
746
|
-
background: var(--bg3);
|
|
747
|
-
display: flex;
|
|
748
|
-
flex-direction: column;
|
|
749
|
-
gap: 4px;
|
|
742
|
+
.provide-graph__detail {
|
|
750
743
|
min-height: 0;
|
|
744
|
+
gap: var(--tracker-space-1);
|
|
751
745
|
}
|
|
752
746
|
|
|
753
|
-
.
|
|
754
|
-
width: 280px;
|
|
755
|
-
display: flex;
|
|
756
|
-
align-items: center;
|
|
757
|
-
justify-content: center;
|
|
758
|
-
color: var(--text3);
|
|
759
|
-
font-size: 12px;
|
|
760
|
-
border: 0.5px dashed var(--border);
|
|
761
|
-
border-radius: var(--radius-lg);
|
|
762
|
-
flex-shrink: 0;
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
.graph-empty {
|
|
747
|
+
.provide-graph__graph-empty {
|
|
766
748
|
display: flex;
|
|
767
749
|
align-items: center;
|
|
768
750
|
justify-content: center;
|
|
769
751
|
min-height: 180px;
|
|
770
752
|
color: var(--text3);
|
|
771
|
-
font-size:
|
|
753
|
+
font-size: var(--tracker-font-size-md);
|
|
772
754
|
}
|
|
773
755
|
|
|
774
|
-
.
|
|
756
|
+
.provide-graph__detail-header {
|
|
775
757
|
display: flex;
|
|
776
758
|
align-items: center;
|
|
777
759
|
justify-content: space-between;
|
|
778
|
-
margin-bottom:
|
|
760
|
+
margin-bottom: var(--tracker-gap-toolbar);
|
|
779
761
|
}
|
|
780
762
|
|
|
781
|
-
.
|
|
782
|
-
font-size:
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
color: var(--text3);
|
|
763
|
+
.provide-graph__detail-title {
|
|
764
|
+
font-size: var(--tracker-font-size-md);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.provide-graph__section-label {
|
|
787
768
|
margin: 8px 0 5px;
|
|
788
769
|
}
|
|
789
770
|
|
|
@@ -798,7 +779,6 @@ const edges = computed<Edge[]>(() => {
|
|
|
798
779
|
flex-direction: column;
|
|
799
780
|
gap: 3px;
|
|
800
781
|
overflow: auto;
|
|
801
|
-
max-height: 220px;
|
|
802
782
|
padding-right: 2px;
|
|
803
783
|
}
|
|
804
784
|
|
|
@@ -813,11 +793,20 @@ const edges = computed<Edge[]>(() => {
|
|
|
813
793
|
}
|
|
814
794
|
|
|
815
795
|
.row-warning {
|
|
816
|
-
font-size:
|
|
796
|
+
font-size: var(--tracker-font-size-sm);
|
|
817
797
|
color: var(--amber);
|
|
818
798
|
padding: 2px 0;
|
|
819
799
|
}
|
|
820
800
|
|
|
801
|
+
.provide-graph__compact-muted {
|
|
802
|
+
padding: 2px 0;
|
|
803
|
+
font-size: var(--tracker-font-size-sm);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.provide-graph__empty-detail {
|
|
807
|
+
margin-top: var(--tracker-space-2);
|
|
808
|
+
}
|
|
809
|
+
|
|
821
810
|
.row-consumers {
|
|
822
811
|
display: flex;
|
|
823
812
|
flex-wrap: wrap;
|
|
@@ -862,7 +851,8 @@ const edges = computed<Edge[]>(() => {
|
|
|
862
851
|
.row-main {
|
|
863
852
|
display: flex;
|
|
864
853
|
align-items: center;
|
|
865
|
-
|
|
854
|
+
flex-wrap: wrap;
|
|
855
|
+
gap: 4px 8px;
|
|
866
856
|
min-width: 0;
|
|
867
857
|
}
|
|
868
858
|
|