baoagency / polaris_view_components

ViewComponents for Polaris Design System
https://polarisviewcomponents.org
MIT License
384 stars 54 forks source link

I placed a basic dropzone down, nothing happened #187

Closed resistorsoftware closed 2 years ago

resistorsoftware commented 2 years ago

I am trying the upload a file, direct to S3. I setup Rails Active Storage for that. I bundled in the latest code for this gem.

I dropped a Dropzone down. Can't drop files on it, or upload with the button? Seems dead. What am I missing? Am I supposed to wire up the button clicks and drag drop code manually? In other words, do I have to make some controller that gets loaded to work with this component?

<%= polaris_card(sectioned: true) do %>
    <%# With direct upload in ActiveStorage %>
    <%= form_with(model: @shop, builder: Polaris::FormBuilder) do |form| %>
      <%= form.polaris_dropzone :svg, accept: 'image/svg+xml', error_overlay_text: 'File type must be .svg', multiple: false,direct_upload: true %>
    <% end %>
  <% end %>
kirillplatonov commented 2 years ago

Probably the update JS package is missing. Do you use it with importmaps or esbuild?

resistorsoftware commented 2 years ago

I am not sure what you mean by the update JS package? Can you give me some idea of what that would mean? How would I know? My package.json is pretty clean so far..

{
  "name": "shopify-hotwire-sample",
  "private": true,
  "scripts": {
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds",
    "build:css": "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css"
  },
  "dependencies": {
    "@hotwired/stimulus": "^3.0.1",
    "@hotwired/turbo-rails": "^7.0.1",
    "@rails/request.js": "^0.0.6",
    "@shopify/app-bridge-utils": "^2.0.5",
    "autoprefixer": "^10.4.0",
    "dotenv": "^10.0.0",
    "dropzone": "^6.0.0-beta.2",
    "esbuild": "^0.13.10",
    "polaris-view-components": "^0.7.0",
    "postcss": "^8.4.4",
    "tailwindcss": "^3.0.1"
  },
  "version": "0.1.0",
  "devDependencies": {}
}

So I am getting an application.js as far as I know, from /assets/builds and the manifest. That does leave me a question though, as well thinking I am getting the application.js, I may not be? I know for the application.js.map which is built, is coming up 404. But that could be due to something entirely different. I see the files, but my server log is is throwing an error due to the map... I really don't get Sprockets for this.. but whatever.

ActionController::RoutingError (No route matches [GET] "/assets/application.js-693ce1287eb6aad8318845f16d6403edc107b765c87b5bad2f3b6558f2ab96ba.map"):

`

resistorsoftware commented 2 years ago

Since the Polaris code from the server defined the controller "polaris-dropzone", and some actions, as per Stimulus, I added a polaris_dropzone_controller.js file to the controllers in the App, and registered that... and then I saw that that hooked up the uploader.

So I guess that my duh moment, and that I have to write the controllers themselves for these Polaris View Components? I was under the impression that they came with their own JS controllers... my bad.

Is that in fact what we have to do, or is there a pattern in play where we not only get the luxury of throwing down components, but they come with their own JS controllers? If so, how do we leverage that?

kirillplatonov commented 2 years ago

You need to install an npm package from Github in order to use unreleased changes (like new Dropzone controller). You can do it via:

yarn add https://github.com/baoagency/polaris_view_components

You'll also need to install build-time dependency so esbuild could resolve dependencies properly:

yarn add @popperjs/core

Once v0.8.0 will be released you can switch back to npm package.

resistorsoftware commented 2 years ago

Ha! I have no idea what that means. I suppose the first thing, telling yarn to use the github, is more specific. OK. Let's say it is. What do I gain from this version? Does that preclude me having to build my own dropzone controller?

As for popperJS? Not sure what that even is, but I will add it, and see what happens!

Thanks!

resistorsoftware commented 2 years ago

Interesting, now I get a JS compilation error

node_modules/polaris-view-components/app/assets/javascripts/polaris_view_components/frame_controller.js:2:30: error: Could not resolve "stimulus-use" (mark it as external to exclude it from the bundle) 11:40:14 js.1 | 2 │ import { useTransition } from "stimulus-use"

resistorsoftware commented 2 years ago

So I naively did a yarn add stimulus-use, which really busted everything, as then stimulus itself failed in every include asking for it. So I stopped that, instead I added an --external:stimulus-use to esbuild, but that quieted down the build, leaving an error in the console saying Dynamic require of stimulus-use is not supported. Sigh..

And the 404 still happens on the map, and I still need my own JS controller for the Dropzone... as far as I can tell...

So I am anxious to know, what was the point of loading the latest JS and popper again?

kirillplatonov commented 2 years ago

Ha! I have no idea what that means. I suppose the first thing, telling yarn to use the github, is more specific. OK. Let's say it is. What do I gain from this version? Does that preclude me having to build my own dropzone controller?

As for popperJS? Not sure what that even is, but I will add it, and see what happens!

Thanks!

It will use the latest version from GitHub. PopperJS is used for popovers and autocomplete.

kirillplatonov commented 2 years ago

Interesting, now I get a JS compilation error

node_modules/polaris-view-components/app/assets/javascripts/polaris_view_components/frame_controller.js:2:30: error: Could not resolve "stimulus-use" (mark it as external to exclude it from the bundle)

11:40:14 js.1 | 2 │ import { useTransition } from "stimulus-use"

Okay. Run this to resolve the error: yarn add stimulus-use@beta

resistorsoftware commented 2 years ago

OK.. that is cleaner. No choking on stimulus-use.

So now my only burning question is... my polaris-dropzone-controller.js code. I have to write and wire up everything for that? I thought in inspecting this repo, you had written it all up.. but apparently, if you did, using it is another thing.

resistorsoftware commented 2 years ago

This is so strange. So I had made my own controller. And the connect() logged ME. My controller. But then I updated the code so that the JS came from Github and the latest JS.

When I noticed your code for the controller for the Dropzone, I pasted that code into my controller. But I noticed, nothing was triggering in my controller anymore. Hmmm.. I guess that means the one you wrote is now the boss!! By this I mean, I had a console.log() message I added in connect() and nothing was ever logged to console. That told me this code was not running.

So I remove my controller code. And sure enough, the file selector worked, and I could browse for an SVG file. Of course, the controller did nothing with the file.. but I am sure that fixable soon enough.

So that seems to answer my burning question. If I throw down a Polaris View Component in Ruby ERB, there is JS that goes with it, auto-provided.

How one overrides that, or hooks into it, is the next task for me I guess.

resistorsoftware commented 2 years ago

I added my S3 credentials to amazon: key in storage.yml for production. I left local as DIsk and the directory "storage". I then added @rails/activestorage, and in the manifest, the //= require activestorage.

At this point, I was hoping to see some action! But nothing. No files move. Being a rookie at some Rails stuff can really suck. I sure will be happy when I get this working!

resistorsoftware commented 2 years ago

The input element generated looks pretty good. Does not actually direct_upload like I want it to, but it is close!

<input accept="" multiple="multiple" data-action="focus->polaris-dropzone#onFocus blur->polaris-dropzone#onBlur change->polaris-dropzone#onChange" data-polaris-dropzone-target="input" data-direct-upload-url="https://banana.test/rails/active_storage/direct_uploads?shop=hans-solo.myshopify.com" type="file" name="file[]" id="file">

I am not sure how you intend this to all work, I am guessing there is a little bit of missing code with respect to Direct Upload and Rails.

resistorsoftware commented 2 years ago

I placed a bunch of logging in the dropzone controller js. So I get the click on the button, and it pulls up a file dialog, where I can pick a file, and it matches the accepts checking... One thing that does not happen though, is none of the direct-upload events fire. So, in a direct upload case, the selected file just sits... neat! I did not know I could just edit the node_modules code and get it live in my browser. Wowza..

In cross-referencing with Direct Uploads Rails documentation... they mention the form needs the direct upload url, token and attachment name... I only see the url in the HTML. And nothing that actually uploads. TBA. I am curious about this.

It is all interesting. A melding I suppose.

I naively threw down a Polaris submit button in the form, and pressing it did invoke the whole upload. It failed with a

ActiveStorage::InvalidDirectUploadTokenError (ActiveStorage::InvalidDirectUploadTokenError):

The values reported at the server were: "direct_upload_token"=>"[FILTERED]", "attachment_name"=>nil} so while did not see a value for the token... I am guessing I am close to the proverbial cigar in having this work.

But still. I can now see it is wired pretty well. Not sure why a submit button is an after thought, or how that will play out with the logic, but this is getting there.

I modified the dropzone_component.rb, such that the input element would generate a direct_upload_attachment_name which apparently is needed for Rails 7, and yet the token still did not validate. I inspected further, and see that the input element is generated with a file_field which is supposed to generate a correct direct-upload-attachment-name and direct-upload-token in the element! AHA... that is not happening for me. I guess I need to learn more about Rails 7 specifics.

I dunno. Guess I will sleep on it and try and figure it out tomorrow. That is a real problem though, direct uploads and Rails 7 and the token problem... https://github.com/rails/rails/issues/43895

resistorsoftware commented 2 years ago

Interesting. I stripped it down in the polaris view comonents to the file_field tag. It does not generate the needed token or attachment name when direct_upload is true. I am guessing that somehow the underlying file_file generator is not up to snuff. I updated the polaris view components I am using to feed off of Rails 7.0.1 but even that failed to improve the render of this crucial element with the correct parameters. Not sure where to turn now...

resistorsoftware commented 2 years ago

So, it seems like the Rails core team made some mistakes, and the advice for Rails 7 is to monkeypatch things back to the old way of doing things, as this new pattern is an itty bitty disaster. So I will follow that directive, betting all will suddenly start working!

resistorsoftware commented 2 years ago

Ok. So with the revert back to Rails 6 Direct Uploads, apparently still even that does not work well (who knew), the upload worked, with a file uploaded to the storage disk! Such progress! So in summary, Polaris View Component Dropzone, when coerced with an added Polaris submit button, submits a direct upload form, and that worked, with Rails 7.0.1, even though that version of Rails has very broken direct uploads!

The only problem now, is that it (the upload) pooped out when Rails blew chunks with the error No Route to POST /home.

I have zero clues as to how a direct upload in this world could finish uploading a file, and then try and POST to /home, but whatever.. I am sure there is an explanation for that somewhere.

resistorsoftware commented 2 years ago

Stuff that currently makes no sense to me.

  1. upload data information exists, in active_storage_blobs. a row dedicated to the file uploaded and info about it
  2. active_atorage_attachments and active_storage_variant_records remain blank

So now a file was uploaded, for a shop, and there is nothing connecting that file to the shop. Also, if the file took a long time to upload, and once it is uploaded, we need to run a job to work on the file, there is no apparent trigger we have to do this?

In the old ways, I would use CarrierWave, and if I added a method to run after the upload completed, in there I could run a job with the name of the shop, and the file.

How do people use this Rails ActiveStorage to achieve that? Nothing I have read so far informs me of these simple things. So much is not obvious with Rails.

resistorsoftware commented 2 years ago

Ok. So I added a column to shop, just simple "fizzbuzz" as a string. Used that fizzbbuzz as the directive to file_field on the Dropzone. Added a POST route to the /home, and saw the params. Neat. fizzbuzz was there. So I attached the upload sent, and wow. Now the attachments table has it, the blob is stored, and I know the store.

So now I can call up that file and do the work on it in a background job. Using an obnoxious but workable: Rails.application.routes.url_helpers.rails_blob_path(shop.fizzbuzz, only_path: true)

The post finished saving the attachment and I just redirected back to /home. Not stellar. But it all worked.

So I guess I am now OK somewhat with Dropzone! I will next get it working with S3 and see how much pain that causes me.

kirillplatonov commented 2 years ago

The issue with direct upload has been fixed in one of the latest Rails 7 releases. Tested it in my apps and it works fine with Dropzone now.

resistorsoftware commented 2 years ago

That was an amazing bit of bumbling that the Rails 7 release team put us all through. They remain dismissive of any use cases beyond what they currently express, with no empathy for people that may want to store files in a system like S3 with any kind of organization other than "Put this in that bucket". So interesting. I rarely interact with the Rails crowd, but it is so true that they are opinionated.