MOBILE-2354 workshop: Sync provider
parent
d000b3da36
commit
3652d0591d
|
@ -0,0 +1,565 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { AddonModWorkshopProvider } from './workshop';
|
||||
import { AddonModWorkshopHelperProvider } from './helper';
|
||||
import { AddonModWorkshopOfflineProvider } from './offline';
|
||||
|
||||
/**
|
||||
* Service to sync workshops.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonModWorkshopSyncProvider extends CoreSyncBaseProvider {
|
||||
|
||||
static AUTO_SYNCED = 'addon_mod_workshop_autom_synced';
|
||||
static MANUAL_SYNCED = 'addon_mod_workshop_manual_synced';
|
||||
static SYNC_TIME = 300000;
|
||||
|
||||
protected componentTranslate: string;
|
||||
|
||||
constructor(translate: TranslateService,
|
||||
appProvider: CoreAppProvider,
|
||||
courseProvider: CoreCourseProvider,
|
||||
private eventsProvider: CoreEventsProvider,
|
||||
loggerProvider: CoreLoggerProvider,
|
||||
sitesProvider: CoreSitesProvider,
|
||||
syncProvider: CoreSyncProvider,
|
||||
textUtils: CoreTextUtilsProvider,
|
||||
private utils: CoreUtilsProvider,
|
||||
private workshopProvider: AddonModWorkshopProvider,
|
||||
private workshopHelper: AddonModWorkshopHelperProvider,
|
||||
private workshopOffline: AddonModWorkshopOfflineProvider) {
|
||||
|
||||
super('AddonModWorkshopSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate);
|
||||
|
||||
this.componentTranslate = courseProvider.translateModuleName('workshop');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an workshop has data to synchronize.
|
||||
*
|
||||
* @param {number} workshopId Workshop ID.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved with boolean: true if has data to sync, false otherwise.
|
||||
*/
|
||||
hasDataToSync(workshopId: number, siteId?: string): Promise<any> {
|
||||
return this.workshopOffline.hasWorkshopOfflineData(workshopId, siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to synchronize all workshops that need it and haven't been synchronized in a while.
|
||||
*
|
||||
* @param {string} [siteId] Site ID to sync. If not defined, sync all sites.
|
||||
* @return {Promise<any>} Promise resolved when the sync is done.
|
||||
*/
|
||||
syncAllWorkshops(siteId?: string): Promise<any> {
|
||||
return this.syncOnSites('all workshops', this.syncAllWorkshopsFunc.bind(this), [], siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync all workshops on a site.
|
||||
*
|
||||
* @param {string} [siteId] Site ID to sync. If not defined, sync all sites.
|
||||
* @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails.
|
||||
*/
|
||||
protected syncAllWorkshopsFunc(siteId?: string): Promise<any> {
|
||||
return this.workshopOffline.getAllWorkshops(siteId).then((workshopIds) => {
|
||||
const promises = [];
|
||||
|
||||
// Sync all workshops that haven't been synced for a while.
|
||||
workshopIds.forEach((workshopId) => {
|
||||
promises.push(this.syncWorkshopIfNeeded(workshopId, siteId).then((data) => {
|
||||
if (data && data.updated) {
|
||||
// Sync done. Send event.
|
||||
this.eventsProvider.trigger(AddonModWorkshopSyncProvider.AUTO_SYNCED, {
|
||||
workshopId: workshopId,
|
||||
warnings: data.warnings
|
||||
}, siteId);
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync a workshop only if a certain time has passed since the last time.
|
||||
*
|
||||
* @param {number} workshopId Workshop ID.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved when the workshop is synced or if it doesn't need to be synced.
|
||||
*/
|
||||
syncWorkshopIfNeeded(workshopId: number, siteId?: string): Promise<any> {
|
||||
return this.isSyncNeeded(workshopId, siteId).then((needed) => {
|
||||
if (needed) {
|
||||
return this.syncWorkshop(workshopId, siteId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to synchronize a workshop.
|
||||
*
|
||||
* @param {number} workshopId Workshop ID.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
|
||||
*/
|
||||
syncWorkshop(workshopId: number, siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
if (this.isSyncing(workshopId, siteId)) {
|
||||
// There's already a sync ongoing for this discussion, return the promise.
|
||||
return this.getOngoingSync(workshopId, siteId);
|
||||
}
|
||||
|
||||
// Verify that workshop isn't blocked.
|
||||
if (this.syncProvider.isBlocked(AddonModWorkshopProvider.COMPONENT, workshopId, siteId)) {
|
||||
this.logger.debug('Cannot sync workshop ' + workshopId + ' because it is blocked.');
|
||||
|
||||
return Promise.reject(this.translate.instant('core.errorsyncblocked', {$a: this.componentTranslate}));
|
||||
}
|
||||
|
||||
this.logger.debug('Try to sync workshop ' + workshopId);
|
||||
|
||||
const syncPromises = [];
|
||||
|
||||
// Get offline submissions to be sent.
|
||||
syncPromises.push(this.workshopOffline.getSubmissions(workshopId, siteId).catch(() => {
|
||||
// No offline data found, return empty array.
|
||||
return [];
|
||||
}));
|
||||
|
||||
// Get offline submission assessments to be sent.
|
||||
syncPromises.push(this.workshopOffline.getAssessments(workshopId, siteId).catch(() => {
|
||||
// No offline data found, return empty array.
|
||||
return [];
|
||||
}));
|
||||
|
||||
// Get offline submission evaluations to be sent.
|
||||
syncPromises.push(this.workshopOffline.getEvaluateSubmissions(workshopId, siteId).catch(() => {
|
||||
// No offline data found, return empty array.
|
||||
return [];
|
||||
}));
|
||||
|
||||
// Get offline assessment evaluations to be sent.
|
||||
syncPromises.push(this.workshopOffline.getEvaluateAssessments(workshopId, siteId).catch(() => {
|
||||
// No offline data found, return empty array.
|
||||
return [];
|
||||
}));
|
||||
|
||||
const result = {
|
||||
warnings: [],
|
||||
updated: false
|
||||
};
|
||||
|
||||
// Get offline submissions to be sent.
|
||||
const syncPromise = Promise.all(syncPromises).then((syncs) => {
|
||||
let courseId;
|
||||
|
||||
// Get courseId from the first object
|
||||
for (const x in syncs) {
|
||||
if (syncs[x].length > 0 && syncs[x][0].courseid) {
|
||||
courseId = syncs[x][0].courseid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!courseId) {
|
||||
// Nothing to sync.
|
||||
return;
|
||||
} else if (!this.appProvider.isOnline()) {
|
||||
// Cannot sync in offline.
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
return this.workshopProvider.getWorkshopById(courseId, workshopId, siteId).then((workshop) => {
|
||||
const submissionsActions = syncs[0],
|
||||
assessments = syncs[1],
|
||||
submissionEvaluations = syncs[2],
|
||||
assessmentEvaluations = syncs[3],
|
||||
promises = [],
|
||||
offlineSubmissions = {};
|
||||
|
||||
submissionsActions.forEach((action) => {
|
||||
if (typeof offlineSubmissions[action.submissionid] == 'undefined') {
|
||||
offlineSubmissions[action.submissionid] = [];
|
||||
}
|
||||
offlineSubmissions[action.submissionid].push(action);
|
||||
});
|
||||
|
||||
Object.keys(offlineSubmissions).forEach((submissionId) => {
|
||||
const submissionActions = offlineSubmissions[submissionId];
|
||||
promises.push(this.syncSubmission(workshop, submissionActions, result, siteId).then(() => {
|
||||
result.updated = true;
|
||||
}));
|
||||
});
|
||||
|
||||
assessments.forEach((assessment) => {
|
||||
promises.push(this.syncAssessment(workshop, assessment, result, siteId).then(() => {
|
||||
result.updated = true;
|
||||
}));
|
||||
});
|
||||
|
||||
submissionEvaluations.forEach((evaluation) => {
|
||||
promises.push(this.syncEvaluateSubmission(workshop, evaluation, result, siteId).then(() => {
|
||||
result.updated = true;
|
||||
}));
|
||||
});
|
||||
|
||||
assessmentEvaluations.forEach((evaluation) => {
|
||||
promises.push(this.syncEvaluateAssessment(workshop, evaluation, result, siteId).then(() => {
|
||||
result.updated = true;
|
||||
}));
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
}).then(() => {
|
||||
if (result.updated) {
|
||||
// Data has been sent to server. Now invalidate the WS calls.
|
||||
return this.workshopProvider.invalidateContentById(workshopId, courseId, siteId).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
});
|
||||
}).then(() => {
|
||||
// Sync finished, set sync time.
|
||||
return this.setSyncTime(workshopId, siteId).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}).then(() => {
|
||||
// All done, return the warnings.
|
||||
return result;
|
||||
});
|
||||
|
||||
return this.addOngoingSync(workshopId, syncPromise, siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize a submission.
|
||||
*
|
||||
* @param {any} workshop Workshop.
|
||||
* @param {any[]} submissionActions Submission actions offline data.
|
||||
* @param {any} result Object with the result of the sync.
|
||||
* @param {string} siteId Site ID.
|
||||
* @return {Promise<any>} Promise resolved if success, rejected otherwise.
|
||||
*/
|
||||
protected syncSubmission(workshop: any, submissionActions: any, result: any, siteId: string): Promise<any> {
|
||||
let discardError;
|
||||
let editing = false;
|
||||
|
||||
// Sort entries by timemodified.
|
||||
submissionActions = submissionActions.sort((a, b) => {
|
||||
return a.timemodified - b.timemodified;
|
||||
});
|
||||
|
||||
let timePromise = null;
|
||||
let submissionId = submissionActions[0].submissionid;
|
||||
|
||||
if (submissionId > 0) {
|
||||
editing = true;
|
||||
timePromise = this.workshopProvider.getSubmission(workshop.id, submissionId, siteId).then((submission) => {
|
||||
return submission.timemodified;
|
||||
}).catch(() => {
|
||||
return -1;
|
||||
});
|
||||
} else {
|
||||
timePromise = Promise.resolve(0);
|
||||
}
|
||||
|
||||
return timePromise.then((timemodified) => {
|
||||
if (timemodified < 0 || timemodified >= submissionActions[0].timemodified) {
|
||||
// The entry was not found in Moodle or the entry has been modified, discard the action.
|
||||
result.updated = true;
|
||||
discardError = this.translate.instant('addon.mod_workshop.warningsubmissionmodified');
|
||||
|
||||
return this.workshopOffline.deleteAllSubmissionActions(workshop.id, submissionId, siteId);
|
||||
}
|
||||
|
||||
let promise = Promise.resolve();
|
||||
|
||||
submissionActions.forEach((action) => {
|
||||
promise = promise.then(() => {
|
||||
submissionId = action.submissionid > 0 ? action.submissionid : submissionId;
|
||||
|
||||
let fileProm;
|
||||
// Upload attachments first if any.
|
||||
if (action.attachmentsid) {
|
||||
fileProm = this.workshopHelper.getSubmissionFilesFromOfflineFilesObject(action.attachmentsid, workshop.id,
|
||||
submissionId, editing, siteId).then((files) => {
|
||||
return this.workshopHelper.uploadOrStoreSubmissionFiles(workshop.id, submissionId, files, editing,
|
||||
false, siteId);
|
||||
});
|
||||
} else {
|
||||
// Remove all files.
|
||||
fileProm = this.workshopHelper.uploadOrStoreSubmissionFiles(workshop.id, submissionId, [], editing, false,
|
||||
siteId);
|
||||
}
|
||||
|
||||
return fileProm.then((attachmentsId) => {
|
||||
// Perform the action.
|
||||
switch (action.action) {
|
||||
case 'add':
|
||||
return this.workshopProvider.addSubmissionOnline(workshop.id, action.title, action.content,
|
||||
attachmentsId, siteId).then((newSubmissionId) => {
|
||||
submissionId = newSubmissionId;
|
||||
});
|
||||
case 'update':
|
||||
return this.workshopProvider.updateSubmissionOnline(submissionId, action.title, action.content,
|
||||
attachmentsId, siteId);
|
||||
case 'delete':
|
||||
return this.workshopProvider.deleteSubmissionOnline(submissionId, siteId);
|
||||
default:
|
||||
return Promise.resolve();
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (error && this.utils.isWebServiceError(error)) {
|
||||
// The WebService has thrown an error, this means it cannot be performed. Discard.
|
||||
discardError = error.message || error.error;
|
||||
} else {
|
||||
// Couldn't connect to server, reject.
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}).then(() => {
|
||||
// Delete the offline data.
|
||||
result.updated = true;
|
||||
|
||||
return this.workshopOffline.deleteSubmissionAction(action.workshopid, action.submissionid, action.action,
|
||||
siteId);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return promise.then(() => {
|
||||
if (discardError) {
|
||||
// Submission was discarded, add a warning.
|
||||
const message = this.translate.instant('core.warningofflinedatadeleted', {
|
||||
component: this.componentTranslate,
|
||||
name: workshop.name,
|
||||
error: discardError
|
||||
});
|
||||
|
||||
if (result.warnings.indexOf(message) == -1) {
|
||||
result.warnings.push(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize an assessment.
|
||||
*
|
||||
* @param {any} workshop Workshop.
|
||||
* @param {any} assessment Assessment offline data.
|
||||
* @param {any} result Object with the result of the sync.
|
||||
* @param {string} siteId Site ID.
|
||||
* @return {Promise<any>} Promise resolved if success, rejected otherwise.
|
||||
*/
|
||||
protected syncAssessment(workshop: any, assessmentData: any, result: any, siteId: string): Promise<any> {
|
||||
let discardError;
|
||||
const assessmentId = assessmentData.assessmentid;
|
||||
|
||||
const timePromise = this.workshopProvider.getAssessment(workshop.id, assessmentId, siteId).then((assessment) => {
|
||||
return assessment.timemodified;
|
||||
}).catch(() => {
|
||||
return -1;
|
||||
});
|
||||
|
||||
return timePromise.then((timemodified) => {
|
||||
if (timemodified < 0 || timemodified >= assessmentData.timemodified) {
|
||||
// The entry was not found in Moodle or the entry has been modified, discard the action.
|
||||
result.updated = true;
|
||||
discardError = this.translate.instant('addon.mod_workshop.warningassessmentmodified');
|
||||
|
||||
return this.workshopOffline.deleteAssessment(workshop.id, assessmentId, siteId);
|
||||
}
|
||||
|
||||
let fileProm;
|
||||
const inputData = assessmentData.inputdata;
|
||||
|
||||
// Upload attachments first if any.
|
||||
if (inputData.feedbackauthorattachmentsid) {
|
||||
fileProm = this.workshopHelper.getAssessmentFilesFromOfflineFilesObject(inputData.feedbackauthorattachmentsid,
|
||||
workshop.id, assessmentId, siteId).then((files) => {
|
||||
return this.workshopHelper.uploadOrStoreAssessmentFiles(workshop.id, assessmentId, files, false, siteId);
|
||||
});
|
||||
} else {
|
||||
// Remove all files.
|
||||
fileProm = this.workshopHelper.uploadOrStoreAssessmentFiles(workshop.id, assessmentId, [], false, siteId);
|
||||
}
|
||||
|
||||
return fileProm.then((attachmentsId) => {
|
||||
inputData.feedbackauthorattachmentsid = attachmentsId || 0;
|
||||
|
||||
return this.workshopProvider.updateAssessmentOnline(assessmentId, inputData, siteId);
|
||||
}).catch((error) => {
|
||||
if (error && this.utils.isWebServiceError(error)) {
|
||||
// The WebService has thrown an error, this means it cannot be performed. Discard.
|
||||
discardError = error.message || error.error;
|
||||
} else {
|
||||
// Couldn't connect to server, reject.
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}).then(() => {
|
||||
// Delete the offline data.
|
||||
result.updated = true;
|
||||
|
||||
return this.workshopOffline.deleteAssessment(workshop.id, assessmentId, siteId);
|
||||
});
|
||||
}).then(() => {
|
||||
if (discardError) {
|
||||
// Assessment was discarded, add a warning.
|
||||
const message = this.translate.instant('core.warningofflinedatadeleted', {
|
||||
component: this.componentTranslate,
|
||||
name: workshop.name,
|
||||
error: discardError
|
||||
});
|
||||
|
||||
if (result.warnings.indexOf(message) == -1) {
|
||||
result.warnings.push(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize a submission evaluation.
|
||||
*
|
||||
* @param {any} workshop Workshop.
|
||||
* @param {any} evaluate Submission evaluation offline data.
|
||||
* @param {any} result Object with the result of the sync.
|
||||
* @param {string} siteId Site ID.
|
||||
* @return {Promise<any>} Promise resolved if success, rejected otherwise.
|
||||
*/
|
||||
protected syncEvaluateSubmission(workshop: any, evaluate: any, result: any, siteId: string): Promise<any> {
|
||||
let discardError;
|
||||
const submissionId = evaluate.submissionid;
|
||||
|
||||
const timePromise = this.workshopProvider.getSubmission(workshop.id, submissionId, siteId).then((submission) => {
|
||||
return submission.timemodified;
|
||||
}).catch(() => {
|
||||
return -1;
|
||||
});
|
||||
|
||||
return timePromise.then((timemodified) => {
|
||||
if (timemodified < 0 || timemodified >= evaluate.timemodified) {
|
||||
// The entry was not found in Moodle or the entry has been modified, discard the action.
|
||||
result.updated = true;
|
||||
discardError = this.translate.instant('addon.mod_workshop.warningsubmissionmodified');
|
||||
|
||||
return this.workshopOffline.deleteEvaluateSubmission(workshop.id, submissionId, siteId);
|
||||
}
|
||||
|
||||
return this.workshopProvider.evaluateSubmissionOnline(submissionId, evaluate.feedbacktext, evaluate.published,
|
||||
evaluate.gradeover, siteId).catch((error) => {
|
||||
if (error && this.utils.isWebServiceError(error)) {
|
||||
// The WebService has thrown an error, this means it cannot be performed. Discard.
|
||||
discardError = error.message || error.error;
|
||||
} else {
|
||||
// Couldn't connect to server, reject.
|
||||
return Promise.reject(error && error.error);
|
||||
}
|
||||
}).then(() => {
|
||||
// Delete the offline data.
|
||||
result.updated = true;
|
||||
|
||||
return this.workshopOffline.deleteEvaluateSubmission(workshop.id, submissionId, siteId);
|
||||
});
|
||||
}).then(() => {
|
||||
if (discardError) {
|
||||
// Assessment was discarded, add a warning.
|
||||
const message = this.translate.instant('core.warningofflinedatadeleted', {
|
||||
component: this.componentTranslate,
|
||||
name: workshop.name,
|
||||
error: discardError
|
||||
});
|
||||
|
||||
if (result.warnings.indexOf(message) == -1) {
|
||||
result.warnings.push(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize a assessment evaluation.
|
||||
*
|
||||
* @param {any} workshop Workshop.
|
||||
* @param {any} evaluate Assessment evaluation offline data.
|
||||
* @param {any} result Object with the result of the sync.
|
||||
* @param {string} siteId Site ID.
|
||||
* @return {Promise<any>} Promise resolved if success, rejected otherwise.
|
||||
*/
|
||||
protected syncEvaluateAssessment(workshop: any, evaluate: any, result: any, siteId: string): Promise<any> {
|
||||
let discardError;
|
||||
const assessmentId = evaluate.assessmentid;
|
||||
|
||||
const timePromise = this.workshopProvider.getAssessment(workshop.id, assessmentId, siteId).then((assessment) => {
|
||||
return assessment.timemodified;
|
||||
}).catch(() => {
|
||||
return -1;
|
||||
});
|
||||
|
||||
return timePromise.then((timemodified) => {
|
||||
if (timemodified < 0 || timemodified >= evaluate.timemodified) {
|
||||
// The entry was not found in Moodle or the entry has been modified, discard the action.
|
||||
result.updated = true;
|
||||
discardError = this.translate.instant('addon.mod_workshop.warningassessmentmodified');
|
||||
|
||||
return this.workshopOffline.deleteEvaluateAssessment(workshop.id, assessmentId, siteId);
|
||||
}
|
||||
|
||||
return this.workshopProvider.evaluateAssessmentOnline(assessmentId, evaluate.feedbacktext, evaluate.weight,
|
||||
evaluate.gradinggradeover, siteId).catch((error) => {
|
||||
if (error && this.utils.isWebServiceError(error)) {
|
||||
// The WebService has thrown an error, this means it cannot be performed. Discard.
|
||||
discardError = error.message || error.error;
|
||||
} else {
|
||||
// Couldn't connect to server, reject.
|
||||
return Promise.reject(error && error.error);
|
||||
}
|
||||
}).then(() => {
|
||||
// Delete the offline data.
|
||||
result.updated = true;
|
||||
|
||||
return this.workshopOffline.deleteEvaluateAssessment(workshop.id, assessmentId, siteId);
|
||||
});
|
||||
}).then(() => {
|
||||
if (discardError) {
|
||||
// Assessment was discarded, add a warning.
|
||||
const message = this.translate.instant('core.warningofflinedatadeleted', {
|
||||
component: this.componentTranslate,
|
||||
name: workshop.name,
|
||||
error: discardError
|
||||
});
|
||||
|
||||
if (result.warnings.indexOf(message) == -1) {
|
||||
result.warnings.push(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue