mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-17 15:03:07 +00:00
83707: Control collection harvest from the UI
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
<div *ngVar="(contentSource$ |async) as contentSource">
|
||||||
|
<div class="container-fluid" *ngIf="shouldShow">
|
||||||
|
<h4>{{ 'collection.source.controls.head' | translate }}</h4>
|
||||||
|
<div>
|
||||||
|
<span class="font-weight-bold">{{'collection.source.controls.harvest.status' | translate}}</span>
|
||||||
|
<span>{{contentSource?.harvestStatus}}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="font-weight-bold">{{'collection.source.controls.harvest.start' | translate}}</span>
|
||||||
|
<span>{{contentSource?.harvestStartTime ? contentSource?.harvestStartTime : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="font-weight-bold">{{'collection.source.controls.harvest.last' | translate}}</span>
|
||||||
|
<span>{{contentSource?.lastHarvested ? contentSource?.lastHarvested : 'collection.source.controls.harvest.no-information'|translate }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class=" btn btn-secondary"
|
||||||
|
[disabled]="!(isEnabled)"
|
||||||
|
(click)="testConfiguration(contentSource)">
|
||||||
|
<span class="d-none d-sm-inline">{{'collection.source.controls.test.submit' | translate}}</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary"
|
||||||
|
[disabled]="!(isEnabled)"
|
||||||
|
(click)="importNow()">
|
||||||
|
<span class="d-none d-sm-inline">{{'collection.source.controls.import.submit' | translate}}</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary"
|
||||||
|
[disabled]="!(isEnabled)"
|
||||||
|
(click)="resetAndReimport()">
|
||||||
|
<span class="d-none d-sm-inline"> {{'collection.source.controls.reset.submit' | translate}}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
@@ -0,0 +1,150 @@
|
|||||||
|
import { Component, Input, OnDestroy } from '@angular/core';
|
||||||
|
import { ScriptDataService } from '../../../../core/data/processes/script-data.service';
|
||||||
|
import { ContentSource } from '../../../../core/shared/content-source.model';
|
||||||
|
import { ProcessDataService } from '../../../../core/data/processes/process-data.service';
|
||||||
|
import {
|
||||||
|
getAllCompletedRemoteData,
|
||||||
|
getAllSucceededRemoteDataPayload,
|
||||||
|
getFirstCompletedRemoteData,
|
||||||
|
getFirstSucceededRemoteDataPayload
|
||||||
|
} from '../../../../core/shared/operators';
|
||||||
|
import { filter, map, switchMap, tap } from 'rxjs/operators';
|
||||||
|
import { hasValue, hasValueOperator } from '../../../../shared/empty.util';
|
||||||
|
import { ProcessStatus } from '../../../../process-page/processes/process-status.model';
|
||||||
|
import { Subscription } from 'rxjs/internal/Subscription';
|
||||||
|
import { RequestService } from '../../../../core/data/request.service';
|
||||||
|
import { NotificationsService } from '../../../../shared/notifications/notifications.service';
|
||||||
|
import { Collection } from '../../../../core/shared/collection.model';
|
||||||
|
import { CollectionDataService } from '../../../../core/data/collection-data.service';
|
||||||
|
import { Observable } from 'rxjs/internal/Observable';
|
||||||
|
import { Process } from '../../../../process-page/processes/process.model';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { BitstreamDataService } from '../../../../core/data/bitstream-data.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-collection-source-controls',
|
||||||
|
templateUrl: './collection-source-controls.component.html',
|
||||||
|
})
|
||||||
|
export class CollectionSourceControlsComponent implements OnDestroy {
|
||||||
|
|
||||||
|
@Input() isEnabled: boolean;
|
||||||
|
@Input() collection: Collection;
|
||||||
|
@Input() shouldShow: boolean;
|
||||||
|
|
||||||
|
contentSource$: Observable<ContentSource>;
|
||||||
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
|
constructor(private scriptDataService: ScriptDataService,
|
||||||
|
private processDataService: ProcessDataService,
|
||||||
|
private requestService: RequestService,
|
||||||
|
private notificationsService: NotificationsService,
|
||||||
|
private collectionService: CollectionDataService,
|
||||||
|
private translateService: TranslateService,
|
||||||
|
private httpClient: HttpClient,
|
||||||
|
private bitstreamService: BitstreamDataService
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.contentSource$ = this.collectionService.findByHref(this.collection._links.self.href, false).pipe(
|
||||||
|
getAllSucceededRemoteDataPayload(),
|
||||||
|
switchMap((collection) => this.collectionService.getContentSource(collection.uuid, false)),
|
||||||
|
getAllSucceededRemoteDataPayload()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
testConfiguration(contentSource) {
|
||||||
|
this.subs.push(this.scriptDataService.invoke('harvest', [
|
||||||
|
{name: '-g', value: null},
|
||||||
|
{name: '-a', value: contentSource.oaiSource},
|
||||||
|
{name: '-i', value: contentSource.oaiSetId},
|
||||||
|
], []).pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
tap((rd) => {
|
||||||
|
if (rd.hasFailed) {
|
||||||
|
this.notificationsService.error(this.translateService.get('collection.source.controls.test.submit.error'));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
filter((rd) => rd.hasSucceeded && hasValue(rd.payload)),
|
||||||
|
switchMap((rd) => this.processDataService.findById(rd.payload.processId, false)),
|
||||||
|
getAllCompletedRemoteData(),
|
||||||
|
filter((rd) => !rd.isStale && (rd.hasSucceeded || rd.hasFailed)),
|
||||||
|
map((rd) => rd.payload),
|
||||||
|
hasValueOperator(),
|
||||||
|
).subscribe((process: Process) => {
|
||||||
|
if (process.processStatus.toString() !== ProcessStatus[ProcessStatus.COMPLETED].toString() &&
|
||||||
|
process.processStatus.toString() !== ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.requestService.setStaleByHrefSubstring(process._links.self.href);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||||
|
this.notificationsService.error(this.translateService.get('collection.source.controls.test.failed'));
|
||||||
|
}
|
||||||
|
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.COMPLETED].toString()) {
|
||||||
|
this.bitstreamService.findByHref(process._links.output.href, false).pipe(getFirstSucceededRemoteDataPayload()).subscribe((bitstream) => {
|
||||||
|
this.httpClient.get(bitstream._links.content.href, {responseType: 'text'}).subscribe((data: any) => {
|
||||||
|
const output = data.replaceAll(new RegExp('.*\\@(.*)', 'g'), '$1')
|
||||||
|
.replaceAll('The script has started', '')
|
||||||
|
.replaceAll('The script has completed', '');
|
||||||
|
this.notificationsService.success(this.translateService.get('collection.source.controls.test.completed'), output);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
importNow() {
|
||||||
|
this.subs.push(this.scriptDataService.invoke('harvest', [
|
||||||
|
{name: '-r', value: null},
|
||||||
|
{name: '-e', value: 'dspacedemo+admin@gmail.com'},
|
||||||
|
{name: '-c', value: this.collection.uuid},
|
||||||
|
], [])
|
||||||
|
.pipe(
|
||||||
|
getFirstCompletedRemoteData(),
|
||||||
|
tap((rd) => {
|
||||||
|
if (rd.hasFailed) {
|
||||||
|
this.notificationsService.error(this.translateService.get('collection.source.controls.test.submit.error'));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
filter((rd) => rd.hasSucceeded && hasValue(rd.payload)),
|
||||||
|
switchMap((rd) => this.processDataService.findById(rd.payload.processId, false)),
|
||||||
|
getAllCompletedRemoteData(),
|
||||||
|
filter((rd) => !rd.isStale && (rd.hasSucceeded || rd.hasFailed)),
|
||||||
|
map((rd) => rd.payload),
|
||||||
|
hasValueOperator(),
|
||||||
|
).subscribe((process) => {
|
||||||
|
if (process.processStatus.toString() !== ProcessStatus[ProcessStatus.COMPLETED].toString() &&
|
||||||
|
process.processStatus.toString() !== ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.requestService.setStaleByHrefSubstring(process._links.self.href);
|
||||||
|
this.requestService.setStaleByHrefSubstring(this.collection._links.self.href);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.FAILED].toString()) {
|
||||||
|
this.notificationsService.error(this.translateService.get('collection.source.controls.import.failed'));
|
||||||
|
}
|
||||||
|
if (process.processStatus.toString() === ProcessStatus[ProcessStatus.COMPLETED].toString()) {
|
||||||
|
this.notificationsService.success(this.translateService.get('collection.source.controls.import.completed'));
|
||||||
|
setTimeout(() => {
|
||||||
|
this.requestService.setStaleByHrefSubstring(this.collection._links.self.href);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
resetAndReimport() {
|
||||||
|
// TODO implement when a single option is present
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs.forEach((sub) => {
|
||||||
|
if (hasValue(sub)) {
|
||||||
|
sub.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@@ -1,57 +1,74 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="d-inline-block float-right">
|
<div class="d-inline-block float-right">
|
||||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||||
[disabled]="!(hasChanges() | async)"
|
[disabled]="!(hasChanges() | async)"
|
||||||
(click)="discard()"><i
|
(click)="discard()"><i
|
||||||
class="fas fa-times"></i>
|
class="fas fa-times"></i>
|
||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
||||||
(click)="reinstate()"><i
|
(click)="reinstate()"><i
|
||||||
class="fas fa-undo-alt"></i>
|
class="fas fa-undo-alt"></i>
|
||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || !isValid() || (initialHarvestType === harvestTypeNone && contentSource.harvestType === initialHarvestType)"
|
<button class="btn btn-primary"
|
||||||
(click)="onSubmit()"><i
|
[disabled]="!(hasChanges() | async) || !isValid() || (initialHarvestType === harvestTypeNone && contentSource.harvestType === initialHarvestType)"
|
||||||
class="fas fa-save"></i>
|
(click)="onSubmit()"><i
|
||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
class="fas fa-save"></i>
|
||||||
</button>
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||||
</div>
|
</button>
|
||||||
<h4>{{ 'collection.edit.tabs.source.head' | translate }}</h4>
|
</div>
|
||||||
<div *ngIf="contentSource" class="form-check mb-4">
|
<h4>{{ 'collection.edit.tabs.source.head' | translate }}</h4>
|
||||||
<input type="checkbox" class="form-check-input" id="externalSourceCheck" [checked]="(contentSource?.harvestType !== harvestTypeNone)" (change)="changeExternalSource()">
|
<div *ngIf="contentSource" class="form-check mb-4">
|
||||||
<label class="form-check-label" for="externalSourceCheck">{{ 'collection.edit.tabs.source.external' | translate }}</label>
|
<input type="checkbox" class="form-check-input" id="externalSourceCheck"
|
||||||
</div>
|
[checked]="(contentSource?.harvestType !== harvestTypeNone)" (change)="changeExternalSource()">
|
||||||
<ds-loading *ngIf="!contentSource" [message]="'loading.content-source' | translate"></ds-loading>
|
<label class="form-check-label"
|
||||||
<h4 *ngIf="contentSource && (contentSource?.harvestType !== harvestTypeNone)">{{ 'collection.edit.tabs.source.form.head' | translate }}</h4>
|
for="externalSourceCheck">{{ 'collection.edit.tabs.source.external' | translate }}</label>
|
||||||
|
</div>
|
||||||
|
<ds-loading *ngIf="!contentSource" [message]="'loading.content-source' | translate"></ds-loading>
|
||||||
|
<h4 *ngIf="contentSource && (contentSource?.harvestType !== harvestTypeNone)">{{ 'collection.edit.tabs.source.form.head' | translate }}</h4>
|
||||||
</div>
|
</div>
|
||||||
<ds-form *ngIf="formGroup && contentSource && (contentSource?.harvestType !== harvestTypeNone)"
|
<div class="row">
|
||||||
[formId]="'collection-source-form-id'"
|
<ds-form *ngIf="formGroup && contentSource && (contentSource?.harvestType !== harvestTypeNone)"
|
||||||
[formGroup]="formGroup"
|
[formId]="'collection-source-form-id'"
|
||||||
[formModel]="formModel"
|
[formGroup]="formGroup"
|
||||||
[formLayout]="formLayout"
|
[formModel]="formModel"
|
||||||
[displaySubmit]="false"
|
[formLayout]="formLayout"
|
||||||
[displayCancel]="false"
|
[displaySubmit]="false"
|
||||||
(dfChange)="onChange($event)"
|
[displayCancel]="false"
|
||||||
(submitForm)="onSubmit()"
|
(dfChange)="onChange($event)"
|
||||||
(cancel)="onCancel()"></ds-form>
|
(submitForm)="onSubmit()"
|
||||||
<div class="container-fluid" *ngIf="(contentSource?.harvestType !== harvestTypeNone)">
|
(cancel)="onCancel()"></ds-form>
|
||||||
<div class="d-inline-block float-right">
|
|
||||||
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
|
||||||
[disabled]="!(hasChanges() | async)"
|
|
||||||
(click)="discard()"><i
|
|
||||||
class="fas fa-times"></i>
|
|
||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
|
||||||
(click)="reinstate()"><i
|
|
||||||
class="fas fa-undo-alt"></i>
|
|
||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-primary" [disabled]="!(hasChanges() | async) || !isValid() || (initialHarvestType === harvestTypeNone && contentSource.harvestType === initialHarvestType)"
|
|
||||||
(click)="onSubmit()"><i
|
|
||||||
class="fas fa-save"></i>
|
|
||||||
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="container mt-2" *ngIf="(contentSource?.harvestType !== harvestTypeNone)">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="d-inline-block float-right ml-1">
|
||||||
|
<button class=" btn btn-danger" *ngIf="!(isReinstatable() | async)"
|
||||||
|
[disabled]="!(hasChanges() | async)"
|
||||||
|
(click)="discard()"><i
|
||||||
|
class="fas fa-times"></i>
|
||||||
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.discard-button" | translate}}</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-warning" *ngIf="isReinstatable() | async"
|
||||||
|
(click)="reinstate()"><i
|
||||||
|
class="fas fa-undo-alt"></i>
|
||||||
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.reinstate-button" | translate}}</span>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary"
|
||||||
|
[disabled]="!(hasChanges() | async) || !isValid() || (initialHarvestType === harvestTypeNone && contentSource.harvestType === initialHarvestType)"
|
||||||
|
(click)="onSubmit()"><i
|
||||||
|
class="fas fa-save"></i>
|
||||||
|
<span class="d-none d-sm-inline"> {{"item.edit.metadata.save-button" | translate}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ds-collection-source-controls
|
||||||
|
[isEnabled]="!(hasChanges()|async)"
|
||||||
|
[shouldShow]="contentSource?.harvestType !== harvestTypeNone"
|
||||||
|
[collection]="(collectionRD$ |async)?.payload"
|
||||||
|
>
|
||||||
|
</ds-collection-source-controls>
|
||||||
|
|
||||||
|
@@ -380,7 +380,7 @@ export class CollectionSourceComponent extends AbstractTrackableComponent implem
|
|||||||
switchMap((uuid) => this.collectionService.getHarvesterEndpoint(uuid)),
|
switchMap((uuid) => this.collectionService.getHarvesterEndpoint(uuid)),
|
||||||
take(1)
|
take(1)
|
||||||
).subscribe((endpoint) => this.requestService.removeByHrefSubstring(endpoint));
|
).subscribe((endpoint) => this.requestService.removeByHrefSubstring(endpoint));
|
||||||
|
this.requestService.setStaleByHrefSubstring(this.contentSource._links.self.href);
|
||||||
// Update harvester
|
// Update harvester
|
||||||
this.collectionRD$.pipe(
|
this.collectionRD$.pipe(
|
||||||
getFirstSucceededRemoteData(),
|
getFirstSucceededRemoteData(),
|
||||||
|
@@ -9,6 +9,7 @@ import { CollectionCurateComponent } from './collection-curate/collection-curate
|
|||||||
import { CollectionSourceComponent } from './collection-source/collection-source.component';
|
import { CollectionSourceComponent } from './collection-source/collection-source.component';
|
||||||
import { CollectionAuthorizationsComponent } from './collection-authorizations/collection-authorizations.component';
|
import { CollectionAuthorizationsComponent } from './collection-authorizations/collection-authorizations.component';
|
||||||
import { CollectionFormModule } from '../collection-form/collection-form.module';
|
import { CollectionFormModule } from '../collection-form/collection-form.module';
|
||||||
|
import { CollectionSourceControlsComponent } from './collection-source/collection-source-controls/collection-source-controls.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module that contains all components related to the Edit Collection page administrator functionality
|
* Module that contains all components related to the Edit Collection page administrator functionality
|
||||||
@@ -26,6 +27,8 @@ import { CollectionFormModule } from '../collection-form/collection-form.module'
|
|||||||
CollectionRolesComponent,
|
CollectionRolesComponent,
|
||||||
CollectionCurateComponent,
|
CollectionCurateComponent,
|
||||||
CollectionSourceComponent,
|
CollectionSourceComponent,
|
||||||
|
|
||||||
|
CollectionSourceControlsComponent,
|
||||||
CollectionAuthorizationsComponent
|
CollectionAuthorizationsComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -138,7 +138,7 @@ export class CollectionDataService extends ComColDataService<Collection> {
|
|||||||
* Get the collection's content harvester
|
* Get the collection's content harvester
|
||||||
* @param collectionId
|
* @param collectionId
|
||||||
*/
|
*/
|
||||||
getContentSource(collectionId: string): Observable<RemoteData<ContentSource>> {
|
getContentSource(collectionId: string, useCachedVersionIfAvailable = true): Observable<RemoteData<ContentSource>> {
|
||||||
const href$ = this.getHarvesterEndpoint(collectionId).pipe(
|
const href$ = this.getHarvesterEndpoint(collectionId).pipe(
|
||||||
isNotEmptyOperator(),
|
isNotEmptyOperator(),
|
||||||
take(1)
|
take(1)
|
||||||
@@ -146,7 +146,7 @@ export class CollectionDataService extends ComColDataService<Collection> {
|
|||||||
|
|
||||||
href$.subscribe((href: string) => {
|
href$.subscribe((href: string) => {
|
||||||
const request = new ContentSourceRequest(this.requestService.generateRequestId(), href);
|
const request = new ContentSourceRequest(this.requestService.generateRequestId(), href);
|
||||||
this.requestService.send(request, true);
|
this.requestService.send(request, useCachedVersionIfAvailable);
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.rdbService.buildSingle<ContentSource>(href$);
|
return this.rdbService.buildSingle<ContentSource>(href$);
|
||||||
|
@@ -70,6 +70,15 @@ export class ContentSource extends CacheableObject {
|
|||||||
*/
|
*/
|
||||||
metadataConfigs: MetadataConfig[];
|
metadataConfigs: MetadataConfig[];
|
||||||
|
|
||||||
|
@autoserializeAs('harvest_status')
|
||||||
|
harvestStatus: string;
|
||||||
|
|
||||||
|
@autoserializeAs('harvest_start_time')
|
||||||
|
harvestStartTime: string;
|
||||||
|
|
||||||
|
@autoserializeAs('last_harvested')
|
||||||
|
lastHarvested: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HALLink}s for this ContentSource
|
* The {@link HALLink}s for this ContentSource
|
||||||
*/
|
*/
|
||||||
|
@@ -881,6 +881,22 @@
|
|||||||
"collection.select.table.title": "Title",
|
"collection.select.table.title": "Title",
|
||||||
|
|
||||||
|
|
||||||
|
"collection.source.controls.head": "Harvest Controls",
|
||||||
|
"collection.source.controls.test.submit.error": "Something went wrong with initiating the testing of the settings",
|
||||||
|
"collection.source.controls.test.failed": "The script to test the settings has failed",
|
||||||
|
"collection.source.controls.test.completed": "The script to test the settings has successfully finished",
|
||||||
|
"collection.source.controls.test.submit": "Test configuration",
|
||||||
|
"collection.source.controls.import.submit.success": "The import has been successfully initiated",
|
||||||
|
"collection.source.controls.import.submit.error": "Something went wrong with initiating the import",
|
||||||
|
"collection.source.controls.import.submit": "Import now",
|
||||||
|
"collection.source.controls.import.failed": "An error occurred during the import",
|
||||||
|
"collection.source.controls.import.completed": "The import completed",
|
||||||
|
"collection.source.controls.reset.submit": "Reset and reimport",
|
||||||
|
"collection.source.controls.harvest.status": "Harvest status:",
|
||||||
|
"collection.source.controls.harvest.start": "Harvest start time:",
|
||||||
|
"collection.source.controls.harvest.last": "Last time harvested:",
|
||||||
|
"collection.source.controls.harvest.no-information": "N/A",
|
||||||
|
|
||||||
|
|
||||||
"collection.source.update.notifications.error.content": "The provided settings have been tested and didn't work.",
|
"collection.source.update.notifications.error.content": "The provided settings have been tested and didn't work.",
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user