satis 2.1.49 → 2.1.50
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/components/satis/attachments/component.css +12 -8
- data/app/components/satis/attachments/component.html.slim +8 -25
- data/app/components/satis/attachments/component.rb +3 -11
- data/app/controllers/satis/attachments_controller.rb +15 -16
- data/app/javascript/satis/controllers/attachment_upload_controller.js +41 -39
- data/app/javascript/satis/controllers/index.js +0 -3
- data/app/views/satis/attachments/_attachment.html.slim +13 -0
- data/app/views/satis/attachments/create.turbo_stream.slim +1 -0
- data/app/views/satis/attachments/destroy.turbo_stream.slim +1 -0
- data/lib/satis/forms/builder.rb +10 -2
- data/lib/satis/version.rb +1 -1
- metadata +4 -2
- data/app/javascript/satis/controllers/attachment_delete_controller.js +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8a393c04d2d3c296a40cbeff2d67c11d77035cacafd6861641422595a051ef1
|
4
|
+
data.tar.gz: eb3403bba306eb4e4953b31abda212636e0dc0f304917fc0ab1c6c533db50d98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69d33e8297502ab3dbe754f7cbca3d886c7cacd529d1356fda0acd6725bd77fe883db23e2cd5c51b2b4cc4deaf7d8ded771e086ddd60f5bdebca6fb5e2932369
|
7
|
+
data.tar.gz: d94edace53c39bb158ff07d39728901fdb849b14e2472c5a4983405ec4ad3d8501670d3a1798902e8056c7c37e46f228e0b26453579d8c626b1ec7e9dcf38767
|
@@ -1,5 +1,5 @@
|
|
1
1
|
.attachments__group {
|
2
|
-
@apply grid gap-6 mt-
|
2
|
+
@apply grid gap-6 mt-0 justify-start;
|
3
3
|
grid-template-columns: repeat(auto-fill, 200px);
|
4
4
|
}
|
5
5
|
|
@@ -13,8 +13,7 @@
|
|
13
13
|
}
|
14
14
|
|
15
15
|
.attachments__attachment .attachments__button {
|
16
|
-
@apply hidden
|
17
|
-
@apply dark:bg-gray-700 dark:text-white;
|
16
|
+
@apply hidden;
|
18
17
|
}
|
19
18
|
|
20
19
|
.attachments__attachment .attachments__button:first-of-type {
|
@@ -26,7 +25,7 @@
|
|
26
25
|
}
|
27
26
|
|
28
27
|
.attachments__attachment:hover .attachments__button {
|
29
|
-
@apply block w-
|
28
|
+
@apply block w-7 h-7 justify-center items-center text-center bg-gray-100 dark:bg-gray-800 dark:text-white;
|
30
29
|
}
|
31
30
|
|
32
31
|
.attachments__attachment .attachments__filename {
|
@@ -85,8 +84,7 @@
|
|
85
84
|
}
|
86
85
|
|
87
86
|
.upload-btn:hover {
|
88
|
-
@apply dark:bg-gray-900 dark:text-white dark:border-gray-700 bg-white;
|
89
|
-
border-color: #999;
|
87
|
+
@apply dark:bg-gray-900 dark:text-white dark:border-gray-700 border-gray-500 bg-white;
|
90
88
|
}
|
91
89
|
|
92
90
|
.upload-btn:focus {
|
@@ -126,8 +124,14 @@
|
|
126
124
|
}
|
127
125
|
|
128
126
|
.uploading .upload-btn {
|
129
|
-
@apply dark:bg-gray-800 dark:border-gray-600 dark:text-white;
|
130
|
-
background-color: #fcf8e3;
|
127
|
+
@apply dark:bg-gray-800 dark:border-gray-600 dark:text-white bg-white;
|
131
128
|
border-color: #f39c12;
|
132
129
|
cursor: not-allowed;
|
133
130
|
}
|
131
|
+
|
132
|
+
.attachments__group .attachment-upload.upload-btn.attachments__attachment {
|
133
|
+
@apply bg-white dark:bg-gray-800 border-2 border-dashed hover:border-gray-500 border-gray-300 p-4 flex flex-col justify-center items-center text-center w-full min-h-[150px] box-border;
|
134
|
+
}
|
135
|
+
.attachments__group .attachment-upload.upload-btn.attachments__attachment.dark {
|
136
|
+
@apply hover:border-white;
|
137
|
+
}
|
@@ -1,25 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
div.attachments__group
|
11
|
-
- model.send(attribute).each do |attachment|
|
12
|
-
div.attachments__attachment(style= attachment_style(attachment))
|
13
|
-
- unless attachment.representable?
|
14
|
-
div.preview-text
|
15
|
-
i.fas.fa-file(aria-hidden="true")
|
16
|
-
|
17
|
-
= link_to Satis::Engine.routes.url_helpers.attachment_path(attachment, sgid: model_sgid, attribute: attribute), data: {turbo_method: :delete, turbo_confirm: "Are you sure you want to delete this attachment?"}, class: 'attachments__button' do
|
18
|
-
i.fas.fa-xmark
|
19
|
-
|
20
|
-
|
21
|
-
= link_to Rails.application.routes.url_helpers.rails_blob_url(attachment, host: request.host + ":#{request.port}"), data: { turbo: true, turbolinks: false }, class: 'attachments__button', download: true do
|
22
|
-
i.fas.fa-download
|
23
|
-
|
24
|
-
span.attachments__filename
|
25
|
-
= attachment.filename
|
1
|
+
turbo-frame id="#{model.id}_#{attribute}_attachments" target="_top" class="attachments__group"
|
2
|
+
div.attachment-upload.upload-btn.attachments__attachment data-controller="satis-attachment-upload" data-satis-attachment-upload-url-value=(model.persisted? ? Satis::Engine.routes.url_helpers.attachments_path(sgid: model_sgid, attribute: attribute) : false) data-satis-attachment-upload-parameter-name-value=(form&.field_name(attribute)||attribute) data-action="click->satis-attachment-upload#handleClick"
|
3
|
+
span.icon.upload
|
4
|
+
i.fas.fa-upload
|
5
|
+
span.icon.uploading
|
6
|
+
i.fal.fa-circle-notch.fa-spin
|
7
|
+
span.button-text data-satis-attachment-upload-target="button" Drag or click to attach files
|
8
|
+
= render partial: "satis/attachments/attachment", collection: model.send(attribute)
|
@@ -1,24 +1,16 @@
|
|
1
1
|
module Satis
|
2
2
|
module Attachments
|
3
3
|
class Component < Satis::ApplicationComponent
|
4
|
-
attr_reader :model, :attribute, :attachments_options
|
4
|
+
attr_reader :model, :attribute, :attachments_options, :form
|
5
5
|
|
6
6
|
def initialize(model, attribute, **options)
|
7
7
|
super()
|
8
|
-
@
|
8
|
+
@form = options[:form]
|
9
|
+
@model = model || form.object
|
9
10
|
@attribute = attribute
|
10
11
|
@attachments_options = options
|
11
12
|
end
|
12
13
|
|
13
|
-
def attachment_style(attachment)
|
14
|
-
if attachment.representable?
|
15
|
-
url = attachment.representation(resize_to_limit: [200, 200]).processed.url
|
16
|
-
"background-image: url(#{url})"
|
17
|
-
else
|
18
|
-
"background-color: f0f0f0"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
14
|
def model_sgid
|
23
15
|
@model.to_sgid(expires_in: nil, for: "satis_attachments")
|
24
16
|
end
|
@@ -4,32 +4,31 @@ module Satis
|
|
4
4
|
class AttachmentsController < ApplicationController
|
5
5
|
before_action :set_objects
|
6
6
|
|
7
|
-
|
8
|
-
def index
|
9
|
-
@attachments = @model.public_send(@attachment_type)
|
10
|
-
render json: @attachments
|
11
|
-
end
|
12
|
-
|
13
7
|
def create
|
14
|
-
params[:attachments]
|
15
|
-
|
16
|
-
end
|
17
|
-
redirect_to request.referer || root_path, notice: "Attachment created successfully."
|
8
|
+
@model.public_send(@attribute).attach(params[:attachments])
|
9
|
+
@attachments = @model.public_send(@attribute).last(params[:attachments].size)
|
18
10
|
|
11
|
+
respond_to do |format|
|
12
|
+
format.html { redirect_to request.referer || root_path, notice: "Attachment created successfully." }
|
13
|
+
format.turbo_stream
|
14
|
+
end
|
19
15
|
end
|
20
16
|
|
21
17
|
def destroy
|
22
|
-
attachment = @model.public_send(@
|
23
|
-
attachment&.purge
|
18
|
+
@attachment = @model.public_send(@attribute).find_by(id: params[:id])
|
19
|
+
@attachment&.purge
|
24
20
|
|
25
|
-
|
21
|
+
respond_to do |format|
|
22
|
+
format.html { redirect_to request.referer || root_path, notice: "Attachment deleted successfully." }
|
23
|
+
format.turbo_stream
|
24
|
+
end
|
26
25
|
end
|
27
26
|
|
28
27
|
private
|
29
28
|
|
30
29
|
def set_objects
|
31
|
-
@
|
32
|
-
@model = GlobalID::Locator.locate_signed(params[:sgid], for:
|
30
|
+
@attribute = params[:attribute] || "attachments"
|
31
|
+
@model = GlobalID::Locator.locate_signed(params[:sgid], for: "satis_attachments")
|
33
32
|
end
|
34
33
|
end
|
35
|
-
end
|
34
|
+
end
|
@@ -1,29 +1,48 @@
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
2
|
+
import { post } from "@rails/request.js"
|
2
3
|
|
3
4
|
export default class AttachmentUploadController extends Controller {
|
4
|
-
static targets = ["
|
5
|
+
static targets = ["button"]
|
6
|
+
|
7
|
+
static values = {
|
8
|
+
url: String,
|
9
|
+
parameterName: String
|
10
|
+
}
|
5
11
|
|
6
12
|
connect() {
|
7
13
|
this.createFileInput()
|
8
14
|
this.addEventListeners()
|
9
15
|
}
|
10
16
|
|
17
|
+
disconnect() {
|
18
|
+
this.fileInput.removeEventListener("change", this.handleChange.bind(this))
|
19
|
+
this.element.removeEventListener("dragover", this.handleDragOver.bind(this))
|
20
|
+
this.element.removeEventListener("dragleave", this.handleDragLeave.bind(this))
|
21
|
+
this.element.removeEventListener("dragenter", this.handleDragEnter.bind(this))
|
22
|
+
this.element.removeEventListener("drop", this.handleDrop.bind(this))
|
23
|
+
}
|
24
|
+
|
11
25
|
createFileInput() {
|
26
|
+
// Mimic rails - this hiddenInput should prevent "old" files from being deleted
|
27
|
+
const hiddenInput = document.createElement("input")
|
28
|
+
hiddenInput.setAttribute("name", `${this.parameterNameValue}[]`)
|
29
|
+
hiddenInput.setAttribute("type", "hidden")
|
30
|
+
hiddenInput.setAttribute("autocomplete", "off")
|
31
|
+
|
32
|
+
this.element.closest('form').appendChild(hiddenInput)
|
33
|
+
|
12
34
|
const input = document.createElement("input")
|
13
|
-
|
35
|
+
|
36
|
+
input.setAttribute("name", `${this.parameterNameValue}[]`)
|
14
37
|
input.setAttribute("type", "file")
|
15
38
|
input.setAttribute("multiple", "multiple")
|
16
39
|
input.style.display = "none"
|
17
|
-
this.element.appendChild(input)
|
18
|
-
this.fileInput = input
|
19
40
|
|
20
|
-
|
21
|
-
|
22
|
-
}
|
41
|
+
this.element.closest('form').appendChild(input)
|
42
|
+
this.fileInput = input
|
23
43
|
}
|
24
44
|
|
25
45
|
addEventListeners() {
|
26
|
-
this.element.addEventListener("click", this.handleClick.bind(this))
|
27
46
|
this.fileInput.addEventListener("change", this.handleChange.bind(this))
|
28
47
|
this.element.addEventListener("dragover", this.handleDragOver.bind(this))
|
29
48
|
this.element.addEventListener("dragleave", this.handleDragLeave.bind(this))
|
@@ -32,12 +51,15 @@ export default class AttachmentUploadController extends Controller {
|
|
32
51
|
}
|
33
52
|
|
34
53
|
handleClick(event) {
|
35
|
-
event.preventDefault()
|
36
54
|
this.fileInput.click()
|
37
55
|
}
|
38
56
|
|
39
57
|
handleChange(event) {
|
40
|
-
this.
|
58
|
+
if (this.hasUrlValue) {
|
59
|
+
this.upload(event.target.files)
|
60
|
+
} else {
|
61
|
+
this.buttonTarget.innerHTML = `${event.target.files.length} files selected`
|
62
|
+
}
|
41
63
|
}
|
42
64
|
|
43
65
|
handleDragOver(event) {
|
@@ -59,7 +81,11 @@ export default class AttachmentUploadController extends Controller {
|
|
59
81
|
event.preventDefault()
|
60
82
|
this.element.classList.remove("dragging")
|
61
83
|
if (event.dataTransfer.files.length > 0) {
|
62
|
-
this.
|
84
|
+
if (this.hasUrlValue) {
|
85
|
+
this.upload(event.dataTransfer.files)
|
86
|
+
} else {
|
87
|
+
this.buttonTarget.innerHTML = `${event.dataTransfer.files.length} files selected`
|
88
|
+
}
|
63
89
|
}
|
64
90
|
}
|
65
91
|
|
@@ -68,41 +94,17 @@ export default class AttachmentUploadController extends Controller {
|
|
68
94
|
if (files.length === 0) return
|
69
95
|
|
70
96
|
let formData = new FormData()
|
71
|
-
if (this.data.has("extra-data")) {
|
72
|
-
for (let [key, value] of Object.entries(JSON.parse(this.data.get("extra-data")))) {
|
73
|
-
formData.append(key, value)
|
74
|
-
}
|
75
|
-
}
|
76
97
|
|
77
98
|
for (let i = 0; i < files.length; i++) {
|
78
|
-
formData.append(
|
99
|
+
formData.append("attachments", files[i])
|
79
100
|
}
|
80
101
|
|
81
102
|
this.element.classList.add("uploading")
|
82
103
|
|
83
|
-
|
84
|
-
method: 'POST',
|
104
|
+
post(this.urlValue, {
|
85
105
|
body: formData,
|
86
|
-
|
87
|
-
|
88
|
-
'Accept': 'text/html, application/json'
|
89
|
-
},
|
90
|
-
redirect: 'follow' // Important: follow redirects
|
91
|
-
}).then((response) => {
|
92
|
-
// Check if the response is a redirect
|
93
|
-
if (response.type === 'opaqueredirect' || response.redirected) {
|
94
|
-
window.location.href = response.url
|
95
|
-
return
|
96
|
-
}
|
97
|
-
|
98
|
-
if (response.ok) {
|
99
|
-
this.element.classList.remove("uploading")
|
100
|
-
window.location.reload(true)
|
101
|
-
} else {
|
102
|
-
throw new Error(response.statusText)
|
103
|
-
}
|
104
|
-
}).catch((error) => {
|
105
|
-
console.log(error)
|
106
|
+
responseKind: 'turbo-stream'
|
107
|
+
}).then(html => {
|
106
108
|
this.element.classList.remove("uploading")
|
107
109
|
})
|
108
110
|
}
|
@@ -59,9 +59,6 @@ application.register("satis-fields-for", FieldsForController);
|
|
59
59
|
import AttachmentUploadController from "satis/controllers/attachment_upload_controller";
|
60
60
|
application.register("satis-attachment-upload", AttachmentUploadController);
|
61
61
|
|
62
|
-
import AttachmentDeleteController from "satis/controllers/attachment_delete_controller";
|
63
|
-
application.register("satis-attachment-delete", AttachmentDeleteController);
|
64
|
-
|
65
62
|
import FormController from "satis/controllers/form_controller";
|
66
63
|
application.register("satis-form", FormController);
|
67
64
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
div.attachments__attachment style=(attachment.representable? ? "background-image: url(#{attachment.representation(resize_to_limit: [200, 200]).processed.url})" : "background-color: f0f0f0") id="attachment_#{attachment.id}"
|
2
|
+
- unless attachment.representable?
|
3
|
+
div.preview-text
|
4
|
+
i.fas.fa-file(aria-hidden="true")
|
5
|
+
|
6
|
+
= link_to Satis::Engine.routes.url_helpers.attachment_path(attachment, sgid: attachment.record.to_sgid(expires_in: nil, for: "satis_attachments"), attribute: attachment.name), data: {turbo_method: :delete, turbo_confirm: "Are you sure you want to delete this attachment?"}, class: 'attachments__button' do
|
7
|
+
i.fas.fa-trash
|
8
|
+
|
9
|
+
= link_to Rails.application.routes.url_helpers.rails_blob_url(attachment, host: request.host + ":#{request.port}"), data: { turbo: false, turbolinks: false }, class: 'attachments__button', download: attachment.filename do
|
10
|
+
i.fas.fa-download
|
11
|
+
|
12
|
+
span.attachments__filename
|
13
|
+
= attachment.filename
|
@@ -0,0 +1 @@
|
|
1
|
+
= turbo_stream.append "#{@attachments.first.record.id}_#{@attachments.first.name}_attachments", partial: "satis/attachments/attachment", collection: @attachments
|
@@ -0,0 +1 @@
|
|
1
|
+
= turbo_stream.remove "attachment_#{@attachment.id}"
|
data/lib/satis/forms/builder.rb
CHANGED
@@ -81,7 +81,7 @@ module Satis
|
|
81
81
|
# FIXME: Yuk - is it possible to detect when this should not be allowed?
|
82
82
|
# Like checking for whether destroy is allowed on assocations?
|
83
83
|
allow_actions = options.key?(:allow_actions) ? options[:allow_actions] : true
|
84
|
-
show_actions = @object.respond_to?("#{name}_attributes=") && @object.send(name).respond_to?(:each) && template_object && allow_actions == true
|
84
|
+
show_actions = @object.respond_to?(:"#{name}_attributes=") && @object.send(name).respond_to?(:each) && template_object && allow_actions == true
|
85
85
|
|
86
86
|
html_options = options[:html] || {}
|
87
87
|
|
@@ -156,6 +156,14 @@ module Satis
|
|
156
156
|
hidden_input(method, options, &block)
|
157
157
|
end
|
158
158
|
|
159
|
+
def attachments(method, options = {}, &block)
|
160
|
+
self.multipart = true
|
161
|
+
safe_join [
|
162
|
+
@template.render(Satis::Attachments::Component.new(object, method, form: self, **value_text_method_options(options),
|
163
|
+
&block))
|
164
|
+
]
|
165
|
+
end
|
166
|
+
|
159
167
|
# Non public
|
160
168
|
|
161
169
|
def input_type_for(method, options)
|
@@ -181,7 +189,7 @@ module Satis
|
|
181
189
|
def form_group(method, options = {}, &block)
|
182
190
|
tag.div(class: "form-group form-group-#{method}", data: options.delete(:data)) do
|
183
191
|
safe_join [
|
184
|
-
|
192
|
+
yield,
|
185
193
|
hint_text(options[:hint]),
|
186
194
|
error_text(method)
|
187
195
|
].compact
|
data/lib/satis/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: satis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.50
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom de Grunt
|
@@ -871,7 +871,6 @@ files:
|
|
871
871
|
- app/javascript/satis/application.js
|
872
872
|
- app/javascript/satis/controllers/application.js
|
873
873
|
- app/javascript/satis/controllers/application_controller.js
|
874
|
-
- app/javascript/satis/controllers/attachment_delete_controller.js
|
875
874
|
- app/javascript/satis/controllers/attachment_upload_controller.js
|
876
875
|
- app/javascript/satis/controllers/fields_for_controller.js
|
877
876
|
- app/javascript/satis/controllers/file_controller.js
|
@@ -890,6 +889,9 @@ files:
|
|
890
889
|
- app/mailers/satis/application_mailer.rb
|
891
890
|
- app/models/satis/application_record.rb
|
892
891
|
- app/models/satis/user_data.rb
|
892
|
+
- app/views/satis/attachments/_attachment.html.slim
|
893
|
+
- app/views/satis/attachments/create.turbo_stream.slim
|
894
|
+
- app/views/satis/attachments/destroy.turbo_stream.slim
|
893
895
|
- app/views/satis/documentation/avatars/index.html.slim
|
894
896
|
- app/views/satis/documentation/cards/index.html.slim
|
895
897
|
- app/views/satis/documentation/editors/index.html.slim
|
@@ -1,48 +0,0 @@
|
|
1
|
-
import { Controller } from "@hotwired/stimulus"
|
2
|
-
import { get } from '@rails/request.js'
|
3
|
-
|
4
|
-
/***
|
5
|
-
* Delete attachments controller
|
6
|
-
*
|
7
|
-
* Deletes an attachments
|
8
|
-
*/
|
9
|
-
export default class AttachmentDeleteController extends Controller {
|
10
|
-
connect() {}
|
11
|
-
|
12
|
-
delete(event) {
|
13
|
-
const self = this
|
14
|
-
|
15
|
-
event.stopPropagation()
|
16
|
-
event.preventDefault()
|
17
|
-
|
18
|
-
const formData = new FormData()
|
19
|
-
formData.append("_method", "DELETE")
|
20
|
-
|
21
|
-
fetch(self.element.getAttribute("href"), {
|
22
|
-
method: "POST",
|
23
|
-
headers: {
|
24
|
-
"X-CSRF-Token": document.querySelector("meta[name=csrf-token]").content,
|
25
|
-
},
|
26
|
-
body: formData,
|
27
|
-
})
|
28
|
-
.then(self.handleErrors)
|
29
|
-
.then((response) => {
|
30
|
-
window.location.reload(true);
|
31
|
-
response.json().then(function (data) {
|
32
|
-
let node = document.querySelector(data.selector)
|
33
|
-
if (node) {
|
34
|
-
node.innerHTML = data.html
|
35
|
-
}
|
36
|
-
})
|
37
|
-
})
|
38
|
-
.catch((error) => {
|
39
|
-
console.log(error)
|
40
|
-
})
|
41
|
-
return false
|
42
|
-
}
|
43
|
-
|
44
|
-
handleErrors(response) {
|
45
|
-
if (!response.ok) throw new Error(response.status)
|
46
|
-
return response
|
47
|
-
}
|
48
|
-
}
|