Skip to content

Commit

Permalink
Adding new async publish feature for single and bulk. (#700)
Browse files Browse the repository at this point in the history
* Adding new async publish feature for single and bulk.

* Fixing type errors.
Disabling buttons during active requests

* Adding get single resource

* Adding ability to publish without Draft. Added draft/live support. Now calling resource instead of allResources when fetching publish status

* Adding more test coverage and ensuring the code is simplified.
Fixed publishing error issue on the initial Post request to publish the language.

* Adding an error label to show if the language had a publishing error.
  • Loading branch information
dr-bizz authored Mar 27, 2024
1 parent 45becd0 commit 2a80955
Show file tree
Hide file tree
Showing 14 changed files with 818 additions and 114 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.toggle-drafts {
width: 100%;
display: flex;
margin-bottom: 15px;
}

.toggle-drafts label.btn {
flex: 0 1 50%;
}

.translation-btn {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 350px;
margin: 0 auto 8px;
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,92 @@
<div class="modal-body">
<h5>Languages without a Draft</h5>
<div class="btn-group btn-group-toggle toggle-drafts" data-toggle="buttons">
<label
class="btn btn-success {{
actionType === 'publish' ? 'btn-success' : 'btn-outline-success'
}}"
(click)="switchActionType('publish')"
>
Publish Languages
</label>
<label
class="btn {{
actionType === 'createDrafts'
? 'btn-secondary'
: 'btn-outline-secondary'
}}"
(click)="switchActionType('createDrafts')"
>
Generate Drafts
</label>
</div>

<div *ngFor="let translation of resource['latest-drafts-translations']">
<label
class="btn-secondary btn-block"
class="btn-outline-secondary btn-block translation-btn"
ngbButtonLabel
*ngIf="translation.is_published"
*ngIf="
actionType === 'publish' ||
(actionType === 'createDrafts' && translation['is-published'])
"
>
<input
type="checkbox"
ngbButton
[(ngModel)]="translation.generateDraft"
/>
{{ translation.language.name }}
<div class="translation-btn-text">
<input
type="checkbox"
ngbButton
[(ngModel)]="translation.selectedForAction"
/>
{{ translation.language.name }}
</div>
<admin-translation-version-badge [translation]="translation">
</admin-translation-version-badge>
</label>
</div>
<br />
<ngb-alert type="info" [dismissible]="false" *ngIf="saving">
Saving...

<ngb-alert
type="success"
[dismissible]="true"
*ngFor="let successMessage of sucessfulMessages"
>
{{ successMessage }}
</ngb-alert>
<ngb-alert type="danger" [dismissible]="false" *ngIf="errorMessage">
{{ errorMessage }}
<ngb-alert type="info" [dismissible]="false" *ngIf="alertMessage">
{{ alertMessage }}
</ngb-alert>
<button class="btn btn-danger" (click)="cancel()">Cancel</button>
<button class="btn btn-success" (click)="showConfirmAlert()">
Generate drafts
</button>
<ngb-alert type="danger" [dismissible]="false" *ngIf="confirmMessage">
{{ confirmMessage }}
<button (click)="generateDrafts()" class="btn btn-dark">Confirm</button>
<button (click)="confirmMessage = null" class="btn btn-secondary">
<ngb-alert
type="danger"
[dismissible]="false"
*ngFor="let error of errorMessage"
>
{{ error }}
</ngb-alert>

<ngb-alert type="info" [dismissible]="false" *ngIf="confirmMessage">
<p>{{ confirmMessage }}</p>
<div class="btn-toolbar justify-content-between">
<button (click)="confirmMessage = null" class="btn btn-danger">
Cancel
</button>
<button (click)="publishOrCreateDrafts()" class="btn btn-success">
Confirm
</button>
</div>
</ngb-alert>

<div class="modal-footer justify-content-between">
<button
class="btn btn-secondary"
(click)="cancel()"
[disabled]="disableButtons"
>
Cancel
</button>
</ngb-alert>
<button
class="btn btn-success"
(click)="showConfirmAlert()"
[disabled]="disableButtons"
>
{{ actionType === 'publish' ? 'Publish' : 'Generate drafts' }}
</button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {
ComponentFixture,
TestBed,
discardPeriodicTasks,
fakeAsync,
tick,
} from '@angular/core/testing';
import {
NgbActiveModal,
NgbAlert,
Expand All @@ -7,20 +13,26 @@ import {
import { MultipleDraftGeneratorComponent } from './multiple-draft-generator.component';
import { FormsModule } from '@angular/forms';
import { DraftService } from '../../service/draft.service';
import { LanguageService } from '../../service/language.service';
import { ResourceService } from '../../service/resource/resource.service';
import { Resource } from '../../models/resource';
import { Translation } from '../../models/translation';
import { By } from '@angular/platform-browser';
import { NgbButtonLabel } from '@ng-bootstrap/ng-bootstrap';
import { Language } from '../../models/language';
import { DebugElement } from '@angular/core';
import { TranslationVersionBadgeComponent } from '../translation/translation-version-badge/translation-version-badge.component';
import { MessageType } from '../../models/message';

describe('MultipleDraftGeneratorComponent', () => {
let comp: MultipleDraftGeneratorComponent;
let fixture: ComponentFixture<MultipleDraftGeneratorComponent>;
let customResourceServiceStub;
let customDraftServiceStub;

const buildTranslation = (
isPublished: boolean,
generateDraft: boolean,
selectedForAction: boolean,
language: string,
) => {
const l = new Language();
Expand All @@ -29,15 +41,57 @@ describe('MultipleDraftGeneratorComponent', () => {
const t = new Translation();
t.language = l;
t.is_published = isPublished;
t.generateDraft = generateDraft;
t['is-published'] = isPublished;
t.selectedForAction = selectedForAction;
return t;
};

beforeEach(() => {
customResourceServiceStub = {
getResource() {},
};
customDraftServiceStub = {
createDraft() {},
publishDraft() {},
};

spyOn(customResourceServiceStub, 'getResource').and.returnValue(
Promise.resolve({
'latest-drafts-translations': [
{
language: { id: 1 },
'publishing-errors': null,
'is-published': false,
},
],
}),
);
spyOn(customDraftServiceStub, 'createDraft').and.returnValue(
Promise.resolve(),
);
spyOn(customDraftServiceStub, 'publishDraft').and.returnValue(
Promise.resolve([
{
'publishing-errors': null,
'is-published': false,
},
]),
);

customResourceServiceStub.getResource();

TestBed.configureTestingModule({
declarations: [MultipleDraftGeneratorComponent],
declarations: [
MultipleDraftGeneratorComponent,
TranslationVersionBadgeComponent,
],
imports: [NgbModule.forRoot(), FormsModule],
providers: [{ provide: DraftService }, { provide: NgbActiveModal }],
providers: [
{ provide: DraftService, useValue: customDraftServiceStub },
{ provide: NgbActiveModal },
{ provide: ResourceService, useValue: customResourceServiceStub },
{ provide: LanguageService },
],
}).compileComponents();

fixture = TestBed.createComponent(MultipleDraftGeneratorComponent);
Expand All @@ -53,25 +107,97 @@ describe('MultipleDraftGeneratorComponent', () => {
const r = new Resource();
r['latest-drafts-translations'] = translations;
comp.resource = r;
comp.actionType = 'publish';

fixture.detectChanges();
});

it('only shows languages without drafts', () => {
it('shows languages with and without drafts', () => {
expect(
fixture.debugElement.queryAll(By.directive(NgbButtonLabel)).length,
).toBe(3);
).toBe(4);
});

it('confirm message lists all languages', () => {
it('shows confirm message to publish selected languages', () => {
comp.showConfirmAlert();
fixture.detectChanges();

const alert: DebugElement = fixture.debugElement.query(
By.directive(NgbAlert),
);
expect(alert.nativeElement.textContent).toContain(
`${comp.baseConfirmMessage} Chinese, French?`,
`Are you sure you want to publish these languages: Chinese, French?`,
);
});

it('shows confirm message to create a draft for selected languages', () => {
comp.actionType = 'createDrafts';
comp.showConfirmAlert();
fixture.detectChanges();

const alert: DebugElement = fixture.debugElement.query(
By.directive(NgbAlert),
);
expect(alert.nativeElement.textContent).toContain(
`Are you sure you want to generate a draft for these languages: Chinese, French?`,
);
});

describe('publishOrCreateDrafts() Publish', () => {
it('should send publish 2 languages, and call isPublished() every 5 seconds ', fakeAsync(() => {
comp.showConfirmAlert();
fixture.detectChanges();
spyOn(comp, 'renderMessage');
spyOn(comp, 'isPublished');
comp.publishOrCreateDrafts();
expect(comp.renderMessage).toHaveBeenCalledWith(
MessageType.success,
'Publishing translations...',
);

tick(5500);
fixture.detectChanges();
discardPeriodicTasks();

fixture.whenStable().then(() => {
expect(customDraftServiceStub.publishDraft).toHaveBeenCalledTimes(2);
expect(comp.errorMessage).toEqual([]);
expect(comp.isPublished).toHaveBeenCalledTimes(1);

tick(5500);
fixture.detectChanges();
discardPeriodicTasks();

expect(comp.isPublished).toHaveBeenCalledTimes(2);
});
}));

it('should return publishing errors and warn the user.', fakeAsync(() => {
customDraftServiceStub.publishDraft.and.returnValue(
Promise.resolve([
{
'publishing-errors': 'Error publishing...',
'is-published': false,
},
]),
);
spyOn(comp, 'renderMessage');
spyOn(comp, 'isPublished');

comp.showConfirmAlert();
fixture.detectChanges();
comp.publishOrCreateDrafts();

tick(5500);
fixture.detectChanges();
discardPeriodicTasks();

fixture.whenStable().then(() => {
expect(comp.errorMessage).toEqual([
'Error publishing...',
'Error publishing...',
]);
});
}));
});
});
Loading

0 comments on commit 2a80955

Please sign in to comment.