Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions openapi-specs/component-catalog-v1.0.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,50 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/RestErrorMessage'
/project/{projectKey}/component/{componentId}:
get:
tags:
- Project-components
summary: Returns the extended information of a project component given both its project key and component ID in the Bitbucket repository.
operationId: getProjectComponentById
parameters:
- name: projectKey
in: path
description: project key.
required: true
schema:
type: string
- name: componentId
in: path
description: component ID.
required: true
schema:
type: string
responses:
"200":
description: The extended information of a project component.
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectComponentExtendedInfo'
"401":
description: Invalid client token on the request.
content:
application/json:
schema:
$ref: '#/components/schemas/RestErrorMessage'
"403":
description: Insufficient permissions for the client to access the resource.
content:
application/json:
schema:
$ref: '#/components/schemas/RestErrorMessage'
"500":
description: Server error.
content:
application/json:
schema:
$ref: '#/components/schemas/RestErrorMessage'
/catalog-descriptors:
get:
tags:
Expand Down Expand Up @@ -847,12 +891,51 @@ components:
canBeDeleted:
type: boolean
example: true
hasAutomatedDeletionWorkflow:
type: boolean
example: true
logoUrl:
type: string
example: https://somepic.jpg
componentUrl:
type: string
example: 'https://bitbucket.com/projects/CATALOGS/repos/project-components/browse/projects'
ProjectComponentParameter:
properties:
name:
type: string
example: 'environment'
values:
type: array
items:
type: string
example:
- 'dev'
- 'test'
ProjectComponentExtendedInfo:
properties:
componentId:
type: string
example: 'nextjs-basic-app'
catalogItemId:
type: string
example: 'some-encoded-info'
catalogItemRef:
type: string
example: 'more-encoded-info'
status:
type: string
example: 'CREATING'
componentUrl:
type: string
example: 'https://bitbucket.com/projects/CATALOGS/repos/project-components/browse/projects'
workflowJobId:
type: string
example: '123456'
parameters:
type: array
items:
$ref: '#/components/schemas/ProjectComponentParameter'
CatalogDescriptor:
properties:
id:
Expand Down Expand Up @@ -1206,6 +1289,12 @@ components:
example: "https://bitbucket.com/projects/DEVSTACK/repos/devstack-component-catalog"
nullable: true

workflowJobId:
type: string
description: the workflow job id from AWX to correlate provisioning status with AWX job status updates
example: "123456"
nullable: true

parameters:
type: array
description: List of name/value string parameters.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div class="dialog-header">
<h2 mat-dialog-title>{{ data.componentName }} - Request Deletion</h2>
<appshell-icon icon="close" (click)="onCancel()"></appshell-icon>
</div>
<mat-dialog-content>
<div class="help-message-ctn">
<appshell-icon class="info-icon" icon="circle_i"></appshell-icon>
<span>To request deletion for deployed components, a change requested is needed.</span>
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button (click)="onCancel()">Cancel</button>
<button mat-flat-button color="accent" (click)="onAccept()">Request</button>
</mat-dialog-actions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
app-request-deletion-dialog {
width: 38.25rem;
display: block !important;
padding: 1.5rem;
box-sizing: border-box;

> * {
padding: 0 !important;
color: var(--appshell-color-dark-green-main) !important;
}

.dialog-header {
margin: 0.5rem 0 0 !important;
display: inline-flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;

h2 {
margin: 0 !important;
padding: 0;
font-family: "AppShellHeadingFont";
font-size: 20px;
font-weight: 500;
line-height: 24px;

&::before,
&::after {
height: auto !important;
}
}

appshell-icon {
cursor: pointer;
}
}

mat-dialog-content {
display: flex;
flex-direction: column;
gap: 16px;
min-height: 100px;

.help-message-ctn {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.75rem;
margin: 1.5rem 0 !important;
padding: 1rem;

background-color: #d2f2f7;
color: #076d7e;

font-size: 14px;
font-weight: 400;
line-height: 20px;
}
}

mat-dialog-actions {
gap: 1rem;

button:first-of-type {
padding: 0.75rem 1rem;

font-size: 0.875rem;
line-height: 1.25rem;

--mdc-text-button-container-height: unset !important;
--mdc-text-button-container-padding-horizontal: 0;

&:hover {
background-color: transparent;
}
}

button:last-of-type {
padding: 0.75rem 1.5rem;
height: auto;

font-size: 0.875rem;
line-height: 1.25rem;

--mdc-filled-button-container-height: unset !important;

display: inline-flex;
align-items: center;

border: 2px solid var(--mdc-filled-button-container-color);
border-radius: 0.125rem;

&:disabled {
border: none;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { CommonModule } from "@angular/common";
import { Component, Inject, ViewEncapsulation } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { MatButtonModule } from "@angular/material/button";
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogContent, MatDialogActions } from "@angular/material/dialog";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatInputModule } from "@angular/material/input";
import { MatRadioModule } from "@angular/material/radio";
import { RequestDeletionDialogData } from "../../models/request-deletion-dialog-data";
import { AppShellIconComponent } from "@opendevstack/ngx-appshell";

@Component({
selector: 'app-request-deletion-dialog',
imports: [
CommonModule,
MatButtonModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
FormsModule,
AppShellIconComponent,
MatDialogContent,
MatDialogActions
],
templateUrl: './request-deletion-simple-dialog.component.html',
styleUrl: './request-deletion-simple-dialog.component.scss',
encapsulation: ViewEncapsulation.None
})
export class RequestDeletionSimpleDialogComponent {

constructor(
public dialogRef: MatDialogRef<RequestDeletionSimpleDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: RequestDeletionDialogData
) {}

onAccept(): void {
this.dialogRef.close(this.data);
}

onCancel(): void {
this.dialogRef.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { By } from '@angular/platform-browser';

import { RequestDeletionSimpleDialogComponent } from './request-deletion-simple-dialog.component';
import { RequestDeletionDialogData } from '../../models/request-deletion-dialog-data';

describe('RequestDeletionSimpleDialogComponent', () => {
let component: RequestDeletionSimpleDialogComponent;
let fixture: ComponentFixture<RequestDeletionSimpleDialogComponent>;
let dialogRefSpy: jasmine.SpyObj<MatDialogRef<RequestDeletionSimpleDialogComponent>>;

const dialogData: RequestDeletionDialogData = {
componentName: 'test-component',
projectKey: 'test-project',
location: 'test-location'
};

beforeEach(async () => {
dialogRefSpy = jasmine.createSpyObj('MatDialogRef', ['close']);

await TestBed.configureTestingModule({
imports: [RequestDeletionSimpleDialogComponent],
providers: [
{ provide: MatDialogRef, useValue: dialogRefSpy },
{ provide: MAT_DIALOG_DATA, useValue: dialogData }
]
}).compileComponents();

fixture = TestBed.createComponent(RequestDeletionSimpleDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should close dialog with data on accept', () => {
component.onAccept();

expect(dialogRefSpy.close).toHaveBeenCalledWith(dialogData);
});

it('should close dialog without data on cancel', () => {
component.onCancel();

expect(dialogRefSpy.close).toHaveBeenCalledWith();
});

it('should call onCancel when close icon is clicked', () => {
spyOn(component, 'onCancel');

const closeIcon = fixture.debugElement.query(
By.css('appshell-icon[icon="close"]')
);
closeIcon.triggerEventHandler('click', null);

expect(component.onCancel).toHaveBeenCalled();
});

it('should call onCancel when Cancel button is clicked', () => {
spyOn(component, 'onCancel');

const cancelButton = fixture.debugElement
.queryAll(By.css('button'))
.find(btn => btn.nativeElement.textContent.trim() === 'Cancel');

cancelButton!.nativeElement.click();

expect(component.onCancel).toHaveBeenCalled();
});

it('should call onAccept when Request button is clicked', () => {
spyOn(component, 'onAccept');

const requestButton = fixture.debugElement
.queryAll(By.css('button'))
.find(btn => btn.nativeElement.textContent.trim() === 'Request');

requestButton!.nativeElement.click();

expect(component.onAccept).toHaveBeenCalled();
});
});
1 change: 1 addition & 0 deletions src/app/models/project-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export interface ProjectComponent {
logo: string | null;
url: string;
canDelete: boolean;
hasAutomatedDeletionWorkflow: boolean;
}
Loading
Loading