DEV: Add support for uploads to form templates (#22232)
This commit is contained in:
parent
acaea2b5c5
commit
b6f03fcecd
|
@ -32,11 +32,10 @@ export default class FormTemplateForm extends Component {
|
|||
type: "dropdown",
|
||||
icon: "chevron-circle-down",
|
||||
},
|
||||
// TODO(@keegan): add support for uploads
|
||||
// {
|
||||
// type: "upload",
|
||||
// icon: "cloud-upload-alt",
|
||||
// },
|
||||
{
|
||||
type: "upload",
|
||||
icon: "cloud-upload-alt",
|
||||
},
|
||||
{
|
||||
type: "multiselect",
|
||||
icon: "bullseye",
|
||||
|
|
|
@ -51,7 +51,7 @@ export const templateFormFields = [
|
|||
type: "upload",
|
||||
structure: `- type: upload
|
||||
attributes:
|
||||
file_types: "jpg, png, gif"
|
||||
file_types: ".jpg, .png, .gif"
|
||||
allow_multiple: false
|
||||
label: "${I18n.t("admin.form_templates.field_placeholders.label")}"
|
||||
validations:
|
||||
|
|
|
@ -7,10 +7,35 @@
|
|||
{{/if}}
|
||||
</label>
|
||||
{{/if}}
|
||||
<input
|
||||
type="file"
|
||||
accept={{@attributes.file_types}}
|
||||
class="form-template-field__upload"
|
||||
multiple={{@attributes.allow_multiple}}
|
||||
|
||||
<input type="hidden" name={{@attributes.label}} value={{this.uploadValue}} />
|
||||
|
||||
<PickFilesButton
|
||||
@fileInputClass="form-template-field__upload"
|
||||
@fileInputId={{this.fileUploadElementId}}
|
||||
@allowMultiple={{@attributes.allow_multiple}}
|
||||
@showButton={{true}}
|
||||
@onFilesPicked={{true}}
|
||||
@icon="upload"
|
||||
@label={{this.uploadStatus}}
|
||||
@fileInputDisabled={{this.disabled}}
|
||||
@acceptedFormatsOverride={{@attributes.file_types}}
|
||||
@acceptedFileTypesString={{@attributes.file_types}}
|
||||
/>
|
||||
|
||||
{{#if this.uploadedFiles}}
|
||||
<ul class="form-template-field__uploaded-files">
|
||||
{{#each this.uploadedFiles as |file|}}
|
||||
<li>
|
||||
{{d-icon "file"}}
|
||||
<a
|
||||
href={{file.url}}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{file.file_name}}</a>
|
||||
<span>{{file.human_filesize}}</span>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</div>
|
|
@ -0,0 +1,69 @@
|
|||
import Component from "@ember/component";
|
||||
import UppyUploadMixin from "discourse/mixins/uppy-upload";
|
||||
import { computed } from "@ember/object";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { dasherize } from "@ember/string";
|
||||
import { isAudio, isImage, isVideo } from "discourse/lib/uploads";
|
||||
|
||||
export default class FormTemplateFieldUpload extends Component.extend(
|
||||
UppyUploadMixin
|
||||
) {
|
||||
@tracked uploadValue;
|
||||
@tracked uploadComplete = false;
|
||||
@tracked uploadedFiles = [];
|
||||
@tracked disabled = this.uploading;
|
||||
@tracked fileUploadElementId = this.attributes?.label
|
||||
? `${dasherize(this.attributes.label)}-uploader`
|
||||
: `${this.elementId}-uploader`;
|
||||
@tracked fileInputSelector = `#${this.fileUploadElementId}`;
|
||||
@tracked id = this.fileUploadElementId;
|
||||
|
||||
@computed("uploading", "uploadValue")
|
||||
get uploadStatus() {
|
||||
if (!this.uploading && !this.uploadValue) {
|
||||
return "upload";
|
||||
}
|
||||
|
||||
if (!this.uploading && this.uploadValue) {
|
||||
this.uploadComplete = true;
|
||||
return "upload";
|
||||
}
|
||||
|
||||
return "uploading";
|
||||
}
|
||||
|
||||
uploadDone(upload) {
|
||||
// If reuploading, clear the existing file
|
||||
if (this.uploadComplete) {
|
||||
this.uploadedFiles = [];
|
||||
this.uploadValue = "";
|
||||
}
|
||||
|
||||
const uploadMarkdown = this.buildMarkdown(upload);
|
||||
this.uploadedFiles.pushObject(upload);
|
||||
|
||||
if (this.uploadValue && this.allowMultipleFiles) {
|
||||
// multiple file upload
|
||||
this.uploadValue = `${this.uploadValue}\n${uploadMarkdown}`;
|
||||
} else {
|
||||
// single file upload
|
||||
this.uploadValue = uploadMarkdown;
|
||||
}
|
||||
}
|
||||
|
||||
buildMarkdown(upload) {
|
||||
if (isImage(upload.url)) {
|
||||
return `![${upload.file_name}|${upload.width}x${upload.height}](${upload.short_url})`;
|
||||
}
|
||||
|
||||
if (isAudio(upload.url)) {
|
||||
return `![${upload.file_name}|audio](${upload.short_url})`;
|
||||
}
|
||||
|
||||
if (isVideo(upload.url)) {
|
||||
return `![${upload.file_name}|video](${upload.short_url})`;
|
||||
}
|
||||
|
||||
return `[${upload.file_name}|attachment](${upload.short_url}) (${upload.human_filesize})`;
|
||||
}
|
||||
}
|
|
@ -91,7 +91,6 @@ export default Component.extend({
|
|||
this.dialog.alert(message);
|
||||
return;
|
||||
}
|
||||
this.onFilesPicked(files);
|
||||
},
|
||||
|
||||
_haveAcceptedTypes(files) {
|
||||
|
|
|
@ -20,4 +20,35 @@
|
|||
margin-left: 0.5em;
|
||||
font-size: var(--font-down-4);
|
||||
}
|
||||
|
||||
&__uploaded-files {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
|
||||
li {
|
||||
padding: 0.5rem;
|
||||
margin-block: 0.25rem;
|
||||
border: 1px solid var(--primary-low-mid);
|
||||
background: var(--primary-low);
|
||||
border-radius: var(--d-border-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
a {
|
||||
@include ellipsis;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
span {
|
||||
color: var(--primary-high);
|
||||
margin-left: auto;
|
||||
font-size: var(--font-down-1);
|
||||
}
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
color: var(--tertiary);
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,8 +119,7 @@ describe "Admin Customize Form Templates", type: :system do
|
|||
expect(form_template_page).to have_input_field("textarea")
|
||||
expect(form_template_page).to have_input_field("checkbox")
|
||||
expect(form_template_page).to have_input_field("dropdown")
|
||||
# TODO(@keegan): Add this back when upload functionality is added
|
||||
# expect(form_template_page).to have_input_field("upload")
|
||||
expect(form_template_page).to have_input_field("upload")
|
||||
expect(form_template_page).to have_input_field("multi-select")
|
||||
end
|
||||
|
||||
|
@ -176,13 +175,12 @@ describe "Admin Customize Form Templates", type: :system do
|
|||
)
|
||||
end
|
||||
|
||||
# TODO(@keegan): Unskip this test when Upload functionality is added
|
||||
xit "should allow quick insertion of upload field" do
|
||||
it "should allow quick insertion of upload field" do
|
||||
quick_insertion_test(
|
||||
"upload",
|
||||
'- type: upload
|
||||
attributes:
|
||||
file_types: "jpg, png, gif"
|
||||
file_types: ".jpg, .png, .gif"
|
||||
allow_multiple: false
|
||||
label: "Enter label here"
|
||||
validations:
|
||||
|
|
|
@ -24,6 +24,34 @@ describe "Composer Form Templates", type: :system do
|
|||
fab!(:form_template_4) do
|
||||
Fabricate(:form_template, name: "Biography", template: "- type: textarea")
|
||||
end
|
||||
fab!(:form_template_5) do
|
||||
Fabricate(
|
||||
:form_template,
|
||||
name: "Medication",
|
||||
template:
|
||||
%Q(
|
||||
- type: input
|
||||
attributes:
|
||||
label: "What is your name?"
|
||||
placeholder: "John Smith"
|
||||
validations:
|
||||
required: false
|
||||
- type: upload
|
||||
attributes:
|
||||
file_types: ".jpg, .png"
|
||||
allow_multiple: false
|
||||
label: "Upload your prescription"
|
||||
validations:
|
||||
required: true
|
||||
- type: upload
|
||||
attributes:
|
||||
file_types: ".jpg, .png, .pdf, .mp3, .mp4"
|
||||
allow_multiple: true
|
||||
label: "Any additional docs"
|
||||
validations:
|
||||
required: false"),
|
||||
)
|
||||
end
|
||||
fab!(:category_with_template_1) do
|
||||
Fabricate(
|
||||
:category,
|
||||
|
@ -60,6 +88,15 @@ describe "Composer Form Templates", type: :system do
|
|||
form_template_ids: [form_template_3.id, form_template_4.id],
|
||||
)
|
||||
end
|
||||
fab!(:category_with_upload_template) do
|
||||
Fabricate(
|
||||
:category,
|
||||
name: "Medical",
|
||||
slug: "medical",
|
||||
topic_count: 2,
|
||||
form_template_ids: [form_template_5.id],
|
||||
)
|
||||
end
|
||||
fab!(:category_no_template) do
|
||||
Fabricate(:category, name: "Staff", slug: "staff", topic_count: 2, form_template_ids: [])
|
||||
end
|
||||
|
@ -73,6 +110,7 @@ describe "Composer Form Templates", type: :system do
|
|||
topic_template: "Testing",
|
||||
)
|
||||
end
|
||||
|
||||
let(:category_page) { PageObjects::Pages::Category.new }
|
||||
let(:composer) { PageObjects::Components::Composer.new }
|
||||
let(:form_template_chooser) { PageObjects::Components::SelectKit.new(".form-template-chooser") }
|
||||
|
@ -80,6 +118,7 @@ describe "Composer Form Templates", type: :system do
|
|||
|
||||
before do
|
||||
SiteSetting.experimental_form_templates = true
|
||||
SiteSetting.authorized_extensions = "*"
|
||||
sign_in user
|
||||
end
|
||||
|
||||
|
@ -195,4 +234,61 @@ describe "Composer Form Templates", type: :system do
|
|||
"Bruce Wayne",
|
||||
)
|
||||
end
|
||||
|
||||
it "creates a post with an upload field" do
|
||||
topic_title = "Bruce Wayne's Medication"
|
||||
|
||||
category_page.visit(category_with_upload_template)
|
||||
category_page.new_topic_button.click
|
||||
attach_file "upload-your-prescription-uploader",
|
||||
"#{Rails.root}/spec/fixtures/images/logo.png",
|
||||
make_visible: true
|
||||
composer.fill_title(topic_title)
|
||||
composer.fill_form_template_field("input", "Bruce Wayne")
|
||||
composer.create
|
||||
|
||||
expect(find("#{topic_page.post_by_number_selector(1)} .cooked")).to have_css(
|
||||
"img[alt='logo.png']",
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't allow uploading an invalid file type" do
|
||||
topic_title = "Bruce Wayne's Medication"
|
||||
|
||||
category_page.visit(category_with_upload_template)
|
||||
category_page.new_topic_button.click
|
||||
attach_file "upload-your-prescription-uploader",
|
||||
"#{Rails.root}/spec/fixtures/images/animated.gif",
|
||||
make_visible: true
|
||||
expect(find("#dialog-holder .dialog-body p", visible: :all)).to have_content(
|
||||
I18n.t("js.pick_files_button.unsupported_file_picked", { types: ".jpg, .png" }),
|
||||
)
|
||||
end
|
||||
|
||||
it "creates a post with multiple uploads" do
|
||||
topic_title = "Peter Parker's Medication"
|
||||
|
||||
category_page.visit(category_with_upload_template)
|
||||
category_page.new_topic_button.click
|
||||
attach_file "upload-your-prescription-uploader",
|
||||
"#{Rails.root}/spec/fixtures/images/logo.png",
|
||||
make_visible: true
|
||||
attach_file "any-additional-docs-uploader",
|
||||
[
|
||||
"#{Rails.root}/spec/fixtures/media/small.mp3",
|
||||
"#{Rails.root}/spec/fixtures/media/small.mp4",
|
||||
"#{Rails.root}/spec/fixtures/pdf/small.pdf",
|
||||
],
|
||||
make_visible: true
|
||||
composer.fill_title(topic_title)
|
||||
composer.fill_form_template_field("input", "Peter Parker}")
|
||||
composer.create
|
||||
|
||||
expect(find("#{topic_page.post_by_number_selector(1)} .cooked")).to have_css(
|
||||
"img[alt='logo.png']",
|
||||
)
|
||||
expect(find("#{topic_page.post_by_number_selector(1)} .cooked")).to have_css("a.attachment")
|
||||
expect(find("#{topic_page.post_by_number_selector(1)} .cooked")).to have_css("audio")
|
||||
expect(find("#{topic_page.post_by_number_selector(1)} .cooked")).to have_css("video")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,7 +62,7 @@ module PageObjects
|
|||
end
|
||||
|
||||
def has_input_field?(type)
|
||||
find(".form-template-field__#{type}").present?
|
||||
find(".form-template-field__#{type}", visible: :all).present?
|
||||
end
|
||||
|
||||
def has_preview_modal?
|
||||
|
|
Loading…
Reference in New Issue