From 5073510329b4bfd07173cb0eb6b9df7789a78ca0 Mon Sep 17 00:00:00 2001 From: nscuro Date: Thu, 4 Jun 2026 14:10:17 +0200 Subject: [PATCH] Improve UX of adding project versions * Makes the version selector more visible by rendering it as a pill, and including an indicator for the number of versions. * Moves the button to add a new version from the project details modal to the version dropdown. Makes it more visible and requires fewer clicks to reach. * Marks latest versions with a star icon instead of a verbose `LATEST VERSION` label. * Migrates cloning itself to the v2 API, which is synchronous and returns the UUID of the cloned project. * Keep the version creation modal open with a spinner until cloning completes. * Navigates to the cloned project after request completion. * Provides inline feedback when a project with the chosen version already exists. * Makes dependencies between to-carry-over project data more visible by automatically toggling them. For example, disabling "Include components" also disables "Include findings", since the latter depends on the former. * Makes the version creation modal a proper form, so submission via enter works. Signed-off-by: nscuro --- src/i18n/locales/de.json | 9 +- src/i18n/locales/en.json | 11 +- src/i18n/locales/es.json | 9 +- src/i18n/locales/fr.json | 9 +- src/i18n/locales/hi.json | 9 +- src/i18n/locales/it.json | 9 +- src/i18n/locales/ja.json | 9 +- src/i18n/locales/pl.json | 9 +- src/i18n/locales/pt-BR.json | 9 +- src/i18n/locales/pt.json | 9 +- src/i18n/locales/ru.json | 9 +- src/i18n/locales/uk-UA.json | 9 +- src/i18n/locales/zh-TW.json | 9 +- src/i18n/locales/zh.json | 9 +- src/views/portfolio/projects/Project.vue | 125 ++++++- .../projects/ProjectAddVersionModal.vue | 315 +++++++++++------- .../projects/ProjectDetailsModal.vue | 11 - 17 files changed, 393 insertions(+), 186 deletions(-) diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 2ff5f252a..d931f6665 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -386,6 +386,7 @@ "add_license": "Lizenz hinzufügen", "add_tag": "Tag hinzufügen", "add_version": "Version hinzufügen", + "add_version_includes_help": null, "administration": "Verwaltung", "affected_components": "Betroffene Komponenten", "affected_projects": "Betroffene Projekte", @@ -635,9 +636,11 @@ "inactive_since": "Inaktiv seit", "inactive_versions": "Inaktive Versionen", "include_acl": "Zugriffskontrollliste einschließen", - "include_audit_history": "Prüfverlauf einschließen", "include_components": "Komponenten einbinden", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Richtlinienverstöße einschließen", + "include_policy_violations_audit_history": null, "include_properties": "Eigenschaften einschließen", "include_services": "Leistungen einschließen", "include_tags": "Tags einschließen", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Keine Datei ausgewählt", + "no_version": null, "non_vulnerable": "Nicht anfällig", "not_affected": "Nicht betroffen", "not_found_in_dependency_graph": "Abhängigkeit konnte im Abhängigkeitsdiagramm nicht gefunden werden", @@ -908,7 +912,6 @@ "profile_update": "Profil aktualisieren", "profile_updated": "Profil aktualisiert", "project_add_collection_tag": "Summiere Daten von Kindern mit diesem Tag", - "project_cloning_in_progress": "Das Projekt wird mit den angegebenen Klonoptionen erstellt", "project_collection_logic_aggregate_direct_children": "Summiere Daten von direkten Kindern", "project_collection_logic_aggregate_direct_children_with_tag": "Summiere Daten von direkten Kindern mit Tag", "project_collection_logic_desc": "Gibt an, ob das Projekt ein Sammlungsprojekt ist und welche Berechnung für die Metriken verwendet werden soll. Sammlungsprojekte haben keine eigenen Komponenten, sondern zeigen Daten ihrer Kinder an, basierend auf der gewählten Berechnungsart.", @@ -929,6 +932,7 @@ "project_retention_type": "Wählen Sie den Aufbewahrungstyp für Projekte aus", "project_supplier_name_desc": "Die Organisation, die die im Projekt beschriebene Komponente geliefert hat", "project_updated": "Projekt aktualisiert", + "project_version_conflict": null, "project_vulnerabilities": "Projektschwachstellen", "projects": "Projekte", "projects_at_risk": "Gefährdete Projekte", @@ -1048,6 +1052,7 @@ "suppressed": "Unterdrückt", "swid": "swid", "swid_tagid": "SWID-Tag-ID", + "switch_version": null, "switch_view": "Während der Suche kann die Ansicht nicht gewechselt werden", "sync_status": null, "tag_name": "Verlinke den Namen", diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 13f1d816e..5549d555e 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -386,6 +386,7 @@ "add_license": "Add License", "add_tag": "Add Tag", "add_version": "Add Version", + "add_version_includes_help": "Choose what data to carry over to the new version.", "administration": "Administration", "affected_components": "Affected Components", "affected_projects": "Affected Projects", @@ -635,9 +636,11 @@ "inactive_since": "Inactive since", "inactive_versions": "Inactive Versions", "include_acl": "Include access control list", - "include_audit_history": "Include audit history", "include_components": "Include components", - "include_policy_violations": "Include Policy Violations", + "include_findings": "Include findings", + "include_findings_audit_history": "Include findings audit history", + "include_policy_violations": "Include policy violations", + "include_policy_violations_audit_history": "Include policy violations audit history", "include_properties": "Include properties", "include_services": "Include services", "include_tags": "Include tags", @@ -694,6 +697,7 @@ "next_page": "Next page", "no_changes": "No changes to save", "no_file_chosen": "No file chosen", + "no_version": "(no version)", "non_vulnerable": "Non Vulnerable", "not_affected": "Not Affected", "not_found_in_dependency_graph": "Dependency could not be found in dependency graph", @@ -908,7 +912,6 @@ "profile_update": "Update Profile", "profile_updated": "Profile updated", "project_add_collection_tag": "Aggregate data of children with this tag", - "project_cloning_in_progress": "The project is being created with the cloning options specified", "project_collection_logic_aggregate_direct_children": "Aggregate direct children", "project_collection_logic_aggregate_direct_children_with_tag": "Aggregate direct children with tag", "project_collection_logic_desc": "Specifies if this project is a collection project and which metrics calculation logic to apply for a collection project. Collection projects do not have own components but display data of their children using one of the available logics.", @@ -929,6 +932,7 @@ "project_retention_type": "Select retention type for projects", "project_supplier_name_desc": "The organization that supplied the component that the project describes", "project_updated": "Project updated", + "project_version_conflict": "A project with version “{version}” already exists.", "project_vulnerabilities": "Project Vulnerabilities", "projects": "Projects", "projects_at_risk": "Projects at Risk", @@ -1048,6 +1052,7 @@ "suppressed": "Suppressed", "swid": "swid", "swid_tagid": "SWID Tag ID", + "switch_version": "Switch version", "switch_view": "Cannot switch view while searching", "sync_status": "Sync Status", "tag_name": "Tag Name", diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index d67ed6fa8..f73ce4afd 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -386,6 +386,7 @@ "add_license": "Agregar licencia", "add_tag": "Añadir etiqueta", "add_version": "Agregar versión", + "add_version_includes_help": null, "administration": "Administración", "affected_components": "Componentes afectados", "affected_projects": "Proyectos afectados", @@ -635,9 +636,11 @@ "inactive_since": "Inactivo desde", "inactive_versions": "Versiones inactivas", "include_acl": "Incluir lista de control de acceso", - "include_audit_history": "Incluir historial de auditoría", "include_components": "Incluir componentes", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Incluir violaciones de políticas", + "include_policy_violations_audit_history": null, "include_properties": "Incluir propiedades", "include_services": "Incluir servicios", "include_tags": "Incluir etiquetas", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Ningún archivo elegido", + "no_version": null, "non_vulnerable": "No vulnerable", "not_affected": "No afectado", "not_found_in_dependency_graph": "No se pudo encontrar la dependencia en el gráfico de dependencia", @@ -908,7 +912,6 @@ "profile_update": "Actualización del perfil", "profile_updated": "Perfil actualizado", "project_add_collection_tag": "Datos agregados de niños con esta etiqueta", - "project_cloning_in_progress": "El proyecto se está creando con las opciones de clonación especificadas.", "project_collection_logic_aggregate_direct_children": "Hijos directos agregados", "project_collection_logic_aggregate_direct_children_with_tag": "Agregar hijos directos con etiqueta", "project_collection_logic_desc": "Especifica si este proyecto es un proyecto de recopilación y qué lógica de cálculo de métricas se aplicará para un proyecto de recopilación. \nLos proyectos de colección no tienen componentes propios pero muestran datos de sus hijos usando una de las lógicas disponibles.", @@ -929,6 +932,7 @@ "project_retention_type": "Seleccionar tipo de retención para proyectos", "project_supplier_name_desc": "La organización que suministró el componente que describe el proyecto.", "project_updated": "Proyecto actualizado", + "project_version_conflict": null, "project_vulnerabilities": "Vulnerabilidades del proyecto", "projects": "Proyectos", "projects_at_risk": "Proyectos en riesgo", @@ -1048,6 +1052,7 @@ "suppressed": "suprimido", "swid": "swid", "swid_tagid": "ID de etiqueta SWID", + "switch_version": null, "switch_view": "No se puede cambiar de vista durante la búsqueda", "sync_status": null, "tag_name": "Nombre de etiqueta", diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 731b1fefe..95c5b2b46 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -386,6 +386,7 @@ "add_license": "Ajouter une licence", "add_tag": "Ajouter un tag", "add_version": "Ajouter une version", + "add_version_includes_help": null, "administration": "Administration", "affected_components": "Composants concernés", "affected_projects": "Projets concernés", @@ -635,9 +636,11 @@ "inactive_since": "Inactif depuis", "inactive_versions": "Versions inactives", "include_acl": "Inclure la liste de contrôle d'accès", - "include_audit_history": "Inclure l'historique d'audit", "include_components": "Inclure les composants", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Inclure les violations des règles", + "include_policy_violations_audit_history": null, "include_properties": "Inclure les propriétés", "include_services": "Inclure les services", "include_tags": "Inclure des balises", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Aucun fichier choisi", + "no_version": null, "non_vulnerable": "Non vulnérable", "not_affected": "Pas affecté", "not_found_in_dependency_graph": "La dépendance est introuvable dans le graph des dépendances", @@ -908,7 +912,6 @@ "profile_update": "Mettre à jour le profil", "profile_updated": "Profil mis à jour", "project_add_collection_tag": "Agréger les données des enfants avec cette balise", - "project_cloning_in_progress": "Le projet est en cours de création avec les options de clonage spécifiées", "project_collection_logic_aggregate_direct_children": "Agréger les enfants directs", "project_collection_logic_aggregate_direct_children_with_tag": "Agréger les enfants directs avec la balise", "project_collection_logic_desc": "Spécifie si ce projet est un projet de collection et quelle logique de calcul de métriques appliquer pour un projet de collection. \nLes projets de collection n’ont pas de composants propres mais affichent les données de leurs enfants en utilisant l’une des logiques disponibles.", @@ -929,6 +932,7 @@ "project_retention_type": "Sélectionnez le type de conservation pour les projets", "project_supplier_name_desc": "L'organisation qui a fourni le composant décrit par le projet", "project_updated": "Projet mis à jour", + "project_version_conflict": null, "project_vulnerabilities": "Vulnérabilités du projet", "projects": "Projets", "projects_at_risk": "Projets à risque", @@ -1048,6 +1052,7 @@ "suppressed": "Supprimé", "swid": "swid", "swid_tagid": "ID de tag SWID", + "switch_version": null, "switch_view": "Impossible de changer de vue pendant la recherche", "sync_status": null, "tag_name": "Nom de la tag", diff --git a/src/i18n/locales/hi.json b/src/i18n/locales/hi.json index 87dca83a4..bbafbe9e2 100644 --- a/src/i18n/locales/hi.json +++ b/src/i18n/locales/hi.json @@ -386,6 +386,7 @@ "add_license": "लाइसेंस जोड़ें", "add_tag": "टैग जोड़ो", "add_version": "संस्करण जोड़ें", + "add_version_includes_help": null, "administration": "प्रशासन", "affected_components": "प्रभावित घटक", "affected_projects": "प्रभावित परियोजनाएँ", @@ -635,9 +636,11 @@ "inactive_since": "तब से निष्क्रिय", "inactive_versions": "निष्क्रिय संस्करण", "include_acl": "पहुँच नियंत्रण सूची शामिल करें", - "include_audit_history": "ऑडिट इतिहास शामिल करें", "include_components": "घटक शामिल करें", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "नीति उल्लंघन शामिल करें", + "include_policy_violations_audit_history": null, "include_properties": "गुण शामिल करें", "include_services": "सेवाएँ शामिल करें", "include_tags": "टैग शामिल करें", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "कोई फ़ाइल चुना नही", + "no_version": null, "non_vulnerable": "गैर असुरक्षित", "not_affected": "प्रभावित नहीं", "not_found_in_dependency_graph": "निर्भरता ग्राफ में निर्भरता नहीं पाई जा सकी", @@ -908,7 +912,6 @@ "profile_update": "प्रोफ़ाइल अपडेट करें", "profile_updated": "प्रोफाइल अद्यतन किया गया", "project_add_collection_tag": "इस टैग के साथ बच्चों का समग्र डेटा", - "project_cloning_in_progress": "परियोजना को निर्दिष्ट क्लोनिंग विकल्पों के साथ बनाया जा रहा है", "project_collection_logic_aggregate_direct_children": "प्रत्यक्ष बच्चों को एकत्रित करें", "project_collection_logic_aggregate_direct_children_with_tag": "टैग के साथ प्रत्यक्ष बच्चों को एकत्रित करें", "project_collection_logic_desc": "निर्दिष्ट करता है कि क्या यह प्रोजेक्ट एक संग्रह प्रोजेक्ट है और संग्रह प्रोजेक्ट के लिए कौन सा मेट्रिक्स गणना तर्क लागू करना है। \nसंग्रह परियोजनाओं में स्वयं के घटक नहीं होते हैं, लेकिन उपलब्ध तर्कों में से किसी एक का उपयोग करके अपने बच्चों का डेटा प्रदर्शित करते हैं।", @@ -929,6 +932,7 @@ "project_retention_type": "परियोजनाओं के लिए अवधारण प्रकार का चयन करें", "project_supplier_name_desc": "वह संगठन जिसने परियोजना में वर्णित घटक की आपूर्ति की", "project_updated": "परियोजना अद्यतन", + "project_version_conflict": null, "project_vulnerabilities": "परियोजना की कमज़ोरियाँ", "projects": "परियोजनाओं", "projects_at_risk": "जोखिम में परियोजनाएँ", @@ -1048,6 +1052,7 @@ "suppressed": "दबा", "swid": "swid", "swid_tagid": "SWID टैग आईडी", + "switch_version": null, "switch_view": "खोज करते समय दृश्य स्विच नहीं किया जा सकता", "sync_status": null, "tag_name": "टैग नाम", diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 33f2456ba..0dad65b02 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -386,6 +386,7 @@ "add_license": "Aggiungi licenza", "add_tag": "Aggiungi Tag", "add_version": "Aggiungi versione", + "add_version_includes_help": null, "administration": "Amministrazione", "affected_components": "Componenti interessati", "affected_projects": "Progetti interessati", @@ -635,9 +636,11 @@ "inactive_since": "Inattivo da", "inactive_versions": "Versioni inattive", "include_acl": "Includere l'elenco di controllo degli accessi", - "include_audit_history": "Includere la cronologia degli audit", "include_components": "Includi componenti", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Includi violazioni delle policy", + "include_policy_violations_audit_history": null, "include_properties": "Includi proprietà", "include_services": "Includi servizi", "include_tags": "Includi tag", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Nessun file scelto", + "no_version": null, "non_vulnerable": "Non vulnerabile", "not_affected": "Non affetto", "not_found_in_dependency_graph": "Impossibile trovare la dipendenza nel grafico delle dipendenze", @@ -908,7 +912,6 @@ "profile_update": "Aggiorna il profilo", "profile_updated": "profilo aggiornato", "project_add_collection_tag": "Aggrega i dati dei bambini con questo tag", - "project_cloning_in_progress": "Il progetto viene creato con le opzioni di clonazione specificate", "project_collection_logic_aggregate_direct_children": "Aggregare i figli diretti", "project_collection_logic_aggregate_direct_children_with_tag": "Aggrega i figli diretti con il tag", "project_collection_logic_desc": "Specifica se questo progetto è un progetto di raccolta e quale logica di calcolo delle metriche applicare per un progetto di raccolta. \nI progetti di raccolta non hanno componenti propri ma visualizzano i dati dei propri figli utilizzando una delle logiche disponibili.", @@ -929,6 +932,7 @@ "project_retention_type": "Seleziona il tipo di conservazione per i progetti", "project_supplier_name_desc": "L'organizzazione che ha fornito il componente descritto dal progetto", "project_updated": "Progetto aggiornato", + "project_version_conflict": null, "project_vulnerabilities": "Vulnerabilità del progetto", "projects": "Progetti", "projects_at_risk": "Progetti a rischio", @@ -1048,6 +1052,7 @@ "suppressed": "Soppresso", "swid": "swid", "swid_tagid": "ID dell'etichetta SWID", + "switch_version": null, "switch_view": "Impossibile cambiare visualizzazione durante la ricerca", "sync_status": null, "tag_name": "Nome dell'etichetta", diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 950712fc0..7d4bad9ac 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -386,6 +386,7 @@ "add_license": "ライセンスを追加", "add_tag": "タグを追加", "add_version": "バージョンを追加", + "add_version_includes_help": null, "administration": "管理", "affected_components": "影響を受けるコンポーネント", "affected_projects": "影響を受けるプロジェクト", @@ -635,9 +636,11 @@ "inactive_since": "以降非アクティブ", "inactive_versions": "非アクティブなバージョン", "include_acl": "アクセス制御リストを含める", - "include_audit_history": "監査履歴を含める", "include_components": "コンポーネントを含める", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "ポリシー違反を含める", + "include_policy_violations_audit_history": null, "include_properties": "プロパティを含める", "include_services": "サービスを含める", "include_tags": "タグを含める", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "ファイルが選択されていません", + "no_version": null, "non_vulnerable": "脆弱ではない", "not_affected": "影響を受けません", "not_found_in_dependency_graph": "依存関係グラフに依存関係が見つかりませんでした", @@ -908,7 +912,6 @@ "profile_update": "プロフィールを更新", "profile_updated": "プロフィール更新", "project_add_collection_tag": "このタグを持つ子のデータを集約します", - "project_cloning_in_progress": "プロジェクトは指定されたクローンオプションで作成されています", "project_collection_logic_aggregate_direct_children": "直接の子を集約する", "project_collection_logic_aggregate_direct_children_with_tag": "タグを使用して直接の子を集約する", "project_collection_logic_desc": "このプロジェクトが収集プロジェクトであるかどうか、および収集プロジェクトにどのメトリック計算ロジックを適用するかを指定します。\nコレクション プロジェクトには独自のコンポーネントはありませんが、利用可能なロジックの 1 つを使用して子のデータを表示します。", @@ -929,6 +932,7 @@ "project_retention_type": "プロジェクトの保持タイプを選択する", "project_supplier_name_desc": "プロジェクトで説明されているコンポーネントを供給した組織", "project_updated": "プロジェクトが更新されました", + "project_version_conflict": null, "project_vulnerabilities": "プロジェクトの脆弱性", "projects": "プロジェクト", "projects_at_risk": "リスクのあるプロジェクト", @@ -1048,6 +1052,7 @@ "suppressed": "抑制されている", "swid": "swid", "swid_tagid": "SWID タグ ID", + "switch_version": null, "switch_view": "検索中にビューを切り替えることはできません", "sync_status": null, "tag_name": "タグ名", diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json index 39dd117cc..537948393 100644 --- a/src/i18n/locales/pl.json +++ b/src/i18n/locales/pl.json @@ -386,6 +386,7 @@ "add_license": "Dodaj licencję", "add_tag": "Dodaj znacznik", "add_version": "Dodaj wersję", + "add_version_includes_help": null, "administration": "Administracja", "affected_components": "Dotknięte komponenty", "affected_projects": "Projekty, których to dotyczy", @@ -635,9 +636,11 @@ "inactive_since": "Nieaktywny od", "inactive_versions": "Nieaktywne wersje", "include_acl": "Dołącz listę kontroli dostępu", - "include_audit_history": "Dołącz historię audytu", "include_components": "Uwzględnij komponenty", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Uwzględnij naruszenia zasad", + "include_policy_violations_audit_history": null, "include_properties": "Uwzględnij właściwości", "include_services": "Uwzględnij usługi", "include_tags": "Dołącz tagi", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Nie wybrano żadnego pliku", + "no_version": null, "non_vulnerable": "Niewrażliwy", "not_affected": "Nie dotyczy", "not_found_in_dependency_graph": "Nie można znaleźć zależności na wykresie zależności", @@ -908,7 +912,6 @@ "profile_update": "Zaktualizować profil", "profile_updated": "Profil zaktualizowany", "project_add_collection_tag": "Zbiorcze dane dzieci z tym tagiem", - "project_cloning_in_progress": "Projekt jest tworzony z określonymi opcjami klonowania", "project_collection_logic_aggregate_direct_children": "Zagregowane bezpośrednie dzieci", "project_collection_logic_aggregate_direct_children_with_tag": "Zagreguj bezpośrednie dzieci ze znacznikiem", "project_collection_logic_desc": "Określa, czy ten projekt jest projektem kolekcji i jaką logikę obliczania metryk należy zastosować w projekcie kolekcji. \nProjekty kolekcji nie mają własnych komponentów, ale wyświetlają dane swoich dzieci przy użyciu jednej z dostępnych logiki.", @@ -929,6 +932,7 @@ "project_retention_type": "Wybierz typ przechowywania projektów", "project_supplier_name_desc": "Organizacja, która dostarczyła komponent opisany w projekcie", "project_updated": "Projekt zaktualizowany", + "project_version_conflict": null, "project_vulnerabilities": "Luki w zabezpieczeniach projektu", "projects": "Projektowanie", "projects_at_risk": "Projekty zagrożone", @@ -1048,6 +1052,7 @@ "suppressed": "Zduszony", "swid": "swid", "swid_tagid": "Identyfikator znacznika SWID", + "switch_version": null, "switch_view": "Nie można przełączyć widoku podczas wyszukiwania", "sync_status": null, "tag_name": "Nazwa znacznika", diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json index 783735478..806796b90 100644 --- a/src/i18n/locales/pt-BR.json +++ b/src/i18n/locales/pt-BR.json @@ -386,6 +386,7 @@ "add_license": "Adicionar licença", "add_tag": "Adicionar etiqueta", "add_version": "Adicionar versão", + "add_version_includes_help": null, "administration": "Administração", "affected_components": "Componentes afetados", "affected_projects": "Projetos afetados", @@ -635,9 +636,11 @@ "inactive_since": "Inativo desde", "inactive_versions": "Versões inativas", "include_acl": "Incluir lista de controle de acesso", - "include_audit_history": "Incluir histórico de auditoria", "include_components": "Incluir componentes", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Incluir violações de política", + "include_policy_violations_audit_history": null, "include_properties": "Incluir propriedades", "include_services": "Incluir serviços", "include_tags": "Incluir tags", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Nenhum arquivo selecionado", + "no_version": null, "non_vulnerable": "Não Vulnerável", "not_affected": "Não afetado", "not_found_in_dependency_graph": "A dependência não foi encontrada no gráfico de dependência", @@ -908,7 +912,6 @@ "profile_update": "Atualizar perfil", "profile_updated": "perfil atualizado", "project_add_collection_tag": "Dados agregados de crianças com esta tag", - "project_cloning_in_progress": "O projeto está sendo criado com as opções de clonagem especificadas", "project_collection_logic_aggregate_direct_children": "Agregar filhos diretos", "project_collection_logic_aggregate_direct_children_with_tag": "Agregar filhos diretos com tag", "project_collection_logic_desc": "Especifica se este projeto é um projeto de coleção e qual lógica de cálculo de métricas aplicar a um projeto de coleção. \nOs projetos de coleção não possuem componentes próprios, mas exibem os dados de seus filhos utilizando uma das lógicas disponíveis.", @@ -929,6 +932,7 @@ "project_retention_type": "Selecione o tipo de retenção para projetos", "project_supplier_name_desc": "A organização que forneceu o componente que o projeto descreve", "project_updated": "Projeto atualizado", + "project_version_conflict": null, "project_vulnerabilities": "Vulnerabilidades do projeto", "projects": "Projetos", "projects_at_risk": "Projetos em risco", @@ -1048,6 +1052,7 @@ "suppressed": "Suprimido", "swid": "swid", "swid_tagid": "ID da etiqueta SWID", + "switch_version": null, "switch_view": "Não é possível mudar de visualização durante a pesquisa", "sync_status": null, "tag_name": "Nome da etiqueta", diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index b457a98ac..a7849a770 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -386,6 +386,7 @@ "add_license": "Adicionar licença", "add_tag": "Adicionar etiqueta", "add_version": "Adicionar versão", + "add_version_includes_help": null, "administration": "Administração", "affected_components": "Componentes afetados", "affected_projects": "Projetos afetados", @@ -635,9 +636,11 @@ "inactive_since": "Inativo desde", "inactive_versions": "Versões inativas", "include_acl": "Incluir lista de controle de acesso", - "include_audit_history": "Incluir histórico de auditoria", "include_components": "Incluir componentes", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Incluir violações de política", + "include_policy_violations_audit_history": null, "include_properties": "Incluir propriedades", "include_services": "Incluir serviços", "include_tags": "Incluir tags", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Nenhum arquivo selecionado", + "no_version": null, "non_vulnerable": "Não Vulnerável", "not_affected": "Não afetado", "not_found_in_dependency_graph": "A dependência não foi encontrada no gráfico de dependência", @@ -908,7 +912,6 @@ "profile_update": "Atualizar perfil", "profile_updated": "perfil atualizado", "project_add_collection_tag": "Dados agregados de crianças com esta tag", - "project_cloning_in_progress": "O projeto está sendo criado com as opções de clonagem especificadas", "project_collection_logic_aggregate_direct_children": "Agregar filhos diretos", "project_collection_logic_aggregate_direct_children_with_tag": "Agregar filhos diretos com tag", "project_collection_logic_desc": "Especifica se este projeto é um projeto de coleção e qual lógica de cálculo de métricas aplicar a um projeto de coleção. \nOs projetos de coleção não possuem componentes próprios, mas exibem os dados de seus filhos utilizando uma das lógicas disponíveis.", @@ -929,6 +932,7 @@ "project_retention_type": "Selecione o tipo de retenção para projetos", "project_supplier_name_desc": "A organização que forneceu o componente que o projeto descreve", "project_updated": "Projeto atualizado", + "project_version_conflict": null, "project_vulnerabilities": "Vulnerabilidades do projeto", "projects": "Projetos", "projects_at_risk": "Projetos em risco", @@ -1048,6 +1052,7 @@ "suppressed": "Suprimido", "swid": "swid", "swid_tagid": "ID da etiqueta SWID", + "switch_version": null, "switch_view": "Não é possível mudar de visualização durante a pesquisa", "sync_status": null, "tag_name": "Nome da etiqueta", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 9488a2262..f5831a66c 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -386,6 +386,7 @@ "add_license": "Добавить лицензию", "add_tag": "Добавить тег", "add_version": "Добавить версию", + "add_version_includes_help": null, "administration": "Администрирование", "affected_components": "Затронутые компоненты", "affected_projects": "Затронутые проекты", @@ -635,9 +636,11 @@ "inactive_since": "Неактивен с", "inactive_versions": "Неактивные версии", "include_acl": "Включить список контроля доступа", - "include_audit_history": "Включить историю аудита", "include_components": "Включить компоненты", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Включить нарушения политик", + "include_policy_violations_audit_history": null, "include_properties": "Включить свойства", "include_services": "Включить службы", "include_tags": "Включить теги", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Файл не выбран", + "no_version": null, "non_vulnerable": "Неуязвимый", "not_affected": "Не затронуто", "not_found_in_dependency_graph": "Зависимость не найдена в графе зависимостей", @@ -908,7 +912,6 @@ "profile_update": "Обновить профиль", "profile_updated": "Профиль обновлён", "project_add_collection_tag": "Совокупные данные детей с этим тегом", - "project_cloning_in_progress": "Проект создаётся с указанными параметрами клонирования", "project_collection_logic_aggregate_direct_children": "Агрегировать прямых дочерних элементов", "project_collection_logic_aggregate_direct_children_with_tag": "Объединить прямых дочерних элементов с помощью тега", "project_collection_logic_desc": "Указывает, является ли этот проект проектом сбора и какую логику расчета метрик следует применить для проекта сбора. \nПроекты-коллекции не имеют собственных компонентов, а отображают данные своих дочерних элементов, используя одну из доступных логик.", @@ -929,6 +932,7 @@ "project_retention_type": "Выберите тип хранения для проектов", "project_supplier_name_desc": "Организация, поставившая компонент, описанный в проекте", "project_updated": "Проект обновлён", + "project_version_conflict": null, "project_vulnerabilities": "Уязвимости проекта", "projects": "Проекты", "projects_at_risk": "Проекты в риске", @@ -1048,6 +1052,7 @@ "suppressed": "Подавлено", "swid": "swid", "swid_tagid": "ID тега SWID", + "switch_version": null, "switch_view": "Невозможно переключить вид при поиске", "sync_status": null, "tag_name": "Название тега", diff --git a/src/i18n/locales/uk-UA.json b/src/i18n/locales/uk-UA.json index 05f7db37e..3dc71e06c 100644 --- a/src/i18n/locales/uk-UA.json +++ b/src/i18n/locales/uk-UA.json @@ -386,6 +386,7 @@ "add_license": "Додати ліцензію", "add_tag": "Додати тег", "add_version": "Додати версію", + "add_version_includes_help": null, "administration": "Адміністрування", "affected_components": "Уражені компоненти", "affected_projects": "Уражені проєкти", @@ -635,9 +636,11 @@ "inactive_since": "Неактивний з", "inactive_versions": "Неактивні версії", "include_acl": "Включити список контролю доступу", - "include_audit_history": "Включити історію аудиту", "include_components": "Включити компоненти", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "Включити порушення політики", + "include_policy_violations_audit_history": null, "include_properties": "Включити властивості", "include_services": "Включити сервіси", "include_tags": "Включити теги", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "Файл не вибрано", + "no_version": null, "non_vulnerable": "Не уразливий", "not_affected": "Не уражений", "not_found_in_dependency_graph": "Залежність не знайдена в графі залежностей", @@ -908,7 +912,6 @@ "profile_update": "Оновити профіль", "profile_updated": "Профіль оновлено", "project_add_collection_tag": "Агрегувати дані дочірніх елементів за цим тегом", - "project_cloning_in_progress": "Проєкт створюється згідно з вказаними параметрами клонування", "project_collection_logic_aggregate_direct_children": "Агрегувати прямі дочірні елементи", "project_collection_logic_aggregate_direct_children_with_tag": "Агрегувати прямі дочірні елементи з тегом", "project_collection_logic_desc": "Визначає, чи є цей проєкт проєктом колекції та яку логіку розрахунку метрик застосовувати для проєкту колекції. Проєкти колекції не мають власних компонентів, але відображають дані своїх дочірніх елементів, використовуючи одну з доступних логік.", @@ -929,6 +932,7 @@ "project_retention_type": "Виберіть тип збереження для проектів", "project_supplier_name_desc": "Організація, яка постачала компонент, описаний проєктом", "project_updated": "Проєкт оновлено", + "project_version_conflict": null, "project_vulnerabilities": "Уразливості проєкту", "projects": "Проєкти", "projects_at_risk": "Проєкти в зоні ризику", @@ -1048,6 +1052,7 @@ "suppressed": "Приховано", "swid": "swid", "swid_tagid": "ID тегу SWID", + "switch_version": null, "switch_view": "Неможливо переключити вигляд під час пошуку", "sync_status": null, "tag_name": "Назва тегу", diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index 5364fec48..222e27b93 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -386,6 +386,7 @@ "add_license": "新增授權", "add_tag": "新增標籤", "add_version": "新增版本", + "add_version_includes_help": null, "administration": "系統設定", "affected_components": "受影響的元件", "affected_projects": "受影響的專案", @@ -635,9 +636,11 @@ "inactive_since": "不活動自", "inactive_versions": "停用版本", "include_acl": "包含存取控制清單", - "include_audit_history": "包含稽核歷史", "include_components": "包含元件", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "包含策略違規", + "include_policy_violations_audit_history": null, "include_properties": "包含屬性", "include_services": "包含服務", "include_tags": "包含標籤", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": "沒有要儲存的更改", "no_file_chosen": "未選取任何檔案", + "no_version": null, "non_vulnerable": "非易受攻擊", "not_affected": "不受影響", "not_found_in_dependency_graph": "在依賴關係圖中找不到依賴關係", @@ -908,7 +912,6 @@ "profile_update": "更新個人資訊", "profile_updated": "個人資料已更新", "project_add_collection_tag": "彙總具有此標籤的子專案資料", - "project_cloning_in_progress": "正在使用指定的複製選項建立專案", "project_collection_logic_aggregate_direct_children": "彙總直接子專案", "project_collection_logic_aggregate_direct_children_with_tag": "使用標籤彙總直接子專案", "project_collection_logic_desc": "指定此專案是否是集合專案以及要為集合專案應用哪些指標計算邏輯。\n集合專案沒有自己的元件,但使用可用邏輯之一顯示其子專案的資料。", @@ -929,6 +932,7 @@ "project_retention_type": "選擇項目的保留類型", "project_supplier_name_desc": "提供專案所述元件的組織", "project_updated": "專案已更新", + "project_version_conflict": null, "project_vulnerabilities": "專案漏洞", "projects": "專案", "projects_at_risk": "面臨風險的專案", @@ -1048,6 +1052,7 @@ "suppressed": "抑制", "swid": "swid", "swid_tagid": "SWID 標籤 ID", + "switch_version": null, "switch_view": "搜尋時無法切換檢視", "sync_status": "同步狀態", "tag_name": "標籤名稱", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 6042fca55..0ab9d1914 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -386,6 +386,7 @@ "add_license": "添加许可证", "add_tag": "添加标签", "add_version": "添加版本", + "add_version_includes_help": null, "administration": "系统设置", "affected_components": "受影响的组件", "affected_projects": "受影响的项目", @@ -635,9 +636,11 @@ "inactive_since": "不活跃自", "inactive_versions": "非活跃版本", "include_acl": "包含访问控制列表", - "include_audit_history": "包含审计历史", "include_components": "包含组件", + "include_findings": null, + "include_findings_audit_history": null, "include_policy_violations": "包含策略违规", + "include_policy_violations_audit_history": null, "include_properties": "包含属性", "include_services": "包含服务", "include_tags": "包含标签", @@ -694,6 +697,7 @@ "next_page": null, "no_changes": null, "no_file_chosen": "未选择文件", + "no_version": null, "non_vulnerable": "无漏洞", "not_affected": "不受影响", "not_found_in_dependency_graph": "在依赖关系图中未找到该依赖", @@ -908,7 +912,6 @@ "profile_update": "更新个人资料", "profile_updated": "个人资料已更新", "project_add_collection_tag": "含此标签的子项汇总数据", - "project_cloning_in_progress": "正在使用指定的克隆选项创建项目", "project_collection_logic_aggregate_direct_children": "聚合直接子项", "project_collection_logic_aggregate_direct_children_with_tag": "按标签聚合直接子项", "project_collection_logic_desc": "指定此项目是否为集合项目,以及集合项目使用哪种指标计算逻辑。\n集合项目不包含自身的组件,而是通过可选逻辑之一展示其子项的数据。", @@ -929,6 +932,7 @@ "project_retention_type": "选择项目的保留类型", "project_supplier_name_desc": "提供该项目所述组件的组织", "project_updated": "项目已更新", + "project_version_conflict": null, "project_vulnerabilities": "项目漏洞", "projects": "项目", "projects_at_risk": "存在风险的项目", @@ -1048,6 +1052,7 @@ "suppressed": "已抑制", "swid": "SWID", "swid_tagid": "SWID 标签 ID", + "switch_version": null, "switch_view": "搜索时无法切换视图", "sync_status": null, "tag_name": "标签名称", diff --git a/src/views/portfolio/projects/Project.vue b/src/views/portfolio/projects/Project.vue index 77b3a1b85..f11d4c350 100644 --- a/src/views/portfolio/projects/Project.vue +++ b/src/views/portfolio/projects/Project.vue @@ -12,7 +12,7 @@ {{ project.name }} - {{ project.version }} {{ $t('message.inactive').toUpperCase() }} - - {{ $t('message.latest_version').toUpperCase() }} - version.active); + return (this.project.versions || []).filter((version) => version.active); }, inactiveProjectVersions() { - return this.project.versions.filter((version) => !version.active); + return (this.project.versions || []).filter((version) => !version.active); + }, + versionCount() { + return this.project.versions && this.project.versions.length > 0 + ? this.project.versions.length + : 1; }, isCollectionProject: function () { return !!this.project.collectionLogic; @@ -636,4 +702,27 @@ export default { max-height: 30rem; overflow-y: auto; } +.add-version-icon { + color: inherit !important; +} +.version-dropdown-toggle.badge { + padding: 0.3em 0.6em; + margin-left: 0.5rem; + vertical-align: middle; + color: inherit; + background-color: transparent; +} +.version-dropdown-toggle.badge:hover { + color: inherit; +} +.version-dropdown-toggle .fa-caret-down { + transition: transform 0.15s ease-in-out; +} +.version-dropdown-toggle[aria-expanded='true'] .fa-caret-down { + transform: rotate(180deg); +} +.version-count { + margin-left: 0.5rem; + padding-left: 0.5rem; +} diff --git a/src/views/portfolio/projects/ProjectAddVersionModal.vue b/src/views/portfolio/projects/ProjectAddVersionModal.vue index aeed9d5ac..170411c0e 100644 --- a/src/views/portfolio/projects/ProjectAddVersionModal.vue +++ b/src/views/portfolio/projects/ProjectAddVersionModal.vue @@ -1,127 +1,127 @@ @@ -138,63 +138,122 @@ export default { data() { return { version: null, + versionInvalidFeedback: null, + makeCloneLatest: false, includeTags: true, includeProperties: true, - includeComponents: true, includeServices: true, - includeAuditHistory: true, includeACL: true, + includeComponents: true, + includeFindings: true, + includeFindingsAuditHistory: true, includePolicyViolations: true, - makeCloneLatest: false, + includePolicyViolationsAuditHistory: true, + isCloning: false, }; }, computed: { isSubmitButtonDisabled() { - const versionInputValue = this.version; - if (versionInputValue) { - /** - * * ideally we would apply the check with the input value trimmed, however, since we are already using 'trim' prop on the input value. - * * trimming the value here is not required. - */ - return versionInputValue.length === 0; + // The input uses the 'trim' prop, so the bound value is already trimmed. + return !this.version || this.version.length === 0; + }, + }, + watch: { + includeComponents(value) { + if (!value) { + this.includeFindings = false; + this.includePolicyViolations = false; + } + }, + includeFindings(value) { + if (value) { + this.includeComponents = true; + } else { + this.includeFindingsAuditHistory = false; + } + }, + includeFindingsAuditHistory(value) { + if (value) { + this.includeFindings = true; + } + }, + includePolicyViolations(value) { + if (value) { + this.includeComponents = true; + } else { + this.includePolicyViolationsAuditHistory = false; + } + }, + includePolicyViolationsAuditHistory(value) { + if (value) { + this.includePolicyViolations = true; } - return true; }, }, methods: { + focusVersionInput: function () { + this.$refs.versionInput?.focus(); + }, createVersion: function () { - let url = `${this.$api.BASE_URL}/${this.$api.URL_PROJECT}/clone`; + if (this.isSubmitButtonDisabled || this.isCloning) { + return; + } + const includes = []; + if (this.includeTags) includes.push('TAGS'); + if (this.includeProperties) includes.push('PROPERTIES'); + if (this.includeServices) includes.push('SERVICES'); + if (this.includeACL) includes.push('ACL'); + if (this.includeComponents) includes.push('COMPONENTS'); + if (this.includeFindings) includes.push('FINDINGS'); + if (this.includeFindingsAuditHistory) + includes.push('FINDINGS_AUDIT_HISTORY'); + if (this.includePolicyViolations) includes.push('POLICY_VIOLATIONS'); + if (this.includePolicyViolationsAuditHistory) + includes.push('POLICY_VIOLATIONS_AUDIT_HISTORY'); + let url = `${this.$api.BASE_URL}/api/v2/projects/${this.uuid}/clone`; + this.isCloning = true; this.axios - .put(url, { - project: this.uuid, + .post(url, { version: this.version, - includeTags: this.includeTags, - includeProperties: this.includeProperties, - includeComponents: this.includeComponents, - includeServices: this.includeServices, - includeAuditHistory: this.includeAuditHistory, - includeACL: this.includeACL, - includePolicyViolations: this.includePolicyViolations, - makeCloneLatest: this.makeCloneLatest, + version_is_latest: this.makeCloneLatest === true, + includes: includes, }) .then((response) => { this.$root.$emit('bv::hide::modal', 'projectAddVersionModal'); - this.$toastr.s(this.$t('message.project_cloning_in_progress')); + this.$toastr.s(this.$t('message.project_created')); + this.$router.push({ + name: 'Project', + params: { uuid: response.data.uuid }, + }); }) .catch((error) => { - this.$toastr.w(this.$t('condition.unsuccessful_action')); + if (error.response && error.response.status === 409) { + this.versionInvalidFeedback = this.$t( + 'message.project_version_conflict', + { version: this.version }, + ); + } else { + this.$toastr.w(this.$t('condition.unsuccessful_action')); + } + }) + .finally(() => { + this.isCloning = false; }); }, resetValues: function () { this.version = null; + this.versionInvalidFeedback = null; + this.makeCloneLatest = false; this.includeTags = true; this.includeProperties = true; - this.includeComponents = true; this.includeServices = true; - this.includeAuditHistory = true; this.includeACL = true; + this.includeComponents = true; + this.includeFindings = true; + this.includeFindingsAuditHistory = true; this.includePolicyViolations = true; - this.makeCloneLatest = false; + this.includePolicyViolationsAuditHistory = true; + this.isCloning = false; }, }, }; diff --git a/src/views/portfolio/projects/ProjectDetailsModal.vue b/src/views/portfolio/projects/ProjectDetailsModal.vue index e8942c836..299a8089e 100644 --- a/src/views/portfolio/projects/ProjectDetailsModal.vue +++ b/src/views/portfolio/projects/ProjectDetailsModal.vue @@ -562,17 +562,6 @@ ]" >{{ $t('message.properties') }} - {{ $t('message.add_version') }}