diff --git a/app.go b/app.go
index 2a24221a..8880ef59 100644
--- a/app.go
+++ b/app.go
@@ -147,6 +147,18 @@ func (a *App) BuildMenu(keyboardService service.KeyboardService) *menu.Menu {
runtime.EventsEmit(a.ctx, string(entities.ActionIncludeComponent))
})
+ // Ignore submenu
+ IgnoreMenu := ActionsMenu.AddSubmenu("Ignore")
+ IgnoreMenu.AddText("Ignore file", nil, func(cd *menu.CallbackData) {
+ runtime.EventsEmit(a.ctx, string(entities.ActionIgnoreFile))
+ })
+ IgnoreMenu.AddText("Ignore folder", nil, func(cd *menu.CallbackData) {
+ runtime.EventsEmit(a.ctx, string(entities.ActionIgnoreFolder))
+ })
+ IgnoreMenu.AddText("Ignore component", nil, func(cd *menu.CallbackData) {
+ runtime.EventsEmit(a.ctx, string(entities.ActionIgnoreComponent))
+ })
+
// Dismiss submenu
DismissMenu := ActionsMenu.AddSubmenu("Dismiss")
DismissMenu.AddText("Dismiss file", nil, func(cd *menu.CallbackData) {
diff --git a/backend/entities/component.go b/backend/entities/component.go
index cbf1c25b..04540616 100644
--- a/backend/entities/component.go
+++ b/backend/entities/component.go
@@ -87,6 +87,7 @@ type FilterAction string
const (
Include FilterAction = "include"
+ Ignore FilterAction = "ignore"
Remove FilterAction = "remove"
Replace FilterAction = "replace"
)
@@ -95,7 +96,7 @@ type ComponentFilterDTO struct {
Path string `json:"path,omitempty"`
Purl string `json:"purl,omitempty"`
Usage string `json:"usage,omitempty"`
- Action FilterAction `json:"action" validate:"required,eq=include|eq=remove|eq=replace"`
+ Action FilterAction `json:"action" validate:"required,eq=include|eq=ignore|eq=remove|eq=replace"`
Comment string `json:"comment,omitempty"`
ReplaceWith string `json:"replace_with,omitempty" validate:"omitempty,valid-purl"`
License string `json:"license,omitempty"`
diff --git a/backend/entities/keyboard.go b/backend/entities/keyboard.go
index 13fa713a..00850ec3 100644
--- a/backend/entities/keyboard.go
+++ b/backend/entities/keyboard.go
@@ -44,6 +44,9 @@ const (
ActionIncludeFile Action = "includeFile"
ActionIncludeComponent Action = "includeComponent"
ActionIncludeFolder Action = "includeFolder"
+ ActionIgnoreFile Action = "ignoreFile"
+ ActionIgnoreComponent Action = "ignoreComponent"
+ ActionIgnoreFolder Action = "ignoreFolder"
ActionDismissFile Action = "dismissFile"
ActionDismissComponent Action = "dismissComponent"
ActionDismissFolder Action = "dismissFolder"
@@ -100,6 +103,9 @@ var AllShortcutActions = []struct {
{ActionIncludeFile, "IncludeFile"},
{ActionIncludeComponent, "IncludeComponent"},
{ActionIncludeFolder, "IncludeFolder"},
+ {ActionIgnoreFile, "IgnoreFile"},
+ {ActionIgnoreComponent, "IgnoreComponent"},
+ {ActionIgnoreFolder, "IgnoreFolder"},
{ActionDismissFile, "DismissFile"},
{ActionDismissComponent, "DismissComponent"},
{ActionDismissFolder, "DismissFolder"},
diff --git a/backend/entities/scanoss_settings.go b/backend/entities/scanoss_settings.go
index f60bf5f9..f5abf203 100644
--- a/backend/entities/scanoss_settings.go
+++ b/backend/entities/scanoss_settings.go
@@ -72,6 +72,7 @@ type SizesSkipSettings struct {
type Bom struct {
Include []ComponentFilter `json:"include,omitempty"`
+ Ignore []ComponentFilter `json:"ignore,omitempty"`
Remove []ComponentFilter `json:"remove,omitempty"`
Replace []ComponentFilter `json:"replace,omitempty"`
}
@@ -87,6 +88,7 @@ type ComponentFilter struct {
type InitialFilters struct {
Include []ComponentFilter
+ Ignore []ComponentFilter
Remove []ComponentFilter
Replace []ComponentFilter
}
@@ -195,10 +197,11 @@ func (sf *SettingsFile) Equal(other *SettingsFile) (bool, error) {
func (sf *SettingsFile) GetResultWorkflowState(result Result) WorkflowState {
included, _ := sf.IsResultIncluded(result)
+ ignored, _ := sf.IsResultIgnored(result)
removed, _ := sf.IsResultRemoved(result)
replaced, _ := sf.IsResultReplaced(result)
- if included || removed || replaced {
+ if included || ignored || removed || replaced {
return Completed
}
@@ -209,6 +212,10 @@ func (sf *SettingsFile) IsResultIncluded(result Result) (bool, int) {
return sf.IsResultInList(result, sf.Bom.Include)
}
+func (sf *SettingsFile) IsResultIgnored(result Result) (bool, int) {
+ return sf.IsResultInList(result, sf.Bom.Ignore)
+}
+
func (sf *SettingsFile) IsResultRemoved(result Result) (bool, int) {
return sf.IsResultInList(result, sf.Bom.Remove)
}
@@ -242,6 +249,9 @@ func (sf *SettingsFile) GetResultFilterConfig(result Result) FilterConfig {
if included, i := sf.IsResultIncluded(result); included {
filterAction = Include
filterType = getResultFilterType(sf.Bom.Include[i])
+ } else if ignored, i := sf.IsResultIgnored(result); ignored {
+ filterAction = Ignore
+ filterType = getResultFilterType(sf.Bom.Ignore[i])
} else if removed, i := sf.IsResultRemoved(result); removed {
filterAction = Remove
filterType = getResultFilterType(sf.Bom.Remove[i])
@@ -274,6 +284,10 @@ func (sf *SettingsFile) GetBomEntryFromResult(result Result) ComponentFilter {
return sf.Bom.Include[i]
}
+ if ignored, i := sf.IsResultIgnored(result); ignored {
+ return sf.Bom.Ignore[i]
+ }
+
if removed, i := sf.IsResultRemoved(result); removed {
return sf.Bom.Remove[i]
}
diff --git a/backend/repository/scanoss_settings_repository_json_impl.go b/backend/repository/scanoss_settings_repository_json_impl.go
index 33f5cd52..4c732a6d 100644
--- a/backend/repository/scanoss_settings_repository_json_impl.go
+++ b/backend/repository/scanoss_settings_repository_json_impl.go
@@ -155,6 +155,8 @@ func (r *ScanossSettingsJsonRepository) AddBomEntry(newEntry entities.ComponentF
targetList = &sf.Bom.Remove
case "include":
targetList = &sf.Bom.Include
+ case "ignore":
+ targetList = &sf.Bom.Ignore
case "replace":
targetList = &sf.Bom.Replace
default:
@@ -173,6 +175,7 @@ func (r *ScanossSettingsJsonRepository) removeDuplicatesFromAllLists(newEntry en
sf.Bom.Remove = removeDuplicatesFromList(sf.Bom.Remove, newEntry)
sf.Bom.Include = removeDuplicatesFromList(sf.Bom.Include, newEntry)
+ sf.Bom.Ignore = removeDuplicatesFromList(sf.Bom.Ignore, newEntry)
sf.Bom.Replace = removeDuplicatesFromList(sf.Bom.Replace, newEntry)
}
@@ -196,6 +199,7 @@ func isDuplicate(entry, newEntry entities.ComponentFilter) bool {
func (r *ScanossSettingsJsonRepository) ClearAllFilters() error {
sf := r.GetSettings()
sf.Bom.Include = []entities.ComponentFilter{}
+ sf.Bom.Ignore = []entities.ComponentFilter{}
sf.Bom.Remove = []entities.ComponentFilter{}
sf.Bom.Replace = []entities.ComponentFilter{}
return nil
@@ -205,13 +209,15 @@ func (r *ScanossSettingsJsonRepository) GetDeclaredPurls() []string {
sf := r.GetSettings()
includedComponents := extractPurlsFromBom(sf.Bom.Include)
+ ignoredComponents := extractPurlsFromBom(sf.Bom.Ignore)
removedComponents := extractPurlsFromBom(sf.Bom.Remove)
replacedComponents := extractPurlsFromBom(sf.Bom.Replace)
- totalLength := len(includedComponents) + len(removedComponents) + len(replacedComponents)
+ totalLength := len(includedComponents) + len(ignoredComponents) + len(removedComponents) + len(replacedComponents)
declaredPurls := make([]string, 0, totalLength)
declaredPurls = append(declaredPurls, includedComponents...)
+ declaredPurls = append(declaredPurls, ignoredComponents...)
declaredPurls = append(declaredPurls, removedComponents...)
declaredPurls = append(declaredPurls, replacedComponents...)
diff --git a/backend/service/component_service_impl.go b/backend/service/component_service_impl.go
index 2beadf24..00c65afe 100644
--- a/backend/service/component_service_impl.go
+++ b/backend/service/component_service_impl.go
@@ -75,6 +75,14 @@ func (s *ComponentServiceImpl) setInitialFilters() {
Action: entities.Include,
})
}
+ for _, ignore := range initialFilters.Ignore {
+ s.initialFilters = append(s.initialFilters, entities.ComponentFilterDTO{
+ Path: ignore.Path,
+ Purl: ignore.Purl,
+ Usage: string(ignore.Usage),
+ Action: entities.Ignore,
+ })
+ }
for _, remove := range initialFilters.Remove {
s.initialFilters = append(s.initialFilters, entities.ComponentFilterDTO{
Path: remove.Path,
@@ -99,10 +107,11 @@ func (s *ComponentServiceImpl) ClearAllFilters() error {
func (s *ComponentServiceImpl) GetInitialFilters() entities.InitialFilters {
sf := s.scanossSettingsRepo.GetSettings()
- include, remove, replace := sf.Bom.Include, sf.Bom.Remove, sf.Bom.Replace
+ include, ignore, remove, replace := sf.Bom.Include, sf.Bom.Ignore, sf.Bom.Remove, sf.Bom.Replace
return entities.InitialFilters{
Include: include,
+ Ignore: ignore,
Remove: remove,
Replace: replace,
}
diff --git a/frontend/src/components/FilterComponentActions.tsx b/frontend/src/components/FilterComponentActions.tsx
index ccc4fcab..c3750f89 100644
--- a/frontend/src/components/FilterComponentActions.tsx
+++ b/frontend/src/components/FilterComponentActions.tsx
@@ -21,7 +21,7 @@
* SOFTWARE.
*/
-import { Check, EyeOff, PackageMinus, Replace } from 'lucide-react';
+import { Ban, Check, EyeOff, PackageMinus, Replace } from 'lucide-react';
import { useCallback, useMemo, useState } from 'react';
import useKeyboardShortcut from '@/hooks/useKeyboardShortcut';
@@ -122,6 +122,11 @@ export default function FilterComponentActions() {
includeFolder: createModalActionHandler(FilterAction.Include, 'folder'),
includeComponent: createModalActionHandler(FilterAction.Include, 'component'),
+ // Ignore: file applies directly, others open modal
+ ignoreFile: createDirectActionHandler(FilterAction.Ignore),
+ ignoreFolder: createModalActionHandler(FilterAction.Ignore, 'folder'),
+ ignoreComponent: createModalActionHandler(FilterAction.Ignore, 'component'),
+
// Dismiss: file applies directly, others open modal
dismissFile: createDirectActionHandler(FilterAction.Remove),
dismissFolder: createModalActionHandler(FilterAction.Remove, 'folder'),
@@ -149,6 +154,11 @@ export default function FilterComponentActions() {
useKeyboardShortcut(KEYBOARD_SHORTCUTS.includeComponent.keys, handlers.includeComponent, { enabled: filterEnabled });
useKeyboardShortcut(KEYBOARD_SHORTCUTS.includeFolder.keys, handlers.includeFolder, { enabled: filterEnabled });
+ // Ignore
+ useKeyboardShortcut(KEYBOARD_SHORTCUTS.ignoreFile.keys, handlers.ignoreFile, { enabled: filterEnabled });
+ useKeyboardShortcut(KEYBOARD_SHORTCUTS.ignoreComponent.keys, handlers.ignoreComponent, { enabled: filterEnabled });
+ useKeyboardShortcut(KEYBOARD_SHORTCUTS.ignoreFolder.keys, handlers.ignoreFolder, { enabled: filterEnabled });
+
// Dismiss
useKeyboardShortcut(KEYBOARD_SHORTCUTS.dismissFile.keys, handlers.dismissFile, { enabled: filterEnabled });
useKeyboardShortcut(KEYBOARD_SHORTCUTS.dismissComponent.keys, handlers.dismissComponent, { enabled: filterEnabled });
@@ -170,6 +180,10 @@ export default function FilterComponentActions() {
[entities.Action.IncludeFile]: handlers.includeFile,
[entities.Action.IncludeComponent]: handlers.includeComponent,
[entities.Action.IncludeFolder]: handlers.includeFolder,
+ // Ignore
+ [entities.Action.IgnoreFile]: handlers.ignoreFile,
+ [entities.Action.IgnoreComponent]: handlers.ignoreComponent,
+ [entities.Action.IgnoreFolder]: handlers.ignoreFolder,
// Dismiss
[entities.Action.DismissFile]: handlers.dismissFile,
[entities.Action.DismissComponent]: handlers.dismissComponent,
@@ -214,6 +228,31 @@ export default function FilterComponentActions() {
+ {/* Ignore */}
+
+
+ Ignore
+
+
+
+
+ File
+ G
+
+
+ Folder
+ Alt+Shift+G
+
+
+ Component
+ Shift+G
+
+
+
+
{/* Dismiss */}
= {
description: 'Open include dialog with folder selected',
keys: 'alt+shift+i',
},
+ [entities.Action.IgnoreFile]: {
+ name: 'Ignore file',
+ description: 'Ignore file directly',
+ keys: 'g, f5',
+ },
+ [entities.Action.IgnoreComponent]: {
+ name: 'Ignore component',
+ description: 'Open ignore dialog with component selected',
+ keys: 'shift+g, shift+f5',
+ },
+ [entities.Action.IgnoreFolder]: {
+ name: 'Ignore folder',
+ description: 'Open ignore dialog with folder selected',
+ keys: 'alt+shift+g',
+ },
[entities.Action.DismissFile]: {
name: 'Dismiss file',
description: 'Dismiss file directly',
diff --git a/frontend/src/modules/components/domain/index.ts b/frontend/src/modules/components/domain/index.ts
index 09c92a0f..e9465b79 100644
--- a/frontend/src/modules/components/domain/index.ts
+++ b/frontend/src/modules/components/domain/index.ts
@@ -31,7 +31,7 @@ export enum FilterAction {
export type FilterBy = 'path' | 'purl';
export const filterActionLabelMap: Record = {
- [FilterAction.Ignore]: 'Omit / Skip',
+ [FilterAction.Ignore]: 'Ignore',
[FilterAction.Include]: 'Include',
[FilterAction.Remove]: 'Dismiss',
[FilterAction.Replace]: 'Replace',
diff --git a/frontend/wailsjs/go/models.ts b/frontend/wailsjs/go/models.ts
index a8d12ef2..5c280971 100755
--- a/frontend/wailsjs/go/models.ts
+++ b/frontend/wailsjs/go/models.ts
@@ -12,6 +12,9 @@ export namespace entities {
IncludeFile = "includeFile",
IncludeComponent = "includeComponent",
IncludeFolder = "includeFolder",
+ IgnoreFile = "ignoreFile",
+ IgnoreComponent = "ignoreComponent",
+ IgnoreFolder = "ignoreFolder",
DismissFile = "dismissFile",
DismissComponent = "dismissComponent",
DismissFolder = "dismissFolder",
@@ -50,16 +53,18 @@ export namespace entities {
}
export class Bom {
include?: ComponentFilter[];
+ ignore?: ComponentFilter[];
remove?: ComponentFilter[];
replace?: ComponentFilter[];
-
+
static createFrom(source: any = {}) {
return new Bom(source);
}
-
+
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.include = this.convertValues(source["include"], ComponentFilter);
+ this.ignore = this.convertValues(source["ignore"], ComponentFilter);
this.remove = this.convertValues(source["remove"], ComponentFilter);
this.replace = this.convertValues(source["replace"], ComponentFilter);
}
@@ -409,16 +414,18 @@ export namespace entities {
}
export class InitialFilters {
Include: ComponentFilter[];
+ Ignore: ComponentFilter[];
Remove: ComponentFilter[];
Replace: ComponentFilter[];
-
+
static createFrom(source: any = {}) {
return new InitialFilters(source);
}
-
+
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.Include = this.convertValues(source["Include"], ComponentFilter);
+ this.Ignore = this.convertValues(source["Ignore"], ComponentFilter);
this.Remove = this.convertValues(source["Remove"], ComponentFilter);
this.Replace = this.convertValues(source["Replace"], ComponentFilter);
}