Widget Angular para mostrar actualizaciones y changelog de BrkRelease en tu aplicación.
- Angular: 17.x, 18.x, 19.x
- Zone.js: >=0.14.0
- RxJS: ^7.8.0
npm install brkrelease-angular
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { BrkReleaseWidgetModule } from 'brkrelease-angular';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule, // Requerido para las llamadas HTTP
BrkReleaseWidgetModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
// app.component.ts
import { Component } from '@angular/core';
import { Release } from 'brkrelease-angular';
@Component({
selector: 'app-root',
template: `
<div class="app">
<!-- Tu aplicación -->
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
(widgetOpen)="onWidgetOpen()"
(widgetClose)="onWidgetClose()"
(releaseClick)="onReleaseClick($event)">
</brkrelease-widget>
</div>
`
})
export class AppComponent {
onWidgetOpen() {
console.log('Widget abierto');
}
onWidgetClose() {
console.log('Widget cerrado');
}
onReleaseClick(release: Release) {
console.log('Release clickeado:', release.title);
}
}
Propiedad | Tipo | Requerido | Por Defecto | Descripción |
---|---|---|---|---|
projectId |
string |
✅ | - | ID del proyecto de BrkRelease |
apiUrl |
string |
✅ | - | URL base de la API de BrkRelease |
theme |
'light' | 'dark' |
❌ | 'light' |
Tema del widget |
position |
'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'sidebar-left' | 'sidebar-right' |
❌ | 'bottom-right' |
Posición del botón o sidebar |
primaryColor |
string |
❌ | - | Color primario del widget (CSS color) |
maxReleases |
number |
❌ | 10 |
Máximo número de releases a mostrar |
publishedOnly |
boolean |
❌ | true |
Mostrar solo releases publicados |
buttonText |
string |
❌ | - | Texto personalizado para el botón |
Evento | Tipo | Descripción |
---|---|---|
widgetOpen |
EventEmitter<void> |
Se emite cuando se abre el widget |
widgetClose |
EventEmitter<void> |
Se emite cuando se cierra el widget |
releaseClick |
EventEmitter<Release> |
Se emite cuando se hace clic en un release |
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
theme="dark">
</brkrelease-widget>
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
primaryColor="#10B981">
</brkrelease-widget>
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
position="top-left">
</brkrelease-widget>
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
theme="dark"
position="bottom-left"
primaryColor="#8B5CF6"
[maxReleases]="5"
[publishedOnly]="true"
buttonText="Ver novedades"
(widgetOpen)="onOpen()"
(widgetClose)="onClose()"
(releaseClick)="onReleaseClick($event)">
</brkrelease-widget>
El widget soporta un modo sidebar que muestra las actualizaciones en un panel lateral fijo, ideal para aplicaciones de escritorio o cuando necesitas que las actualizaciones sean más prominentes.
A diferencia del modo modal tradicional que muestra un botón flotante, el modo sidebar:
- Muestra un panel lateral fijo en el lado izquierdo o derecho de la pantalla
- Permanece visible y accesible en todo momento
- Se integra mejor con interfaces de aplicaciones de escritorio
- Permite una navegación más fluida entre actualizaciones
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
position="sidebar-left"
theme="light">
</brkrelease-widget>
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
position="sidebar-right"
theme="dark"
primaryColor="#3B82F6">
</brkrelease-widget>
Cuando uses el modo sidebar, necesitarás ajustar el contenido principal de tu aplicación para evitar que se superponga:
/* Para sidebar izquierdo */
.main-content {
margin-left: 320px; /* Ancho del sidebar + margen */
}
/* Para sidebar derecho */
.main-content {
margin-right: 320px; /* Ancho del sidebar + margen */
}
/* Responsive: ocultar sidebar en móviles */
@media (max-width: 768px) {
.main-content {
margin-left: 0;
margin-right: 0;
}
}
// app.component.ts
import { Component } from '@angular/core';
import { Release } from 'brkrelease-angular';
@Component({
selector: 'app-root',
template: `
<div class="app-layout">
<!-- Sidebar Widget -->
<brkrelease-widget
projectId="mi-proyecto-id"
apiUrl="https://api.brakodev.com"
position="sidebar-left"
theme="light"
primaryColor="#10B981"
[maxReleases]="8"
(releaseClick)="onReleaseClick($event)">
</brkrelease-widget>
<!-- Contenido Principal -->
<main class="main-content">
<h1>Mi Aplicación</h1>
<p>El contenido principal de tu aplicación va aquí.</p>
</main>
</div>
`,
styles: [`
.app-layout {
display: flex;
min-height: 100vh;
}
.main-content {
flex: 1;
padding: 2rem;
margin-left: 320px; /* Espacio para el sidebar */
}
@media (max-width: 768px) {
.main-content {
margin-left: 0;
}
}
`]
})
export class AppComponent {
onReleaseClick(release: Release) {
console.log('Release seleccionado:', release.title);
}
}
// app.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { BrkReleaseWidgetComponent, Release } from 'brkrelease-angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, HttpClientModule, BrkReleaseWidgetComponent],
template: `
<div class="app">
<!-- Tu aplicación -->
<brkrelease-widget
projectId="tu-proyecto-id"
apiUrl="https://api.brakodev.com"
(releaseClick)="onReleaseClick($event)">
</brkrelease-widget>
</div>
`
})
export class AppComponent {
onReleaseClick(release: Release) {
console.log('Release:', release.title);
}
}
// release-notification.service.ts
import { Injectable } from '@angular/core';
import { BrkReleaseApiService, Release } from 'brkrelease-angular';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ReleaseNotificationService {
constructor(private releaseLabApi: BrkReleaseApiService) {}
getLatestReleases(apiUrl: string, projectId: string): Observable<Release[]> {
return this.releaseLabApi.getReleases(apiUrl, projectId, { limit: 5 })
.pipe(
map(response => response.releases)
);
}
checkForUpdates(apiUrl: string, projectId: string, since: string) {
return this.releaseLabApi.hasNewReleases(apiUrl, projectId, since);
}
}
// custom-release-widget.component.ts
import { Component, OnInit } from '@angular/core';
import { ReleaseNotificationService } from './release-notification.service';
@Component({
selector: 'app-custom-release-widget',
template: `
<div class="custom-widget">
<button (click)="toggleWidget()" class="custom-button">
Ver actualizaciones
<span *ngIf="hasNewReleases" class="badge">New!</span>
</button>
<div *ngIf="isOpen" class="custom-modal">
<div *ngFor="let release of releases" class="release-item">
<h3>{{release.title}}</h3>
<p>{{release.content}}</p>
</div>
</div>
</div>
`
})
export class CustomReleaseWidgetComponent implements OnInit {
isOpen = false;
releases: Release[] = [];
hasNewReleases = false;
constructor(private releaseService: ReleaseNotificationService) {}
ngOnInit() {
this.loadReleases();
}
loadReleases() {
this.releaseService.getLatestReleases(
'https://api.brakodev.com',
'tu-proyecto-id'
).subscribe(releases => {
this.releases = releases;
});
}
toggleWidget() {
this.isOpen = !this.isOpen;
}
}
import {
Release,
Project,
ReleaseLabWidgetConfig,
ReleaseType,
WidgetTheme
} from '@releaselab/angular';
// Ejemplo de uso con tipos
const handleRelease = (release: Release) => {
console.log(`Release ${release.title} de tipo ${release.type}`);
};
const config: ReleaseLabWidgetConfig = {
projectId: 'mi-proyecto',
apiUrl: 'http://localhost:3001',
theme: 'dark',
position: 'bottom-right'
};
El widget incluye:
- Responsive: Se adapta a móviles, tablets y escritorio
- Accesibilidad: Navegación por teclado, ARIA labels, ESC para cerrar
- Temas: Soporte completo para modo claro y oscuro
- Animaciones: Transiciones suaves y feedback visual
El widget usa date-fns
con locales en español por defecto:
// Para cambiar el idioma, puedes extender el componente
import { es, en } from 'date-fns/locale';
// En tu servicio personalizado
formatDistanceToNow(date, { locale: en }) // Inglés
formatDistanceToNow(date, { locale: es }) // Español (por defecto)
El widget maneja automáticamente:
- Errores de red y APIs no disponibles
- Estados de carga con spinners
- Mensajes de error amigables al usuario
- Fallbacks cuando no hay datos
Para incluir el widget en tu build de producción, asegúrate de que tu angular.json
incluya:
{
"build": {
"options": {
"allowedCommonJsDependencies": [
"date-fns",
"axios"
]
}
}
}
// widget.component.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { BrkReleaseWidgetComponent } from 'brkrelease-angular';
describe('ReleaseLabWidgetComponent', () => {
let component: BrkReleaseWidgetComponent;
let fixture: ComponentFixture<BrkReleaseWidgetComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HttpClientTestingModule, BrkReleaseWidgetComponent]
}).compileComponents();
fixture = TestBed.createComponent(BrkReleaseWidgetComponent);
component = fixture.componentInstance;
component.projectId = 'test-project';
component.apiUrl = 'http://localhost:3001';
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should emit widgetOpen when opened', () => {
spyOn(component.widgetOpen, 'emit');
component.openWidget();
expect(component.widgetOpen.emit).toHaveBeenCalled();
});
});
MIT License - Ver archivo LICENSE para más detalles.
¡Las contribuciones son bienvenidas! Ver CONTRIBUTING.md para más información.
Usa GitHub Issues para reportar bugs o solicitar nuevas funcionalidades.