elspais 0.11.2__py3-none-any.whl → 0.43.5__py3-none-any.whl
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.
- elspais/__init__.py +1 -10
- elspais/{sponsors/__init__.py → associates.py} +102 -56
- elspais/cli.py +366 -69
- elspais/commands/__init__.py +9 -3
- elspais/commands/analyze.py +118 -169
- elspais/commands/changed.py +12 -23
- elspais/commands/config_cmd.py +10 -13
- elspais/commands/edit.py +33 -13
- elspais/commands/example_cmd.py +319 -0
- elspais/commands/hash_cmd.py +161 -183
- elspais/commands/health.py +1177 -0
- elspais/commands/index.py +98 -115
- elspais/commands/init.py +99 -22
- elspais/commands/reformat_cmd.py +41 -433
- elspais/commands/rules_cmd.py +2 -2
- elspais/commands/trace.py +443 -324
- elspais/commands/validate.py +193 -411
- elspais/config/__init__.py +799 -5
- elspais/{core/content_rules.py → content_rules.py} +20 -2
- elspais/docs/cli/assertions.md +67 -0
- elspais/docs/cli/commands.md +304 -0
- elspais/docs/cli/config.md +262 -0
- elspais/docs/cli/format.md +66 -0
- elspais/docs/cli/git.md +45 -0
- elspais/docs/cli/health.md +190 -0
- elspais/docs/cli/hierarchy.md +60 -0
- elspais/docs/cli/ignore.md +72 -0
- elspais/docs/cli/mcp.md +245 -0
- elspais/docs/cli/quickstart.md +58 -0
- elspais/docs/cli/traceability.md +89 -0
- elspais/docs/cli/validation.md +96 -0
- elspais/graph/GraphNode.py +383 -0
- elspais/graph/__init__.py +40 -0
- elspais/graph/annotators.py +927 -0
- elspais/graph/builder.py +1886 -0
- elspais/graph/deserializer.py +248 -0
- elspais/graph/factory.py +284 -0
- elspais/graph/metrics.py +127 -0
- elspais/graph/mutations.py +161 -0
- elspais/graph/parsers/__init__.py +156 -0
- elspais/graph/parsers/code.py +213 -0
- elspais/graph/parsers/comments.py +112 -0
- elspais/graph/parsers/config_helpers.py +29 -0
- elspais/graph/parsers/heredocs.py +225 -0
- elspais/graph/parsers/journey.py +131 -0
- elspais/graph/parsers/remainder.py +79 -0
- elspais/graph/parsers/requirement.py +347 -0
- elspais/graph/parsers/results/__init__.py +6 -0
- elspais/graph/parsers/results/junit_xml.py +229 -0
- elspais/graph/parsers/results/pytest_json.py +313 -0
- elspais/graph/parsers/test.py +305 -0
- elspais/graph/relations.py +78 -0
- elspais/graph/serialize.py +216 -0
- elspais/html/__init__.py +8 -0
- elspais/html/generator.py +731 -0
- elspais/html/templates/trace_view.html.j2 +2151 -0
- elspais/mcp/__init__.py +45 -29
- elspais/mcp/__main__.py +5 -1
- elspais/mcp/file_mutations.py +138 -0
- elspais/mcp/server.py +1998 -244
- elspais/testing/__init__.py +3 -3
- elspais/testing/config.py +3 -0
- elspais/testing/mapper.py +1 -1
- elspais/testing/scanner.py +301 -12
- elspais/utilities/__init__.py +1 -0
- elspais/utilities/docs_loader.py +115 -0
- elspais/utilities/git.py +607 -0
- elspais/{core → utilities}/hasher.py +8 -22
- elspais/utilities/md_renderer.py +189 -0
- elspais/{core → utilities}/patterns.py +56 -51
- elspais/utilities/reference_config.py +626 -0
- elspais/validation/__init__.py +19 -0
- elspais/validation/format.py +264 -0
- {elspais-0.11.2.dist-info → elspais-0.43.5.dist-info}/METADATA +7 -4
- elspais-0.43.5.dist-info/RECORD +80 -0
- elspais/config/defaults.py +0 -179
- elspais/config/loader.py +0 -494
- elspais/core/__init__.py +0 -21
- elspais/core/git.py +0 -346
- elspais/core/models.py +0 -320
- elspais/core/parser.py +0 -639
- elspais/core/rules.py +0 -509
- elspais/mcp/context.py +0 -172
- elspais/mcp/serializers.py +0 -112
- elspais/reformat/__init__.py +0 -50
- elspais/reformat/detector.py +0 -112
- elspais/reformat/hierarchy.py +0 -247
- elspais/reformat/line_breaks.py +0 -218
- elspais/reformat/prompts.py +0 -133
- elspais/reformat/transformer.py +0 -266
- elspais/trace_view/__init__.py +0 -55
- elspais/trace_view/coverage.py +0 -183
- elspais/trace_view/generators/__init__.py +0 -12
- elspais/trace_view/generators/base.py +0 -334
- elspais/trace_view/generators/csv.py +0 -118
- elspais/trace_view/generators/markdown.py +0 -170
- elspais/trace_view/html/__init__.py +0 -33
- elspais/trace_view/html/generator.py +0 -1140
- elspais/trace_view/html/templates/base.html +0 -283
- elspais/trace_view/html/templates/components/code_viewer_modal.html +0 -14
- elspais/trace_view/html/templates/components/file_picker_modal.html +0 -20
- elspais/trace_view/html/templates/components/legend_modal.html +0 -69
- elspais/trace_view/html/templates/components/review_panel.html +0 -118
- elspais/trace_view/html/templates/partials/review/help/help-panel.json +0 -244
- elspais/trace_view/html/templates/partials/review/help/onboarding.json +0 -77
- elspais/trace_view/html/templates/partials/review/help/tooltips.json +0 -237
- elspais/trace_view/html/templates/partials/review/review-comments.js +0 -928
- elspais/trace_view/html/templates/partials/review/review-data.js +0 -961
- elspais/trace_view/html/templates/partials/review/review-help.js +0 -679
- elspais/trace_view/html/templates/partials/review/review-init.js +0 -177
- elspais/trace_view/html/templates/partials/review/review-line-numbers.js +0 -429
- elspais/trace_view/html/templates/partials/review/review-packages.js +0 -1029
- elspais/trace_view/html/templates/partials/review/review-position.js +0 -540
- elspais/trace_view/html/templates/partials/review/review-resize.js +0 -115
- elspais/trace_view/html/templates/partials/review/review-status.js +0 -659
- elspais/trace_view/html/templates/partials/review/review-sync.js +0 -992
- elspais/trace_view/html/templates/partials/review-styles.css +0 -2238
- elspais/trace_view/html/templates/partials/scripts.js +0 -1741
- elspais/trace_view/html/templates/partials/styles.css +0 -1756
- elspais/trace_view/models.py +0 -378
- elspais/trace_view/review/__init__.py +0 -63
- elspais/trace_view/review/branches.py +0 -1142
- elspais/trace_view/review/models.py +0 -1200
- elspais/trace_view/review/position.py +0 -591
- elspais/trace_view/review/server.py +0 -1032
- elspais/trace_view/review/status.py +0 -455
- elspais/trace_view/review/storage.py +0 -1343
- elspais/trace_view/scanning.py +0 -213
- elspais/trace_view/specs/README.md +0 -84
- elspais/trace_view/specs/tv-d00001-template-architecture.md +0 -36
- elspais/trace_view/specs/tv-d00002-css-extraction.md +0 -37
- elspais/trace_view/specs/tv-d00003-js-extraction.md +0 -43
- elspais/trace_view/specs/tv-d00004-build-embedding.md +0 -40
- elspais/trace_view/specs/tv-d00005-test-format.md +0 -78
- elspais/trace_view/specs/tv-d00010-review-data-models.md +0 -33
- elspais/trace_view/specs/tv-d00011-review-storage.md +0 -33
- elspais/trace_view/specs/tv-d00012-position-resolution.md +0 -33
- elspais/trace_view/specs/tv-d00013-git-branches.md +0 -31
- elspais/trace_view/specs/tv-d00014-review-api-server.md +0 -31
- elspais/trace_view/specs/tv-d00015-status-modifier.md +0 -27
- elspais/trace_view/specs/tv-d00016-js-integration.md +0 -33
- elspais/trace_view/specs/tv-p00001-html-generator.md +0 -33
- elspais/trace_view/specs/tv-p00002-review-system.md +0 -29
- elspais-0.11.2.dist-info/RECORD +0 -101
- {elspais-0.11.2.dist-info → elspais-0.43.5.dist-info}/WHEEL +0 -0
- {elspais-0.11.2.dist-info → elspais-0.43.5.dist-info}/entry_points.txt +0 -0
- {elspais-0.11.2.dist-info → elspais-0.43.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,679 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TraceView Review Help System
|
|
3
|
-
*
|
|
4
|
-
* Provides:
|
|
5
|
-
* - Contextual tooltips loaded from tooltips.json
|
|
6
|
-
* - Onboarding wizard loaded from onboarding.json
|
|
7
|
-
* - Help panel loaded from help-panel.json
|
|
8
|
-
*
|
|
9
|
-
* IMPLEMENTS REQUIREMENTS:
|
|
10
|
-
* REQ-tv-d00016: Review JavaScript Integration
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// Ensure TraceView.review namespace exists
|
|
14
|
-
window.TraceView = window.TraceView || {};
|
|
15
|
-
TraceView.review = TraceView.review || {};
|
|
16
|
-
|
|
17
|
-
(function(review) {
|
|
18
|
-
'use strict';
|
|
19
|
-
|
|
20
|
-
// Help data loaded from JSON files
|
|
21
|
-
let tooltipsData = null;
|
|
22
|
-
let onboardingData = null;
|
|
23
|
-
let helpPanelData = null;
|
|
24
|
-
|
|
25
|
-
// State
|
|
26
|
-
let onboardingStep = 0;
|
|
27
|
-
let helpPanelVisible = false;
|
|
28
|
-
|
|
29
|
-
// ==========================================================================
|
|
30
|
-
// Data Loading
|
|
31
|
-
// ==========================================================================
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Load help data from JSON files
|
|
35
|
-
* @param {string} baseUrl - Base URL for help files
|
|
36
|
-
*/
|
|
37
|
-
async function loadHelpData(baseUrl = '/help') {
|
|
38
|
-
try {
|
|
39
|
-
const [tooltipsResp, onboardingResp, helpPanelResp] = await Promise.all([
|
|
40
|
-
fetch(`${baseUrl}/tooltips.json`),
|
|
41
|
-
fetch(`${baseUrl}/onboarding.json`),
|
|
42
|
-
fetch(`${baseUrl}/help-panel.json`)
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
if (tooltipsResp.ok) {
|
|
46
|
-
tooltipsData = await tooltipsResp.json();
|
|
47
|
-
}
|
|
48
|
-
if (onboardingResp.ok) {
|
|
49
|
-
onboardingData = await onboardingResp.json();
|
|
50
|
-
}
|
|
51
|
-
if (helpPanelResp.ok) {
|
|
52
|
-
helpPanelData = await helpPanelResp.json();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
console.log('Help data loaded successfully');
|
|
56
|
-
} catch (e) {
|
|
57
|
-
console.warn('Failed to load help data:', e);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ==========================================================================
|
|
62
|
-
// Tooltips
|
|
63
|
-
// ==========================================================================
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Get tooltip content for an element
|
|
67
|
-
* @param {string} helpId - Help ID (e.g., "header.review-mode-toggle")
|
|
68
|
-
* @returns {object|null} Tooltip data with title and text
|
|
69
|
-
*/
|
|
70
|
-
function getTooltip(helpId) {
|
|
71
|
-
if (!tooltipsData?.tooltips) return null;
|
|
72
|
-
|
|
73
|
-
const parts = helpId.split('.');
|
|
74
|
-
if (parts.length !== 2) return null;
|
|
75
|
-
|
|
76
|
-
const [section, id] = parts;
|
|
77
|
-
return tooltipsData.tooltips[section]?.[id] || null;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Initialize tooltips for elements with data-help-id attribute
|
|
82
|
-
* @param {Element} container - Container to search within
|
|
83
|
-
*/
|
|
84
|
-
function initTooltips(container = document) {
|
|
85
|
-
container.querySelectorAll('[data-help-id]').forEach(el => {
|
|
86
|
-
const helpId = el.getAttribute('data-help-id');
|
|
87
|
-
const tooltip = getTooltip(helpId);
|
|
88
|
-
|
|
89
|
-
if (tooltip) {
|
|
90
|
-
// Set title attribute for native tooltip
|
|
91
|
-
el.setAttribute('title', `${tooltip.title}: ${tooltip.text}`);
|
|
92
|
-
|
|
93
|
-
// Add help indicator
|
|
94
|
-
if (!el.querySelector('.rs-help-indicator')) {
|
|
95
|
-
const indicator = document.createElement('span');
|
|
96
|
-
indicator.className = 'rs-help-indicator';
|
|
97
|
-
indicator.textContent = '?';
|
|
98
|
-
indicator.setAttribute('title', tooltip.text);
|
|
99
|
-
el.appendChild(indicator);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ==========================================================================
|
|
106
|
-
// Onboarding Wizard
|
|
107
|
-
// ==========================================================================
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Check if onboarding should be shown
|
|
111
|
-
* @returns {boolean} True if onboarding should be shown
|
|
112
|
-
*/
|
|
113
|
-
function shouldShowOnboarding() {
|
|
114
|
-
if (!onboardingData?.wizard) return false;
|
|
115
|
-
|
|
116
|
-
const settings = onboardingData.wizard.settings;
|
|
117
|
-
if (!settings.showOnFirstVisit) return false;
|
|
118
|
-
|
|
119
|
-
const storageKey = settings.storageKey || 'traceview-review-onboarding-complete';
|
|
120
|
-
return localStorage.getItem(storageKey) !== 'true';
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Show onboarding wizard
|
|
125
|
-
*/
|
|
126
|
-
function showOnboarding() {
|
|
127
|
-
if (!onboardingData?.wizard) {
|
|
128
|
-
console.warn('Onboarding data not loaded');
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
onboardingStep = 0;
|
|
133
|
-
renderOnboardingStep();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Render current onboarding step
|
|
138
|
-
*/
|
|
139
|
-
function renderOnboardingStep() {
|
|
140
|
-
const wizard = onboardingData.wizard;
|
|
141
|
-
const steps = wizard.steps;
|
|
142
|
-
|
|
143
|
-
// Remove any existing overlay
|
|
144
|
-
const existingOverlay = document.querySelector('.rs-onboarding-overlay');
|
|
145
|
-
if (existingOverlay) {
|
|
146
|
-
existingOverlay.remove();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Check if completed
|
|
150
|
-
if (onboardingStep >= steps.length) {
|
|
151
|
-
renderOnboardingCompletion();
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const step = steps[onboardingStep];
|
|
156
|
-
const overlay = document.createElement('div');
|
|
157
|
-
overlay.className = 'rs-onboarding-overlay';
|
|
158
|
-
|
|
159
|
-
overlay.innerHTML = `
|
|
160
|
-
<div class="rs-onboarding-modal rs-onboarding-${step.position || 'center'}">
|
|
161
|
-
<div class="rs-onboarding-header">
|
|
162
|
-
<span class="rs-onboarding-step-indicator">
|
|
163
|
-
Step ${onboardingStep + 1} of ${steps.length}
|
|
164
|
-
</span>
|
|
165
|
-
${wizard.settings.canSkip ? `
|
|
166
|
-
<button class="rs-btn rs-btn-link rs-onboarding-skip">Skip Tour</button>
|
|
167
|
-
` : ''}
|
|
168
|
-
</div>
|
|
169
|
-
<h3 class="rs-onboarding-title">${step.title}</h3>
|
|
170
|
-
<div class="rs-onboarding-content">
|
|
171
|
-
${formatMarkdownSimple(step.content)}
|
|
172
|
-
</div>
|
|
173
|
-
<div class="rs-onboarding-actions">
|
|
174
|
-
${step.buttons.back ? `
|
|
175
|
-
<button class="rs-btn rs-onboarding-back">${step.buttons.back}</button>
|
|
176
|
-
` : ''}
|
|
177
|
-
${step.buttons.next ? `
|
|
178
|
-
<button class="rs-btn rs-btn-primary rs-onboarding-next">${step.buttons.next}</button>
|
|
179
|
-
` : ''}
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
`;
|
|
183
|
-
|
|
184
|
-
document.body.appendChild(overlay);
|
|
185
|
-
|
|
186
|
-
// Highlight target element if specified
|
|
187
|
-
if (step.highlight) {
|
|
188
|
-
const target = document.querySelector(step.highlight);
|
|
189
|
-
if (target) {
|
|
190
|
-
target.classList.add('rs-onboarding-highlight');
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Bind events
|
|
195
|
-
overlay.querySelector('.rs-onboarding-next')?.addEventListener('click', nextOnboardingStep);
|
|
196
|
-
overlay.querySelector('.rs-onboarding-back')?.addEventListener('click', prevOnboardingStep);
|
|
197
|
-
overlay.querySelector('.rs-onboarding-skip')?.addEventListener('click', completeOnboarding);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Render onboarding completion screen
|
|
202
|
-
*/
|
|
203
|
-
function renderOnboardingCompletion() {
|
|
204
|
-
const completion = onboardingData.wizard.completion;
|
|
205
|
-
const overlay = document.createElement('div');
|
|
206
|
-
overlay.className = 'rs-onboarding-overlay';
|
|
207
|
-
|
|
208
|
-
overlay.innerHTML = `
|
|
209
|
-
<div class="rs-onboarding-modal rs-onboarding-center">
|
|
210
|
-
<h3 class="rs-onboarding-title">${completion.title}</h3>
|
|
211
|
-
<div class="rs-onboarding-content">
|
|
212
|
-
${formatMarkdownSimple(completion.content)}
|
|
213
|
-
</div>
|
|
214
|
-
<div class="rs-onboarding-actions">
|
|
215
|
-
<button class="rs-btn rs-btn-primary rs-onboarding-close">${completion.buttons.close}</button>
|
|
216
|
-
${completion.buttons.docs ? `
|
|
217
|
-
<button class="rs-btn rs-onboarding-docs">${completion.buttons.docs}</button>
|
|
218
|
-
` : ''}
|
|
219
|
-
</div>
|
|
220
|
-
</div>
|
|
221
|
-
`;
|
|
222
|
-
|
|
223
|
-
document.body.appendChild(overlay);
|
|
224
|
-
|
|
225
|
-
overlay.querySelector('.rs-onboarding-close')?.addEventListener('click', completeOnboarding);
|
|
226
|
-
overlay.querySelector('.rs-onboarding-docs')?.addEventListener('click', () => {
|
|
227
|
-
window.open('docs/traceview-review-user-guide.md', '_blank');
|
|
228
|
-
completeOnboarding();
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
function nextOnboardingStep() {
|
|
233
|
-
clearOnboardingHighlights();
|
|
234
|
-
onboardingStep++;
|
|
235
|
-
renderOnboardingStep();
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function prevOnboardingStep() {
|
|
239
|
-
clearOnboardingHighlights();
|
|
240
|
-
onboardingStep = Math.max(0, onboardingStep - 1);
|
|
241
|
-
renderOnboardingStep();
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function completeOnboarding() {
|
|
245
|
-
clearOnboardingHighlights();
|
|
246
|
-
const overlay = document.querySelector('.rs-onboarding-overlay');
|
|
247
|
-
if (overlay) {
|
|
248
|
-
overlay.remove();
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Mark as completed
|
|
252
|
-
const storageKey = onboardingData.wizard.settings.storageKey || 'traceview-review-onboarding-complete';
|
|
253
|
-
localStorage.setItem(storageKey, 'true');
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function clearOnboardingHighlights() {
|
|
257
|
-
document.querySelectorAll('.rs-onboarding-highlight').forEach(el => {
|
|
258
|
-
el.classList.remove('rs-onboarding-highlight');
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// ==========================================================================
|
|
263
|
-
// Help Panel
|
|
264
|
-
// ==========================================================================
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Toggle help panel visibility
|
|
268
|
-
*/
|
|
269
|
-
function toggleHelpPanel() {
|
|
270
|
-
if (helpPanelVisible) {
|
|
271
|
-
hideHelpPanel();
|
|
272
|
-
} else {
|
|
273
|
-
showHelpPanel();
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Show help panel
|
|
279
|
-
*/
|
|
280
|
-
function showHelpPanel() {
|
|
281
|
-
if (!helpPanelData?.helpPanel) {
|
|
282
|
-
console.warn('Help panel data not loaded');
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Remove existing panel
|
|
287
|
-
const existing = document.querySelector('.rs-help-panel');
|
|
288
|
-
if (existing) {
|
|
289
|
-
existing.remove();
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const panel = helpPanelData.helpPanel;
|
|
293
|
-
const panelEl = document.createElement('div');
|
|
294
|
-
panelEl.className = 'rs-help-panel';
|
|
295
|
-
|
|
296
|
-
let sectionsHtml = panel.sections.map(section => `
|
|
297
|
-
<div class="rs-help-section" data-section-id="${section.id}">
|
|
298
|
-
<h4 class="rs-help-section-header" ${panel.settings.collapsible ? 'style="cursor: pointer;"' : ''}>
|
|
299
|
-
<span>${section.title}</span>
|
|
300
|
-
${panel.settings.collapsible ? '<span class="rs-help-expand-icon">V</span>' : ''}
|
|
301
|
-
</h4>
|
|
302
|
-
<div class="rs-help-section-content" ${panel.settings.defaultExpanded?.includes(section.id) ? '' : 'style="display: none;"'}>
|
|
303
|
-
${section.items.map(item => `
|
|
304
|
-
<div class="rs-help-item" data-item-id="${item.id}">
|
|
305
|
-
<div class="rs-help-question">${item.question}</div>
|
|
306
|
-
<div class="rs-help-answer">${formatMarkdownSimple(item.answer)}</div>
|
|
307
|
-
</div>
|
|
308
|
-
`).join('')}
|
|
309
|
-
</div>
|
|
310
|
-
</div>
|
|
311
|
-
`).join('');
|
|
312
|
-
|
|
313
|
-
panelEl.innerHTML = `
|
|
314
|
-
<div class="rs-help-panel-header">
|
|
315
|
-
<h3>${panel.title}</h3>
|
|
316
|
-
<button class="rs-btn rs-btn-sm rs-help-close">x</button>
|
|
317
|
-
</div>
|
|
318
|
-
${panel.settings.searchable ? `
|
|
319
|
-
<div class="rs-help-search">
|
|
320
|
-
<input type="text" class="rs-help-search-input" placeholder="Search help...">
|
|
321
|
-
</div>
|
|
322
|
-
` : ''}
|
|
323
|
-
<div class="rs-help-sections">
|
|
324
|
-
${sectionsHtml}
|
|
325
|
-
</div>
|
|
326
|
-
<div class="rs-help-footer">
|
|
327
|
-
<p>${panel.footer.text}</p>
|
|
328
|
-
<div class="rs-help-links">
|
|
329
|
-
${panel.footer.links.map(link => `
|
|
330
|
-
<a href="${link.url}" class="rs-help-link">${link.label}</a>
|
|
331
|
-
`).join('')}
|
|
332
|
-
</div>
|
|
333
|
-
</div>
|
|
334
|
-
`;
|
|
335
|
-
|
|
336
|
-
document.body.appendChild(panelEl);
|
|
337
|
-
helpPanelVisible = true;
|
|
338
|
-
|
|
339
|
-
// Bind events
|
|
340
|
-
panelEl.querySelector('.rs-help-close').addEventListener('click', hideHelpPanel);
|
|
341
|
-
|
|
342
|
-
// Collapsible sections
|
|
343
|
-
if (panel.settings.collapsible) {
|
|
344
|
-
panelEl.querySelectorAll('.rs-help-section-header').forEach(header => {
|
|
345
|
-
header.addEventListener('click', () => {
|
|
346
|
-
const content = header.nextElementSibling;
|
|
347
|
-
const icon = header.querySelector('.rs-help-expand-icon');
|
|
348
|
-
if (content.style.display === 'none') {
|
|
349
|
-
content.style.display = 'block';
|
|
350
|
-
if (icon) icon.textContent = 'V';
|
|
351
|
-
} else {
|
|
352
|
-
content.style.display = 'none';
|
|
353
|
-
if (icon) icon.textContent = '>';
|
|
354
|
-
}
|
|
355
|
-
});
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// Search functionality
|
|
360
|
-
if (panel.settings.searchable) {
|
|
361
|
-
const searchInput = panelEl.querySelector('.rs-help-search-input');
|
|
362
|
-
searchInput.addEventListener('input', (e) => {
|
|
363
|
-
const query = e.target.value.toLowerCase();
|
|
364
|
-
filterHelpItems(panelEl, query);
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Hide help panel
|
|
371
|
-
*/
|
|
372
|
-
function hideHelpPanel() {
|
|
373
|
-
const panel = document.querySelector('.rs-help-panel');
|
|
374
|
-
if (panel) {
|
|
375
|
-
panel.remove();
|
|
376
|
-
}
|
|
377
|
-
helpPanelVisible = false;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Filter help items based on search query
|
|
382
|
-
*/
|
|
383
|
-
function filterHelpItems(panelEl, query) {
|
|
384
|
-
panelEl.querySelectorAll('.rs-help-item').forEach(item => {
|
|
385
|
-
const question = item.querySelector('.rs-help-question').textContent.toLowerCase();
|
|
386
|
-
const answer = item.querySelector('.rs-help-answer').textContent.toLowerCase();
|
|
387
|
-
|
|
388
|
-
if (query === '' || question.includes(query) || answer.includes(query)) {
|
|
389
|
-
item.style.display = 'block';
|
|
390
|
-
} else {
|
|
391
|
-
item.style.display = 'none';
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
// Show/hide sections based on whether they have visible items
|
|
396
|
-
panelEl.querySelectorAll('.rs-help-section').forEach(section => {
|
|
397
|
-
const visibleItems = section.querySelectorAll('.rs-help-item[style="display: block;"], .rs-help-item:not([style])');
|
|
398
|
-
const content = section.querySelector('.rs-help-section-content');
|
|
399
|
-
if (query && visibleItems.length > 0) {
|
|
400
|
-
content.style.display = 'block';
|
|
401
|
-
}
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// ==========================================================================
|
|
406
|
-
// Utilities
|
|
407
|
-
// ==========================================================================
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Simple markdown-like formatting
|
|
411
|
-
*/
|
|
412
|
-
function formatMarkdownSimple(text) {
|
|
413
|
-
if (!text) return '';
|
|
414
|
-
|
|
415
|
-
// Bold
|
|
416
|
-
text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
417
|
-
|
|
418
|
-
// Code blocks
|
|
419
|
-
text = text.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
|
|
420
|
-
|
|
421
|
-
// Inline code
|
|
422
|
-
text = text.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
423
|
-
|
|
424
|
-
// Line breaks
|
|
425
|
-
text = text.replace(/\n/g, '<br>');
|
|
426
|
-
|
|
427
|
-
return text;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Create help button for header
|
|
432
|
-
*/
|
|
433
|
-
function createHelpButton() {
|
|
434
|
-
const btn = document.createElement('button');
|
|
435
|
-
btn.className = 'rs-btn rs-btn-sm rs-help-btn';
|
|
436
|
-
btn.innerHTML = '?';
|
|
437
|
-
btn.title = 'Help';
|
|
438
|
-
btn.addEventListener('click', toggleHelpPanel);
|
|
439
|
-
return btn;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Create replay onboarding button
|
|
444
|
-
*/
|
|
445
|
-
function createReplayOnboardingButton() {
|
|
446
|
-
const btn = document.createElement('button');
|
|
447
|
-
btn.className = 'rs-btn rs-btn-sm rs-replay-onboarding-btn';
|
|
448
|
-
btn.textContent = 'Tour';
|
|
449
|
-
btn.title = 'Replay onboarding tour';
|
|
450
|
-
btn.addEventListener('click', () => {
|
|
451
|
-
// Reset onboarding state
|
|
452
|
-
const storageKey = onboardingData?.wizard?.settings?.storageKey || 'traceview-review-onboarding-complete';
|
|
453
|
-
localStorage.removeItem(storageKey);
|
|
454
|
-
showOnboarding();
|
|
455
|
-
});
|
|
456
|
-
return btn;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// ==========================================================================
|
|
460
|
-
// Help Menu
|
|
461
|
-
// ==========================================================================
|
|
462
|
-
|
|
463
|
-
let helpMenuOpen = false;
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Create help menu dropdown
|
|
467
|
-
* @returns {HTMLElement} The complete help menu container
|
|
468
|
-
*/
|
|
469
|
-
function createHelpMenu() {
|
|
470
|
-
const container = document.createElement('div');
|
|
471
|
-
container.className = 'rs-help-menu-container';
|
|
472
|
-
container.id = 'rs-help-menu';
|
|
473
|
-
|
|
474
|
-
container.innerHTML = `
|
|
475
|
-
<button class="rs-help-menu-btn" id="rs-help-menu-btn">
|
|
476
|
-
<span>? Help</span>
|
|
477
|
-
<span class="rs-menu-arrow">V</span>
|
|
478
|
-
</button>
|
|
479
|
-
<div class="rs-help-menu-dropdown" id="rs-help-menu-dropdown">
|
|
480
|
-
<div class="rs-help-menu-section">
|
|
481
|
-
<button class="rs-help-menu-item" id="rs-menu-tour">
|
|
482
|
-
<span class="rs-menu-icon">[T]</span>
|
|
483
|
-
<span class="rs-menu-label">Take Tour</span>
|
|
484
|
-
</button>
|
|
485
|
-
<button class="rs-help-menu-item" id="rs-menu-help-panel">
|
|
486
|
-
<span class="rs-menu-icon">[?]</span>
|
|
487
|
-
<span class="rs-menu-label">Help Panel</span>
|
|
488
|
-
<span class="rs-menu-shortcut">?</span>
|
|
489
|
-
</button>
|
|
490
|
-
</div>
|
|
491
|
-
<div class="rs-help-menu-section">
|
|
492
|
-
<div class="rs-help-menu-section-label">Documentation</div>
|
|
493
|
-
<a href="docs/traceview-review-quick-start.md" target="_blank" class="rs-help-menu-item">
|
|
494
|
-
<span class="rs-menu-icon">[Q]</span>
|
|
495
|
-
<span class="rs-menu-label">Quick Start</span>
|
|
496
|
-
</a>
|
|
497
|
-
<a href="docs/traceview-review-user-guide.md" target="_blank" class="rs-help-menu-item">
|
|
498
|
-
<span class="rs-menu-icon">[U]</span>
|
|
499
|
-
<span class="rs-menu-label">User Guide</span>
|
|
500
|
-
</a>
|
|
501
|
-
</div>
|
|
502
|
-
</div>
|
|
503
|
-
`;
|
|
504
|
-
|
|
505
|
-
// Bind events after DOM is created
|
|
506
|
-
const btn = container.querySelector('#rs-help-menu-btn');
|
|
507
|
-
const dropdown = container.querySelector('#rs-help-menu-dropdown');
|
|
508
|
-
|
|
509
|
-
btn.addEventListener('click', (e) => {
|
|
510
|
-
e.stopPropagation();
|
|
511
|
-
toggleHelpMenu(btn, dropdown);
|
|
512
|
-
});
|
|
513
|
-
|
|
514
|
-
container.querySelector('#rs-menu-tour').addEventListener('click', () => {
|
|
515
|
-
closeHelpMenu(btn, dropdown);
|
|
516
|
-
// Reset onboarding state and show
|
|
517
|
-
const storageKey = onboardingData?.wizard?.settings?.storageKey || 'traceview-review-onboarding-complete';
|
|
518
|
-
localStorage.removeItem(storageKey);
|
|
519
|
-
showOnboarding();
|
|
520
|
-
});
|
|
521
|
-
|
|
522
|
-
container.querySelector('#rs-menu-help-panel').addEventListener('click', () => {
|
|
523
|
-
closeHelpMenu(btn, dropdown);
|
|
524
|
-
showHelpPanel();
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
// Close menu when clicking outside
|
|
528
|
-
document.addEventListener('click', (e) => {
|
|
529
|
-
if (!container.contains(e.target)) {
|
|
530
|
-
closeHelpMenu(btn, dropdown);
|
|
531
|
-
}
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
// Close menu on ESC key
|
|
535
|
-
document.addEventListener('keydown', (e) => {
|
|
536
|
-
if (e.key === 'Escape' && helpMenuOpen) {
|
|
537
|
-
closeHelpMenu(btn, dropdown);
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
return container;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* Toggle help menu open/closed
|
|
546
|
-
*/
|
|
547
|
-
function toggleHelpMenu(btn, dropdown) {
|
|
548
|
-
helpMenuOpen = !helpMenuOpen;
|
|
549
|
-
btn.classList.toggle('open', helpMenuOpen);
|
|
550
|
-
dropdown.classList.toggle('open', helpMenuOpen);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Close help menu
|
|
555
|
-
*/
|
|
556
|
-
function closeHelpMenu(btn, dropdown) {
|
|
557
|
-
helpMenuOpen = false;
|
|
558
|
-
btn?.classList.remove('open');
|
|
559
|
-
dropdown?.classList.remove('open');
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// ==========================================================================
|
|
563
|
-
// Initialization
|
|
564
|
-
// ==========================================================================
|
|
565
|
-
|
|
566
|
-
/**
|
|
567
|
-
* Initialize help system
|
|
568
|
-
* @param {object} options - Configuration options
|
|
569
|
-
*/
|
|
570
|
-
async function init(options = {}) {
|
|
571
|
-
const baseUrl = options.helpBaseUrl || '/help';
|
|
572
|
-
|
|
573
|
-
await loadHelpData(baseUrl);
|
|
574
|
-
|
|
575
|
-
// Initialize tooltips
|
|
576
|
-
initTooltips(document);
|
|
577
|
-
|
|
578
|
-
// Show onboarding if first visit
|
|
579
|
-
if (shouldShowOnboarding()) {
|
|
580
|
-
showOnboarding();
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
console.log('Help system initialized');
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// ==========================================================================
|
|
587
|
-
// Exports
|
|
588
|
-
// ==========================================================================
|
|
589
|
-
|
|
590
|
-
review.help = {
|
|
591
|
-
init,
|
|
592
|
-
loadHelpData,
|
|
593
|
-
initTooltips,
|
|
594
|
-
getTooltip,
|
|
595
|
-
showOnboarding,
|
|
596
|
-
showHelpPanel,
|
|
597
|
-
hideHelpPanel,
|
|
598
|
-
toggleHelpPanel,
|
|
599
|
-
createHelpButton,
|
|
600
|
-
createReplayOnboardingButton,
|
|
601
|
-
createHelpMenu
|
|
602
|
-
};
|
|
603
|
-
|
|
604
|
-
})(TraceView.review);
|
|
605
|
-
|
|
606
|
-
// Add ReviewSystem alias with help functions (REQ-d00092)
|
|
607
|
-
window.ReviewSystem = window.ReviewSystem || {};
|
|
608
|
-
var RS = window.ReviewSystem;
|
|
609
|
-
|
|
610
|
-
// Help menu toggle from button (for HTML onclick handlers)
|
|
611
|
-
function toggleHelpMenuFromBtn(btn) {
|
|
612
|
-
const dropdown = document.getElementById('rs-help-menu-dropdown');
|
|
613
|
-
const isOpen = dropdown?.classList.toggle('open');
|
|
614
|
-
btn?.classList.toggle('open', isOpen);
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// Filter help content (for search input)
|
|
618
|
-
function filterHelpContent(query) {
|
|
619
|
-
const searchQuery = (query || '').toLowerCase();
|
|
620
|
-
const panel = document.querySelector('.rs-help-panel');
|
|
621
|
-
if (!panel) return;
|
|
622
|
-
|
|
623
|
-
panel.querySelectorAll('.rs-help-item').forEach(item => {
|
|
624
|
-
const question = item.querySelector('.rs-help-question')?.textContent?.toLowerCase() || '';
|
|
625
|
-
const answer = item.querySelector('.rs-help-answer')?.textContent?.toLowerCase() || '';
|
|
626
|
-
|
|
627
|
-
if (searchQuery === '' || question.includes(searchQuery) || answer.includes(searchQuery)) {
|
|
628
|
-
item.style.display = 'block';
|
|
629
|
-
} else {
|
|
630
|
-
item.style.display = 'none';
|
|
631
|
-
}
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
// Render help panel content
|
|
636
|
-
function renderHelpPanelContent(container) {
|
|
637
|
-
// Placeholder - content populated dynamically
|
|
638
|
-
if (container && TraceView.review.help) {
|
|
639
|
-
TraceView.review.help.showHelpPanel();
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Setup global help handlers for keyboard shortcuts
|
|
644
|
-
function setupGlobalHelpHandlers() {
|
|
645
|
-
document.addEventListener('keydown', function(e) {
|
|
646
|
-
if (e.key === '?' && !e.target.matches('input, textarea')) {
|
|
647
|
-
e.preventDefault();
|
|
648
|
-
if (TraceView.review.help) {
|
|
649
|
-
TraceView.review.help.toggleHelpPanel();
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
if (e.key === 'Escape') {
|
|
653
|
-
// Close any open help panels/menus
|
|
654
|
-
const dropdown = document.getElementById('rs-help-menu-dropdown');
|
|
655
|
-
const btn = document.getElementById('rs-help-menu-btn');
|
|
656
|
-
if (dropdown?.classList.contains('open')) {
|
|
657
|
-
dropdown.classList.remove('open');
|
|
658
|
-
btn?.classList.remove('open');
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
// Initialize global handlers on DOMContentLoaded
|
|
665
|
-
document.addEventListener('DOMContentLoaded', setupGlobalHelpHandlers);
|
|
666
|
-
|
|
667
|
-
// Export to RS.help namespace
|
|
668
|
-
RS.help = {
|
|
669
|
-
init: TraceView.review.help.init,
|
|
670
|
-
toggleHelpPanel: TraceView.review.help.toggleHelpPanel,
|
|
671
|
-
toggleHelpMenuFromBtn: toggleHelpMenuFromBtn,
|
|
672
|
-
startTour: TraceView.review.help.showOnboarding,
|
|
673
|
-
filterHelpContent: filterHelpContent,
|
|
674
|
-
showOnboarding: TraceView.review.help.showOnboarding,
|
|
675
|
-
renderHelpPanelContent: renderHelpPanelContent,
|
|
676
|
-
hideHelpPanel: TraceView.review.help.hideHelpPanel,
|
|
677
|
-
showHelpPanel: TraceView.review.help.showHelpPanel,
|
|
678
|
-
setupGlobalHelpHandlers: setupGlobalHelpHandlers
|
|
679
|
-
};
|