mirror of
https://github.com/discourse/discourse.git
synced 2025-02-24 14:45:24 +08:00
UX: Wizard and theme install modal improvements (#30788)
* Fix tabbing inputs on first wizard step, the user would end up on "Skip to content" for the page "behind" the wizard. If the wizard is showing we can just not render the skip to content element * Only show the required wizard steps in the counter, so we do X/4 rather than X/6 at the top of the page. * Change to "Setting up your theme..." by default, but if the install takes 10s or more add a note that things are still happening and to be patient.
This commit is contained in:
parent
59a2a70806
commit
f329acba71
@ -14,6 +14,7 @@ import dIcon from "discourse/helpers/d-icon";
|
||||
import withEventValue from "discourse/helpers/with-event-value";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import discourseLater from "discourse/lib/later";
|
||||
import { POPULAR_THEMES } from "discourse/lib/popular-themes";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import InstallThemeItem from "admin/components/install-theme-item";
|
||||
@ -41,6 +42,7 @@ export default class InstallThemeModal extends Component {
|
||||
@tracked duplicateRemoteThemeWarning;
|
||||
@tracked themeCannotBeInstalled;
|
||||
@tracked name;
|
||||
@tracked loadingTimePassed;
|
||||
|
||||
recordType = this.args.model.recordType || "theme";
|
||||
keyGenUrl = this.args.model.keyGenUrl || "/admin/themes/generate_key_pair";
|
||||
@ -121,6 +123,14 @@ export default class InstallThemeModal extends Component {
|
||||
});
|
||||
}
|
||||
|
||||
get installingMessage() {
|
||||
if (this.loadingTimePassed > 10) {
|
||||
return i18n("admin.customize.theme.installing_message_long_time");
|
||||
}
|
||||
|
||||
return i18n("admin.customize.theme.installing_message");
|
||||
}
|
||||
|
||||
themeHasSameUrl(theme, url) {
|
||||
const themeUrl = theme.remote_theme?.remote_url;
|
||||
return (
|
||||
@ -167,18 +177,7 @@ export default class InstallThemeModal extends Component {
|
||||
@action
|
||||
async installTheme() {
|
||||
if (this.create) {
|
||||
this.loading = true;
|
||||
const theme = this.store.createRecord(this.recordType);
|
||||
try {
|
||||
await theme.save({ name: this.name, component: this.component });
|
||||
this.args.model.addTheme(theme);
|
||||
this.args.closeModal();
|
||||
} catch (err) {
|
||||
popupAjaxError(err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
return;
|
||||
return this.#createTheme();
|
||||
}
|
||||
|
||||
let options = {
|
||||
@ -225,6 +224,8 @@ export default class InstallThemeModal extends Component {
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
this.loadingTimePassed = 0;
|
||||
this.#backgroundLoading();
|
||||
const result = await ajax(this.importUrl, options);
|
||||
const theme = this.store.createRecord(this.recordType, result.theme);
|
||||
this.args.model.addTheme(theme);
|
||||
@ -234,6 +235,34 @@ export default class InstallThemeModal extends Component {
|
||||
return popupAjaxError(err);
|
||||
}
|
||||
this.themeCannotBeInstalled = i18n("admin.customize.theme.force_install");
|
||||
} finally {
|
||||
this.loadingTimePassed = 0;
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
#backgroundLoading() {
|
||||
if (this.loading) {
|
||||
discourseLater(() => {
|
||||
if (this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadingTimePassed += 1;
|
||||
this.#backgroundLoading();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
async #createTheme() {
|
||||
this.loading = true;
|
||||
const theme = this.store.createRecord(this.recordType);
|
||||
try {
|
||||
await theme.save({ name: this.name, component: this.component });
|
||||
this.args.model.addTheme(theme);
|
||||
this.args.closeModal();
|
||||
} catch (err) {
|
||||
popupAjaxError(err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
@ -275,7 +304,7 @@ export default class InstallThemeModal extends Component {
|
||||
<div class="install-theme-content">
|
||||
<ConditionalLoadingSection
|
||||
@isLoading={{this.loading}}
|
||||
@title={{i18n "admin.customize.theme.installing_message"}}
|
||||
@title={{this.installingMessage}}
|
||||
>
|
||||
{{#if this.popular}}
|
||||
<div class="popular-theme-items">
|
||||
|
@ -22,6 +22,7 @@ export default class ApplicationController extends Controller {
|
||||
sidebarDisabledRouteOverride = false;
|
||||
navigationMenuQueryParamOverride = null;
|
||||
showSiteHeader = true;
|
||||
showSkipToContent = true;
|
||||
|
||||
get showFooter() {
|
||||
return this.footer.showFooter;
|
||||
|
@ -14,6 +14,7 @@ export default class WizardRoute extends Route {
|
||||
this.controllerFor("application").setProperties({
|
||||
showTop: false,
|
||||
showSiteHeader: false,
|
||||
showSkipToContent: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -25,6 +26,7 @@ export default class WizardRoute extends Route {
|
||||
this.controllerFor("application").setProperties({
|
||||
showTop: true,
|
||||
showSiteHeader: true,
|
||||
showSkipToContent: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||
ctx.fillStyle = textColor;
|
||||
ctx.fillText(
|
||||
titles[idx],
|
||||
cols[0] - margin * 0.25,
|
||||
cols[0] - margin * 0.1,
|
||||
textPos + categoryHeight * 0.36
|
||||
);
|
||||
|
||||
|
@ -10,6 +10,8 @@ import emoji from "discourse/helpers/emoji";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import WizardField from "./wizard-field";
|
||||
|
||||
const READY_STEP_INDEX = 5;
|
||||
|
||||
export default class WizardStepComponent extends Component {
|
||||
@tracked saving = false;
|
||||
|
||||
@ -25,6 +27,12 @@ export default class WizardStepComponent extends Component {
|
||||
return this.step.id;
|
||||
}
|
||||
|
||||
// We don't want to show the step counter for optional steps after
|
||||
// the "Ready" step.
|
||||
get showStepCounter() {
|
||||
return this.args.step.displayIndex < READY_STEP_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Step Back Button? Primary Action Secondary Action
|
||||
* ------------------------------------------------------------------
|
||||
@ -172,18 +180,20 @@ export default class WizardStepComponent extends Component {
|
||||
{{didInsert this.autoFocus}}
|
||||
{{didUpdate this.stepChanged @step.id}}
|
||||
>
|
||||
<div class="wizard-container__step-counter">
|
||||
<span class="wizard-container__step-text">
|
||||
{{i18n "wizard.step-text"}}
|
||||
</span>
|
||||
<span class="wizard-container__step-count">
|
||||
{{i18n
|
||||
"wizard.step"
|
||||
current=@step.displayIndex
|
||||
total=@wizard.totalSteps
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
{{#if this.showStepCounter}}
|
||||
<div class="wizard-container__step-counter">
|
||||
<span class="wizard-container__step-text">
|
||||
{{i18n "wizard.step-text"}}
|
||||
</span>
|
||||
<span class="wizard-container__step-count">
|
||||
{{i18n
|
||||
"wizard.step"
|
||||
current=@step.displayIndex
|
||||
total=@wizard.totalSteps
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="wizard-container">
|
||||
<div class="wizard-container__step-contents">
|
||||
|
@ -24,7 +24,9 @@ export default class Wizard {
|
||||
}
|
||||
|
||||
get totalSteps() {
|
||||
return this.steps.length;
|
||||
// We used to use this.steps.length() here, but we don't want to
|
||||
// include optional steps after "Ready" here.
|
||||
return 4;
|
||||
}
|
||||
|
||||
get title() {
|
||||
|
@ -2,7 +2,9 @@
|
||||
<DVirtualHeight />
|
||||
|
||||
<DiscourseRoot {{did-insert this.trackDiscoursePainted}}>
|
||||
<a href="#main-container" id="skip-link">{{i18n "skip_to_main_content"}}</a>
|
||||
{{#if this.showSkipToContent}}
|
||||
<a href="#main-container" id="skip-link">{{i18n "skip_to_main_content"}}</a>
|
||||
{{/if}}
|
||||
<DDocument />
|
||||
<PageLoadingSlider />
|
||||
<PluginOutlet
|
||||
|
@ -6146,7 +6146,8 @@ en:
|
||||
install_upload: "From your device"
|
||||
install_git_repo: "From a git repository"
|
||||
install_create: "Create new"
|
||||
installing_message: "Installing theme, this may take several minutes..."
|
||||
installing_message: "Setting up your new theme…"
|
||||
installing_message_long_time: "Setting up your new theme is taking a little longer than expected, please hang tight…"
|
||||
duplicate_remote_theme: "The theme component “%{name}” is already installed, are you sure you want to install another copy?"
|
||||
force_install: "The theme cannot be installed because the Git repository is inaccessible. Are you sure you want to continue installing it?"
|
||||
create_placeholder: "Create Placeholder"
|
||||
|
Loading…
x
Reference in New Issue
Block a user