lula2 0.3.3 → 0.3.4-nightly.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.
Files changed (56) hide show
  1. package/dist/_app/immutable/assets/0.D6CB7gA7.css +1 -0
  2. package/dist/_app/immutable/chunks/BITsSGhD.js +65 -0
  3. package/dist/_app/immutable/chunks/BcKIo18J.js +3 -0
  4. package/dist/_app/immutable/chunks/{C9p1zaS8.js → BhjtS45v.js} +1 -1
  5. package/dist/_app/immutable/chunks/{cvagBx-i.js → BkFSJLu9.js} +1 -1
  6. package/dist/_app/immutable/chunks/CHdfnWSV.js +1 -0
  7. package/dist/_app/immutable/chunks/{ZLxiKtk1.js → CzIDw1HQ.js} +1 -1
  8. package/dist/_app/immutable/chunks/{DkTmghUd.js → DknPZycG.js} +1 -1
  9. package/dist/_app/immutable/chunks/{C2RwV308.js → DwdPeWTx.js} +1 -1
  10. package/dist/_app/immutable/chunks/{EhHGBAhB.js → vNis_B2V.js} +1 -1
  11. package/dist/_app/immutable/entry/{app.DlQKiOqI.js → app.rFT55pRO.js} +2 -2
  12. package/dist/_app/immutable/entry/start.BWvTyytY.js +1 -0
  13. package/dist/_app/immutable/nodes/{0.BebGxk-A.js → 0.CMylckYT.js} +1 -1
  14. package/dist/_app/immutable/nodes/{1.DfUs1HjM.js → 1.DPLsosR-.js} +1 -1
  15. package/dist/_app/immutable/nodes/{2.CrOeZTVE.js → 2.DvLMOmaz.js} +1 -1
  16. package/dist/_app/immutable/nodes/{3.D6SgInYh.js → 3.hM9U_7ZV.js} +1 -1
  17. package/dist/_app/immutable/nodes/4.DNVoxjQw.js +11 -0
  18. package/dist/_app/version.json +1 -1
  19. package/dist/cli/commands/ui.js +10 -10
  20. package/dist/cli/server/index.js +10 -10
  21. package/dist/cli/server/server.js +10 -10
  22. package/dist/cli/server/websocketServer.js +10 -10
  23. package/dist/index.html +10 -10
  24. package/dist/index.js +10 -10
  25. package/package.json +20 -21
  26. package/src/lib/components/control-sets/ControlSetSelector.svelte +1 -1
  27. package/src/lib/components/controls/ControlDetailsPanel.svelte +1 -1
  28. package/src/lib/components/controls/ControlsList.svelte +4 -48
  29. package/src/lib/components/controls/DynamicControlEditor.svelte +2 -2
  30. package/src/lib/components/controls/MappingCard.svelte +1 -1
  31. package/src/lib/components/controls/MappingForm.svelte +1 -1
  32. package/src/lib/components/controls/renderers/EditableFieldRenderer.svelte +1 -1
  33. package/src/lib/components/controls/renderers/FieldRenderer.svelte +2 -2
  34. package/src/lib/components/controls/tabs/CustomFieldsTab.svelte +2 -2
  35. package/src/lib/components/controls/tabs/ImplementationTab.svelte +3 -3
  36. package/src/lib/components/controls/tabs/MappingsTab.svelte +1 -1
  37. package/src/lib/components/controls/tabs/OverviewTab.svelte +4 -4
  38. package/src/lib/components/controls/tabs/TimelineTab.svelte +2 -3
  39. package/src/lib/components/controls/utils/ProcessedTextRenderer.svelte +4 -4
  40. package/src/lib/components/forms/DynamicControlForm.svelte +10 -10
  41. package/src/lib/components/forms/DynamicField.svelte +4 -4
  42. package/src/lib/components/forms/FormField.svelte +1 -1
  43. package/src/lib/components/setup/ExistingControlSets.svelte +1 -1
  44. package/src/lib/components/setup/SpreadsheetImport.svelte +8 -10
  45. package/src/lib/components/ui/CustomDropdown.svelte +1 -1
  46. package/src/lib/components/ui/FilterBuilder.svelte +4 -4
  47. package/src/lib/components/ui/TabNavigation.svelte +1 -1
  48. package/src/lib/components/version-control/DiffViewer.svelte +1 -1
  49. package/src/lib/components/version-control/YamlDiffViewer.svelte +2 -2
  50. package/src/stores/compliance.ts +2 -69
  51. package/dist/_app/immutable/assets/0.BeyRWDYp.css +0 -1
  52. package/dist/_app/immutable/chunks/BTTmO90G.js +0 -65
  53. package/dist/_app/immutable/chunks/Dz_3mPpR.js +0 -1
  54. package/dist/_app/immutable/chunks/z5X83jua.js +0 -3
  55. package/dist/_app/immutable/entry/start.CuPBZjFh.js +0 -1
  56. package/dist/_app/immutable/nodes/4.Be0URtGy.js +0 -11
@@ -12,7 +12,7 @@
12
12
  readonly?: boolean;
13
13
  }
14
14
 
15
- let { fieldName, field, value, readonly = true }: Props = $props();
15
+ let { fieldName, field, value }: Props = $props();
16
16
 
17
17
  const displayName = $derived(
18
18
  field?.original_name || fieldName.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase())
@@ -46,4 +46,4 @@
46
46
  <span class="whitespace-pre-line">{value}</span>
47
47
  {/if}
48
48
  </div>
49
- </div>
49
+ </div>
@@ -105,9 +105,9 @@
105
105
  Additional fields specific to your organization
106
106
  </div>
107
107
  <div class="space-y-8">
108
- {#each fieldGroups as fieldGroup}
108
+ {#each fieldGroups as fieldGroup, index (index)}
109
109
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
110
- {#each fieldGroup as [fieldName, field]}
110
+ {#each fieldGroup as [fieldName, field], index (index)}
111
111
  <div class={getFieldLayoutClass(field)}>
112
112
  <EditableFieldRenderer
113
113
  {fieldName}
@@ -102,9 +102,9 @@
102
102
  <div class="space-y-4">
103
103
  <div class="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 p-6">
104
104
  <div class="space-y-8">
105
- {#each fieldGroups as fieldGroup}
105
+ {#each fieldGroups as fieldGroup, index (index)}
106
106
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
107
- {#each fieldGroup as [fieldName, field]}
107
+ {#each fieldGroup as [fieldName, field], index (index)}
108
108
  <div class={getFieldLayoutClass(field)}>
109
109
  <FieldRenderer
110
110
  {fieldName}
@@ -124,4 +124,4 @@
124
124
  <p class="text-gray-500 dark:text-gray-400">No implementation fields available</p>
125
125
  </div>
126
126
  {/if}
127
- </div>
127
+ </div>
@@ -99,7 +99,7 @@
99
99
  <!-- Existing Mappings -->
100
100
  {#if mappings.length > 0}
101
101
  <div class="space-y-4">
102
- {#each mappings as mapping}
102
+ {#each mappings as mapping (mapping.uuid)}
103
103
  {#if editingMapping && editingMapping.uuid === mapping.uuid}
104
104
  <!-- Edit Form in place of the mapping being edited -->
105
105
  <div
@@ -107,9 +107,9 @@
107
107
  <div class="space-y-4">
108
108
  <div class="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 p-6">
109
109
  <div class="space-y-8">
110
- {#each fieldGroups as fieldGroup}
110
+ {#each fieldGroups as fieldGroup, index (index)}
111
111
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
112
- {#each fieldGroup as [fieldName, field]}
112
+ {#each fieldGroup as [fieldName, field], index (index)}
113
113
  <div class={getFieldLayoutClass(field)}>
114
114
  <FieldRenderer
115
115
  {fieldName}
@@ -136,7 +136,7 @@
136
136
  <h3 class="text-lg font-semibold text-gray-900 dark:text-white">Control Properties</h3>
137
137
  <div class="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 p-6">
138
138
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
139
- {#each Object.entries(control.properties) as [key, value]}
139
+ {#each Object.entries(control.properties) as [key, value], index (index)}
140
140
  <FieldRenderer
141
141
  fieldName={key.replace(/_/g, ' ')}
142
142
  field={null}
@@ -148,4 +148,4 @@
148
148
  </div>
149
149
  </div>
150
150
  {/if}
151
- </div>
151
+ </div>
@@ -3,11 +3,10 @@
3
3
 
4
4
  <script lang="ts">
5
5
  import { TimelineItem } from '$components/version-control';
6
- import type { Control } from '$lib/types';
7
6
  import { EmptyState } from '../../ui';
8
7
 
9
8
  interface Props {
10
- control: Control;
9
+ // control: Control;
11
10
  timeline?: any; // Timeline type from control.timeline
12
11
  }
13
12
 
@@ -26,7 +25,7 @@
26
25
  {:else if commits.length > 0}
27
26
  <div class="mb-4">
28
27
  <div class="space-y-6">
29
- {#each commits as commit, index}
28
+ {#each commits as commit, index (index)}
30
29
  <TimelineItem {commit} showConnector={index < commits.length - 1} />
31
30
  {/each}
32
31
  </div>
@@ -14,7 +14,7 @@
14
14
  </script>
15
15
 
16
16
  <div class="space-y-3">
17
- {#each sections as section}
17
+ {#each sections as section, index (index)}
18
18
  {#if section.type === 'header'}
19
19
  <h4 class="font-semibold text-gray-900 dark:text-gray-100 mt-4 first:mt-0">
20
20
  {section.content}
@@ -23,9 +23,9 @@
23
23
  <div class="overflow-x-auto">
24
24
  <table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
25
25
  <tbody class="divide-y divide-gray-200 dark:divide-gray-700">
26
- {#each section.data.rows as row, _i}
26
+ {#each section.data.rows as row, index (index)}
27
27
  <tr class="hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors">
28
- {#each row.columns as column, j}
28
+ {#each row.columns as column, j (j)}
29
29
  <td class="px-3 py-2 text-sm {j === 0 ? 'font-medium text-gray-900 dark:text-gray-100' : 'text-gray-600 dark:text-gray-400'}">
30
30
  {#if column.startsWith('CCI-')}
31
31
  <code class="px-1.5 py-0.5 text-xs bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded">
@@ -47,7 +47,7 @@
47
47
  </div>
48
48
  {:else if section.type === 'list' && section.data?.items}
49
49
  <ul class="space-y-1 ml-4">
50
- {#each section.data.items as item}
50
+ {#each section.data.items as item, index (index)}
51
51
  <li class="flex items-start">
52
52
  <span class="text-gray-400 dark:text-gray-500 mr-2 flex-shrink-0">•</span>
53
53
  <span class="text-gray-600 dark:text-gray-400 text-sm">{item}</span>
@@ -128,8 +128,8 @@
128
128
  {#if readonly}
129
129
  <!-- View Mode: Clean minimal layout -->
130
130
  <div class="space-y-6">
131
- {#each Object.entries(fieldGroups) as [_groupName, fields]}
132
- {#each [fields] as fieldList}
131
+ {#each Object.entries(fieldGroups) as [_groupName, fields], index (index)}
132
+ {#each [fields] as fieldList, a (a)}
133
133
  {@const importantFields = fieldList.filter((f) =>
134
134
  ['id', 'title', 'priority', 'status'].includes(f.id)
135
135
  )}
@@ -147,7 +147,7 @@
147
147
  {#if importantFields.length > 0}
148
148
  <div class="pb-4 border-b border-gray-200 dark:border-gray-700">
149
149
  <div class="flex flex-wrap items-center gap-6">
150
- {#each importantFields as field}
150
+ {#each importantFields as field, index (index)}
151
151
  {@const value = control[field.id]}
152
152
  {#if value !== undefined && value !== null && value !== ''}
153
153
  <div class="flex items-center space-x-3">
@@ -181,7 +181,7 @@
181
181
  {/if}
182
182
 
183
183
  <!-- Content sections -->
184
- {#each contentFields as field}
184
+ {#each contentFields as field, index (index)}
185
185
  {@const value = control[field.id]}
186
186
 
187
187
  {#if field.type === 'textarea'}
@@ -206,7 +206,7 @@
206
206
  </span>
207
207
  </h3>
208
208
  <div class="space-y-2">
209
- {#each value as item}
209
+ {#each value as item, index (index)}
210
210
  <div class="flex items-start space-x-3 py-2">
211
211
  <div class="flex-shrink-0 w-1.5 h-1.5 bg-blue-600 rounded-full mt-2"></div>
212
212
  <div class="text-gray-900 dark:text-white leading-relaxed">
@@ -226,13 +226,13 @@
226
226
  </span>
227
227
  </h3>
228
228
  <div class="space-y-3">
229
- {#each value as item, _index}
229
+ {#each value as item, index (index)}
230
230
  <div
231
231
  class="bg-gray-50 dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700"
232
232
  >
233
233
  {#if field.arraySchema}
234
234
  <dl class="space-y-2">
235
- {#each Object.entries(field.arraySchema) as [key, schema]}
235
+ {#each Object.entries(field.arraySchema) as [key, schema], index (index)}
236
236
  {@const schemaObj = schema as any}
237
237
  {#if item[key]}
238
238
  <div class="flex justify-between">
@@ -281,7 +281,7 @@
281
281
  {:else}
282
282
  <!-- Edit Mode: Enhanced form layout -->
283
283
  <div class="space-y-10">
284
- {#each Object.entries(fieldGroups) as [groupName, fields]}
284
+ {#each Object.entries(fieldGroups) as [groupName, fields], index (index)}
285
285
  <section
286
286
  class="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-sm overflow-hidden"
287
287
  >
@@ -300,7 +300,7 @@
300
300
  <div class="p-8">
301
301
  <!-- Improved grid layout for simple fields -->
302
302
  <div class="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-8 mb-10">
303
- {#each fields as field}
303
+ {#each fields as field, index (index)}
304
304
  {#if !['textarea', 'string-array', 'object-array'].includes(field.type)}
305
305
  <div class="space-y-2">
306
306
  <DynamicField
@@ -317,7 +317,7 @@
317
317
 
318
318
  <!-- Enhanced full-width fields with better spacing -->
319
319
  <div class="space-y-10">
320
- {#each fields as field}
320
+ {#each fields as field, index (index)}
321
321
  {#if ['textarea', 'string-array', 'object-array'].includes(field.type)}
322
322
  <div
323
323
  class="bg-gray-50 dark:bg-gray-800 rounded-xl p-6 border border-gray-200 dark:border-gray-700"
@@ -140,7 +140,7 @@
140
140
  {#if !field.required}
141
141
  <option value="">-- Select an option --</option>
142
142
  {/if}
143
- {#each field.options as option}
143
+ {#each field.options as option (option)}
144
144
  <option value={option}>{option}</option>
145
145
  {/each}
146
146
  </select>
@@ -221,7 +221,7 @@
221
221
  </button>
222
222
  </div>
223
223
  {:else}
224
- {#each ensureArray() as item, index}
224
+ {#each ensureArray() as item, index (index)}
225
225
  <div
226
226
  class="group relative p-4 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm hover:shadow-md transition-shadow"
227
227
  >
@@ -349,7 +349,7 @@
349
349
  </button>
350
350
  </div>
351
351
  {:else}
352
- {#each ensureArray() as item, index}
352
+ {#each ensureArray() as item, index (index)}
353
353
  <div
354
354
  class="group relative bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-sm hover:shadow-md transition-all duration-200"
355
355
  >
@@ -409,7 +409,7 @@
409
409
  <div class="p-4">
410
410
  {#if field.arraySchema}
411
411
  <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
412
- {#each Object.entries(field.arraySchema) as [key, schemaObj]}
412
+ {#each Object.entries(field.arraySchema) as [key, schemaObj], index (index)}
413
413
  {@const schema = schemaObj as any}
414
414
  <div class="space-y-2">
415
415
  <label
@@ -63,7 +63,7 @@
63
63
  class="{baseInputClass} {errorClass} {successClass} cursor-pointer"
64
64
  onchange={onChange}
65
65
  >
66
- {#each options as option}
66
+ {#each options as option (option)}
67
67
  <option value={option}>{option}</option>
68
68
  {/each}
69
69
  </select>
@@ -165,7 +165,7 @@
165
165
  </div>
166
166
  {:else if controlSets.length > 0}
167
167
  <div class="space-y-3">
168
- {#each controlSets as controlSet}
168
+ {#each controlSets as controlSet, index (index)}
169
169
  {@const isCurrent = isCurrentControlSet(controlSet)}
170
170
  <div
171
171
  on:click={() => !isCurrent && selectControlSet(controlSet)}
@@ -13,8 +13,6 @@
13
13
  let sampleData: any[] = [];
14
14
  let controlCount = 0;
15
15
  let rowPreviews: { row: number; preview: string }[] = [];
16
- // Make availableFields reactive to both fields and fieldConfigs changes
17
- $: availableFields = fields.filter((f) => fields.includes(f));
18
16
 
19
17
  // Field configuration for tabs
20
18
  type TabAssignment = 'overview' | 'implementation' | 'mappings' | 'custom' | null;
@@ -426,7 +424,7 @@
426
424
 
427
425
  // Add field schema configuration - include all fields that are assigned to a tab
428
426
  const fieldSchema = Array.from(fieldConfigs.entries())
429
- .filter(([field, config]) => config.tab !== null)
427
+ .filter(([_field, config]) => config.tab !== null)
430
428
  .map(([field, config]) => ({
431
429
  fieldName: cleanFieldName(field),
432
430
  ...config
@@ -622,7 +620,7 @@
622
620
  }}
623
621
  class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"
624
622
  >
625
- {#each sheets as sheet}
623
+ {#each sheets as sheet (sheet)}
626
624
  <option value={sheet}>{sheet}</option>
627
625
  {/each}
628
626
  </select>
@@ -644,7 +642,7 @@
644
642
  on:change={loadSheetData}
645
643
  class="bg-white border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:text-white"
646
644
  >
647
- {#each rowPreviews as preview}
645
+ {#each rowPreviews as preview (preview.row)}
648
646
  <option value={preview.row}>
649
647
  Row {preview.row}: {preview.preview}
650
648
  </option>
@@ -671,7 +669,7 @@
671
669
  required
672
670
  >
673
671
  <option value="" disabled>Select Control ID field</option>
674
- {#each fields as field}
672
+ {#each fields as field (field)}
675
673
  {@const exampleValue =
676
674
  sampleData.length > 0 && sampleData[0][field]
677
675
  ? String(sampleData[0][field]).slice(0, 30)
@@ -834,7 +832,7 @@
834
832
  >
835
833
  {#each Array.from(fieldConfigs.entries())
836
834
  .filter(([_field, config]) => config.tab === 'implementation')
837
- .sort((a, b) => a[1].displayOrder - b[1].displayOrder) as [field, _config], index (field)}
835
+ .sort((a, b) => a[1].displayOrder - b[1].displayOrder) as [field, _config], _index (field)}
838
836
  <div
839
837
  draggable="true"
840
838
  on:dragstart={(e) => handleFieldDragStart(e, field)}
@@ -1010,15 +1008,15 @@
1010
1008
  class="text-xs text-gray-700 uppercase bg-gray-100 dark:bg-gray-600 dark:text-gray-400"
1011
1009
  >
1012
1010
  <tr>
1013
- {#each fields.slice(0, 5) as field}
1011
+ {#each fields.slice(0, 5) as field (field)}
1014
1012
  <th class="px-4 py-2">{field}</th>
1015
1013
  {/each}
1016
1014
  </tr>
1017
1015
  </thead>
1018
1016
  <tbody>
1019
- {#each sampleData as row}
1017
+ {#each sampleData as row, i (i)}
1020
1018
  <tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
1021
- {#each fields.slice(0, 5) as field}
1019
+ {#each fields.slice(0, 5) as field (field)}
1022
1020
  <td class="px-4 py-2">{row[field] || ''}</td>
1023
1021
  {/each}
1024
1022
  </tr>
@@ -74,7 +74,7 @@
74
74
  >
75
75
  <slot name="header" />
76
76
 
77
- {#each options as option}
77
+ {#each options as option, index (index)}
78
78
  <button
79
79
  type="button"
80
80
  class={twMerge(
@@ -191,7 +191,7 @@
191
191
  <p class="text-sm text-gray-500 dark:text-gray-400">No filters</p>
192
192
  {:else}
193
193
  <div class="space-y-2">
194
- {#each $activeFilters as filter, index}
194
+ {#each $activeFilters as filter, index (index)}
195
195
  <div
196
196
  class="flex items-center justify-between bg-gray-50 dark:bg-gray-700 p-2 rounded-md"
197
197
  >
@@ -262,7 +262,7 @@
262
262
  >
263
263
  Overview Fields
264
264
  </div>
265
- {#each fieldsByTab.overview as field}
265
+ {#each fieldsByTab.overview as field (field)}
266
266
  <button
267
267
  class={twMerge(
268
268
  'w-full text-left px-3 py-2 text-sm',
@@ -288,7 +288,7 @@
288
288
  >
289
289
  Implementation Fields
290
290
  </div>
291
- {#each fieldsByTab.implementation as field}
291
+ {#each fieldsByTab.implementation as field (field)}
292
292
  <button
293
293
  class={twMerge(
294
294
  'w-full text-left px-3 py-2 text-sm',
@@ -315,7 +315,7 @@
315
315
  >
316
316
  Custom Fields
317
317
  </div>
318
- {#each fieldsByTab.custom as field}
318
+ {#each fieldsByTab.custom as field (field)}
319
319
  <button
320
320
  class={twMerge(
321
321
  'w-full text-left px-3 py-2 text-sm',
@@ -21,7 +21,7 @@
21
21
 
22
22
  <nav class="border-b border-gray-200 dark:border-gray-700 flex-shrink-0">
23
23
  <div class="flex space-x-4">
24
- {#each tabs as tab}
24
+ {#each tabs as tab, index (index)}
25
25
  <button
26
26
  onclick={() => !tab.disabled && onSelect(tab.id)}
27
27
  disabled={tab.disabled}
@@ -213,7 +213,7 @@
213
213
  {/if}
214
214
 
215
215
  <div class="diff-content max-h-96 overflow-y-auto">
216
- {#each parsedDiff as line}
216
+ {#each parsedDiff as line, index (index)}
217
217
  <div
218
218
  class="diff-line flex {line.type === 'addition'
219
219
  ? 'bg-green-50 dark:bg-green-900/20'
@@ -272,7 +272,7 @@
272
272
  {#if showDetailedView}
273
273
  <!-- Detailed view with full context -->
274
274
  <div class="divide-y divide-gray-200 dark:divide-gray-600">
275
- {#each yamlDiff.changes as change}
275
+ {#each yamlDiff.changes as change, i (i)}
276
276
  <div class="p-3 {getChangeColor(change.type)}">
277
277
  <div class="flex items-start space-x-3">
278
278
  <div
@@ -337,7 +337,7 @@
337
337
  {:else}
338
338
  <!-- Summary view - more compact -->
339
339
  <div class="p-4 space-y-2">
340
- {#each yamlDiff.changes as change}
340
+ {#each yamlDiff.changes as change (change)}
341
341
  <div class="flex items-center space-x-2 text-sm">
342
342
  <span
343
343
  class="w-5 h-5 rounded-full flex items-center justify-center text-xs font-bold {getChangeColor(
@@ -1,9 +1,9 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Lula Authors
3
3
 
4
- import type { Control, ControlWithMappings, Mapping } from '$lib/types';
4
+ import type { Control, Mapping } from '$lib/types';
5
5
  import { appState } from '$lib/websocket';
6
- import { derived, get, writable } from 'svelte/store';
6
+ import { get, writable } from 'svelte/store';
7
7
 
8
8
  /**
9
9
  * Shared filter operator options used across the application
@@ -57,73 +57,6 @@ export const searchTerm = writable('');
57
57
  export const selectedControl = writable<Control | null>(null);
58
58
  export const activeFilters = writable<FilterCondition[]>([]);
59
59
 
60
- export const filteredControls = derived(
61
- [controls, searchTerm, activeFilters],
62
- ([$controls, $searchTerm, $activeFilters]) => {
63
- let results = $controls;
64
-
65
- // Apply search term
66
- if ($searchTerm) {
67
- const term = $searchTerm.toLowerCase();
68
- results = results.filter((c) => JSON.stringify(c).toLowerCase().includes(term));
69
- }
70
-
71
- // Apply advanced filters
72
- if ($activeFilters.length > 0) {
73
- results = results.filter((control) => {
74
- // Cast to ControlWithDynamicFields for dynamic field access
75
- const dynamicControl = control as Record<string, unknown>;
76
-
77
- // Control must match all filters
78
- return $activeFilters.every((filter) => {
79
- const fieldValue = dynamicControl[filter.fieldName];
80
-
81
- // For exists/not_exists operators, we just need to check if the field has a value
82
- if (filter.operator === 'exists') {
83
- return fieldValue !== undefined && fieldValue !== null && fieldValue !== '';
84
- } else if (filter.operator === 'not_exists') {
85
- return fieldValue === undefined || fieldValue === null || fieldValue === '';
86
- }
87
-
88
- // For other operators, convert values to strings for comparison
89
- const fieldValueStr = String(fieldValue).toLowerCase();
90
- const filterValueStr =
91
- filter.value !== undefined ? String(filter.value).toLowerCase() : '';
92
-
93
- switch (filter.operator) {
94
- case 'equals':
95
- return fieldValueStr === filterValueStr;
96
-
97
- case 'not_equals':
98
- return fieldValueStr !== filterValueStr;
99
-
100
- case 'includes':
101
- return fieldValueStr.includes(filterValueStr);
102
-
103
- case 'not_includes':
104
- return !fieldValueStr.includes(filterValueStr);
105
-
106
- default:
107
- return true;
108
- }
109
- });
110
- });
111
- }
112
-
113
- return results;
114
- }
115
- );
116
-
117
- export const controlsWithMappings = derived(
118
- [controls, mappings],
119
- ([$controls, $mappings]): ControlWithMappings[] => {
120
- return $controls.map((control) => ({
121
- ...control,
122
- mappings: $mappings.filter((m) => m.control_id === control.id)
123
- }));
124
- }
125
- );
126
-
127
60
  // Store actions - mostly for local state management
128
61
  // All server operations now go through WebSocket
129
62
  export const complianceStore = {