mirror of https://github.com/Squidex/squidex.git
45 changed files with 1057 additions and 276 deletions
@ -0,0 +1,33 @@ |
|||
// ==========================================================================
|
|||
// MongoEventConsumerInfo.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using MongoDB.Bson; |
|||
using MongoDB.Bson.Serialization.Attributes; |
|||
using Squidex.Infrastructure.CQRS.Events; |
|||
|
|||
namespace Squidex.Infrastructure.MongoDb |
|||
{ |
|||
public sealed class MongoEventConsumerInfo : IEventConsumerInfo |
|||
{ |
|||
[BsonId] |
|||
[BsonRepresentation(BsonType.String)] |
|||
public string Name { get; set; } |
|||
|
|||
[BsonElement] |
|||
[BsonIgnoreIfDefault] |
|||
public bool IsStopped { get; set; } |
|||
|
|||
[BsonElement] |
|||
[BsonIgnoreIfDefault] |
|||
public bool IsResetting { get; set; } |
|||
|
|||
[BsonElement] |
|||
[BsonRequired] |
|||
public long LastHandledEventNumber { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
// ==========================================================================
|
|||
// MongoEventConsumerInfoRepository.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Bson; |
|||
using MongoDB.Driver; |
|||
using Squidex.Infrastructure.CQRS.Events; |
|||
|
|||
namespace Squidex.Infrastructure.MongoDb |
|||
{ |
|||
public sealed class MongoEventConsumerInfoRepository : MongoRepositoryBase<MongoEventConsumerInfo>, IEventConsumerInfoRepository |
|||
{ |
|||
public MongoEventConsumerInfoRepository(IMongoDatabase database) |
|||
: base(database) |
|||
{ |
|||
} |
|||
|
|||
protected override string CollectionName() |
|||
{ |
|||
return "EventPositions"; |
|||
} |
|||
|
|||
public async Task<IReadOnlyList<IEventConsumerInfo>> QueryAsync() |
|||
{ |
|||
var entities = await Collection.Find(new BsonDocument()).SortBy(x => x.Name).ToListAsync(); |
|||
|
|||
return entities.OfType<IEventConsumerInfo>().ToList(); |
|||
} |
|||
|
|||
public async Task<IEventConsumerInfo> FindAsync(string consumerName) |
|||
{ |
|||
var entity = await Collection.Find(x => x.Name == consumerName).FirstOrDefaultAsync(); |
|||
|
|||
return entity; |
|||
} |
|||
|
|||
public async Task CreateAsync(string consumerName) |
|||
{ |
|||
if (await Collection.CountAsync(x => x.Name == consumerName) == 0) |
|||
{ |
|||
try |
|||
{ |
|||
await Collection.InsertOneAsync(new MongoEventConsumerInfo { Name = consumerName, LastHandledEventNumber = -1 }); |
|||
} |
|||
catch (MongoWriteException ex) |
|||
{ |
|||
if (ex.WriteError?.Category != ServerErrorCategory.DuplicateKey) |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public Task StartAsync(string consumerName) |
|||
{ |
|||
return Collection.UpdateOneAsync(x => x.Name == consumerName, Update.Unset(x => x.IsStopped)); |
|||
} |
|||
|
|||
public Task StopAsync(string consumerName) |
|||
{ |
|||
return Collection.UpdateOneAsync(x => x.Name == consumerName, Update.Set(x => x.IsStopped, true)); |
|||
} |
|||
|
|||
public Task SetLastHandledEventNumberAsync(string consumerName, long eventNumber) |
|||
{ |
|||
return Collection.UpdateOneAsync(x => x.Name == consumerName, Update.Set(x => x.LastHandledEventNumber, eventNumber).Unset(x => x.IsResetting).Unset(x => x.IsStopped)); |
|||
} |
|||
|
|||
public Task ResetAsync(string consumerName) |
|||
{ |
|||
return Collection.UpdateOneAsync(x => x.Name == consumerName, Update.Set(x => x.IsResetting, true)); |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +1,21 @@ |
|||
// ==========================================================================
|
|||
// IEventCatchConsumer.cs
|
|||
// IEventCatchConsumerInfo.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Infrastructure.CQRS.Events |
|||
{ |
|||
public interface IEventCatchConsumer |
|||
public interface IEventConsumerInfo |
|||
{ |
|||
Task<long> GetLastHandledEventNumber(); |
|||
long LastHandledEventNumber { get; } |
|||
|
|||
bool IsStopped { get; } |
|||
|
|||
bool IsResetting { get; } |
|||
|
|||
Task On(Envelope<IEvent> @event, long eventNumber); |
|||
string Name { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
// ==========================================================================
|
|||
// IEventCatchConsumerControlStore.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Squidex.Infrastructure.CQRS.Events |
|||
{ |
|||
public interface IEventConsumerInfoRepository |
|||
{ |
|||
Task<IReadOnlyList<IEventConsumerInfo>> QueryAsync(); |
|||
|
|||
Task<IEventConsumerInfo> FindAsync(string consumerName); |
|||
|
|||
Task CreateAsync(string consumerName); |
|||
|
|||
Task StartAsync(string consumerName); |
|||
|
|||
Task StopAsync(string consumerName); |
|||
|
|||
Task ResetAsync(string consumerName); |
|||
|
|||
Task SetLastHandledEventNumberAsync(string consumerName, long eventNumber); |
|||
} |
|||
} |
|||
@ -1,74 +0,0 @@ |
|||
// ==========================================================================
|
|||
// MongoDbStore.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using MongoDB.Bson; |
|||
using MongoDB.Bson.Serialization.Attributes; |
|||
using MongoDB.Driver; |
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.CQRS; |
|||
using Squidex.Infrastructure.CQRS.Events; |
|||
using Squidex.Infrastructure.MongoDb; |
|||
|
|||
namespace Squidex.Read.MongoDb.Utils |
|||
{ |
|||
public sealed class EventPosition |
|||
{ |
|||
[BsonId] |
|||
[BsonRepresentation(BsonType.String)] |
|||
public string Name { get; set; } |
|||
|
|||
[BsonElement] |
|||
[BsonRequired] |
|||
public long EventNumber { get; set; } |
|||
} |
|||
|
|||
public sealed class MongoDbConsumerWrapper : MongoRepositoryBase<EventPosition>, IEventCatchConsumer |
|||
{ |
|||
private static readonly UpdateOptions upsert = new UpdateOptions { IsUpsert = true }; |
|||
private readonly IEventConsumer eventConsumer; |
|||
private readonly string eventStoreName; |
|||
|
|||
public MongoDbConsumerWrapper(IMongoDatabase database, IEventConsumer eventConsumer) |
|||
: base(database) |
|||
{ |
|||
Guard.NotNull(eventConsumer, nameof(eventConsumer)); |
|||
|
|||
this.eventConsumer = eventConsumer; |
|||
|
|||
eventStoreName = eventConsumer.GetType().Name; |
|||
} |
|||
|
|||
protected override string CollectionName() |
|||
{ |
|||
return "EventPositions"; |
|||
} |
|||
|
|||
public async Task On(Envelope<IEvent> @event, long eventNumber) |
|||
{ |
|||
await eventConsumer.On(@event); |
|||
|
|||
await SetLastHandledEventNumber(eventNumber); |
|||
} |
|||
|
|||
private Task SetLastHandledEventNumber(long eventNumber) |
|||
{ |
|||
return Collection.ReplaceOneAsync(x => x.Name == eventStoreName, new EventPosition { Name = eventStoreName, EventNumber = eventNumber }, upsert); |
|||
} |
|||
|
|||
public async Task<long> GetLastHandledEventNumber() |
|||
{ |
|||
var collectionPosition = |
|||
await Collection |
|||
.Find(x => x.Name == eventStoreName).SortByDescending(x => x.EventNumber).Limit(1) |
|||
.FirstOrDefaultAsync(); |
|||
|
|||
return collectionPosition?.EventNumber ?? -1; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,71 @@ |
|||
// ==========================================================================
|
|||
// EventConsumersController.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using NSwag.Annotations; |
|||
using Squidex.Controllers.Api.EventConsumers.Models; |
|||
using Squidex.Infrastructure.CQRS.Events; |
|||
using Squidex.Infrastructure.Reflection; |
|||
using Squidex.Pipeline; |
|||
|
|||
namespace Squidex.Controllers.Api.EventConsumers |
|||
{ |
|||
[ApiExceptionFilter] |
|||
[Authorize(Roles = "administrator")] |
|||
[SwaggerIgnore] |
|||
public sealed class EventConsumersController : Controller |
|||
{ |
|||
private readonly IEventConsumerInfoRepository eventConsumerRepository; |
|||
|
|||
public EventConsumersController(IEventConsumerInfoRepository eventConsumerRepository) |
|||
{ |
|||
this.eventConsumerRepository = eventConsumerRepository; |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("event-consumers/")] |
|||
public async Task<IActionResult> GetEventConsumers() |
|||
{ |
|||
var entities = await eventConsumerRepository.QueryAsync(); |
|||
|
|||
var models = entities.Select(x => SimpleMapper.Map(x, new EventConsumerDto())).ToList(); |
|||
|
|||
return Ok(models); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("event-consumers/{name}/start")] |
|||
public async Task<IActionResult> Start(string name) |
|||
{ |
|||
await eventConsumerRepository.StartAsync(name); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("event-consumers/{name}/stop")] |
|||
public async Task<IActionResult> Stop(string name) |
|||
{ |
|||
await eventConsumerRepository.StopAsync(name); |
|||
|
|||
return NoContent(); |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("event-consumers/{name}/reset")] |
|||
public async Task<IActionResult> Reset(string name) |
|||
{ |
|||
await eventConsumerRepository.ResetAsync(name); |
|||
|
|||
return NoContent(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// ==========================================================================
|
|||
// EventConsumerDto.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
namespace Squidex.Controllers.Api.EventConsumers.Models |
|||
{ |
|||
public sealed class EventConsumerDto |
|||
{ |
|||
public long LastHandledEventNumber { get; set; } |
|||
|
|||
public bool IsStopped { get; set; } |
|||
|
|||
public bool IsResetting { get; set; } |
|||
|
|||
public string Name { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
<div class="sidebar"> |
|||
<ul class="nav flex-column"> |
|||
<li class="nav-item"> |
|||
<a class="nav-link" routerLink="event-consumers" routerLinkActive="active"> |
|||
<i class="nav-icon icon-time"></i> <div class="nav-text">Event Consumers</div> |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
|
|||
<div class="panel-container"> |
|||
<router-outlet></router-outlet> |
|||
</div> |
|||
@ -0,0 +1,46 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
.sidebar { |
|||
@include fixed($size-navbar-height, auto, 0, 0); |
|||
@include box-shadow-colored(2px, 0, 0, $color-dark1-border2); |
|||
min-width: $size-sidebar-width; |
|||
max-width: $size-sidebar-width; |
|||
border-right: 1px solid $color-dark1-border1; |
|||
background: $color-dark1-background; |
|||
z-index: 100; |
|||
} |
|||
|
|||
.nav { |
|||
&-icon { |
|||
font-size: 2rem; |
|||
} |
|||
|
|||
&-text { |
|||
font-size: .9rem; |
|||
} |
|||
|
|||
&-link { |
|||
& { |
|||
@include transition(color .3s ease); |
|||
padding: 1.25rem; |
|||
display: block; |
|||
text-align: center; |
|||
text-decoration: none; |
|||
color: $color-dark1-foreground; |
|||
} |
|||
|
|||
&:hover, |
|||
&.active { |
|||
color: $color-dark1-focus-foreground; |
|||
|
|||
.nav-icon { |
|||
color: $color-theme-blue; |
|||
} |
|||
} |
|||
|
|||
&.active { |
|||
background: $color-dark1-active-background; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component } from '@angular/core'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-administration-area', |
|||
styleUrls: ['./administration-area.component.scss'], |
|||
templateUrl: './administration-area.component.html' |
|||
}) |
|||
export class AdministrationAreaComponent { |
|||
|
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
export * from './pages/event-consumers/event-consumers-page.component'; |
|||
|
|||
export * from './administration-area.component'; |
|||
@ -0,0 +1,48 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
|
|||
import { |
|||
SqxFrameworkModule, |
|||
SqxSharedModule |
|||
} from 'shared'; |
|||
|
|||
import { |
|||
AdministrationAreaComponent, |
|||
EventConsumersPage |
|||
} from './declarations'; |
|||
|
|||
const routes: Routes = [ |
|||
{ |
|||
path: '', |
|||
component: AdministrationAreaComponent, |
|||
children: [ |
|||
{ |
|||
path: '', |
|||
children: [{ |
|||
path: 'event-consumers', |
|||
component: EventConsumersPage |
|||
}] |
|||
} |
|||
] |
|||
} |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [ |
|||
SqxFrameworkModule, |
|||
SqxSharedModule, |
|||
RouterModule.forChild(routes) |
|||
], |
|||
declarations: [ |
|||
AdministrationAreaComponent, |
|||
EventConsumersPage |
|||
] |
|||
}) |
|||
export class SqxFeatureAdministrationModule { } |
|||
@ -0,0 +1,64 @@ |
|||
<sqx-title message="Event Consumers"></sqx-title> |
|||
|
|||
<sqx-panel theme="light" panelWidth="50rem"> |
|||
<div class="panel-header"> |
|||
<div class="panel-title-row"> |
|||
<h3 class="panel-title">EventConsumers</h3> |
|||
</div> |
|||
|
|||
<a class="panel-close" routerLink="['..']"> |
|||
<i class="icon-close"></i> |
|||
</a> |
|||
</div> |
|||
|
|||
<div class="panel-main"> |
|||
<div class="panel-content panel-content-scroll"> |
|||
<table class="table table-items table-fixed"> |
|||
<colgroup> |
|||
<col style="width: 100%" /> |
|||
<col style="width: 160px" /> |
|||
<col style="width: 160px" /> |
|||
</colgroup> |
|||
|
|||
<thead> |
|||
<tr> |
|||
<th> |
|||
Name |
|||
</th> |
|||
<th class="col-right"> |
|||
Event Number |
|||
</th> |
|||
<th class="col-right"> |
|||
Options |
|||
</th> |
|||
</tr> |
|||
</thead> |
|||
|
|||
<tbody> |
|||
<template ngFor let-eventConsumer [ngForOf]="eventConsumers"> |
|||
<tr> |
|||
<td> |
|||
<span class="truncate">{{eventConsumer.name}}</span> |
|||
</td> |
|||
<td class="col-right"> |
|||
<span>{{eventConsumer.lastHandledEventNumber}}</span> |
|||
</td> |
|||
<td class="col-right"> |
|||
<button class="btn btn-simple" (click)="reset(eventConsumer.name)" *ngIf="!eventConsumer.isResetting"> |
|||
<i class="icon icon-reset"></i> |
|||
</button> |
|||
<button class="btn btn-simple" (click)="start(eventConsumer.name)" *ngIf="eventConsumer.isStopped"> |
|||
<i class="icon icon-play"></i> |
|||
</button> |
|||
<button class="btn btn-simple" (click)="stop(eventConsumer.name)" *ngIf="!eventConsumer.isStopped"> |
|||
<i class="icon icon-pause"></i> |
|||
</button> |
|||
</td> |
|||
</tr> |
|||
<tr class="spacer"></tr> |
|||
</template> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</sqx-panel> |
|||
@ -0,0 +1,10 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
button { |
|||
display: inline-block; |
|||
} |
|||
|
|||
.col-right { |
|||
text-align: right; |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, OnDestroy, OnInit } from '@angular/core'; |
|||
import { Observable, Subscription } from 'rxjs'; |
|||
|
|||
import { |
|||
EventConsumerDto, |
|||
EventConsumersService, |
|||
ImmutableArray |
|||
} from 'shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-event-consumers-page', |
|||
styleUrls: ['./event-consumers-page.component.scss'], |
|||
templateUrl: './event-consumers-page.component.html' |
|||
}) |
|||
export class EventConsumersPage implements OnInit, OnDestroy { |
|||
private subscription: Subscription; |
|||
|
|||
public eventConsumers = ImmutableArray.empty<EventConsumerDto>(); |
|||
|
|||
constructor( |
|||
private readonly eventConsumersService: EventConsumersService |
|||
) { |
|||
} |
|||
|
|||
public ngOnInit() { |
|||
this.subscription = |
|||
Observable.timer(0, 4000) |
|||
.switchMap(_ => this.eventConsumersService.getEventConsumers()) |
|||
.subscribe(dtos => { |
|||
this.eventConsumers = ImmutableArray.of(dtos); |
|||
}); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
this.subscription.unsubscribe(); |
|||
} |
|||
|
|||
public start(name: string) { |
|||
this.eventConsumersService.startEventConsumer(name) |
|||
.subscribe(() => { |
|||
this.eventConsumers = this.eventConsumers.map(e => { |
|||
if (e.name === name) { |
|||
return new EventConsumerDto(name, e.lastHandledEventNumber, false, e.isResetting); |
|||
} else { |
|||
return e; |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
public stop(name: string) { |
|||
this.eventConsumersService.stopEventConsumer(name) |
|||
.subscribe(() => { |
|||
this.eventConsumers = this.eventConsumers.map(e => { |
|||
if (e.name === name) { |
|||
return new EventConsumerDto(name, e.lastHandledEventNumber, true, e.isResetting); |
|||
} else { |
|||
return e; |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
public reset(name: string) { |
|||
this.eventConsumersService.resetEventConsumer(name) |
|||
.subscribe(() => { |
|||
this.eventConsumers = this.eventConsumers.map(e => { |
|||
if (e.name === name) { |
|||
return new EventConsumerDto(name, e.lastHandledEventNumber, e.isStopped, true); |
|||
} else { |
|||
return e; |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,76 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import 'framework/angular/http-extensions'; |
|||
|
|||
import { ApiUrlConfig } from 'framework'; |
|||
import { AuthService } from './auth.service'; |
|||
|
|||
export class EventConsumerDto { |
|||
constructor( |
|||
public readonly name: string, |
|||
public readonly lastHandledEventNumber: number, |
|||
public readonly isStopped: boolean, |
|||
public readonly isResetting: boolean |
|||
) { |
|||
} |
|||
} |
|||
|
|||
@Injectable() |
|||
export class EventConsumersService { |
|||
constructor( |
|||
private readonly authService: AuthService, |
|||
private readonly apiUrl: ApiUrlConfig |
|||
) { |
|||
} |
|||
|
|||
public getEventConsumers(): Observable<EventConsumerDto[]> { |
|||
const url = this.apiUrl.buildUrl('/api/event-consumers'); |
|||
|
|||
return this.authService.authGet(url) |
|||
.map(response => response.json()) |
|||
.map(response => { |
|||
const items: any[] = response; |
|||
|
|||
return items.map(item => { |
|||
return new EventConsumerDto( |
|||
item.name, |
|||
item.lastHandledEventNumber, |
|||
item.isStopped, |
|||
item.isResetting); |
|||
}); |
|||
}) |
|||
.catchError('Failed to load event consumers. Please reload.'); |
|||
} |
|||
|
|||
public startEventConsumer(name: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/event-consumers/${name}/start`); |
|||
|
|||
return this.authService.authPut(url, {}) |
|||
.map(response => response.json()) |
|||
.catchError('Failed to start event consumer. Please reload.'); |
|||
} |
|||
|
|||
public stopEventConsumer(name: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/event-consumers/${name}/stop`); |
|||
|
|||
return this.authService.authPut(url, {}) |
|||
.map(response => response.json()) |
|||
.catchError('Failed to stop event consumer. Please reload.'); |
|||
} |
|||
|
|||
public resetEventConsumer(name: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/event-consumers/${name}/reset`); |
|||
|
|||
return this.authService.authPut(url, {}) |
|||
.map(response => response.json()) |
|||
.catchError('Failed to reset event consumer. Please reload.'); |
|||
} |
|||
} |
|||
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue