diff --git a/.eslintrc.js b/.eslintrc.js index 2ed7280464..54d868a23e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -26,6 +26,7 @@ module.exports = { '@typescript-eslint/no-explicit-any': 'warn', 'no-debugger': 'error', 'ember/no-empty-glimmer-component-classes': 'off', + 'ember/no-pause-test': 'error', }, overrides: [ // node files diff --git a/app/components/ak-svg/severity-override-success.hbs b/app/components/ak-svg/severity-override-success.hbs new file mode 100644 index 0000000000..ee21208673 --- /dev/null +++ b/app/components/ak-svg/severity-override-success.hbs @@ -0,0 +1,55 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/components/ak-svg/severity-reset-success.hbs b/app/components/ak-svg/severity-reset-success.hbs new file mode 100644 index 0000000000..ce074da052 --- /dev/null +++ b/app/components/ak-svg/severity-reset-success.hbs @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/components/analysis-risk/overridden-icon/index.ts b/app/components/analysis-risk/overridden-icon/index.ts index 31fadb9482..838243489e 100644 --- a/app/components/analysis-risk/overridden-icon/index.ts +++ b/app/components/analysis-risk/overridden-icon/index.ts @@ -1,7 +1,7 @@ import Component from '@glimmer/component'; export interface AnalysisRiskOverriddenIconSignature { - Element: Element; + Element: SVGElement; } export default class AnalysisRiskOverriddenIconComponent extends Component {} diff --git a/app/components/analysis-risk/override-details-icon/index.hbs b/app/components/analysis-risk/override-details-icon/index.hbs new file mode 100644 index 0000000000..3cbac5991a --- /dev/null +++ b/app/components/analysis-risk/override-details-icon/index.hbs @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/app/components/analysis-risk/override-details-icon/index.ts b/app/components/analysis-risk/override-details-icon/index.ts new file mode 100644 index 0000000000..57e631c7cd --- /dev/null +++ b/app/components/analysis-risk/override-details-icon/index.ts @@ -0,0 +1,13 @@ +import Component from '@glimmer/component'; + +export interface AnalysisRiskOverrideDetailsIconSignature { + Element: SVGElement; +} + +export default class AnalysisRiskOverrideDetailsIconComponent extends Component {} + +declare module '@glint/environment-ember-loose/registry' { + export default interface Registry { + 'AnalysisRisk::OverrideDetailsIcon': typeof AnalysisRiskOverrideDetailsIconComponent; + } +} diff --git a/app/components/analysis-risk/override-edit-drawer/content/index.hbs b/app/components/analysis-risk/override-edit-drawer/content/index.hbs new file mode 100644 index 0000000000..6526f66d36 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/content/index.hbs @@ -0,0 +1,10 @@ +
+ {{#let (component this.activeComponent) as |ActiveComponent|}} + + {{/let}} +
\ No newline at end of file diff --git a/app/components/analysis-risk/override-edit-drawer/content/index.scss b/app/components/analysis-risk/override-edit-drawer/content/index.scss new file mode 100644 index 0000000000..6a00e39c17 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/content/index.scss @@ -0,0 +1,9 @@ +.edit-analysis-content { + width: 650px; + border: 1px solid + var(--analysis-risk-override-edit-drawer-content-border-color); + border-radius: var( + --analysis-risk-override-edit-drawer-content-border-radius + ); + margin: 1.5em; +} diff --git a/app/components/analysis-risk/override-edit-drawer/content/index.ts b/app/components/analysis-risk/override-edit-drawer/content/index.ts new file mode 100644 index 0000000000..f0dfe6f143 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/content/index.ts @@ -0,0 +1,50 @@ +import { action } from '@ember/object'; +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; + +import { AnalysisRiskDataModel, OverrideEditDrawerAppBarData } from '..'; + +export interface AnalysisRiskOverrideEditDrawerContentSignature { + Args: { + dataModel: AnalysisRiskDataModel; + setAppBarData: (appBarData: OverrideEditDrawerAppBarData) => void; + drawerCloseHandler: () => void; + }; +} + +export type ActiveContentComponent = + | 'analysis-risk/override-edit-drawer/override-details' + | 'analysis-risk/override-edit-drawer/override-form' + | 'analysis-risk/override-edit-drawer/reset-confirm'; + +export default class AnalysisRiskOverrideEditDrawerContentComponent extends Component { + @tracked showOverrideFormToEdit = false; + @tracked activeComponent: ActiveContentComponent; + + constructor( + owner: unknown, + args: AnalysisRiskOverrideEditDrawerContentSignature['Args'] + ) { + super(owner, args); + + this.activeComponent = this.args.dataModel.isOverridden + ? 'analysis-risk/override-edit-drawer/override-details' + : 'analysis-risk/override-edit-drawer/override-form'; + } + + @action + handleShowOverrideFormToEdit(value: boolean) { + this.showOverrideFormToEdit = value; + } + + @action + setActiveComponent(component: ActiveContentComponent) { + this.activeComponent = component; + } +} + +declare module '@glint/environment-ember-loose/registry' { + export default interface Registry { + 'AnalysisRisk::OverrideEditDrawer::Content': typeof AnalysisRiskOverrideEditDrawerContentComponent; + } +} diff --git a/app/components/analysis-risk/override-edit-drawer/divider/index.hbs b/app/components/analysis-risk/override-edit-drawer/divider/index.hbs new file mode 100644 index 0000000000..da4f75fd33 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/divider/index.hbs @@ -0,0 +1,10 @@ +
+
+ + + {{@label}} + +
\ No newline at end of file diff --git a/app/components/analysis-risk/override-edit-drawer/divider/index.scss b/app/components/analysis-risk/override-edit-drawer/divider/index.scss new file mode 100644 index 0000000000..e3dcc8f280 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/divider/index.scss @@ -0,0 +1,35 @@ +.divider-container { + width: 100px; + height: 24px; + position: relative; + + .divider { + width: 100%; + border-bottom: 1px dashed + var(--analysis-risk-override-edit-drawer-divider-color); + z-index: -1; + } + + .divider, + .divider-label { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + + .divider-label { + z-index: 1; + min-width: 32px; + height: 24px; + border-radius: 6px; + box-sizing: border-box; + padding: 0 0.75em; + background-color: var( + --analysis-risk-override-edit-drawer-divider-label-background-color + ); + font-size: 0.857rem !important; + display: inline-flex; + align-items: center; + } +} diff --git a/app/components/analysis-risk/override-edit-drawer/divider/index.ts b/app/components/analysis-risk/override-edit-drawer/divider/index.ts new file mode 100644 index 0000000000..b0431b5953 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/divider/index.ts @@ -0,0 +1,16 @@ +import Component from '@glimmer/component'; + +export interface AnalysisRiskOverrideEditDrawerDividerSignature { + Args: { + label: string; + }; +} + +export default class AnalysisRiskOverrideEditDrawerDividerComponent extends Component {} + +declare module '@glint/environment-ember-loose/registry' { + export default interface Registry { + 'AnalysisRisk::OverrideEditDrawer::Divider': typeof AnalysisRiskOverrideEditDrawerDividerComponent; + 'analysis-risk/override-edit-drawer/divider': typeof AnalysisRiskOverrideEditDrawerDividerComponent; + } +} diff --git a/app/components/analysis-risk/override-edit-drawer/index.hbs b/app/components/analysis-risk/override-edit-drawer/index.hbs new file mode 100644 index 0000000000..b0df25add9 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/index.hbs @@ -0,0 +1,37 @@ + + + + {{#if this.appBarData.onBackClick}} + + + + {{/if}} + + + {{this.appBarData.title}} + + + + + + + + + + \ No newline at end of file diff --git a/app/components/analysis-risk/override-edit-drawer/index.ts b/app/components/analysis-risk/override-edit-drawer/index.ts new file mode 100644 index 0000000000..f395789a93 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/index.ts @@ -0,0 +1,78 @@ +import { action } from '@ember/object'; +import { service } from '@ember/service'; +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import IntlService from 'ember-intl/services/intl'; +import { next } from '@ember/runloop'; +import { ComponentLike } from '@glint/template'; + +import AnalysisModel from 'irene/models/analysis'; +import VulnerabilityPreferenceModel from 'irene/models/vulnerability-preference'; + +export interface AnalysisRiskOverrideEditDrawerSignature { + Args: { + dataModel: AnalysisRiskDataModel; + open: boolean; + onClose: () => void; + }; +} + +type ResetConfirmComponent = ComponentLike<{ + dataModel: AnalysisRiskDataModel; + resetHandler: (all?: boolean) => void; + resetCancelHandler?: () => void; + isResetRunning: boolean; + isResetSuccess: boolean; +}>; + +export interface AnalysisRiskDataModel { + model: AnalysisModel | VulnerabilityPreferenceModel; + vulnerabilityName: string; + computedRisk: number; + isOverridden?: boolean; + risk?: number | null; + overriddenRisk?: number | null; + status?: number; + overriddenRiskComment: string | null; + overriddenBy: string | null; + overrideCriteria: string | null; + overrideCriteriaOptions: { label: string; value: string }[]; + overriddenOn: Date | null; + overrideSuccessMessage: string; + showOverrideSuccessOriginalToOverriddenRisk?: boolean; + ignoreVulnerabilityHelperText: string; + + resetConfirmComponent: ResetConfirmComponent; + + resetOverrideHandler: (all: boolean) => Promise; + + editSaveOverrideHandler: ( + risk: number, + comment: string, + all: boolean + ) => Promise; +} + +export type OverrideEditDrawerAppBarData = { + title: string; + onBackClick?: (event: Event) => void; +}; + +export default class AnalysisRiskOverrideEditDrawerComponent extends Component { + @service declare intl: IntlService; + + @tracked appBarData?: OverrideEditDrawerAppBarData; + + @action + setAppBarData(appBarData: OverrideEditDrawerAppBarData) { + next(this, () => { + this.appBarData = appBarData; + }); + } +} + +declare module '@glint/environment-ember-loose/registry' { + export default interface Registry { + 'AnalysisRisk::OverrideEditDrawer': typeof AnalysisRiskOverrideEditDrawerComponent; + } +} diff --git a/app/components/analysis-risk/override-edit-drawer/override-details/index.hbs b/app/components/analysis-risk/override-edit-drawer/override-details/index.hbs new file mode 100644 index 0000000000..eb591d3750 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/override-details/index.hbs @@ -0,0 +1,110 @@ + + + + +
+ + + {{t 'editOverrideVulnerability.overriddenAs'}} + + + + + {{t (risk-text @dataModel.overriddenRisk)}} + + + + + + {{this.overrideCriteriaText @dataModel.overrideCriteria}} + + + + + + + + + {{t 'reason'}} + + + + {{@dataModel.overriddenRiskComment}} + + + + + + + + {{#each this.overrideAuditDetails as |oad|}} + + {{#if oad.icon}} + + {{else}} + + {{/if}} + + + {{oad.label}} + - + + + {{#if oad.renderValue}} + + + + + + + + {{else}} + + {{oad.value}} + + {{/if}} + + {{/each}} + +
+ + + + + + {{t 'edit'}} + + + + {{t 'resetOverride'}} + + \ No newline at end of file diff --git a/app/components/analysis-risk/override-edit-drawer/override-details/index.scss b/app/components/analysis-risk/override-edit-drawer/override-details/index.scss new file mode 100644 index 0000000000..a6b2949bcf --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/override-details/index.scss @@ -0,0 +1,17 @@ +.overridden-as-value-container { + padding: 0.75em 1em; + border: 1px solid + var(--analysis-risk-override-edit-drawer-override-details-border-color); + border-radius: var( + --analysis-risk-override-edit-drawer-override-details-border-radius + ); + box-sizing: border-box; +} + +.overridden-details-chip { + border: 1px solid + var(--analysis-risk-override-edit-drawer-override-details-border-color); + border-radius: 2.142em; + padding: 0.35em 1em; + box-sizing: border-box; +} diff --git a/app/components/analysis-risk/override-edit-drawer/override-details/index.ts b/app/components/analysis-risk/override-edit-drawer/override-details/index.ts new file mode 100644 index 0000000000..8b9cd3cb83 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/override-details/index.ts @@ -0,0 +1,102 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; +import IntlService from 'ember-intl/services/intl'; +import { isEmpty } from '@ember/utils'; +import dayjs from 'dayjs'; + +import { AnalysisRiskDataModel, OverrideEditDrawerAppBarData } from '..'; +import { ActiveContentComponent } from '../content'; +import ENUMS from 'irene/enums'; + +type OverrideAuditDetail = { + label: string; + icon: string; + value: string; + renderValue?: boolean; +}; + +export interface AnalysisRiskOverrideEditDrawerOverrideDetailsSignature { + Args: { + dataModel: AnalysisRiskDataModel; + setActiveComponent: (component: ActiveContentComponent) => void; + setAppBarData: (appBarData: OverrideEditDrawerAppBarData) => void; + }; +} + +export default class AnalysisRiskOverrideEditDrawerOverrideDetailsComponent extends Component { + @service declare intl: IntlService; + + constructor( + owner: unknown, + args: AnalysisRiskOverrideEditDrawerOverrideDetailsSignature['Args'] + ) { + super(owner, args); + + this.args.setAppBarData({ title: this.intl.t('overrideDetails') }); + } + + get dataModel() { + return this.args.dataModel; + } + + get showOriginalAndOverriddenSeverity() { + return ( + !isEmpty(this.dataModel.risk) && !isEmpty(this.dataModel.overriddenRisk) + ); + } + + get overrideAuditDetails() { + return [ + { + label: this.intl.t('editOverrideVulnerability.overriddenOn'), + icon: 'event', + value: dayjs(this.dataModel.overriddenOn).format('MMM DD, YYYY'), + }, + { + label: this.intl.t('editOverrideVulnerability.overriddenBy'), + icon: 'account-circle', + value: this.dataModel.overriddenBy, + }, + this.showOriginalAndOverriddenSeverity && { + label: this.intl.t('editOverrideVulnerability.overriddenSeverity'), + renderValue: true, + }, + ].filter(Boolean) as OverrideAuditDetail[]; + } + + @action + overrideCriteriaText(criteria: string | null) { + switch (criteria) { + case ENUMS.ANALYSIS_OVERRIDE_CRITERIA.CURRENT_FILE: + return this.intl.t('currentFileOnly'); + + case ENUMS.ANALYSIS_OVERRIDE_CRITERIA.ALL_FUTURE_UPLOAD: + return this.intl.t('allFutureAnalyses'); + + default: + return ''; + } + } + + @action + handleEditOverrideClick() { + this.args.setActiveComponent( + 'analysis-risk/override-edit-drawer/override-form' + ); + } + + @action + handleResetOverrideClick() { + this.args.setActiveComponent( + 'analysis-risk/override-edit-drawer/reset-confirm' + ); + } +} + +declare module '@glint/environment-ember-loose/registry' { + export default interface Registry { + 'AnalysisRisk::OverrideEditDrawer::OverrideDetails': typeof AnalysisRiskOverrideEditDrawerOverrideDetailsComponent; + 'analysis-risk/override-edit-drawer/override-details': typeof AnalysisRiskOverrideEditDrawerOverrideDetailsComponent; + } +} diff --git a/app/components/analysis-risk/override-edit-drawer/override-form/index.hbs b/app/components/analysis-risk/override-edit-drawer/override-form/index.hbs new file mode 100644 index 0000000000..2a50b24070 --- /dev/null +++ b/app/components/analysis-risk/override-edit-drawer/override-form/index.hbs @@ -0,0 +1,194 @@ +{{#if this.showOverrideSuccess}} + + + + + {{@dataModel.overrideSuccessMessage}} + + + {{#if @dataModel.showOverrideSuccessOriginalToOverriddenRisk}} + + + + + + + + {{/if}} + +{{else}} + + + + +
+ + + {{t 'editOverrideVulnerability.overrideTo'}} + + + + + {{this.riskSelectOptionLabel aks.value}} + + + + + {{#if this.criteriaTextIfSingleOption}} + + {{this.criteriaTextIfSingleOption}} + + {{else}} + + {{aks.label}} + + {{/if}} + + + {{#if this.riskOrCriteriaSelectValidationMessage}} + + {{this.riskOrCriteriaSelectValidationMessage}} + + {{else}} + {{#if this.isIgnoreVulnerabilitySelected}} + + + + + {{@dataModel.ignoreVulnerabilityHelperText}} + + + {{/if}} + {{/if}} + + + + + {{t 'reason'}} + + +