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,284 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { createEventDispatcher } from 'svelte';
|
|
4
|
+
import { appState } from '$lib/websocket';
|
|
5
|
+
|
|
6
|
+
const dispatch = createEventDispatcher();
|
|
7
|
+
|
|
8
|
+
interface ControlSet {
|
|
9
|
+
path: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
controlCount: number;
|
|
13
|
+
file: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export let controlSets: ControlSet[] = [];
|
|
17
|
+
|
|
18
|
+
let isLoading = false;
|
|
19
|
+
let errorMessage = '';
|
|
20
|
+
let selectedSet: ControlSet | null = null;
|
|
21
|
+
|
|
22
|
+
// Get current control set path from appState
|
|
23
|
+
$: currentPath = $appState.currentPath || '';
|
|
24
|
+
|
|
25
|
+
// React to control sets prop changes
|
|
26
|
+
$: if (controlSets) {
|
|
27
|
+
if (controlSets.length === 0) {
|
|
28
|
+
errorMessage = 'No existing control sets found. Try importing from a spreadsheet instead.';
|
|
29
|
+
} else {
|
|
30
|
+
// Find available control sets (not current)
|
|
31
|
+
const availableSets = controlSets.filter((cs) => !isCurrentControlSet(cs));
|
|
32
|
+
if (availableSets.length === 1) {
|
|
33
|
+
// Auto-select if only one non-current control set found
|
|
34
|
+
selectedSet = availableSets[0];
|
|
35
|
+
} else if (availableSets.length === 0 && controlSets.length > 0) {
|
|
36
|
+
// All control sets are current
|
|
37
|
+
errorMessage = 'already-using-only-set';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function selectControlSet(controlSet: ControlSet) {
|
|
43
|
+
// Don't select if it's the current control set
|
|
44
|
+
if (isCurrentControlSet(controlSet)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
selectedSet = controlSet;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function useSelectedControlSet() {
|
|
51
|
+
if (selectedSet && !isCurrentControlSet(selectedSet)) {
|
|
52
|
+
dispatch('selected', { path: selectedSet.path });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isCurrentControlSet(controlSet: ControlSet): boolean {
|
|
57
|
+
// Check if this is the currently active control set
|
|
58
|
+
// Normalize paths for comparison (remove trailing slashes)
|
|
59
|
+
const normalizedCurrentPath = currentPath?.replace(/\/$/, '');
|
|
60
|
+
const normalizedControlSetPath = controlSet.path?.replace(/\/$/, '');
|
|
61
|
+
|
|
62
|
+
return !!(
|
|
63
|
+
normalizedCurrentPath &&
|
|
64
|
+
normalizedControlSetPath &&
|
|
65
|
+
normalizedCurrentPath === normalizedControlSetPath
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<div class="space-y-6">
|
|
71
|
+
<div class="text-center">
|
|
72
|
+
<h2 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">
|
|
73
|
+
Select an Existing Control Set
|
|
74
|
+
</h2>
|
|
75
|
+
<p class="text-gray-600 dark:text-gray-400">
|
|
76
|
+
Choose from control sets found in your project directory
|
|
77
|
+
</p>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
{#if isLoading}
|
|
81
|
+
<div class="flex justify-center py-12">
|
|
82
|
+
<div class="text-center">
|
|
83
|
+
<svg
|
|
84
|
+
class="animate-spin h-8 w-8 text-blue-600 mx-auto mb-4"
|
|
85
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
86
|
+
fill="none"
|
|
87
|
+
viewBox="0 0 24 24"
|
|
88
|
+
>
|
|
89
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"
|
|
90
|
+
></circle>
|
|
91
|
+
<path
|
|
92
|
+
class="opacity-75"
|
|
93
|
+
fill="currentColor"
|
|
94
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
95
|
+
></path>
|
|
96
|
+
</svg>
|
|
97
|
+
<p class="text-gray-500 dark:text-gray-400">Scanning for control sets...</p>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
{:else if errorMessage === 'already-using-only-set'}
|
|
101
|
+
<div class="text-center space-y-6">
|
|
102
|
+
<div
|
|
103
|
+
class="p-6 bg-gradient-to-br from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 rounded-lg border-2 border-green-500"
|
|
104
|
+
>
|
|
105
|
+
<svg
|
|
106
|
+
class="w-12 h-12 text-green-600 mx-auto mb-4"
|
|
107
|
+
fill="currentColor"
|
|
108
|
+
viewBox="0 0 20 20"
|
|
109
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
110
|
+
>
|
|
111
|
+
<path
|
|
112
|
+
fill-rule="evenodd"
|
|
113
|
+
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
|
114
|
+
clip-rule="evenodd"
|
|
115
|
+
></path>
|
|
116
|
+
</svg>
|
|
117
|
+
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-2">
|
|
118
|
+
Already Using Control Set
|
|
119
|
+
</h3>
|
|
120
|
+
<p class="text-gray-600 dark:text-gray-400 mb-4">
|
|
121
|
+
You are already using the only available control set in this project.
|
|
122
|
+
</p>
|
|
123
|
+
{#if controlSets.length > 0}
|
|
124
|
+
<div class="text-sm text-gray-500 dark:text-gray-400">
|
|
125
|
+
<span class="font-medium">{controlSets[0].name}</span>
|
|
126
|
+
{#if controlSets[0].controlCount}
|
|
127
|
+
<span class="ml-2">({controlSets[0].controlCount} controls)</span>
|
|
128
|
+
{/if}
|
|
129
|
+
</div>
|
|
130
|
+
{/if}
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div class="flex justify-center gap-4">
|
|
134
|
+
<a
|
|
135
|
+
href="/"
|
|
136
|
+
class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors shadow-lg"
|
|
137
|
+
>
|
|
138
|
+
Continue to Controls
|
|
139
|
+
</a>
|
|
140
|
+
<button
|
|
141
|
+
on:click={() => dispatch('tab-change', { tab: 'import' })}
|
|
142
|
+
class="px-6 py-3 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-900 dark:text-white font-medium rounded-lg transition-colors"
|
|
143
|
+
>
|
|
144
|
+
Import New Control Set
|
|
145
|
+
</button>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
{:else if errorMessage}
|
|
149
|
+
<div
|
|
150
|
+
class="p-4 text-sm text-yellow-800 rounded-lg bg-yellow-50 dark:bg-gray-800 dark:text-yellow-300"
|
|
151
|
+
>
|
|
152
|
+
<div class="flex items-center">
|
|
153
|
+
<svg
|
|
154
|
+
class="flex-shrink-0 inline w-4 h-4 mr-3"
|
|
155
|
+
aria-hidden="true"
|
|
156
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
157
|
+
fill="currentColor"
|
|
158
|
+
viewBox="0 0 20 20"
|
|
159
|
+
>
|
|
160
|
+
<path
|
|
161
|
+
d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"
|
|
162
|
+
/>
|
|
163
|
+
</svg>
|
|
164
|
+
<span>{errorMessage}</span>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
{:else if controlSets.length > 0}
|
|
168
|
+
<div class="space-y-3">
|
|
169
|
+
{#each controlSets as controlSet}
|
|
170
|
+
{@const isCurrent = isCurrentControlSet(controlSet)}
|
|
171
|
+
<div
|
|
172
|
+
on:click={() => !isCurrent && selectControlSet(controlSet)}
|
|
173
|
+
on:keydown={(e) => e.key === 'Enter' && !isCurrent && selectControlSet(controlSet)}
|
|
174
|
+
role="button"
|
|
175
|
+
tabindex="0"
|
|
176
|
+
class="p-4 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 rounded-lg border-2 transition-all duration-200 {isCurrent
|
|
177
|
+
? 'border-green-500 !bg-gradient-to-br from-green-50 to-emerald-50 dark:from-green-900/20 dark:to-emerald-900/20 cursor-not-allowed opacity-75'
|
|
178
|
+
: selectedSet === controlSet
|
|
179
|
+
? 'border-blue-500 !bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-blue-900/20 dark:to-indigo-900/20 shadow-lg cursor-pointer'
|
|
180
|
+
: 'border-gray-200 dark:border-gray-700 hover:border-blue-300 dark:hover:border-blue-700 hover:shadow-md cursor-pointer'}"
|
|
181
|
+
>
|
|
182
|
+
<div class="flex items-center justify-between">
|
|
183
|
+
<div class="flex-1">
|
|
184
|
+
<div class="flex items-center gap-3">
|
|
185
|
+
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">
|
|
186
|
+
{controlSet.name}
|
|
187
|
+
</h3>
|
|
188
|
+
<span
|
|
189
|
+
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200"
|
|
190
|
+
>
|
|
191
|
+
{controlSet.controlCount || 0} controls
|
|
192
|
+
</span>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
{#if controlSet.description}
|
|
196
|
+
<p class="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
|
197
|
+
{controlSet.description}
|
|
198
|
+
</p>
|
|
199
|
+
{/if}
|
|
200
|
+
|
|
201
|
+
<div class="flex items-center gap-4 mt-2">
|
|
202
|
+
<span class="text-xs text-gray-500 dark:text-gray-400">
|
|
203
|
+
<svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
|
204
|
+
<path
|
|
205
|
+
fill-rule="evenodd"
|
|
206
|
+
d="M2 6a2 2 0 012-2h12a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zm2-1a1 1 0 00-1 1v8a1 1 0 001 1h12a1 1 0 001-1V6a1 1 0 00-1-1H4z"
|
|
207
|
+
clip-rule="evenodd"
|
|
208
|
+
/>
|
|
209
|
+
</svg>
|
|
210
|
+
{controlSet.path || 'root'}
|
|
211
|
+
</span>
|
|
212
|
+
{#if controlSet.file}
|
|
213
|
+
<span class="text-xs text-gray-500 dark:text-gray-400">
|
|
214
|
+
<svg class="inline w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
|
215
|
+
<path
|
|
216
|
+
fill-rule="evenodd"
|
|
217
|
+
d="M4 3a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V5a2 2 0 00-2-2H4zm12 12H4l4-8 3 6 2-4 3 6z"
|
|
218
|
+
clip-rule="evenodd"
|
|
219
|
+
/>
|
|
220
|
+
</svg>
|
|
221
|
+
{controlSet.file}
|
|
222
|
+
</span>
|
|
223
|
+
{/if}
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
<div class="flex items-center ml-4">
|
|
228
|
+
{#if isCurrent}
|
|
229
|
+
<div class="flex flex-col items-center">
|
|
230
|
+
<svg
|
|
231
|
+
class="w-8 h-8 text-green-600"
|
|
232
|
+
fill="currentColor"
|
|
233
|
+
viewBox="0 0 20 20"
|
|
234
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
235
|
+
>
|
|
236
|
+
<path
|
|
237
|
+
fill-rule="evenodd"
|
|
238
|
+
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
|
239
|
+
clip-rule="evenodd"
|
|
240
|
+
></path>
|
|
241
|
+
</svg>
|
|
242
|
+
<span class="text-xs text-green-600 font-medium mt-1">Current</span>
|
|
243
|
+
</div>
|
|
244
|
+
{:else if selectedSet === controlSet}
|
|
245
|
+
<svg
|
|
246
|
+
class="w-8 h-8 text-blue-600"
|
|
247
|
+
fill="currentColor"
|
|
248
|
+
viewBox="0 0 20 20"
|
|
249
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
250
|
+
>
|
|
251
|
+
<path
|
|
252
|
+
fill-rule="evenodd"
|
|
253
|
+
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
|
254
|
+
clip-rule="evenodd"
|
|
255
|
+
></path>
|
|
256
|
+
</svg>
|
|
257
|
+
{:else}
|
|
258
|
+
<svg
|
|
259
|
+
class="w-8 h-8 text-gray-300 dark:text-gray-600"
|
|
260
|
+
fill="none"
|
|
261
|
+
viewBox="0 0 20 20"
|
|
262
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
263
|
+
>
|
|
264
|
+
<circle cx="10" cy="10" r="9" stroke="currentColor" stroke-width="2" />
|
|
265
|
+
</svg>
|
|
266
|
+
{/if}
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
{/each}
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
{#if selectedSet}
|
|
274
|
+
<div class="mt-6 flex justify-center">
|
|
275
|
+
<button
|
|
276
|
+
on:click={useSelectedControlSet}
|
|
277
|
+
class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-medium rounded-lg transition-colors shadow-lg"
|
|
278
|
+
>
|
|
279
|
+
Use Selected Control Set
|
|
280
|
+
</button>
|
|
281
|
+
</div>
|
|
282
|
+
{/if}
|
|
283
|
+
{/if}
|
|
284
|
+
</div>
|