lula2 0.0.5 → 0.0.6
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 +291 -8
- package/dist/_app/env.js +1 -0
- package/dist/_app/immutable/assets/0.DtiRW3lO.css +1 -0
- package/dist/_app/immutable/assets/DynamicControlEditor.BkVTzFZ-.css +1 -0
- package/dist/_app/immutable/chunks/7x_q-1ab.js +1 -0
- package/dist/_app/immutable/chunks/B19gt6-g.js +2 -0
- package/dist/_app/immutable/chunks/BR-0Dorr.js +1 -0
- package/dist/_app/immutable/chunks/B_3ksxz5.js +2 -0
- package/dist/_app/immutable/chunks/Bg_R1qWi.js +3 -0
- package/dist/_app/immutable/chunks/D3aNP_lg.js +1 -0
- package/dist/_app/immutable/chunks/D4Q_ObIy.js +1 -0
- package/dist/_app/immutable/chunks/DsnmJJEf.js +1 -0
- package/dist/_app/immutable/chunks/XY2j_owG.js +66 -0
- package/dist/_app/immutable/chunks/rzN25oDf.js +1 -0
- package/dist/_app/immutable/entry/app.r0uOd9qg.js +2 -0
- package/dist/_app/immutable/entry/start.DvoqR0rc.js +1 -0
- package/dist/_app/immutable/nodes/0.Ct6FAss_.js +1 -0
- package/dist/_app/immutable/nodes/1.DLoKuy8Q.js +1 -0
- package/dist/_app/immutable/nodes/2.IRkwSmiB.js +1 -0
- package/dist/_app/immutable/nodes/3.BrTg-ZHv.js +1 -0
- package/dist/_app/immutable/nodes/4.Blq-4WQS.js +9 -0
- package/dist/_app/version.json +1 -0
- package/dist/cli/commands/crawl.js +128 -0
- package/dist/cli/commands/ui.js +2769 -0
- package/dist/cli/commands/version.js +30 -0
- package/dist/cli/server/index.js +2713 -0
- package/dist/cli/server/server.js +2702 -0
- package/dist/cli/server/serverState.js +1199 -0
- package/dist/cli/server/spreadsheetRoutes.js +788 -0
- package/dist/cli/server/types.js +0 -0
- package/dist/cli/server/websocketServer.js +2625 -0
- package/dist/cli/utils/debug.js +24 -0
- package/dist/favicon.svg +1 -0
- package/dist/index.html +38 -0
- package/dist/index.js +2924 -37
- package/dist/lula.png +0 -0
- package/dist/lula2 +2 -0
- package/package.json +120 -72
- package/src/app.css +192 -0
- package/src/app.d.ts +13 -0
- package/src/app.html +13 -0
- package/src/lib/actions/fadeWhenScrollable.ts +39 -0
- package/src/lib/actions/modal.ts +230 -0
- package/src/lib/actions/tooltip.ts +82 -0
- package/src/lib/components/control-sets/ControlSetInfo.svelte +20 -0
- package/src/lib/components/control-sets/ControlSetSelector.svelte +46 -0
- package/src/lib/components/control-sets/index.ts +5 -0
- package/src/lib/components/controls/ControlDetailsPanel.svelte +235 -0
- package/src/lib/components/controls/ControlsList.svelte +608 -0
- package/src/lib/components/controls/DynamicControlEditor.svelte +298 -0
- package/src/lib/components/controls/MappingCard.svelte +105 -0
- package/src/lib/components/controls/MappingForm.svelte +188 -0
- package/src/lib/components/controls/index.ts +9 -0
- package/src/lib/components/controls/renderers/EditableFieldRenderer.svelte +103 -0
- package/src/lib/components/controls/renderers/FieldRenderer.svelte +49 -0
- package/src/lib/components/controls/renderers/index.ts +5 -0
- package/src/lib/components/controls/tabs/CustomFieldsTab.svelte +130 -0
- package/src/lib/components/controls/tabs/ImplementationTab.svelte +127 -0
- package/src/lib/components/controls/tabs/MappingsTab.svelte +182 -0
- package/src/lib/components/controls/tabs/OverviewTab.svelte +151 -0
- package/src/lib/components/controls/tabs/TimelineTab.svelte +41 -0
- package/src/lib/components/controls/tabs/index.ts +8 -0
- package/src/lib/components/controls/utils/ProcessedTextRenderer.svelte +63 -0
- package/src/lib/components/controls/utils/textProcessor.ts +164 -0
- package/src/lib/components/forms/DynamicControlForm.svelte +340 -0
- package/src/lib/components/forms/DynamicField.svelte +494 -0
- package/src/lib/components/forms/FormField.svelte +107 -0
- package/src/lib/components/forms/index.ts +6 -0
- package/src/lib/components/setup/ExistingControlSets.svelte +284 -0
- package/src/lib/components/setup/SpreadsheetImport.svelte +968 -0
- package/src/lib/components/setup/index.ts +5 -0
- package/src/lib/components/ui/Dropdown.svelte +107 -0
- package/src/lib/components/ui/EmptyState.svelte +80 -0
- package/src/lib/components/ui/FeatureToggle.svelte +50 -0
- package/src/lib/components/ui/SearchBar.svelte +73 -0
- package/src/lib/components/ui/StatusBadge.svelte +79 -0
- package/src/lib/components/ui/TabNavigation.svelte +48 -0
- package/src/lib/components/ui/Tooltip.svelte +120 -0
- package/src/lib/components/ui/index.ts +10 -0
- package/src/lib/components/version-control/DiffViewer.svelte +292 -0
- package/src/lib/components/version-control/TimelineItem.svelte +107 -0
- package/src/lib/components/version-control/YamlDiffViewer.svelte +428 -0
- package/src/lib/components/version-control/index.ts +6 -0
- package/src/lib/form-types.ts +57 -0
- package/src/lib/formatUtils.ts +17 -0
- package/src/lib/index.ts +5 -0
- package/src/lib/types.ts +180 -0
- package/src/lib/websocket.ts +359 -0
- package/src/routes/+layout.svelte +236 -0
- package/src/routes/+page.svelte +38 -0
- package/src/routes/control/[id]/+page.svelte +112 -0
- package/src/routes/setup/+page.svelte +241 -0
- package/src/stores/compliance.ts +95 -0
- package/src/styles/highlightjs.css +20 -0
- package/src/styles/modal.css +58 -0
- package/src/styles/tables.css +111 -0
- package/src/styles/tooltip.css +65 -0
- package/dist/controls/index.d.ts +0 -18
- package/dist/controls/index.d.ts.map +0 -1
- package/dist/controls/index.js +0 -18
- package/dist/crawl.d.ts +0 -62
- package/dist/crawl.d.ts.map +0 -1
- package/dist/crawl.js +0 -172
- package/dist/index.d.ts +0 -8
- package/dist/index.d.ts.map +0 -1
- package/src/controls/index.ts +0 -19
- package/src/crawl.ts +0 -227
- package/src/index.ts +0 -46
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
|
2
|
+
<!-- SPDX-FileCopyrightText: 2023-Present The Lula Authors -->
|
|
3
|
+
|
|
4
|
+
<script lang="ts">
|
|
5
|
+
interface Props {
|
|
6
|
+
diff: string;
|
|
7
|
+
fileName?: string;
|
|
8
|
+
language?: string;
|
|
9
|
+
compact?: boolean;
|
|
10
|
+
showToggle?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
diff,
|
|
15
|
+
fileName = '',
|
|
16
|
+
language = 'yaml',
|
|
17
|
+
compact = false,
|
|
18
|
+
showToggle = true
|
|
19
|
+
}: Props = $props();
|
|
20
|
+
|
|
21
|
+
let isCompact = $state(compact);
|
|
22
|
+
let parsedDiff: DiffLine[] = $derived(
|
|
23
|
+
isCompact ? getCompactDiff(parseDiff(diff)) : parseDiff(diff)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
interface DiffLine {
|
|
27
|
+
type: 'context' | 'addition' | 'deletion' | 'header' | 'hunk';
|
|
28
|
+
content: string;
|
|
29
|
+
oldLineNumber?: number;
|
|
30
|
+
newLineNumber?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseDiff(diffText: string): DiffLine[] {
|
|
34
|
+
const lines = diffText.split('\n');
|
|
35
|
+
const parsedLines: DiffLine[] = [];
|
|
36
|
+
let oldLineNumber = 1;
|
|
37
|
+
let newLineNumber = 1;
|
|
38
|
+
let inDiffContent = false;
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
const line = lines[i];
|
|
42
|
+
|
|
43
|
+
// Skip file headers (--- and +++ lines) but include them
|
|
44
|
+
if (line.startsWith('---') || line.startsWith('+++')) {
|
|
45
|
+
parsedLines.push({ type: 'header', content: line });
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Handle hunk headers like @@ -4,7 +4,7 @@
|
|
50
|
+
if (line.startsWith('@@')) {
|
|
51
|
+
const match = line.match(/@@\s-(\d+)(?:,\d+)?\s\+(\d+)(?:,\d+)?\s@@/);
|
|
52
|
+
if (match) {
|
|
53
|
+
oldLineNumber = parseInt(match[1]);
|
|
54
|
+
newLineNumber = parseInt(match[2]);
|
|
55
|
+
inDiffContent = true;
|
|
56
|
+
}
|
|
57
|
+
parsedLines.push({ type: 'hunk', content: line });
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// If we haven't seen a hunk header yet, check if this looks like diff content anyway
|
|
62
|
+
if (!inDiffContent) {
|
|
63
|
+
// Sometimes diffs don't have proper hunk headers, so check if line looks like diff content
|
|
64
|
+
if (line.startsWith('+') || line.startsWith('-') || line.startsWith(' ')) {
|
|
65
|
+
inDiffContent = true;
|
|
66
|
+
// Set reasonable default line numbers if we don't have hunk info
|
|
67
|
+
if (oldLineNumber === 1 && newLineNumber === 1) {
|
|
68
|
+
oldLineNumber = 1;
|
|
69
|
+
newLineNumber = 1;
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Handle actual diff lines
|
|
77
|
+
if (line.startsWith('+')) {
|
|
78
|
+
parsedLines.push({
|
|
79
|
+
type: 'addition',
|
|
80
|
+
content: line.slice(1),
|
|
81
|
+
newLineNumber: newLineNumber++
|
|
82
|
+
});
|
|
83
|
+
} else if (line.startsWith('-')) {
|
|
84
|
+
parsedLines.push({
|
|
85
|
+
type: 'deletion',
|
|
86
|
+
content: line.slice(1),
|
|
87
|
+
oldLineNumber: oldLineNumber++
|
|
88
|
+
});
|
|
89
|
+
} else if (line.startsWith(' ')) {
|
|
90
|
+
// Context line (unchanged)
|
|
91
|
+
parsedLines.push({
|
|
92
|
+
type: 'context',
|
|
93
|
+
content: line.slice(1),
|
|
94
|
+
oldLineNumber: oldLineNumber++,
|
|
95
|
+
newLineNumber: newLineNumber++
|
|
96
|
+
});
|
|
97
|
+
} else if (line === '' && inDiffContent) {
|
|
98
|
+
// Empty line in diff
|
|
99
|
+
parsedLines.push({
|
|
100
|
+
type: 'context',
|
|
101
|
+
content: '',
|
|
102
|
+
oldLineNumber: oldLineNumber++,
|
|
103
|
+
newLineNumber: newLineNumber++
|
|
104
|
+
});
|
|
105
|
+
} else if (inDiffContent) {
|
|
106
|
+
// Treat unknown lines as context if we're in diff content
|
|
107
|
+
parsedLines.push({
|
|
108
|
+
type: 'context',
|
|
109
|
+
content: line,
|
|
110
|
+
oldLineNumber: oldLineNumber++,
|
|
111
|
+
newLineNumber: newLineNumber++
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return parsedLines;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function highlightYaml(content: string): string {
|
|
120
|
+
// Simple YAML syntax highlighting
|
|
121
|
+
return content
|
|
122
|
+
.replace(
|
|
123
|
+
/^(\s*)([a-zA-Z_][a-zA-Z0-9_-]*)\s*:/gm,
|
|
124
|
+
'$1<span class="text-blue-600 dark:text-blue-400 font-medium">$2</span>:'
|
|
125
|
+
)
|
|
126
|
+
.replace(/:\s*("[^"]*")/g, ': <span class="text-green-600 dark:text-green-400">$1</span>')
|
|
127
|
+
.replace(/:\s*(\d+)/g, ': <span class="text-purple-600 dark:text-purple-400">$1</span>')
|
|
128
|
+
.replace(
|
|
129
|
+
/:\s*(true|false|null)/g,
|
|
130
|
+
': <span class="text-orange-600 dark:text-orange-400">$1</span>'
|
|
131
|
+
)
|
|
132
|
+
.replace(/^\s*-\s/gm, '<span class="text-gray-500 dark:text-gray-400">-</span> ')
|
|
133
|
+
.replace(/#.*$/gm, '<span class="text-gray-500 dark:text-gray-400 italic">$&</span>');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function getCompactDiff(lines: DiffLine[]): DiffLine[] {
|
|
137
|
+
const result: DiffLine[] = [];
|
|
138
|
+
const contextRadius = 2; // Show 2 lines of context around changes
|
|
139
|
+
|
|
140
|
+
// Find all changed lines (additions and deletions)
|
|
141
|
+
const changedLineIndices = new Set<number>();
|
|
142
|
+
lines.forEach((line, index) => {
|
|
143
|
+
if (line.type === 'addition' || line.type === 'deletion') {
|
|
144
|
+
// Add the changed line and context around it
|
|
145
|
+
for (
|
|
146
|
+
let i = Math.max(0, index - contextRadius);
|
|
147
|
+
i <= Math.min(lines.length - 1, index + contextRadius);
|
|
148
|
+
i++
|
|
149
|
+
) {
|
|
150
|
+
changedLineIndices.add(i);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Always include headers and hunks
|
|
156
|
+
lines.forEach((line, index) => {
|
|
157
|
+
if (line.type === 'header' || line.type === 'hunk' || changedLineIndices.has(index)) {
|
|
158
|
+
result.push(line);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<div class="diff-viewer border border-gray-200 dark:border-gray-600 rounded-lg overflow-hidden">
|
|
167
|
+
{#if fileName || showToggle}
|
|
168
|
+
<div
|
|
169
|
+
class="bg-gray-50 dark:bg-gray-800 px-4 py-2 border-b border-gray-200 dark:border-gray-600"
|
|
170
|
+
>
|
|
171
|
+
<div class="flex items-center justify-between">
|
|
172
|
+
{#if fileName}
|
|
173
|
+
<div class="flex items-center space-x-2">
|
|
174
|
+
<svg
|
|
175
|
+
class="w-4 h-4 text-gray-500"
|
|
176
|
+
fill="none"
|
|
177
|
+
stroke="currentColor"
|
|
178
|
+
viewBox="0 0 24 24"
|
|
179
|
+
>
|
|
180
|
+
<path
|
|
181
|
+
stroke-linecap="round"
|
|
182
|
+
stroke-linejoin="round"
|
|
183
|
+
stroke-width="2"
|
|
184
|
+
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
185
|
+
/>
|
|
186
|
+
</svg>
|
|
187
|
+
<span class="text-sm font-medium text-gray-700 dark:text-gray-300 font-mono"
|
|
188
|
+
>{fileName}</span
|
|
189
|
+
>
|
|
190
|
+
</div>
|
|
191
|
+
{:else}
|
|
192
|
+
<div></div>
|
|
193
|
+
{/if}
|
|
194
|
+
|
|
195
|
+
{#if showToggle}
|
|
196
|
+
<button
|
|
197
|
+
onclick={() => (isCompact = !isCompact)}
|
|
198
|
+
class="inline-flex items-center px-2 py-1 text-xs font-medium text-gray-600 dark:text-gray-400 hover:text-gray-800 dark:hover:text-gray-200 bg-gray-100 dark:bg-gray-700 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
|
|
199
|
+
>
|
|
200
|
+
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
201
|
+
<path
|
|
202
|
+
stroke-linecap="round"
|
|
203
|
+
stroke-linejoin="round"
|
|
204
|
+
stroke-width="2"
|
|
205
|
+
d="M4 6h16M4 10h16M4 14h16M4 18h16"
|
|
206
|
+
/>
|
|
207
|
+
</svg>
|
|
208
|
+
{isCompact ? 'Full' : 'Compact'}
|
|
209
|
+
</button>
|
|
210
|
+
{/if}
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
{/if}
|
|
214
|
+
|
|
215
|
+
<div class="diff-content max-h-96 overflow-y-auto">
|
|
216
|
+
{#each parsedDiff as line}
|
|
217
|
+
<div
|
|
218
|
+
class="diff-line flex {line.type === 'addition'
|
|
219
|
+
? 'bg-green-50 dark:bg-green-900/20'
|
|
220
|
+
: line.type === 'deletion'
|
|
221
|
+
? 'bg-red-50 dark:bg-red-900/20'
|
|
222
|
+
: line.type === 'hunk'
|
|
223
|
+
? 'bg-gray-100 dark:bg-gray-800'
|
|
224
|
+
: line.type === 'header'
|
|
225
|
+
? 'bg-gray-100 dark:bg-gray-800'
|
|
226
|
+
: 'bg-white dark:bg-gray-900'}"
|
|
227
|
+
>
|
|
228
|
+
<!-- Line numbers -->
|
|
229
|
+
<div
|
|
230
|
+
class="line-numbers flex text-xs text-gray-400 dark:text-gray-500 font-mono select-none border-r border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-750"
|
|
231
|
+
>
|
|
232
|
+
<div class="w-8 px-2 py-1 text-right">
|
|
233
|
+
{line.type !== 'addition' && line.oldLineNumber ? line.oldLineNumber : ''}
|
|
234
|
+
</div>
|
|
235
|
+
<div class="w-8 px-2 py-1 text-right">
|
|
236
|
+
{line.type !== 'deletion' && line.newLineNumber ? line.newLineNumber : ''}
|
|
237
|
+
</div>
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<!-- Change indicator -->
|
|
241
|
+
<div
|
|
242
|
+
class="change-indicator w-6 flex items-center justify-center text-sm font-mono {line.type ===
|
|
243
|
+
'addition'
|
|
244
|
+
? 'text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-900/20'
|
|
245
|
+
: line.type === 'deletion'
|
|
246
|
+
? 'text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20'
|
|
247
|
+
: 'text-gray-400 dark:text-gray-500'}"
|
|
248
|
+
>
|
|
249
|
+
{line.type === 'addition' ? '+' : line.type === 'deletion' ? '-' : ''}
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<!-- Content -->
|
|
253
|
+
<div
|
|
254
|
+
class="content flex-1 px-2 py-1 font-mono text-sm leading-relaxed whitespace-pre-wrap {line.type ===
|
|
255
|
+
'hunk'
|
|
256
|
+
? 'text-gray-600 dark:text-gray-400 font-medium'
|
|
257
|
+
: line.type === 'header'
|
|
258
|
+
? 'text-gray-500 dark:text-gray-400'
|
|
259
|
+
: 'text-gray-900 dark:text-gray-100'}"
|
|
260
|
+
>
|
|
261
|
+
{#if language === 'yaml' && (line.type === 'context' || line.type === 'addition' || line.type === 'deletion')}
|
|
262
|
+
{@html highlightYaml(line.content)}
|
|
263
|
+
{:else}
|
|
264
|
+
{line.content}
|
|
265
|
+
{/if}
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
{/each}
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
|
|
272
|
+
<style>
|
|
273
|
+
.diff-viewer {
|
|
274
|
+
font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.diff-line:hover {
|
|
278
|
+
background-color: rgba(59, 130, 246, 0.05);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.diff-line.bg-green-50:hover {
|
|
282
|
+
background-color: rgba(34, 197, 94, 0.1);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.diff-line.bg-red-50:hover {
|
|
286
|
+
background-color: rgba(239, 68, 68, 0.1);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
:global(.dark) .diff-line:hover {
|
|
290
|
+
background-color: rgba(59, 130, 246, 0.1);
|
|
291
|
+
}
|
|
292
|
+
</style>
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
|
2
|
+
<!-- SPDX-FileCopyrightText: 2023-Present The Lula Authors -->
|
|
3
|
+
|
|
4
|
+
<script lang="ts">
|
|
5
|
+
import type { GitCommit } from '$lib/types';
|
|
6
|
+
import { DiffViewer, YamlDiffViewer } from '.';
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
commit: GitCommit & { type?: string; fileType?: string; source?: 'control' | 'mapping' };
|
|
10
|
+
showConnector?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { commit, showConnector = false }: Props = $props();
|
|
14
|
+
|
|
15
|
+
function formatDate(dateString: string): string {
|
|
16
|
+
return new Date(dateString).toLocaleDateString('en-US', {
|
|
17
|
+
year: 'numeric',
|
|
18
|
+
month: 'short',
|
|
19
|
+
day: 'numeric',
|
|
20
|
+
hour: '2-digit',
|
|
21
|
+
minute: '2-digit'
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div class="relative">
|
|
27
|
+
<!-- Connector line -->
|
|
28
|
+
{#if showConnector}
|
|
29
|
+
<div class="absolute left-4 top-12 bottom-0 w-0.5 bg-gray-200 dark:bg-gray-800"></div>
|
|
30
|
+
{/if}
|
|
31
|
+
|
|
32
|
+
<!-- Timeline item -->
|
|
33
|
+
<div class="relative">
|
|
34
|
+
<!-- Icon/dot -->
|
|
35
|
+
<div
|
|
36
|
+
class="absolute left-0 mt-1.5 w-8 h-8 rounded-full border-2 border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-900 flex items-center justify-center"
|
|
37
|
+
>
|
|
38
|
+
{#if commit.isPending}
|
|
39
|
+
<div class="w-3 h-3 rounded-full bg-amber-400 animate-pulse"></div>
|
|
40
|
+
{:else if commit.source === 'mapping' || commit.type === 'mapping'}
|
|
41
|
+
<div class="w-3 h-3 rounded-full bg-green-500"></div>
|
|
42
|
+
{:else}
|
|
43
|
+
<div class="w-3 h-3 rounded-full bg-blue-500"></div>
|
|
44
|
+
{/if}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<!-- Content card -->
|
|
48
|
+
<div
|
|
49
|
+
class="ml-12 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-sm hover:shadow-md transition-all duration-200"
|
|
50
|
+
>
|
|
51
|
+
<!-- Header -->
|
|
52
|
+
<div
|
|
53
|
+
class="px-6 py-4 border-b border-gray-100 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 rounded-t-xl"
|
|
54
|
+
>
|
|
55
|
+
<div class="flex items-center justify-between">
|
|
56
|
+
<div class="flex items-center space-x-3">
|
|
57
|
+
<h4 class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
|
58
|
+
{commit.fileType ||
|
|
59
|
+
(commit.source === 'mapping' || commit.type === 'mapping'
|
|
60
|
+
? 'Mappings'
|
|
61
|
+
: 'Control File')}
|
|
62
|
+
</h4>
|
|
63
|
+
{#if commit.isPending}
|
|
64
|
+
<span
|
|
65
|
+
class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300"
|
|
66
|
+
>
|
|
67
|
+
Pending
|
|
68
|
+
</span>
|
|
69
|
+
{:else}
|
|
70
|
+
<span
|
|
71
|
+
class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400"
|
|
72
|
+
>
|
|
73
|
+
{commit.shortHash}
|
|
74
|
+
</span>
|
|
75
|
+
{/if}
|
|
76
|
+
</div>
|
|
77
|
+
<p class="text-xs text-gray-500 dark:text-gray-400">
|
|
78
|
+
{formatDate(commit.date)}
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<p class="text-xs text-gray-600 dark:text-gray-400 mt-1">
|
|
83
|
+
{commit.author}
|
|
84
|
+
</p>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<!-- Content -->
|
|
88
|
+
<div class="px-6 py-4">
|
|
89
|
+
<pre
|
|
90
|
+
class="text-sm text-gray-700 dark:text-gray-300 leading-relaxed whitespace-pre-wrap font-sans">{commit.message}</pre>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<!-- Always show diff content -->
|
|
94
|
+
<div class="p-2">
|
|
95
|
+
{#if commit.diff && !commit.yamlDiff?.hasChanges}
|
|
96
|
+
<div class="border-t border-gray-200 dark:border-gray-700">
|
|
97
|
+
<DiffViewer diff={commit.diff} />
|
|
98
|
+
</div>
|
|
99
|
+
{:else if commit.yamlDiff?.hasChanges}
|
|
100
|
+
<div class="border-t border-gray-200 dark:border-gray-700">
|
|
101
|
+
<YamlDiffViewer yamlDiff={commit.yamlDiff} />
|
|
102
|
+
</div>
|
|
103
|
+
{/if}
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|