lula2 0.8.8 → 0.8.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lula2",
3
- "version": "0.8.8",
3
+ "version": "0.8.9",
4
4
  "description": "A tool for managing compliance as code in your GitHub repositories.",
5
5
  "bin": {
6
6
  "lula2": "./dist/lula2"
@@ -63,7 +63,7 @@
63
63
  "express-rate-limit": "8.2.1",
64
64
  "flowbite": "4.0.1",
65
65
  "glob": "13.0.0",
66
- "isomorphic-git": "1.36.0",
66
+ "isomorphic-git": "1.36.1",
67
67
  "js-yaml": "4.1.1",
68
68
  "multer": "2.0.2",
69
69
  "open": "11.0.0",
@@ -28,9 +28,9 @@
28
28
 
29
29
  let { control }: Props = $props();
30
30
 
31
- // Component state
32
- let editedControl = $state({ ...control });
33
- let originalControl = $state({ ...control });
31
+ // Component state - initialize with reactive derived values
32
+ let editedControl = $state<Control>({ ...control });
33
+ let originalControl = $state<Control>({ ...control });
34
34
  let activeTab = $state<'details' | 'narrative' | 'custom' | 'mappings' | 'history'>('details');
35
35
  let saveDebounceTimeout: ReturnType<typeof setTimeout> | null = null;
36
36
  let isSaving = $state(false);
@@ -47,6 +47,51 @@
47
47
  isSaving ? 'saving' : (hasChanges ? 'unsaved' : (showSavedMessage ? 'just-saved' : 'clean'))
48
48
  );
49
49
 
50
+ // Formatted control with CCI definitions properly split
51
+ const formattedControl = $derived.by(() => {
52
+ const viewModel = { ...editedControl };
53
+
54
+ const cciRaw = viewModel.cci;
55
+ const defRaw = viewModel.cci_definition ?? viewModel["cci-definition"];
56
+
57
+ if (typeof cciRaw !== "string" || typeof defRaw !== "string") {
58
+ return viewModel;
59
+ }
60
+
61
+ const cciList = cciRaw
62
+ .split(";")
63
+ .map((c) => c.trim())
64
+ .filter(Boolean);
65
+
66
+ if (cciList.length < 2) return viewModel;
67
+
68
+ const text = defRaw;
69
+ const segments: string[] = [];
70
+
71
+ // Find start indexes of each CCI in the definition
72
+ const positions = cciList
73
+ .map((cci) => {
74
+ const idx = text.indexOf(`${cci}:`);
75
+ return idx >= 0 ? { cci, idx } : null;
76
+ })
77
+ .filter((v): v is { cci: string; idx: number } => Boolean(v))
78
+ .sort((a, b) => a.idx - b.idx);
79
+
80
+ for (let i = 0; i < positions.length; i++) {
81
+ const start = positions[i].idx;
82
+ const end = positions[i + 1]?.idx ?? text.length;
83
+ segments.push(text.slice(start, end).trim());
84
+ }
85
+
86
+ if (segments.length > 0) {
87
+ const formatted = segments.join("\n\n\n");
88
+ viewModel.cci_definition = formatted;
89
+ viewModel["cci-definition"] = formatted;
90
+ }
91
+
92
+ return viewModel;
93
+ });
94
+
50
95
  // Check if tabs have any fields
51
96
  const hasCustomFields = $derived(() => {
52
97
  if (!fieldSchema) return false;
@@ -60,12 +105,14 @@
60
105
 
61
106
  // Watch for control changes - only reset when ID changes
62
107
  $effect(() => {
63
- if (control.id !== editedControl?.id) {
108
+ // Access control within the effect to properly track changes
109
+ const currentControl = control;
110
+ if (currentControl.id !== editedControl?.id) {
64
111
  if (saveDebounceTimeout) {
65
112
  clearTimeout(saveDebounceTimeout);
66
113
  }
67
- editedControl = { ...control };
68
- originalControl = { ...control };
114
+ editedControl = { ...currentControl };
115
+ originalControl = { ...currentControl };
69
116
  activeTab = 'details';
70
117
  }
71
118
  });
@@ -211,9 +258,9 @@
211
258
  <main class="flex-1 overflow-auto pt-4">
212
259
  <div class="">
213
260
  {#if activeTab === 'details'}
214
- <OverviewTab control={editedControl} {fieldSchema} />
261
+ <OverviewTab control={formattedControl} {fieldSchema} />
215
262
  {:else if activeTab === 'narrative'}
216
- <ImplementationTab control={editedControl} {fieldSchema} />
263
+ <ImplementationTab control={formattedControl} {fieldSchema} />
217
264
  {:else if activeTab === 'custom'}
218
265
  <CustomFieldsTab
219
266
  control={editedControl}
@@ -222,12 +269,11 @@
222
269
  />
223
270
  {:else if activeTab === 'mappings'}
224
271
  <MappingsTab
225
- {control}
272
+ control={formattedControl}
226
273
  mappings={associatedMappings}
227
274
  />
228
275
  {:else if activeTab === 'history'}
229
276
  <TimelineTab
230
- {control}
231
277
  timeline={control.timeline}
232
278
  />
233
279
  {/if}
@@ -23,7 +23,7 @@
23
23
  field &&
24
24
  (field.ui_type === 'textarea' || field.ui_type === 'long_text') &&
25
25
  typeof value === 'string' &&
26
- value.includes('\n')
26
+ value.includes('\n') && !value.includes('\n\n\n')
27
27
  );
28
28
  </script>
29
29