project-logbook 1.1.0 → 1.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/README.md +5 -0
- package/dist/commands/build.js +7 -4
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/log.js +2 -0
- package/dist/commands/log.js.map +1 -1
- package/dist/commands/new-helpers.d.ts +25 -0
- package/dist/commands/new-helpers.js +106 -0
- package/dist/commands/new-helpers.js.map +1 -0
- package/dist/commands/new.js +91 -92
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/release.js +2 -0
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/start.d.ts +1 -1
- package/dist/commands/start.js +154 -42
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.js +3 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts +15 -0
- package/dist/commands/watch.js +153 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/autolink.d.ts +5 -0
- package/dist/lib/autolink.js +36 -2
- package/dist/lib/autolink.js.map +1 -1
- package/dist/lib/build-helpers.d.ts +12 -3
- package/dist/lib/build-helpers.js +70 -65
- package/dist/lib/build-helpers.js.map +1 -1
- package/dist/lib/build-steps.js +2 -1
- package/dist/lib/build-steps.js.map +1 -1
- package/dist/lib/config.d.ts +8 -0
- package/dist/lib/config.js +7 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/custom-card-renderer.js +2 -1
- package/dist/lib/custom-card-renderer.js.map +1 -1
- package/dist/lib/entry-href.d.ts +7 -0
- package/dist/lib/entry-href.js +8 -0
- package/dist/lib/entry-href.js.map +1 -0
- package/dist/lib/markdown-processors.d.ts +6 -2
- package/dist/lib/markdown-processors.js +9 -7
- package/dist/lib/markdown-processors.js.map +1 -1
- package/dist/lib/post-template.js +3 -3
- package/dist/lib/post-template.js.map +1 -1
- package/dist/lib/template-helpers.js +3 -2
- package/dist/lib/template-helpers.js.map +1 -1
- package/dist/lib/template-types.d.ts +2 -0
- package/dist/lib/templates.js +5 -3
- package/dist/lib/templates.js.map +1 -1
- package/dist/linters/jira-prefix.js +32 -16
- package/dist/linters/jira-prefix.js.map +1 -1
- package/dist/templates/CONTRIBUTING.md +35 -3
- package/dist/templates/about-watch.md +29 -0
- package/dist/templates/adr.md +34 -0
- package/dist/templates/hub.css +677 -0
- package/dist/templates/hub.js +628 -0
- package/dist/templates/index.md +5 -4
- package/dist/templates/steer.txt +14 -1
- package/dist/utils/id.d.ts +1 -1
- package/dist/utils/id.js +4 -1
- package/dist/utils/id.js.map +1 -1
- package/dist/utils/prompt.d.ts +6 -0
- package/dist/utils/prompt.js +59 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/watch/collector.d.ts +14 -0
- package/dist/watch/collector.js +33 -0
- package/dist/watch/collector.js.map +1 -0
- package/dist/watch/collectors/acli.d.ts +15 -0
- package/dist/watch/collectors/acli.js +197 -0
- package/dist/watch/collectors/acli.js.map +1 -0
- package/dist/watch/collectors/entries.d.ts +9 -0
- package/dist/watch/collectors/entries.js +90 -0
- package/dist/watch/collectors/entries.js.map +1 -0
- package/dist/watch/collectors/git.d.ts +12 -0
- package/dist/watch/collectors/git.js +58 -0
- package/dist/watch/collectors/git.js.map +1 -0
- package/dist/watch/collectors/glab.d.ts +10 -0
- package/dist/watch/collectors/glab.js +184 -0
- package/dist/watch/collectors/glab.js.map +1 -0
- package/dist/watch/collectors/index.d.ts +10 -0
- package/dist/watch/collectors/index.js +21 -0
- package/dist/watch/collectors/index.js.map +1 -0
- package/dist/watch/collectors/jira.d.ts +3 -0
- package/dist/watch/collectors/jira.js +110 -0
- package/dist/watch/collectors/jira.js.map +1 -0
- package/dist/watch/collectors/type-guards.d.ts +17 -0
- package/dist/watch/collectors/type-guards.js +35 -0
- package/dist/watch/collectors/type-guards.js.map +1 -0
- package/dist/watch/collectors/types.d.ts +37 -0
- package/dist/watch/collectors/types.js +9 -0
- package/dist/watch/collectors/types.js.map +1 -0
- package/dist/watch/dashboard-html.d.ts +11 -0
- package/dist/watch/dashboard-html.js +73 -0
- package/dist/watch/dashboard-html.js.map +1 -0
- package/dist/watch/dashboard-script.d.ts +12 -0
- package/dist/watch/dashboard-script.js +20 -0
- package/dist/watch/dashboard-script.js.map +1 -0
- package/dist/watch/dashboard-styles.d.ts +12 -0
- package/dist/watch/dashboard-styles.js +20 -0
- package/dist/watch/dashboard-styles.js.map +1 -0
- package/dist/watch/dashboard.d.ts +12 -0
- package/dist/watch/dashboard.js +50 -0
- package/dist/watch/dashboard.js.map +1 -0
- package/dist/watch/git-utils.d.ts +30 -0
- package/dist/watch/git-utils.js +101 -0
- package/dist/watch/git-utils.js.map +1 -0
- package/dist/watch/hub-state.d.ts +37 -0
- package/dist/watch/hub-state.js +55 -0
- package/dist/watch/hub-state.js.map +1 -0
- package/dist/watch/hub.d.ts +2 -0
- package/dist/watch/hub.js +219 -0
- package/dist/watch/hub.js.map +1 -0
- package/dist/watch/log-utils.d.ts +13 -0
- package/dist/watch/log-utils.js +24 -0
- package/dist/watch/log-utils.js.map +1 -0
- package/dist/watch/notify.d.ts +18 -0
- package/dist/watch/notify.js +45 -0
- package/dist/watch/notify.js.map +1 -0
- package/dist/watch/state.d.ts +34 -0
- package/dist/watch/state.js +36 -0
- package/dist/watch/state.js.map +1 -0
- package/dist/watch/strategies/behind-default.d.ts +5 -0
- package/dist/watch/strategies/behind-default.js +21 -0
- package/dist/watch/strategies/behind-default.js.map +1 -0
- package/dist/watch/strategies/idle.d.ts +5 -0
- package/dist/watch/strategies/idle.js +21 -0
- package/dist/watch/strategies/idle.js.map +1 -0
- package/dist/watch/strategies/in-progress.d.ts +5 -0
- package/dist/watch/strategies/in-progress.js +21 -0
- package/dist/watch/strategies/in-progress.js.map +1 -0
- package/dist/watch/strategies/index.d.ts +34 -0
- package/dist/watch/strategies/index.js +148 -0
- package/dist/watch/strategies/index.js.map +1 -0
- package/dist/watch/strategies/jira-not-in-review.d.ts +2 -0
- package/dist/watch/strategies/jira-not-in-review.js +29 -0
- package/dist/watch/strategies/jira-not-in-review.js.map +1 -0
- package/dist/watch/strategies/jira-still-open.d.ts +2 -0
- package/dist/watch/strategies/jira-still-open.js +31 -0
- package/dist/watch/strategies/jira-still-open.js.map +1 -0
- package/dist/watch/strategies/mr-approval-optional.d.ts +5 -0
- package/dist/watch/strategies/mr-approval-optional.js +21 -0
- package/dist/watch/strategies/mr-approval-optional.js.map +1 -0
- package/dist/watch/strategies/mr-approved.d.ts +5 -0
- package/dist/watch/strategies/mr-approved.js +21 -0
- package/dist/watch/strategies/mr-approved.js.map +1 -0
- package/dist/watch/strategies/mr-conflicts.d.ts +5 -0
- package/dist/watch/strategies/mr-conflicts.js +21 -0
- package/dist/watch/strategies/mr-conflicts.js.map +1 -0
- package/dist/watch/strategies/mr-draft.d.ts +5 -0
- package/dist/watch/strategies/mr-draft.js +21 -0
- package/dist/watch/strategies/mr-draft.js.map +1 -0
- package/dist/watch/strategies/mr-open-comments.d.ts +5 -0
- package/dist/watch/strategies/mr-open-comments.js +21 -0
- package/dist/watch/strategies/mr-open-comments.js.map +1 -0
- package/dist/watch/strategies/narrative-missing.d.ts +5 -0
- package/dist/watch/strategies/narrative-missing.js +21 -0
- package/dist/watch/strategies/narrative-missing.js.map +1 -0
- package/dist/watch/strategies/no-mr.d.ts +5 -0
- package/dist/watch/strategies/no-mr.js +21 -0
- package/dist/watch/strategies/no-mr.js.map +1 -0
- package/dist/watch/strategies/pipeline-failed.d.ts +5 -0
- package/dist/watch/strategies/pipeline-failed.js +21 -0
- package/dist/watch/strategies/pipeline-failed.js.map +1 -0
- package/dist/watch/strategies/pipeline-running.d.ts +5 -0
- package/dist/watch/strategies/pipeline-running.js +21 -0
- package/dist/watch/strategies/pipeline-running.js.map +1 -0
- package/dist/watch/strategies/ready-for-release.d.ts +7 -0
- package/dist/watch/strategies/ready-for-release.js +35 -0
- package/dist/watch/strategies/ready-for-release.js.map +1 -0
- package/dist/watch/strategies/ready-to-commit.d.ts +5 -0
- package/dist/watch/strategies/ready-to-commit.js +21 -0
- package/dist/watch/strategies/ready-to-commit.js.map +1 -0
- package/dist/watch/strategies/ready-to-push.d.ts +5 -0
- package/dist/watch/strategies/ready-to-push.js +21 -0
- package/dist/watch/strategies/ready-to-push.js.map +1 -0
- package/dist/watch/strategies/released.d.ts +6 -0
- package/dist/watch/strategies/released.js +21 -0
- package/dist/watch/strategies/released.js.map +1 -0
- package/dist/watch/strategies/squash-merged.d.ts +6 -0
- package/dist/watch/strategies/squash-merged.js +21 -0
- package/dist/watch/strategies/squash-merged.js.map +1 -0
- package/dist/watch/strategies/types.d.ts +31 -0
- package/dist/watch/strategies/types.js +12 -0
- package/dist/watch/strategies/types.js.map +1 -0
- package/dist/watch/strategies/unstaged-changes.d.ts +5 -0
- package/dist/watch/strategies/unstaged-changes.js +21 -0
- package/dist/watch/strategies/unstaged-changes.js.map +1 -0
- package/dist/watch/strategies/wrong-branch.d.ts +6 -0
- package/dist/watch/strategies/wrong-branch.js +26 -0
- package/dist/watch/strategies/wrong-branch.js.map +1 -0
- package/dist/watch/types.d.ts +190 -0
- package/dist/watch/types.js +25 -0
- package/dist/watch/types.js.map +1 -0
- package/dist/watch/watcher-fs.d.ts +39 -0
- package/dist/watch/watcher-fs.js +105 -0
- package/dist/watch/watcher-fs.js.map +1 -0
- package/dist/watch/watcher-http.d.ts +19 -0
- package/dist/watch/watcher-http.js +47 -0
- package/dist/watch/watcher-http.js.map +1 -0
- package/dist/watch/watcher.d.ts +4 -0
- package/dist/watch/watcher.js +174 -0
- package/dist/watch/watcher.js.map +1 -0
- package/package.json +3 -2
- package/src/templates/CONTRIBUTING.md +35 -3
- package/src/templates/about-watch.md +29 -0
- package/src/templates/adr.md +34 -0
- package/src/templates/hub.css +677 -0
- package/src/templates/hub.js +628 -0
- package/src/templates/index.md +5 -4
- package/src/templates/steer.txt +14 -1
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitLab collector for logbook watch.
|
|
3
|
+
*
|
|
4
|
+
* Uses the `glab` CLI to query merge requests and pipeline status for the
|
|
5
|
+
* current branch. Runs on interval (30s) since it calls an external API.
|
|
6
|
+
*
|
|
7
|
+
* Falls back gracefully when `glab` is not installed or not authenticated.
|
|
8
|
+
*/
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
import { getCurrentBranch } from '../../lib/git-helpers.js';
|
|
11
|
+
import { getDefaultBranch } from '../../lib/git-helpers.js';
|
|
12
|
+
import { parsePipelineStatus } from './type-guards.js';
|
|
13
|
+
/** Check if glab CLI is available and authenticated. */
|
|
14
|
+
async function isGlabAvailable() {
|
|
15
|
+
try {
|
|
16
|
+
execSync('glab --version', {
|
|
17
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
18
|
+
});
|
|
19
|
+
// Check auth status — "glab auth status" exits 0 when logged in.
|
|
20
|
+
execSync('glab auth status', {
|
|
21
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
22
|
+
});
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Fetch MRs from glab for the current branch, returning parsed items. */
|
|
30
|
+
function fetchMrs(cwd) {
|
|
31
|
+
try {
|
|
32
|
+
const output = execSync('glab mr list --output json --state opened --per-page 100', {
|
|
33
|
+
encoding: 'utf8',
|
|
34
|
+
cwd,
|
|
35
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
36
|
+
}).trim();
|
|
37
|
+
if (!output)
|
|
38
|
+
return [];
|
|
39
|
+
const items = JSON.parse(output);
|
|
40
|
+
return items;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Fetch pipeline status for the current branch. */
|
|
47
|
+
function fetchPipelineStatus(cwd, branch) {
|
|
48
|
+
try {
|
|
49
|
+
const output = execSync(`glab ci status --branch "${branch}" --output json`, {
|
|
50
|
+
encoding: 'utf8',
|
|
51
|
+
cwd,
|
|
52
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
53
|
+
}).trim();
|
|
54
|
+
if (!output)
|
|
55
|
+
return 'none';
|
|
56
|
+
const parsed = JSON.parse(output);
|
|
57
|
+
return parsePipelineStatus(parsed.status);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return 'none';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Check if branch has recent running/failed pipelines via glab pipeline list. */
|
|
64
|
+
function hasRecentPipeline(cwd, branch, status) {
|
|
65
|
+
try {
|
|
66
|
+
const output = execSync(`glab pipeline list --branch "${branch}" --output json --per-page 5`, {
|
|
67
|
+
encoding: 'utf8',
|
|
68
|
+
cwd,
|
|
69
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
70
|
+
}).trim();
|
|
71
|
+
if (!output)
|
|
72
|
+
return false;
|
|
73
|
+
const pipelines = JSON.parse(output);
|
|
74
|
+
return pipelines.some((p) => p.status === status);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Determine MR status from a glab MR item. */
|
|
81
|
+
function determineMrStatus(mr, _branch) {
|
|
82
|
+
if (mr.state === 'merged')
|
|
83
|
+
return 'merged';
|
|
84
|
+
if (mr.state === 'closed')
|
|
85
|
+
return 'none';
|
|
86
|
+
// Draft check (GitLab 14+)
|
|
87
|
+
if (mr.draft === true)
|
|
88
|
+
return 'draft';
|
|
89
|
+
// Conflicts detection
|
|
90
|
+
if (mr.conflicts)
|
|
91
|
+
return 'open';
|
|
92
|
+
// Approval-based status
|
|
93
|
+
const approvalsLeft = mr.approvals_left ?? 0;
|
|
94
|
+
const approvalsRequired = mr.approvals_required ?? 0;
|
|
95
|
+
const changesRequested = (mr.reviewers ?? []).some((r) => r.state === 'CHANGED');
|
|
96
|
+
if (approvalsRequired > 0 && approvalsLeft === 0 && !changesRequested) {
|
|
97
|
+
return 'approved';
|
|
98
|
+
}
|
|
99
|
+
if (approvalsRequired === 0) {
|
|
100
|
+
return 'approval-optional';
|
|
101
|
+
}
|
|
102
|
+
if (changesRequested) {
|
|
103
|
+
return 'changes-requested';
|
|
104
|
+
}
|
|
105
|
+
// Open comments detection
|
|
106
|
+
if (mr.merge_status === 'cannot_be_merged') {
|
|
107
|
+
return 'open';
|
|
108
|
+
}
|
|
109
|
+
return 'open';
|
|
110
|
+
}
|
|
111
|
+
export const glabCollector = {
|
|
112
|
+
name: 'glab',
|
|
113
|
+
schedule: { type: 'interval', ms: 30_000 },
|
|
114
|
+
async available(_cwd) {
|
|
115
|
+
return isGlabAvailable();
|
|
116
|
+
},
|
|
117
|
+
async collect(cwd, state) {
|
|
118
|
+
const branch = getCurrentBranch(cwd);
|
|
119
|
+
if (!branch)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
const mrs = fetchMrs(cwd)
|
|
123
|
+
.filter((mr) => mr.source_branch === branch)
|
|
124
|
+
.sort((a, b) => b.iid - a.iid);
|
|
125
|
+
if (mrs.length === 0) {
|
|
126
|
+
state.mrStatus = 'none';
|
|
127
|
+
state.mrUrl = undefined;
|
|
128
|
+
state.mrTitle = undefined;
|
|
129
|
+
state.mrOpenThreads = undefined;
|
|
130
|
+
state.mrHasConflicts = undefined;
|
|
131
|
+
state.glabOpenMrs = [];
|
|
132
|
+
state.glabLastUpdated = new Date().toISOString();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const mr = mrs[0];
|
|
136
|
+
// Check pipeline status via mr head_pipeline first, fall back to ci status
|
|
137
|
+
if (mr.head_pipeline) {
|
|
138
|
+
state.pipelineStatus = parsePipelineStatus(mr.head_pipeline.status);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
state.pipelineStatus = fetchPipelineStatus(cwd, branch);
|
|
142
|
+
}
|
|
143
|
+
// Fallback: check for recent running/failed pipelines if head_pipeline is stale
|
|
144
|
+
if (state.pipelineStatus === 'none' || state.pipelineStatus === 'passed') {
|
|
145
|
+
const defaultBranch = getDefaultBranch(cwd);
|
|
146
|
+
if (branch !== defaultBranch) {
|
|
147
|
+
if (hasRecentPipeline(cwd, branch, 'running')) {
|
|
148
|
+
state.pipelineStatus = 'running';
|
|
149
|
+
}
|
|
150
|
+
else if (hasRecentPipeline(cwd, branch, 'failed')) {
|
|
151
|
+
state.pipelineStatus = 'failed';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
state.mrStatus = determineMrStatus(mr, branch);
|
|
156
|
+
state.mrUrl = mr.web_url;
|
|
157
|
+
state.mrTitle = mr.title;
|
|
158
|
+
state.mrHasConflicts = mr.conflicts;
|
|
159
|
+
// Count open threads (note_count - resolved)
|
|
160
|
+
state.mrOpenThreads = 0;
|
|
161
|
+
// Build full MR list for the GitLab tab (all open MRs for the project).
|
|
162
|
+
const allMrs = fetchMrs(cwd);
|
|
163
|
+
const projectUrl = allMrs[0]?.web_url ? allMrs[0].web_url.replace(/\/-\/merge_requests\/\d+$/, '') : '';
|
|
164
|
+
state.glabOpenMrs = allMrs.map((item) => ({
|
|
165
|
+
iid: item.iid,
|
|
166
|
+
title: item.title,
|
|
167
|
+
status: item.state,
|
|
168
|
+
comments: 0,
|
|
169
|
+
url: item.web_url,
|
|
170
|
+
sourceBranch: item.source_branch,
|
|
171
|
+
projectUrl: projectUrl ? projectUrl : item.web_url.replace(/\/-\/merge_requests\/\d+$/, ''),
|
|
172
|
+
projectName: projectUrl
|
|
173
|
+
.split('/')
|
|
174
|
+
.pop()
|
|
175
|
+
?.replace(/\.git$/, '') ?? '',
|
|
176
|
+
}));
|
|
177
|
+
state.glabLastUpdated = new Date().toISOString();
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Collector failed — state retains previous values.
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
//# sourceMappingURL=glab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glab.js","sourceRoot":"","sources":["../../../src/watch/collectors/glab.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collector registry for logbook watch.
|
|
3
|
+
*
|
|
4
|
+
* Exports all available collectors. The watcher runner checks `available()`
|
|
5
|
+
* for each and only activates those whose prerequisites are met.
|
|
6
|
+
*/
|
|
7
|
+
import type { Collector } from './types.js';
|
|
8
|
+
/** All registered collectors. */
|
|
9
|
+
/** acli takes priority over jira when both are available — order matters. */
|
|
10
|
+
export declare const ALL_COLLECTORS: Collector[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collector registry for logbook watch.
|
|
3
|
+
*
|
|
4
|
+
* Exports all available collectors. The watcher runner checks `available()`
|
|
5
|
+
* for each and only activates those whose prerequisites are met.
|
|
6
|
+
*/
|
|
7
|
+
import { gitCollector } from './git.js';
|
|
8
|
+
import { entriesCollector } from './entries.js';
|
|
9
|
+
import { glabCollector } from './glab.js';
|
|
10
|
+
import { acliCollector } from './acli.js';
|
|
11
|
+
import { jiraCollector } from './jira.js';
|
|
12
|
+
/** All registered collectors. */
|
|
13
|
+
/** acli takes priority over jira when both are available — order matters. */
|
|
14
|
+
export const ALL_COLLECTORS = [
|
|
15
|
+
gitCollector,
|
|
16
|
+
entriesCollector,
|
|
17
|
+
glabCollector,
|
|
18
|
+
acliCollector,
|
|
19
|
+
jiraCollector,
|
|
20
|
+
];
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/watch/collectors/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE1C,iCAAiC;AACjC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,YAAY;IACZ,gBAAgB;IAChB,aAAa;IACb,aAAa;IACb,aAAa;CACd,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/** HTTP Jira collector — fallback when acli is not available. */
|
|
2
|
+
import { request } from 'node:https';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import { getConfig } from '../../lib/config.js';
|
|
5
|
+
import { getCurrentBranch } from '../../lib/git-helpers.js';
|
|
6
|
+
import { extractTicketFromBranch } from '../git-utils.js';
|
|
7
|
+
import { isJiraIssue } from './type-guards.js';
|
|
8
|
+
function buildAssignedJql(accountId) {
|
|
9
|
+
return `assignee = "${accountId}" AND resolution = Unresolved ORDER BY updated DESC`;
|
|
10
|
+
}
|
|
11
|
+
function httpGet(url, token, timeout = 5000) {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
const req = request(url, { method: 'GET', headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' }, timeout }, (res) => {
|
|
14
|
+
const chunks = [];
|
|
15
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
16
|
+
res.on('end', () => {
|
|
17
|
+
if (res.statusCode !== 200) {
|
|
18
|
+
resolve(null);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
23
|
+
resolve(parsed);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
resolve(null);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
req.on('error', () => resolve(null));
|
|
31
|
+
req.on('timeout', () => {
|
|
32
|
+
req.destroy();
|
|
33
|
+
resolve(null);
|
|
34
|
+
});
|
|
35
|
+
req.end();
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function fetchMyself(baseUrl, token) {
|
|
39
|
+
return httpGet(new URL('/rest/api/3/myself', baseUrl), token, 5000);
|
|
40
|
+
}
|
|
41
|
+
function searchIssues(baseUrl, token, jql) {
|
|
42
|
+
const url = new URL('/rest/api/3/search', baseUrl);
|
|
43
|
+
url.searchParams.set('jql', jql);
|
|
44
|
+
url.searchParams.set('fields', 'summary,status,updated,assignee');
|
|
45
|
+
url.searchParams.set('maxResults', '50');
|
|
46
|
+
return httpGet(url, token, 10_000).then((body) => {
|
|
47
|
+
const issues = (body?.issues ?? []).filter(isJiraIssue);
|
|
48
|
+
return issues;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function fetchIssue(baseUrl, token, issueKey) {
|
|
52
|
+
const url = new URL(`/rest/api/3/issue/${issueKey}`, baseUrl);
|
|
53
|
+
url.searchParams.set('fields', 'summary,status,updated,assignee');
|
|
54
|
+
return httpGet(url, token, 5000).then((body) => (body && isJiraIssue(body) ? body : null));
|
|
55
|
+
}
|
|
56
|
+
function getJiraToken() {
|
|
57
|
+
return process.env.JIRA_API_TOKEN;
|
|
58
|
+
}
|
|
59
|
+
export const jiraCollector = {
|
|
60
|
+
name: 'jira',
|
|
61
|
+
schedule: { type: 'interval', ms: 60_000 },
|
|
62
|
+
async available(_cwd) {
|
|
63
|
+
if (!getJiraToken())
|
|
64
|
+
return false;
|
|
65
|
+
try {
|
|
66
|
+
execSync('which acli', { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
async collect(cwd, state) {
|
|
74
|
+
try {
|
|
75
|
+
const config = getConfig(cwd);
|
|
76
|
+
const baseUrl = config.jiraBaseUrl;
|
|
77
|
+
const token = getJiraToken();
|
|
78
|
+
if (!baseUrl || !token) {
|
|
79
|
+
state.jiraStatus = undefined;
|
|
80
|
+
state.jiraAssignedIssues = [];
|
|
81
|
+
state.jiraLastUpdated = new Date().toISOString();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const myself = await fetchMyself(baseUrl, token);
|
|
85
|
+
if (!myself) {
|
|
86
|
+
state.jiraAssignedIssues = [];
|
|
87
|
+
state.jiraLastUpdated = new Date().toISOString();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const rawIssues = await searchIssues(baseUrl, token, buildAssignedJql(myself.accountId));
|
|
91
|
+
state.jiraAssignedIssues = rawIssues.map((issue) => ({
|
|
92
|
+
key: issue.key,
|
|
93
|
+
summary: issue.fields.summary,
|
|
94
|
+
status: issue.fields.status.name,
|
|
95
|
+
url: `${baseUrl}/browse/${issue.key}`,
|
|
96
|
+
jiraBaseUrl: baseUrl,
|
|
97
|
+
updated: issue.fields.updated,
|
|
98
|
+
}));
|
|
99
|
+
const branch = getCurrentBranch(cwd);
|
|
100
|
+
const ticketKey = state.activeTicketId ?? (branch ? extractTicketFromBranch(branch, config.jiraPrefix) : undefined);
|
|
101
|
+
if (ticketKey) {
|
|
102
|
+
const issue = await fetchIssue(baseUrl, token, ticketKey);
|
|
103
|
+
state.jiraStatus = issue?.fields.status.name;
|
|
104
|
+
}
|
|
105
|
+
state.jiraLastUpdated = new Date().toISOString();
|
|
106
|
+
}
|
|
107
|
+
catch { }
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=jira.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira.js","sourceRoot":"","sources":["../../../src/watch/collectors/jira.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Type guards for GitLab and Jira API response types. */
|
|
2
|
+
interface JiraIssueRaw {
|
|
3
|
+
key: string;
|
|
4
|
+
fields: {
|
|
5
|
+
summary: string;
|
|
6
|
+
status: {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
updated: string;
|
|
10
|
+
assignee: {
|
|
11
|
+
displayName: string;
|
|
12
|
+
} | null;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function isJiraIssue(value: unknown): value is JiraIssueRaw;
|
|
16
|
+
export declare function parsePipelineStatus(status: string): 'running' | 'passed' | 'failed' | 'pending' | 'canceled' | 'none';
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Type guards for GitLab and Jira API response types. */
|
|
2
|
+
export function isJiraIssue(value) {
|
|
3
|
+
if (!value || typeof value !== 'object')
|
|
4
|
+
return false;
|
|
5
|
+
if (!('key' in value) || !('fields' in value))
|
|
6
|
+
return false;
|
|
7
|
+
if (typeof value.key !== 'string')
|
|
8
|
+
return false;
|
|
9
|
+
const fields = value.fields;
|
|
10
|
+
if (!fields || typeof fields !== 'object')
|
|
11
|
+
return false;
|
|
12
|
+
if (!('summary' in fields) || !('status' in fields))
|
|
13
|
+
return false;
|
|
14
|
+
if (typeof fields.summary !== 'string')
|
|
15
|
+
return false;
|
|
16
|
+
const status = fields.status;
|
|
17
|
+
if (!status || typeof status !== 'object')
|
|
18
|
+
return false;
|
|
19
|
+
return 'name' in status && typeof status.name === 'string';
|
|
20
|
+
}
|
|
21
|
+
export function parsePipelineStatus(status) {
|
|
22
|
+
const lower = status.toLowerCase();
|
|
23
|
+
if (lower === 'running')
|
|
24
|
+
return 'running';
|
|
25
|
+
if (lower === 'passed' || lower === 'success')
|
|
26
|
+
return 'passed';
|
|
27
|
+
if (lower === 'failed')
|
|
28
|
+
return 'failed';
|
|
29
|
+
if (lower === 'pending')
|
|
30
|
+
return 'pending';
|
|
31
|
+
if (lower === 'canceled')
|
|
32
|
+
return 'canceled';
|
|
33
|
+
return 'none';
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=type-guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-guards.js","sourceRoot":"","sources":["../../../src/watch/collectors/type-guards.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAY1D,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5D,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAChD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAC5B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACxD,OAAO,MAAM,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAC/D,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACxC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collector interface for logbook watch.
|
|
3
|
+
*
|
|
4
|
+
* A collector gathers a subset of metrics from a specific source (git, files,
|
|
5
|
+
* CLI tools, APIs). Each collector runs independently on its own schedule and
|
|
6
|
+
* writes its results into the shared WatcherState.
|
|
7
|
+
*/
|
|
8
|
+
import type { WatcherState } from '../state.js';
|
|
9
|
+
/** Schedule type for a collector. */
|
|
10
|
+
export type CollectorSchedule =
|
|
11
|
+
/** Runs on file-system events (instant, debounced). */
|
|
12
|
+
{
|
|
13
|
+
type: 'fs';
|
|
14
|
+
patterns: string[];
|
|
15
|
+
}
|
|
16
|
+
/** Runs on a fixed interval. */
|
|
17
|
+
| {
|
|
18
|
+
type: 'interval';
|
|
19
|
+
ms: number;
|
|
20
|
+
};
|
|
21
|
+
/** A collector that gathers metrics from a specific source. */
|
|
22
|
+
export interface Collector {
|
|
23
|
+
/** Human-readable name for logging. */
|
|
24
|
+
name: string;
|
|
25
|
+
/** When this collector should run. */
|
|
26
|
+
schedule: CollectorSchedule;
|
|
27
|
+
/**
|
|
28
|
+
* Check if this collector is available (e.g., CLI tool installed).
|
|
29
|
+
* Returns false if prerequisites are missing — collector will be skipped.
|
|
30
|
+
*/
|
|
31
|
+
available(cwd: string): Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* Collect metrics and write them into the shared state.
|
|
34
|
+
* Must not throw — failures should result in undefined/default values.
|
|
35
|
+
*/
|
|
36
|
+
collect(cwd: string, state: WatcherState): Promise<void>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collector interface for logbook watch.
|
|
3
|
+
*
|
|
4
|
+
* A collector gathers a subset of metrics from a specific source (git, files,
|
|
5
|
+
* CLI tools, APIs). Each collector runs independently on its own schedule and
|
|
6
|
+
* writes its results into the shared WatcherState.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/watch/collectors/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard HTML structure for logbook watch hub.
|
|
3
|
+
*
|
|
4
|
+
* Provides the page skeleton with tab navigation and content areas.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generate the HTML body structure with tab navigation.
|
|
8
|
+
*
|
|
9
|
+
* @param aboutHtml - Pre-rendered HTML content for the About tab.
|
|
10
|
+
*/
|
|
11
|
+
export declare function dashboardHtml(aboutHtml: string): string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard HTML structure for logbook watch hub.
|
|
3
|
+
*
|
|
4
|
+
* Provides the page skeleton with tab navigation and content areas.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generate the HTML body structure with tab navigation.
|
|
8
|
+
*
|
|
9
|
+
* @param aboutHtml - Pre-rendered HTML content for the About tab.
|
|
10
|
+
*/
|
|
11
|
+
export function dashboardHtml(aboutHtml) {
|
|
12
|
+
return `
|
|
13
|
+
<header>
|
|
14
|
+
<h1>Logbook Hub</h1>
|
|
15
|
+
</header>
|
|
16
|
+
<nav class="tab-bar">
|
|
17
|
+
<button class="tab-btn active" data-tab="projects">Local Projects <span class="tab-count" id="project-count">0</span></button>
|
|
18
|
+
<button class="tab-btn" data-tab="jira">Jira <span class="tab-count" id="jira-count">0</span></button>
|
|
19
|
+
<button class="tab-btn" data-tab="gitlab">GitLab <span class="tab-count" id="gitlab-count">0</span></button>
|
|
20
|
+
<button class="tab-btn" data-tab="help">Help</button>
|
|
21
|
+
<button class="tab-btn" data-tab="about">About</button>
|
|
22
|
+
</nav>
|
|
23
|
+
<div class="container">
|
|
24
|
+
<div id="tab-projects" class="tab-content active">
|
|
25
|
+
<div class="tab-header-row" style="justify-content: flex-end;">
|
|
26
|
+
<button class="sort-toggle" id="sort-toggle">Sort (Newest)</button>
|
|
27
|
+
</div>
|
|
28
|
+
<div id="projects" class="projects">
|
|
29
|
+
<div class="empty">Waiting for projects to connect...</div>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
<div id="tab-help" class="tab-content">
|
|
33
|
+
<h2 class="tab-heading">Status Badges Reference</h2>
|
|
34
|
+
<p class="tab-description">
|
|
35
|
+
These badges appear on project cards based on the current state of your code, merge requests, and Jira tickets.
|
|
36
|
+
Badges marked "blocked by" will not appear if the blocking badge is already active.
|
|
37
|
+
</p>
|
|
38
|
+
<table class="help-table">
|
|
39
|
+
<thead><tr><th>Badge</th><th>Source</th><th>Severity</th><th>Description</th><th>Blocked By</th></tr></thead>
|
|
40
|
+
<tbody id="help-table-body"><tr><td colspan="5" class="table-loading">Loading...</td></tr></tbody>
|
|
41
|
+
</table>
|
|
42
|
+
</div>
|
|
43
|
+
<div id="tab-about" class="tab-content">
|
|
44
|
+
<div class="about-content">${aboutHtml}</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div id="tab-jira" class="tab-content">
|
|
47
|
+
<div class="tab-header-row">
|
|
48
|
+
<h2 class="tab-heading">Assigned Jira Issues</h2>
|
|
49
|
+
<button class="sort-toggle" id="jira-sort-toggle">Sort (Updated)</button>
|
|
50
|
+
</div>
|
|
51
|
+
<div id="jira-issues-content">
|
|
52
|
+
<div class="placeholder-msg">No assigned Jira issues found.<br>Set the <code>JIRA_API_TOKEN</code> environment variable and connect a project with <code>jiraBaseUrl</code> configured.</div>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="tab-collector-footer" id="jira-tab-footer" style="display:none"></div>
|
|
55
|
+
</div>
|
|
56
|
+
<div id="tab-gitlab" class="tab-content">
|
|
57
|
+
<h2 class="tab-heading">Open Merge Requests</h2>
|
|
58
|
+
<div id="gitlab-mrs-content">
|
|
59
|
+
<div class="placeholder-msg">No open merge requests found.<br>Install the <code>glab</code> CLI and run <code>glab auth login</code> to connect.</div>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="tab-collector-footer" id="gitlab-tab-footer" style="display:none"></div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="connection-status" id="conn-status">connected</div>
|
|
65
|
+
<div class="lightbox" id="lightbox">
|
|
66
|
+
<div class="lightbox-content">
|
|
67
|
+
<button class="lightbox-close" id="lightbox-close">×</button>
|
|
68
|
+
<div class="lightbox-title" id="lightbox-title"></div>
|
|
69
|
+
<div class="lightbox-body" id="lightbox-body"></div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>`;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=dashboard-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-html.js","sourceRoot":"","sources":["../../src/watch/dashboard-html.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAgC0B,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;SA2BnC,CAAC;AACV,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard client-side JavaScript for logbook watch hub.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the static hub.js template file instead of embedding JavaScript
|
|
5
|
+
* in a TypeScript string literal.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Read and return the Hub JavaScript wrapped in a script tag.
|
|
9
|
+
*
|
|
10
|
+
* @returns A `<script>` element string with the full dashboard JS.
|
|
11
|
+
*/
|
|
12
|
+
export declare function dashboardScript(): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard client-side JavaScript for logbook watch hub.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the static hub.js template file instead of embedding JavaScript
|
|
5
|
+
* in a TypeScript string literal.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { getTemplatesDir } from '../lib/migrations.js';
|
|
10
|
+
/**
|
|
11
|
+
* Read and return the Hub JavaScript wrapped in a script tag.
|
|
12
|
+
*
|
|
13
|
+
* @returns A `<script>` element string with the full dashboard JS.
|
|
14
|
+
*/
|
|
15
|
+
export function dashboardScript() {
|
|
16
|
+
const jsPath = join(getTemplatesDir(), 'hub.js');
|
|
17
|
+
const js = readFileSync(jsPath, 'utf8');
|
|
18
|
+
return `<script>\n${js}\n</script>`;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=dashboard-script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-script.js","sourceRoot":"","sources":["../../src/watch/dashboard-script.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,aAAa,EAAE,aAAa,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard CSS styles for logbook watch hub.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the static hub.css template file instead of embedding CSS
|
|
5
|
+
* in a TypeScript string literal.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Read and return the Hub CSS wrapped in a style tag.
|
|
9
|
+
*
|
|
10
|
+
* @returns A `<style>` element string with the full dashboard CSS.
|
|
11
|
+
*/
|
|
12
|
+
export declare function dashboardStyles(): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard CSS styles for logbook watch hub.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the static hub.css template file instead of embedding CSS
|
|
5
|
+
* in a TypeScript string literal.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { getTemplatesDir } from '../lib/migrations.js';
|
|
10
|
+
/**
|
|
11
|
+
* Read and return the Hub CSS wrapped in a style tag.
|
|
12
|
+
*
|
|
13
|
+
* @returns A `<style>` element string with the full dashboard CSS.
|
|
14
|
+
*/
|
|
15
|
+
export function dashboardStyles() {
|
|
16
|
+
const cssPath = join(getTemplatesDir(), 'hub.css');
|
|
17
|
+
const css = readFileSync(cssPath, 'utf8');
|
|
18
|
+
return `<style>\n${css}\n</style>`;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=dashboard-styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-styles.js","sourceRoot":"","sources":["../../src/watch/dashboard-styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,YAAY,GAAG,YAAY,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard assembler for logbook watch hub.
|
|
3
|
+
*
|
|
4
|
+
* The "logbook Hub" is the web-based UI for `logbook watch` instances. It
|
|
5
|
+
* composes the full HTML page from separate style, script, and HTML modules.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Generate the full dashboard HTML document.
|
|
9
|
+
*
|
|
10
|
+
* @returns Complete HTML string for the dashboard page.
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateDashboardHtml(): Promise<string>;
|