2021-10-12 18:47:33 +03:00
|
|
|
import Component from '@glimmer/component';
|
|
|
|
import {isThemeValidationError} from 'ghost-admin/services/ajax';
|
|
|
|
import {inject as service} from '@ember/service';
|
2022-02-09 13:49:38 +03:00
|
|
|
import {task} from 'ember-concurrency';
|
2021-10-12 18:47:33 +03:00
|
|
|
import {tracked} from '@glimmer/tracking';
|
|
|
|
|
2022-03-14 13:52:04 +03:00
|
|
|
export default class InstallThemeModal extends Component {
|
2021-10-12 18:47:33 +03:00
|
|
|
@service ajax;
|
|
|
|
@service ghostPaths;
|
|
|
|
@service store;
|
|
|
|
@service themeManagement;
|
|
|
|
|
|
|
|
@tracked installedTheme = null;
|
|
|
|
@tracked installError = '';
|
|
|
|
@tracked validationWarnings = [];
|
|
|
|
@tracked validationErrors = [];
|
|
|
|
@tracked fatalValidationErrors = [];
|
|
|
|
|
|
|
|
themes = this.store.peekAll('theme');
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super(...arguments);
|
|
|
|
this.refreshThemesTask.perform();
|
|
|
|
}
|
|
|
|
|
|
|
|
get themeName() {
|
2021-11-12 15:57:13 +03:00
|
|
|
return this.args.data.theme?.name || this.args.data.ref.split('/')[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
get themeRef() {
|
|
|
|
return this.args.data.theme?.ref || this.args.data.ref;
|
2021-10-12 18:47:33 +03:00
|
|
|
}
|
|
|
|
|
2021-10-18 14:32:31 +03:00
|
|
|
get isDefaultTheme() {
|
2021-11-18 01:46:03 +03:00
|
|
|
return this.themeName.toLowerCase() === 'casper';
|
2021-10-18 14:32:31 +03:00
|
|
|
}
|
|
|
|
|
2021-10-12 18:47:33 +03:00
|
|
|
get isConfirming() {
|
2021-10-18 14:32:31 +03:00
|
|
|
return !this.installSuccess && !this.installError && !this.installFailure;
|
2021-10-12 18:47:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
get installSuccess() {
|
|
|
|
return !!this.installedTheme;
|
|
|
|
}
|
|
|
|
|
|
|
|
get installFailure() {
|
|
|
|
return !this.installSuccess && (this.validationErrors.length || this.fatalValidationErrors.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
get willOverwriteExisting() {
|
2021-10-18 14:32:31 +03:00
|
|
|
return !this.isDefaultTheme && this.themes.findBy('name', this.themeName.toLowerCase());
|
2021-10-12 18:47:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
get hasWarningsOrErrors() {
|
|
|
|
return this.validationWarnings.length > 0 || this.validationErrors.length > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
get shouldShowInstall() {
|
2021-10-18 14:32:31 +03:00
|
|
|
return !this.installSuccess && !this.installFailure;
|
2021-10-12 18:47:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
@task
|
|
|
|
*refreshThemesTask() {
|
|
|
|
yield this.store.findAll('theme', {reload: true});
|
|
|
|
}
|
|
|
|
|
|
|
|
@task
|
|
|
|
*installThemeTask() {
|
|
|
|
try {
|
2021-10-18 14:32:31 +03:00
|
|
|
if (this.isDefaultTheme) {
|
|
|
|
// default theme can't be installed, only activated
|
2021-11-12 15:57:13 +03:00
|
|
|
const defaultTheme = this.store.peekRecord('theme', 'casper');
|
2021-10-18 14:32:31 +03:00
|
|
|
yield this.themeManagement.activateTask.perform(defaultTheme, {skipErrors: true});
|
|
|
|
this.installedTheme = defaultTheme;
|
|
|
|
|
|
|
|
// let modal opener do any other background stuff
|
|
|
|
this.args.data.onSuccess?.();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-12 15:57:13 +03:00
|
|
|
const url = this.ghostPaths.url.api('themes/install') + `?source=github&ref=${this.themeRef}`;
|
2021-10-12 18:47:33 +03:00
|
|
|
const result = yield this.ajax.post(url);
|
|
|
|
|
|
|
|
this.installError = '';
|
|
|
|
|
|
|
|
if (result.themes) {
|
|
|
|
// show theme in list immediately
|
|
|
|
this.store.pushPayload(result);
|
|
|
|
|
|
|
|
this.installedTheme = this.store.peekRecord('theme', result.themes[0].name);
|
|
|
|
|
|
|
|
this.validationWarnings = this.installedTheme.warnings || [];
|
|
|
|
this.validationErrors = this.installedTheme.errors || [];
|
|
|
|
this.fatalValidationErrors = [];
|
|
|
|
|
|
|
|
// activate but prevent additional error modal from showing
|
|
|
|
yield this.themeManagement.activateTask.perform(this.installedTheme, {skipErrors: true});
|
|
|
|
|
|
|
|
// let modal opener do any other background stuff
|
|
|
|
this.args.data.onSuccess?.();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
if (isThemeValidationError(error)) {
|
|
|
|
this.resetErrors();
|
|
|
|
|
|
|
|
let errors = error.payload.errors[0].details.errors;
|
|
|
|
let fatalErrors = [];
|
|
|
|
let normalErrors = [];
|
|
|
|
|
|
|
|
// to have a proper grouping of fatal errors and none fatal, we need to check
|
|
|
|
// our errors for the fatal property
|
|
|
|
if (errors && errors.length > 0) {
|
|
|
|
for (let i = 0; i < errors.length; i += 1) {
|
|
|
|
if (errors[i].fatal) {
|
|
|
|
fatalErrors.push(errors[i]);
|
|
|
|
} else {
|
|
|
|
normalErrors.push(errors[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.fatalValidationErrors = fatalErrors;
|
|
|
|
this.validationErrors = normalErrors;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error.payload?.errors) {
|
|
|
|
this.installError = error.payload.errors[0].message;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.installError = error.message;
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|