Browse Source

Layout fixes. (#755)

pull/758/head
Sebastian Stehle 4 years ago
committed by GitHub
parent
commit
3e1f0a9896
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      backend/i18n/frontend_en.json
  2. 6
      backend/i18n/frontend_it.json
  3. 6
      backend/i18n/frontend_nl.json
  4. 6
      backend/i18n/frontend_zh.json
  5. 8
      backend/i18n/source/frontend_en.json
  6. 18
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs
  7. 6
      backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs
  8. 2
      backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs
  9. 17
      backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventsDto.cs
  10. 43
      backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs
  11. 10
      frontend/app/features/rules/pages/events/rule-event.component.html
  12. 11
      frontend/app/features/rules/pages/events/rule-event.component.scss
  13. 12
      frontend/app/features/rules/pages/events/rule-events-page.component.html
  14. 6
      frontend/app/features/rules/pages/events/rule-events-page.component.scss
  15. 4
      frontend/app/features/rules/pages/events/rule-events-page.component.ts
  16. 40
      frontend/app/features/rules/pages/simulator/rule-simulator-page.component.scss
  17. 28
      frontend/app/features/rules/pages/simulator/simulated-rule-event.component.html
  18. 38
      frontend/app/features/rules/pages/simulator/simulated-rule-event.component.scss
  19. 8
      frontend/app/shared/services/rules.service.spec.ts
  20. 6
      frontend/app/shared/services/rules.service.ts
  21. 15
      frontend/app/shared/state/rule-events.state.spec.ts
  22. 26
      frontend/app/shared/state/rule-events.state.ts

8
backend/i18n/frontend_en.json

@ -220,6 +220,7 @@
"common.bookmarks": "Bookmarks",
"common.bytes": "bytes",
"common.cancel": "Cancel",
"common.cancelAll": "Cancel All",
"common.category": "Category",
"common.clear": "Clear",
"common.clientId": "Client Id",
@ -251,6 +252,7 @@
"common.delete": "Delete",
"common.description": "Description",
"common.designer": "Designer",
"common.details": "Details",
"common.disable": "Disable",
"common.disabled": "Disabled",
"common.displayName": "Display Name",
@ -667,7 +669,11 @@
"rules.refreshTooltip": "Refresh Rules",
"rules.reloaded": "Rules reloaded.",
"rules.restarted": "Rule will start to run in a few seconds.",
"rules.ruleEvents.cancelFailed": "Failed to cancel rule event. Please reload.",
"rules.ruleEvents.cancelAllConfirmText": "Do you really want to cancel all events?",
"rules.ruleEvents.cancelAllConfirmTitle": "Cancel all events",
"rules.ruleEvents.cancelConfirmText": "Do you really want to cancel this event?",
"rules.ruleEvents.cancelConfirmTitle": "Cancel event",
"rules.ruleEvents.cancelFailed": "Failed to cancel rule event(s). Please reload.",
"rules.ruleEvents.enqueue": "Enqueue",
"rules.ruleEvents.enqueued": "Events enqueued. Will be resend in a few seconds.",
"rules.ruleEvents.enqueueFailed": "Failed to enqueue rule event. Please reload.",

6
backend/i18n/frontend_it.json

@ -220,6 +220,7 @@
"common.bookmarks": "Bookmarks",
"common.bytes": "byte",
"common.cancel": "Annulla",
"common.cancelAll": "Cancel All",
"common.category": "Categoria",
"common.clear": "Pulisci",
"common.clientId": "Client Id",
@ -251,6 +252,7 @@
"common.delete": "Cancella",
"common.description": "Descrizione",
"common.designer": "Designer",
"common.details": "Details",
"common.disable": "Disable",
"common.disabled": "Disabled",
"common.displayName": "Nome visualizzato",
@ -667,6 +669,10 @@
"rules.refreshTooltip": "Aggiorna le Regole",
"rules.reloaded": "Regole ricaricate.",
"rules.restarted": "La Regola sarà eseguita fra pochi secondi.",
"rules.ruleEvents.cancelAllConfirmText": "Do you really want to cancel all events?",
"rules.ruleEvents.cancelAllConfirmTitle": "Cancel all events",
"rules.ruleEvents.cancelConfirmText": "Do you really want to cancel this event?",
"rules.ruleEvents.cancelConfirmTitle": "Cancel event",
"rules.ruleEvents.cancelFailed": "Non è stato possibile cancellare l'evento della regola. Per favore ricarica.",
"rules.ruleEvents.enqueue": "Metti in coda",
"rules.ruleEvents.enqueued": "Eventi messo in coda. L'evento potrà essere rieseguito fra pochi secondi.",

6
backend/i18n/frontend_nl.json

@ -220,6 +220,7 @@
"common.bookmarks": "Bookmarks",
"common.bytes": "bytes",
"common.cancel": "Annuleren",
"common.cancelAll": "Cancel All",
"common.category": "Category",
"common.clear": "Wissen",
"common.clientId": "Client-ID",
@ -251,6 +252,7 @@
"common.delete": "Verwijderen",
"common.description": "Beschrijving",
"common.designer": "Designer",
"common.details": "Details",
"common.disable": "Disable",
"common.disabled": "Disabled",
"common.displayName": "Weergavenaam",
@ -667,6 +669,10 @@
"rules.refreshTooltip": "Vernieuwingsregels",
"rules.reloaded": "Regels herladen.",
"rules.restarted": "Regel begint over een paar seconden te lopen.",
"rules.ruleEvents.cancelAllConfirmText": "Do you really want to cancel all events?",
"rules.ruleEvents.cancelAllConfirmTitle": "Cancel all events",
"rules.ruleEvents.cancelConfirmText": "Do you really want to cancel this event?",
"rules.ruleEvents.cancelConfirmTitle": "Cancel event",
"rules.ruleEvents.cancelFailed": "Annuleren van regelgebeurtenis is mislukt. Laad opnieuw.",
"rules.ruleEvents.enqueue": "Enqueue",
"rules.ruleEvents.enqueued": "Evenementen in de wachtrij geplaatst. Worden over enkele seconden opnieuw verzonden.",

6
backend/i18n/frontend_zh.json

@ -220,6 +220,7 @@
"common.bookmarks": "书签",
"common.bytes": "bytes",
"common.cancel": "取消",
"common.cancelAll": "Cancel All",
"common.category": "类别",
"common.clear": "清除",
"common.clientId": "客户端 ID",
@ -251,6 +252,7 @@
"common.delete": "删除",
"common.description": "说明",
"common.designer": "设计师",
"common.details": "Details",
"common.disable": "Disable",
"common.disabled": "已禁用",
"common.displayName": "显示名称",
@ -667,6 +669,10 @@
"rules.refreshTooltip": "刷新规则",
"rules.reloaded": "规则重新加载。",
"rules.restarted": "规则将在几秒钟后开始运行。",
"rules.ruleEvents.cancelAllConfirmText": "Do you really want to cancel all events?",
"rules.ruleEvents.cancelAllConfirmTitle": "Cancel all events",
"rules.ruleEvents.cancelConfirmText": "Do you really want to cancel this event?",
"rules.ruleEvents.cancelConfirmTitle": "Cancel event",
"rules.ruleEvents.cancelFailed": "取消规则事件失败。请重新加载。",
"rules.ruleEvents.enqueue": "入队",
"rules.ruleEvents.enqueued": "事件已入队。将在几秒钟后重新发送。",

8
backend/i18n/source/frontend_en.json

@ -220,6 +220,7 @@
"common.bookmarks": "Bookmarks",
"common.bytes": "bytes",
"common.cancel": "Cancel",
"common.cancelAll": "Cancel All",
"common.category": "Category",
"common.clear": "Clear",
"common.clientId": "Client Id",
@ -251,6 +252,7 @@
"common.delete": "Delete",
"common.description": "Description",
"common.designer": "Designer",
"common.details": "Details",
"common.disable": "Disable",
"common.disabled": "Disabled",
"common.displayName": "Display Name",
@ -667,7 +669,11 @@
"rules.refreshTooltip": "Refresh Rules",
"rules.reloaded": "Rules reloaded.",
"rules.restarted": "Rule will start to run in a few seconds.",
"rules.ruleEvents.cancelFailed": "Failed to cancel rule event. Please reload.",
"rules.ruleEvents.cancelAllConfirmText": "Do you really want to cancel all events?",
"rules.ruleEvents.cancelAllConfirmTitle": "Cancel all events",
"rules.ruleEvents.cancelConfirmText": "Do you really want to cancel this event?",
"rules.ruleEvents.cancelConfirmTitle": "Cancel event",
"rules.ruleEvents.cancelFailed": "Failed to cancel rule event(s). Please reload.",
"rules.ruleEvents.enqueue": "Enqueue",
"rules.ruleEvents.enqueued": "Events enqueued. Will be resend in a few seconds.",
"rules.ruleEvents.enqueueFailed": "Failed to enqueue rule event. Please reload.",

18
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEventRepository.cs

@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
await Collection.InsertOneIfNotExistsAsync(entity);
}
public Task CancelAsync(DomainId id)
public Task CancelByEventAsync(DomainId id)
{
return Collection.UpdateOneAsync(x => x.DocumentId == id,
Update
@ -117,6 +117,22 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules
.Set(x => x.JobResult, RuleJobResult.Cancelled));
}
public Task CancelByRuleAsync(DomainId ruleId)
{
return Collection.UpdateOneAsync(x => x.RuleId == ruleId,
Update
.Set(x => x.NextAttempt, null)
.Set(x => x.JobResult, RuleJobResult.Cancelled));
}
public Task CancelByAppAsync(DomainId appId)
{
return Collection.UpdateOneAsync(x => x.DocumentId == appId,
Update
.Set(x => x.NextAttempt, null)
.Set(x => x.JobResult, RuleJobResult.Cancelled));
}
public Task UpdateAsync(RuleJob job, RuleJobUpdate update)
{
Guard.NotNull(job, nameof(job));

6
backend/src/Squidex.Domain.Apps.Entities/Rules/Repositories/IRuleEventRepository.cs

@ -44,7 +44,11 @@ namespace Squidex.Domain.Apps.Entities.Rules.Repositories
Task EnqueueAsync(DomainId id, Instant nextAttempt);
Task CancelAsync(DomainId id);
Task CancelByEventAsync(DomainId eventId);
Task CancelByRuleAsync(DomainId ruleId);
Task CancelByAppAsync(DomainId appId);
Task QueryPendingAsync(Instant now, Func<IRuleEventEntity, Task> callback, CancellationToken ct = default);

2
backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventDto.cs

@ -82,7 +82,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models
if (NextAttempt != null)
{
AddDeleteLink("delete", resources.Url<RulesController>(x => nameof(x.DeleteEvent), values));
AddDeleteLink("cancel", resources.Url<RulesController>(x => nameof(x.DeleteEvent), values));
}
return this;

17
backend/src/Squidex/Areas/Api/Controllers/Rules/Models/RuleEventsDto.cs

@ -26,7 +26,7 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models
/// </summary>
public long Total { get; set; }
public static RuleEventsDto FromRuleEvents(IResultList<IRuleEventEntity> ruleEvents, Resources resources)
public static RuleEventsDto FromRuleEvents(IResultList<IRuleEventEntity> ruleEvents, Resources resources, DomainId? ruleId)
{
var result = new RuleEventsDto
{
@ -34,15 +34,26 @@ namespace Squidex.Areas.Api.Controllers.Rules.Models
Items = ruleEvents.Select(x => RuleEventDto.FromRuleEvent(x, resources)).ToArray()
};
return result.CreateLinks(resources);
return result.CreateLinks(resources, ruleId);
}
private RuleEventsDto CreateLinks(Resources resources)
private RuleEventsDto CreateLinks(Resources resources, DomainId? ruleId)
{
var values = new { app = resources.App };
AddSelfLink(resources.Url<RulesController>(x => nameof(x.GetEvents), values));
if (ruleId != null)
{
var routeValeus = new { values.app, id = ruleId };
AddDeleteLink("cancel", resources.Url<RulesController>(x => nameof(x.DeleteRuleEvents), routeValeus));
}
else
{
AddDeleteLink("cancel", resources.Url<RulesController>(x => nameof(x.DeleteEvents), values));
}
return this;
}
}

43
backend/src/Squidex/Areas/Api/Controllers/Rules/RulesController.cs

@ -264,6 +264,26 @@ namespace Squidex.Areas.Api.Controllers.Rules
return NoContent();
}
/// <summary>
/// Cancels all rule events.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <param name="id">The id of the rule to cancel.</param>
/// <returns>
/// 204 => Rule events cancelled.
/// </returns>
[HttpDelete]
[Route("apps/{app}/rules/{id}/events/")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ApiPermissionOrAnonymous(Permissions.AppRulesEvents)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteRuleEvents(string app, DomainId id)
{
await ruleEventsRepository.CancelByRuleAsync(id);
return NoContent();
}
/// <summary>
/// Simulate a rule.
/// </summary>
@ -334,7 +354,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
{
var ruleEvents = await ruleEventsRepository.QueryByAppAsync(AppId, ruleId, skip, take);
var response = RuleEventsDto.FromRuleEvents(ruleEvents, Resources);
var response = RuleEventsDto.FromRuleEvents(ruleEvents, Resources, ruleId);
return Ok(response);
}
@ -366,6 +386,25 @@ namespace Squidex.Areas.Api.Controllers.Rules
return NoContent();
}
/// <summary>
/// Cancels all events.
/// </summary>
/// <param name="app">The name of the app.</param>
/// <returns>
/// 204 => Events cancelled.
/// </returns>
[HttpDelete]
[Route("apps/{app}/rules/events/")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ApiPermissionOrAnonymous(Permissions.AppRulesEvents)]
[ApiCosts(1)]
public async Task<IActionResult> DeleteEvents(string app)
{
await ruleEventsRepository.CancelByAppAsync(App.Id);
return NoContent();
}
/// <summary>
/// Cancels an event.
/// </summary>
@ -388,7 +427,7 @@ namespace Squidex.Areas.Api.Controllers.Rules
return NotFound();
}
await ruleEventsRepository.CancelAsync(id);
await ruleEventsRepository.CancelByRuleAsync(id);
return NoContent();
}

10
frontend/app/features/rules/pages/events/rule-event.component.html

@ -1,4 +1,4 @@
<tr [class.expanded]="expanded" class="table-items-row" [class.expanded]>
<tr [class.expanded]="expanded" class="table-items-row">
<td class="cell-label">
<span class="badge rounded-pill badge-{{jobResultClass}}">{{event.jobResult}}</span>
</td>
@ -34,11 +34,15 @@
{{ 'rules.ruleEvents.nextAttemptLabel' | sqxTranslate }}: <ng-container *ngIf="event.nextAttempt">{{event.nextAttempt | sqxFromNow}}</ng-container>
</div>
<div class="col-3 text-end">
<button type="button" class="btn btn-text-danger btn-sm me-1" (click)="cancel.emit()" [class.hidden]="!event.nextAttempt">
<button type="button" class="btn btn-danger me-1" [class.hidden]="!event.nextAttempt"
(sqxConfirmClick)="cancel.emit()"
confirmTitle="i18n:rules.ruleEvents.cancelConfirmTitle"
confirmText="i18n:rules.ruleEvents.cancelConfirmText"
confirmRememberKey="cancelRuleEvent">
{{ 'common.cancel' | sqxTranslate }}
</button>
<button type="button" class="btn btn-success btn-sm" (click)="enqueue.emit()">
<button type="button" class="btn btn-success" (click)="enqueue.emit()">
{{ 'rules.ruleEvents.enqueue' | sqxTranslate }}
</button>
</div>

11
frontend/app/features/rules/pages/events/rule-event.component.scss

@ -18,21 +18,22 @@ td {
}
.event {
&-stats {
font-size: $font-smallest;
}
&-header,
&-dump,
&-stats {
padding: .75rem 1.25rem;
}
&-stats {
font-size: $font-smallest;
font-weight: normal;
padding-bottom: 0;
}
&-header {
background: $color-border-light;
border: 0;
border-bottom: 2px solid $color-border;
padding: .75rem 1.25rem;
position: relative;
h4 {

12
frontend/app/features/rules/pages/events/rule-events-page.component.html

@ -1,10 +1,20 @@
<sqx-title message="i18n:rules.ruleEvents.listPageTitle"></sqx-title>
<sqx-layout layout="main" titleText="i18n:common.events" titleIcon="events" [width]="50">
<sqx-layout layout="main" titleText="i18n:common.events" titleIcon="events" [width]="50" [hideSidebar]="true">
<ng-container menu>
<button type="button" class="btn btn-text-secondary" (click)="reload()" title="i18n:rules.refreshEventsTooltip" shortcut="CTRL + B">
<i class="icon-reset"></i> {{ 'common.refresh' | sqxTranslate }}
</button>
<ng-container *ngIf="ruleEventsState.canCancelAll | async">
<button type="button" class="btn btn-danger ms-2"
(sqxConfirmClick)="cancelAll()"
confirmTitle="i18n:rules.ruleEvents.cancelAllConfirmTitle"
confirmText="i18n:rules.ruleEvents.cancelAllConfirmText"
confirmRememberKey="cancelAllRuleEvents">
{{ 'common.cancelAll' | sqxTranslate }}
</button>
</ng-container>
</ng-container>
<ng-container>

6
frontend/app/features/rules/pages/events/rule-events-page.component.scss

@ -0,0 +1,6 @@
:host ::ng-deep {
.panel2-slice {
border-left: 1px solid $color-border;
border-right: 1px solid $color-border;
}
}

4
frontend/app/features/rules/pages/events/rule-events-page.component.ts

@ -51,6 +51,10 @@ export class RuleEventsPageComponent extends ResourceOwner implements OnInit {
this.ruleEventsState.enqueue(event);
}
public cancelAll() {
this.ruleEventsState.cancelAll();
}
public cancel(event: RuleEventDto) {
this.ruleEventsState.cancel(event);
}

40
frontend/app/features/rules/pages/simulator/rule-simulator-page.component.scss

@ -1,38 +1,6 @@
h3 {
margin-bottom: 1rem;
}
.expanded {
border-bottom: 0;
}
.event {
&-stats {
font-size: $font-smallest;
}
&-dump {
@include text-code;
height: 20rem;
margin-bottom: 0;
margin-top: 1rem;
}
&-header {
background: $color-white;
border: 0;
margin: -.75rem -1.25rem;
margin-bottom: 1rem;
padding: .75rem 1.25rem;
position: relative;
&::before {
@include caret-top($color-white);
@include absolute(-1.1rem, 1.8rem, auto, auto);
}
h3 {
margin: 0;
}
:host ::ng-deep {
.panel2-slice {
border-left: 1px solid $color-border;
border-right: 1px solid $color-border;
}
}

28
frontend/app/features/rules/pages/simulator/simulated-rule-event.component.html

@ -1,4 +1,4 @@
<tr [class.expanded]="expanded">
<tr [class.expanded]="expanded" class="table-items-row">
<td class="cell-label">
<span class="badge rounded-pill badge-{{statusClass}}">{{status}}</span>
</td>
@ -15,17 +15,23 @@
</td>
</tr>
<tr *ngIf="expanded">
<td colspan="4">
<div class="form-group" *ngIf="event.actionData">
<label>{{ 'rules.actionData' | sqxTranslate }}</label>
<sqx-code-editor [ngModel]="data" [disabled]="true" [wordWrap]="true" height="auto"></sqx-code-editor>
<td colspan="4" class="details">
<div class="event-header">
<h4>{{ 'common.details' | sqxTranslate }}</h4>
</div>
<div class="form-group" *ngIf="event.error">
<label>{{ 'common.error' | sqxTranslate }}</label>
<sqx-code-editor [ngModel]="event.error" [disabled]="true" [wordWrap]="true" height="auto"></sqx-code-editor>
<div class="row event-dump">
<div class="form-group" *ngIf="event.actionData">
<label>{{ 'rules.actionData' | sqxTranslate }}</label>
<sqx-code-editor [ngModel]="data" [disabled]="true" [wordWrap]="true" height="auto"></sqx-code-editor>
</div>
<div class="form-group" *ngIf="event.error">
<label>{{ 'common.error' | sqxTranslate }}</label>
<sqx-code-editor [ngModel]="event.error" [disabled]="true" [wordWrap]="true" height="auto"></sqx-code-editor>
</div>
</div>
</td>
</tr>

38
frontend/app/features/rules/pages/simulator/simulated-rule-event.component.scss

@ -1,4 +1,38 @@
td {
&.details {
border-top: 0;
border-top-left-radius: 0 !important;
border-top-right-radius: 0 !important;
padding: 0 !important;
}
}
.expanded {
border-bottom: 0;
.table-items-row {
&.expanded {
td {
border-bottom: 0;
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
}
}
.event {
&-header,
&-dump {
padding: .75rem 1.25rem;
}
&-header {
background: $color-border-light;
border: 0;
border-bottom: 2px solid $color-border;
position: relative;
h4 {
font-size: 1rem;
font-weight: 500;
margin: 0;
}
}
}

8
frontend/app/shared/services/rules.service.spec.ts

@ -343,17 +343,17 @@ describe('RulesService', () => {
req.flush({});
}));
it('should make delete request to cancel rule event',
it('should make delete request to cancel all rule events',
inject([RulesService, HttpTestingController], (rulesService: RulesService, httpMock: HttpTestingController) => {
const resource: Resource = {
_links: {
delete: { method: 'DELETE', href: '/api/apps/my-app/rules/events/123' },
cancel: { method: 'DELETE', href: '/api/apps/my-app/rules/events' },
},
};
rulesService.cancelEvent('my-app', resource).subscribe();
rulesService.cancelEvents('my-app', resource).subscribe();
const req = httpMock.expectOne('http://service/p/api/apps/my-app/rules/events/123');
const req = httpMock.expectOne('http://service/p/api/apps/my-app/rules/events');
expect(req.request.method).toEqual('DELETE');
expect(req.request.headers.get('If-Match')).toBeNull();

6
frontend/app/shared/services/rules.service.ts

@ -375,14 +375,14 @@ export class RulesService {
pretifyError('i18n:rules.ruleEvents.enqueueFailed'));
}
public cancelEvent(appName: string, resource: Resource): Observable<any> {
const link = resource._links['delete'];
public cancelEvents(appName: string, resource: Resource): Observable<any> {
const link = resource._links['cancel'];
const url = this.apiUrl.buildUrl(link.href);
return HTTP.requestVersioned(this.http, link.method, url).pipe(
tap(() => {
this.analytics.trackEvent('Rule', 'EventDequeued', appName);
this.analytics.trackEvent('Rule', 'EventsCancelled', appName);
}),
pretifyError('i18n:rules.ruleEvents.cancelFailed'));
}

15
frontend/app/shared/state/rule-events.state.spec.ts

@ -111,13 +111,24 @@ describe('RuleEventsState', () => {
});
it('should call service if cancelling event', () => {
rulesService.setup(x => x.cancelEvent(app, oldRuleEvents[0]))
rulesService.setup(x => x.cancelEvents(app, oldRuleEvents[0]))
.returns(() => of({}));
ruleEventsState.cancel(oldRuleEvents[0]).subscribe();
expect().nothing();
rulesService.verify(x => x.cancelEvent(app, oldRuleEvents[0]), Times.once());
rulesService.verify(x => x.cancelEvents(app, oldRuleEvents[0]), Times.once());
});
it('should call service if cancelling all events', () => {
rulesService.setup(x => x.cancelEvents(app, It.isAny()))
.returns(() => of({}));
ruleEventsState.cancelAll().subscribe();
expect().nothing();
rulesService.verify(x => x.cancelEvents(app, It.isAny()), Times.once());
});
});

26
frontend/app/shared/state/rule-events.state.ts

@ -6,7 +6,7 @@
*/
import { Injectable } from '@angular/core';
import { DialogService, getPagingInfo, ListState, shareSubscribed, State } from '@app/framework';
import { DialogService, getPagingInfo, hasAnyLink, ListState, ResourceLinks, shareSubscribed, State } from '@app/framework';
import { EMPTY, Observable } from 'rxjs';
import { finalize, tap } from 'rxjs/operators';
import { RuleEventDto, RulesService } from './../services/rules.service';
@ -18,6 +18,9 @@ interface Snapshot extends ListState {
// The current rule id.
ruleId?: string;
// The resource links.
links: ResourceLinks;
}
@Injectable()
@ -37,12 +40,16 @@ export class RuleEventsState extends State<Snapshot> {
public isLoading =
this.project(x => x.isLoading === true);
public canCancelAll =
this.project(x => hasAnyLink(x.links, 'cancel'));
constructor(
private readonly appsState: AppsState,
private readonly dialogs: DialogService,
private readonly rulesService: RulesService,
) {
super({
links: {},
ruleEvents: [],
page: 0,
pageSize: 30,
@ -67,7 +74,7 @@ export class RuleEventsState extends State<Snapshot> {
pageSize,
pageSize * page,
ruleId).pipe(
tap(({ total, items: ruleEvents }) => {
tap(({ total, items: ruleEvents, _links: links }) => {
if (isReload) {
this.dialogs.notifyInfo('i18n:rules.ruleEvents.reloaded');
}
@ -75,6 +82,7 @@ export class RuleEventsState extends State<Snapshot> {
return this.next({
isLoaded: true,
isLoading: false,
links,
ruleEvents,
total,
}, 'Loading Success');
@ -93,8 +101,20 @@ export class RuleEventsState extends State<Snapshot> {
shareSubscribed(this.dialogs));
}
public cancelAll(): Observable<any> {
return this.rulesService.cancelEvents(this.appsState.appName, { _links: this.snapshot.links }).pipe(
tap(() => {
return this.next(s => {
const ruleEvents = s.ruleEvents.map(x => setCancelled(x));
return { ...s, ruleEvents, isLoaded: true };
}, 'CancelAll');
}),
shareSubscribed(this.dialogs));
}
public cancel(event: RuleEventDto): Observable<any> {
return this.rulesService.cancelEvent(this.appsState.appName, event).pipe(
return this.rulesService.cancelEvents(this.appsState.appName, event).pipe(
tap(() => {
return this.next(s => {
const ruleEvents = s.ruleEvents.replacedBy('id', setCancelled(event));

Loading…
Cancel
Save