DEV: Convert theme-upload modal to component-based API (#22699)

This commit is contained in:
Isaac Janzen 2023-07-26 12:46:02 -05:00 committed by GitHub
parent a5b810fe18
commit f3b7351ff6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 167 additions and 186 deletions

View File

@ -0,0 +1,47 @@
<DModal
class="add-upload-modal"
@title={{i18n "admin.customize.theme.add_upload"}}
@closeModal={{@closeModal}}
@flash={{this.flash}}
>
<:body>
<div class="inputs">
<section class="field">
<input
{{on "change" this.updateName}}
type="file"
id="file-input"
accept="*"
/>
<label for="file-input">
{{i18n "admin.customize.theme.upload_file_tip"}}
</label>
</section>
<section class="field">
<label for="theme-variable-name">
{{i18n "admin.customize.theme.variable_name"}}
</label>
<Input id="theme-variable-name" @value={{this.name}} />
</section>
{{#if this.fileSelected}}
{{#if this.errorMessage}}
<span class="alert alert-error">{{this.errorMessage}}</span>
{{/if}}
{{/if}}
</div>
</:body>
<:footer>
<DButton
@action={{this.upload}}
@disabled={{this.disabled}}
class="btn btn-primary"
@icon="upload"
@label="admin.customize.theme.upload"
/>
<DButton
class="btn-flat d-modal-cancel"
@action={{@closeModal}}
@label="cancel"
/>
</:footer>
</DModal>

View File

@ -0,0 +1,112 @@
import Component from "@glimmer/component";
import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";
import I18n from "I18n";
import { ajax } from "discourse/lib/ajax";
import { isEmpty } from "@ember/utils";
const THEME_FIELD_VARIABLE_TYPE_IDS = [2, 3, 4];
const SCSS_VARIABLE_NAMES = [
// common/foundation/colors.scss
"primary",
"secondary",
"tertiary",
"quaternary",
"header_background",
"header_primary",
"highlight",
"danger",
"success",
"love",
// common/foundation/math.scss
"E",
"PI",
"LN2",
"SQRT2",
// common/foundation/variables.scss
"small-width",
"medium-width",
"large-width",
"google",
"instagram",
"facebook",
"cas",
"twitter",
"github",
"base-font-size",
"base-line-height",
"base-font-family",
"primary-low",
"primary-medium",
"secondary-low",
"secondary-medium",
"tertiary-low",
"quaternary-low",
"highlight-low",
"highlight-medium",
"danger-low",
"danger-medium",
"success-low",
"love-low",
];
export default class ThemeUploadAdd extends Component {
@tracked name;
@tracked fileSelected = false;
@tracked flash;
get disabled() {
return this.errorMessage && this.fileSelected;
}
get errorMessage() {
if (!this.name) {
return;
} else if (!this.name.match(/^[a-z_][a-z0-9_-]*$/i)) {
return I18n.t("admin.customize.theme.variable_name_error.invalid_syntax");
} else if (SCSS_VARIABLE_NAMES.includes(name.toLowerCase())) {
return I18n.t("admin.customize.theme.variable_name_error.no_overwrite");
} else if (
this.args.model.themeFields.some(
(tf) =>
THEME_FIELD_VARIABLE_TYPE_IDS.includes(tf.type_id) &&
this.name === tf.name
)
) {
return I18n.t("admin.customize.theme.variable_name_error.must_be_unique");
}
}
@action
updateName(e) {
if (isEmpty(this.name)) {
this.name = e.target.files[0].name.split(".")[0];
}
this.fileSelected = e.target.files[0];
}
@action
async upload() {
const file = document.getElementById("file-input").files[0];
const options = {
type: "POST",
processData: false,
contentType: false,
data: new FormData(),
};
options.data.append("file", file);
try {
const result = await ajax("/admin/themes/upload_asset", options);
const upload = {
upload_id: result.upload_id,
name: this.name,
original_filename: file.name,
};
this.args.model.addUpload(upload);
this.args.closeModal();
} catch (e) {
this.flash = e.jqXHR.responseJSON.errors.join(". ");
}
}
}

View File

@ -14,14 +14,15 @@ import ThemeSettings from "admin/models/theme-settings";
import discourseComputed from "discourse-common/utils/decorators";
import { makeArray } from "discourse-common/lib/helpers";
import { popupAjaxError } from "discourse/lib/ajax-error";
import showModal from "discourse/lib/show-modal";
import { url } from "discourse/lib/computed";
import ThemeUploadAddModal from "../components/theme-upload-add";
const THEME_UPLOAD_VAR = 2;
export default class AdminCustomizeThemesShowController extends Controller {
@service dialog;
@service router;
@service modal;
editRouteName = "adminCustomizeThemes.edit";
@ -274,7 +275,12 @@ export default class AdminCustomizeThemesShowController extends Controller {
@action
addUploadModal() {
showModal("admin-add-upload", { admin: true, name: "" });
this.modal.show(ThemeUploadAddModal, {
model: {
themeFields: this.model.theme_fields,
addUpload: this.addUpload,
},
});
}
@action

View File

@ -1,146 +0,0 @@
import { action } from "@ember/object";
import { and, not } from "@ember/object/computed";
import Controller, { inject as controller } from "@ember/controller";
import discourseComputed from "discourse-common/utils/decorators";
import { observes } from "@ember-decorators/object";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { ajax } from "discourse/lib/ajax";
import { isEmpty } from "@ember/utils";
import { popupAjaxError } from "discourse/lib/ajax-error";
const THEME_FIELD_VARIABLE_TYPE_IDS = [2, 3, 4];
const SCSS_VARIABLE_NAMES = [
// common/foundation/colors.scss
"primary",
"secondary",
"tertiary",
"quaternary",
"header_background",
"header_primary",
"highlight",
"danger",
"success",
"love",
// common/foundation/math.scss
"E",
"PI",
"LN2",
"SQRT2",
// common/foundation/variables.scss
"small-width",
"medium-width",
"large-width",
"google",
"instagram",
"facebook",
"cas",
"twitter",
"github",
"base-font-size",
"base-line-height",
"base-font-family",
"primary-low",
"primary-medium",
"secondary-low",
"secondary-medium",
"tertiary-low",
"quaternary-low",
"highlight-low",
"highlight-medium",
"danger-low",
"danger-medium",
"success-low",
"love-low",
];
export default class AdminAddUploadController extends Controller.extend(
ModalFunctionality
) {
@controller adminCustomizeThemesShow;
uploadUrl = "/admin/themes/upload_asset";
@and("nameValid", "fileSelected") enabled;
@not("enabled") disabled;
onShow() {
this.set("name", null);
this.set("fileSelected", false);
}
@discourseComputed("name", "adminCustomizeThemesShow.model.theme_fields")
errorMessage(name, themeFields) {
if (name) {
if (!name.match(/^[a-z_][a-z0-9_-]*$/i)) {
return I18n.t(
"admin.customize.theme.variable_name_error.invalid_syntax"
);
} else if (SCSS_VARIABLE_NAMES.includes(name.toLowerCase())) {
return I18n.t("admin.customize.theme.variable_name_error.no_overwrite");
} else if (
themeFields.some(
(tf) =>
THEME_FIELD_VARIABLE_TYPE_IDS.includes(tf.type_id) &&
name === tf.name
)
) {
return I18n.t(
"admin.customize.theme.variable_name_error.must_be_unique"
);
}
}
return null;
}
@discourseComputed("errorMessage")
nameValid(errorMessage) {
return null === errorMessage;
}
@observes("name")
uploadChanged() {
const file = $("#file-input")[0];
this.set("fileSelected", file && file.files[0]);
}
@action
updateName() {
let name = this.name;
if (isEmpty(name)) {
name = $("#file-input")[0].files[0].name;
this.set("name", name.split(".")[0]);
}
this.uploadChanged();
}
@action
upload() {
const file = $("#file-input")[0].files[0];
const options = {
type: "POST",
processData: false,
contentType: false,
data: new FormData(),
};
options.data.append("file", file);
ajax(this.uploadUrl, options)
.then((result) => {
const upload = {
upload_id: result.upload_id,
name: this.name,
original_filename: file.name,
};
this.adminCustomizeThemesShow.send("addUpload", upload);
this.send("closeModal");
})
.catch((e) => {
popupAjaxError(e);
});
}
}

View File

@ -1,37 +0,0 @@
<DModalBody @class="add-upload-modal" @title="admin.customize.theme.add_upload">
<div class="inputs">
<section class="field">
<input
onchange={{action "updateName"}}
type="file"
id="file-input"
accept="*"
/>
<label for="file-input">{{i18n
"admin.customize.theme.upload_file_tip"
}}</label>
</section>
<section class="field">
<label for="theme-variable-name">{{i18n
"admin.customize.theme.variable_name"
}}</label>
<Input id="theme-variable-name" @value={{this.name}} />
</section>
{{#if this.fileSelected}}
{{#if this.errorMessage}}
<span class="alert alert-error">{{this.errorMessage}}</span>
{{/if}}
{{/if}}
</div>
</DModalBody>
<div class="modal-footer">
<DButton
@action={{action "upload"}}
@disabled={{this.disabled}}
@class="btn btn-primary"
@icon="upload"
@label="admin.customize.theme.upload"
/>
<DModalCancel @close={{route-action "closeModal"}} />
</div>

View File

@ -54,7 +54,6 @@ const KNOWN_LEGACY_MODALS = [
"tag-upload",
"topic-summary",
"user-status",
"admin-add-upload",
"admin-merge-users-prompt",
"admin-start-backup",
"admin-watched-word-test",