@worca/ui 0.2.0 → 0.3.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/app/styles.css CHANGED
@@ -3937,3 +3937,120 @@ sl-details.learnings-panel::part(content) {
3937
3937
  .project-worca-version { font-size: 11px; color: var(--muted); font-family: var(--sl-font-mono); margin-top: 2px; }
3938
3938
  .project-worca-version--behind { color: var(--status-failed, #dc2626); }
3939
3939
 
3940
+ /* ─── Bead tooltip content ──────────────────────────────────────────── */
3941
+ .bead-tooltip-content {
3942
+ max-width: 540px;
3943
+ padding: 4px 2px;
3944
+ display: flex;
3945
+ flex-direction: column;
3946
+ gap: 2px;
3947
+ }
3948
+
3949
+ .bead-tooltip-header {
3950
+ display: flex;
3951
+ align-items: center;
3952
+ justify-content: space-between;
3953
+ gap: 12px;
3954
+ }
3955
+
3956
+ sl-tooltip.bead-tooltip::part(body) {
3957
+ pointer-events: auto;
3958
+ }
3959
+
3960
+ .bead-tooltip-badges {
3961
+ display: flex;
3962
+ align-items: center;
3963
+ gap: 4px;
3964
+ }
3965
+
3966
+ .bead-tooltip-id {
3967
+ font-family: var(--sl-font-mono);
3968
+ font-size: 11px;
3969
+ opacity: 0.7;
3970
+ font-weight: 600;
3971
+ text-transform: uppercase;
3972
+ letter-spacing: 0.03em;
3973
+ }
3974
+
3975
+ .bead-tooltip-separator {
3976
+ border: none;
3977
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
3978
+ margin: 4px 0;
3979
+ }
3980
+
3981
+ .bead-tooltip-label {
3982
+ font-size: 11px;
3983
+ opacity: 0.7;
3984
+ font-weight: 600;
3985
+ text-transform: uppercase;
3986
+ letter-spacing: 0.03em;
3987
+ }
3988
+
3989
+ .bead-tooltip-title {
3990
+ font-weight: 600;
3991
+ font-size: 13px;
3992
+ margin-bottom: 4px;
3993
+ }
3994
+
3995
+ .bead-tooltip-excerpt {
3996
+ font-size: 12px;
3997
+ white-space: pre-wrap;
3998
+ margin-bottom: 2px;
3999
+ }
4000
+
4001
+ .bead-tooltip-footer {
4002
+ display: flex;
4003
+ justify-content: flex-end;
4004
+ margin-top: 6px;
4005
+ }
4006
+
4007
+ .bead-tooltip-copy {
4008
+ display: inline-flex;
4009
+ align-items: center;
4010
+ gap: 4px;
4011
+ background: rgba(255, 255, 255, 0.15);
4012
+ color: inherit;
4013
+ border: 1px solid rgba(255, 255, 255, 0.25);
4014
+ border-radius: 4px;
4015
+ padding: 3px 8px;
4016
+ font-size: 11px;
4017
+ cursor: pointer;
4018
+ transition: background 0.15s;
4019
+ }
4020
+
4021
+ .bead-tooltip-copy:hover {
4022
+ background: rgba(255, 255, 255, 0.25);
4023
+ }
4024
+
4025
+ /* ─── Graph node tooltip overlays ─────────────────────────────────── */
4026
+ .run-beads-graph {
4027
+ position: relative;
4028
+ }
4029
+
4030
+ .graph-tooltip-trigger {
4031
+ position: absolute;
4032
+ cursor: pointer;
4033
+ }
4034
+
4035
+ .bead-chip-tooltip {
4036
+ display: flex;
4037
+ flex-direction: column;
4038
+ gap: 3px;
4039
+ max-width: 240px;
4040
+ padding: 2px 0;
4041
+ }
4042
+
4043
+ .bead-chip-tooltip-id {
4044
+ font-family: var(--sl-font-mono);
4045
+ font-size: 12px;
4046
+ font-weight: 600;
4047
+ }
4048
+
4049
+ .bead-chip-tooltip-title {
4050
+ font-size: 12px;
4051
+ color: var(--muted);
4052
+ white-space: nowrap;
4053
+ overflow: hidden;
4054
+ text-overflow: ellipsis;
4055
+ }
4056
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worca/ui",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Pipeline monitoring UI for worca-cc",
5
5
  "license": "MIT",
6
6
  "author": "Sinisha Djukic",
package/server/watcher.js CHANGED
@@ -26,22 +26,9 @@ function isTerminal(status) {
26
26
  );
27
27
  }
28
28
 
29
- function isPipelineRunning(worcaDir) {
30
- const pidPath = join(worcaDir, 'pipeline.pid');
31
- if (!existsSync(pidPath)) return false;
32
- try {
33
- const pid = parseInt(readFileSync(pidPath, 'utf8').trim(), 10);
34
- process.kill(pid, 0); // signal 0 = check if alive
35
- return true;
36
- } catch {
37
- return false; // stale PID or unreadable
38
- }
39
- }
40
-
41
29
  export function discoverRuns(worcaDir) {
42
30
  const runs = [];
43
31
  const seenIds = new Set();
44
- const pipelineRunning = isPipelineRunning(worcaDir);
45
32
 
46
33
  // 1. Check active_run pointer for the current run
47
34
  const activeRunPath = join(worcaDir, 'active_run');
@@ -51,7 +38,8 @@ export function discoverRuns(worcaDir) {
51
38
  const candidate = join(worcaDir, 'runs', activeId, 'status.json');
52
39
  if (existsSync(candidate)) {
53
40
  const status = JSON.parse(readFileSync(candidate, 'utf8'));
54
- const active = !isTerminal(status) && pipelineRunning;
41
+ const active =
42
+ !isTerminal(status) && status.pipeline_status === 'running';
55
43
  const id = createRunId(status);
56
44
  runs.push({ id, active, ...status });
57
45
  seenIds.add(id);
@@ -88,7 +76,8 @@ export function discoverRuns(worcaDir) {
88
76
  const status = JSON.parse(readFileSync(statusPath, 'utf8'));
89
77
  const id = createRunId(status);
90
78
  if (!seenIds.has(id)) {
91
- const active = !isTerminal(status) && pipelineRunning;
79
+ const active =
80
+ !isTerminal(status) && status.pipeline_status === 'running';
92
81
  runs.push({ id, active, ...status });
93
82
  seenIds.add(id);
94
83
  }
@@ -142,7 +131,6 @@ export function discoverRuns(worcaDir) {
142
131
  export async function discoverRunsAsync(worcaDir) {
143
132
  const runs = [];
144
133
  const seenIds = new Set();
145
- const pipelineRunning = isPipelineRunning(worcaDir); // cheap check (one stat + one kill)
146
134
 
147
135
  // 1. Active run
148
136
  const activeRunPath = join(worcaDir, 'active_run');
@@ -150,7 +138,7 @@ export async function discoverRunsAsync(worcaDir) {
150
138
  const activeId = (await readFile(activeRunPath, 'utf8')).trim();
151
139
  const candidate = join(worcaDir, 'runs', activeId, 'status.json');
152
140
  const status = JSON.parse(await readFile(candidate, 'utf8'));
153
- const active = !isTerminal(status) && pipelineRunning;
141
+ const active = !isTerminal(status) && status.pipeline_status === 'running';
154
142
  const id = createRunId(status);
155
143
  runs.push({ id, active, ...status });
156
144
  seenIds.add(id);
@@ -191,7 +179,8 @@ export async function discoverRunsAsync(worcaDir) {
191
179
  );
192
180
  const id = createRunId(status);
193
181
  if (!seenIds.has(id)) {
194
- const active = !isTerminal(status) && pipelineRunning;
182
+ const active =
183
+ !isTerminal(status) && status.pipeline_status === 'running';
195
184
  runs.push({ id, active, ...status });
196
185
  seenIds.add(id);
197
186
  }