Skip to content

Commit

Permalink
feat(integrations): create integration
Browse files Browse the repository at this point in the history
  • Loading branch information
pes-spyro-soft-com committed Mar 21, 2024
1 parent 2ead07e commit 91fbf33
Show file tree
Hide file tree
Showing 19 changed files with 1,105 additions and 0 deletions.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Expand Up @@ -125,6 +125,12 @@ export class GioSideNavComponent implements OnInit, OnDestroy {
displayName: 'APIs',
category: 'Apis',
},
{
icon: 'gio:box',
routerLink: './integrations',
displayName: 'Integrations',
category: 'Integrations',
},
{
icon: 'gio:multi-window',
routerLink: './applications',
Expand Down
@@ -0,0 +1,18 @@
import { Integration } from '../../management/integrations/integrations.model';

export function fakeIntegration(attribute?: Partial<Integration>) {
const base: Integration = {
id: 'test_id',
name: 'test_name',
description: 'test_description',
provider: 'test_provider',
owner: 'test_owner',
status: 'test_status',
agent: 'test_agent',
}

return {
...base,
...attribute
}
}
@@ -0,0 +1,107 @@
<!--
Copyright (C) 2015 The Gravitee team (http://gravitee.io)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<div>
<div class="page-header">
<h1>Integrations</h1>
<span class="page-header__description">Connect to third-party API gateways and event brokers to create a unified control plane and API portal with
Gravitee</span>
</div>


<mat-card>
<mat-card-content>
<div class="card-header">
<div class="card-header__title">
<h3>Create Integration</h3>
</div>

<div class="card-header__actions">
<button
mat-raised-button
[disabled]="false"
data-testid="exit-create-integration-button"
routerLink=".."
>
<mat-icon svgIcon="gio:cancel"></mat-icon>
Exit without saving
</button>
</div>
</div>


<form [formGroup]="informationForm" class="form" (ngSubmit)="onSubmit()">
<div class="form__body">
<mat-card class="form-card">
<mat-card-content>
<div>
<h5>General Information</h5>
<p class="info">Enter the general information for this new integration.</p>
</div>
<div>
<mat-form-field appearance="outline" class="form-field">
<input
id="name"
type="text"
matInput
formControlName="name"
required="true"
data-testid="create-integration-name-input"
/>
<mat-label>Name</mat-label>
<mat-error *ngIf="informationForm.controls.name.errors?.required">Name is required</mat-error>
</mat-form-field>
</div>
<div>
<mat-form-field appearance="outline" class="form-field">
<textarea
id="description"
matInput #input
maxlength="250"
formControlName="description"
rows="2"
data-testid="create-integration-description"
></textarea>
<mat-label>Description</mat-label>
<mat-hint align="start">{{ input.value.length }}/250</mat-hint>
</mat-form-field>
</div>
</mat-card-content>
</mat-card>
</div>

<div class="form__actions">
<button
mat-flat-button
[disabled]="true"
data-testid="back-create-integration-button"
routerLink=".."
>
Back
</button>

<button
type="submit"
mat-raised-button
color="primary"
data-testid="create-integration-submit-button"
[disabled]="!informationForm.valid"
>
Create Integration
</button>
</div>
</form>

</mat-card-content>
</mat-card>
</div>
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

@use '@angular/material' as mat;
@use '@gravitee/ui-particles-angular' as gio;
@use '../../../scss/gio-layout' as gio-layout;

:host {
@include gio-layout.gio-responsive-content-container
}

.page-header {
margin-bottom: 24px;

&__description {
color: mat.get-color-from-palette(gio.$mat-space-palette, 'lighter40');
}
}

.card-header {
display: flex;
justify-content: space-between;
padding-bottom: 24px;

&__title {
display: flex;
flex-direction: column;
justify-content: center;

h3 {
margin: 0;
}
}
}

.form {
&__body {
display: flex;
justify-content: center;
padding: 24px 0;

.mat-mdc-card {
width: 600px;
border: 1px solid var(--Dove-Darker10, #E7E8EF);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.20);
}
}

&__actions {
display: flex;
justify-content: space-between;
padding-top: 24px;
}

.form-field {
width: 100%;
}
}

textarea {
resize: none;
}

.info {
color: mat.get-color-from-palette(gio.$mat-space-palette, 'lighter40');
}


@@ -0,0 +1,78 @@
/*
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule, NoopAnimationsModule } from '@angular/platform-browser/animations';
import { HttpTestingController } from '@angular/common/http/testing';
import { InteractivityChecker } from '@angular/cdk/a11y';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';


import { CreateIntegrationComponent } from './create-integration.component';
import { CreateIntegrationHarness } from './create-integration.harness';

import { IntegrationsModule } from '../integrations.module';
import { CONSTANTS_TESTING, GioTestingModule } from '../../../shared/testing';

describe('CreateIntegrationComponent', () => {
let fixture: ComponentFixture<CreateIntegrationComponent>;
let componentHarness: CreateIntegrationHarness;
let httpTestingController: HttpTestingController;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [CreateIntegrationComponent],
imports: [GioTestingModule, IntegrationsModule, BrowserAnimationsModule, NoopAnimationsModule]
})
.overrideProvider(InteractivityChecker, {
useValue: {
isFocusable: () => true, // This traps focus checks and so avoid warnings when dealing with
isTabbable: () => true // This traps focus checks and so avoid warnings when dealing with
}
})
.compileComponents();
});

beforeEach(async () => {
fixture = TestBed.createComponent(CreateIntegrationComponent);
httpTestingController = TestBed.inject(HttpTestingController);
componentHarness = await TestbedHarnessEnvironment.harnessForFixture(fixture, CreateIntegrationHarness);
fixture.detectChanges();
});

afterEach(() => {
httpTestingController.verify();
});

describe('form', () => {
it('should not submit empty form', async () => {
await componentHarness.clickOnSubmit();
httpTestingController.expectNone(`${CONSTANTS_TESTING.env.v2BaseURL}/integrations`);
});

it('should create integration with valid form', async () => {
await componentHarness.setName('TEST123');
await componentHarness.clickOnSubmit();
expectIntegrationPostRequest();
})
});

function expectIntegrationPostRequest(): void {
const req = httpTestingController.expectOne(`${CONSTANTS_TESTING.env.v2BaseURL}/integrations`);
req.flush([]);
expect(req.request.method).toEqual('POST');
}
});
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Component, DestroyRef, inject } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { FormBuilder, Validators } from '@angular/forms';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { catchError, tap } from 'rxjs/operators';
import { EMPTY } from 'rxjs';

import { CreateIntegrationPayload } from '../integrations.model';
import { IntegrationsService } from '../../../services-ngx/integrations.service';
import { SnackBarService } from '../../../services-ngx/snack-bar.service';

@Component({
selector: 'app-create-integration',
templateUrl: './create-integration.component.html',
styleUrls: ['./create-integration.component.scss']
})
export class CreateIntegrationComponent {
public isLoading = false;
private destroyRef = inject(DestroyRef);

public informationForm = this.formBuilder.group({
name: ['', Validators.minLength(1)],
description: ['']
});

constructor(
private integrationsService: IntegrationsService,
private formBuilder: FormBuilder,
private readonly router: Router,
private activatedRoute: ActivatedRoute,
private snackBarService: SnackBarService
) {
}

public onSubmit(): void {
const payload: CreateIntegrationPayload = {
name: this.informationForm.controls.name.getRawValue(),
description: this.informationForm.controls.description.getRawValue(),
provider: 'AWS'
};

this.isLoading = true;
this.integrationsService
.createIntegration(payload)
.pipe(
tap(() => {
this.isLoading = false;
this.snackBarService.success(`Integration ${payload.name} created successfully`);
}),
catchError((_) => {
this.isLoading = false;
this.snackBarService.error('An error occurred. Integration not created');
return EMPTY;
}),
takeUntilDestroyed(this.destroyRef)
)
.subscribe(() => {
this.isLoading = false;
this.router.navigate(['..'], { relativeTo: this.activatedRoute });
});
}
}

0 comments on commit 91fbf33

Please sign in to comment.