potassium 6.5.0 → 6.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +30 -1
  4. data/docs/CONTRIBUTING.md +2 -2
  5. data/lib/potassium/assets/.circleci/config.yml.erb +31 -8
  6. data/lib/potassium/assets/.eslintrc.json +16 -9
  7. data/lib/potassium/assets/.rubocop.yml +1 -0
  8. data/lib/potassium/assets/Aptfile +5 -0
  9. data/lib/potassium/assets/README.yml +30 -6
  10. data/lib/potassium/assets/active_admin/admin-component.vue +22 -30
  11. data/lib/potassium/assets/app/javascript/api/index.ts +55 -0
  12. data/lib/potassium/assets/app/javascript/{app.spec.js → components/app.spec.ts} +1 -1
  13. data/lib/potassium/assets/app/javascript/components/app.vue +9 -0
  14. data/lib/potassium/assets/app/javascript/types/vue.d.ts +5 -0
  15. data/lib/potassium/assets/app/javascript/utils/case-converter.ts +39 -0
  16. data/lib/potassium/assets/app/jobs/shrine_promote_job.rb +14 -0
  17. data/lib/potassium/assets/app/mailers/application_mailer.rb +1 -1
  18. data/lib/potassium/assets/app/mailers/example_mailer.rb +6 -0
  19. data/lib/potassium/assets/app/serializers/base_serializer.rb +3 -0
  20. data/lib/potassium/assets/app/serializers/concerns/image_handling_attributes.rb +20 -0
  21. data/lib/potassium/assets/app/uploaders/cover_image_uploader.rb +52 -0
  22. data/lib/potassium/assets/app/views/example_mailer/example_mail.html.mjml +7 -0
  23. data/lib/potassium/assets/app/views/layouts/default_mail.html.mjml +49 -0
  24. data/lib/potassium/assets/config/initializers/shrine/plugins/image_handling_utilities.rb +143 -0
  25. data/lib/potassium/assets/config/mailer.rb.erb +0 -2
  26. data/lib/potassium/assets/config/shrine.rb +15 -0
  27. data/lib/potassium/assets/config/webpack/rules/css.js +5 -0
  28. data/lib/potassium/assets/config/webpack/rules/index.js +11 -0
  29. data/lib/potassium/assets/config/webpack/rules/jquery.js +11 -0
  30. data/lib/potassium/assets/config/webpack/rules/typescript.js +32 -0
  31. data/lib/potassium/assets/config/webpack/rules/vue.js +19 -0
  32. data/lib/potassium/assets/config/webpack/webpack.config.js +4 -0
  33. data/lib/potassium/assets/public/mails/platanus-logo.png +0 -0
  34. data/lib/potassium/assets/tsconfig.json +32 -0
  35. data/lib/potassium/cli/commands/create.rb +3 -1
  36. data/lib/potassium/cli_options.rb +15 -3
  37. data/lib/potassium/platanus_config.rb +20 -0
  38. data/lib/potassium/recipes/admin.rb +50 -1
  39. data/lib/potassium/recipes/api.rb +6 -85
  40. data/lib/potassium/recipes/coverage.rb +31 -0
  41. data/lib/potassium/recipes/file_storage.rb +50 -0
  42. data/lib/potassium/recipes/front_end.rb +96 -110
  43. data/lib/potassium/recipes/google_tag_manager.rb +1 -1
  44. data/lib/potassium/recipes/mailer.rb +22 -10
  45. data/lib/potassium/recipes/mjml.rb +31 -0
  46. data/lib/potassium/recipes/node.rb +11 -13
  47. data/lib/potassium/recipes/style.rb +10 -2
  48. data/lib/potassium/recipes/vue_admin.rb +38 -8
  49. data/lib/potassium/templates/application.rb +1 -0
  50. data/lib/potassium/version.rb +8 -3
  51. data/spec/features/api_spec.rb +6 -1
  52. data/spec/features/coverage_spec.rb +17 -0
  53. data/spec/features/file_storage_spec.rb +102 -26
  54. data/spec/features/front_end_spec.rb +17 -46
  55. data/spec/features/mailer_spec.rb +79 -33
  56. data/spec/features/mjml_spec.rb +53 -0
  57. data/spec/features/vue_admin_spec.rb +0 -10
  58. data/spec/support/shared_examples.rb +5 -0
  59. metadata +30 -21
  60. data/lib/potassium/assets/active_admin/admin_application.js +0 -14
  61. data/lib/potassium/assets/active_admin/init_activeadmin_vue.rb +0 -10
  62. data/lib/potassium/assets/app/graphql/graphql_controller.rb +0 -55
  63. data/lib/potassium/assets/app/graphql/mutations/login_mutation.rb +0 -23
  64. data/lib/potassium/assets/app/graphql/queries/base_query.rb +0 -4
  65. data/lib/potassium/assets/app/graphql/types/base/base_argument.rb +0 -4
  66. data/lib/potassium/assets/app/graphql/types/base/base_enum.rb +0 -4
  67. data/lib/potassium/assets/app/graphql/types/base/base_field.rb +0 -5
  68. data/lib/potassium/assets/app/graphql/types/base/base_input_object.rb +0 -5
  69. data/lib/potassium/assets/app/graphql/types/base/base_interface.rb +0 -7
  70. data/lib/potassium/assets/app/graphql/types/base/base_object.rb +0 -5
  71. data/lib/potassium/assets/app/graphql/types/base/base_scalar.rb +0 -4
  72. data/lib/potassium/assets/app/graphql/types/base/base_union.rb +0 -4
  73. data/lib/potassium/assets/app/graphql/types/mutation_type.rb +0 -10
  74. data/lib/potassium/assets/app/graphql/types/query_type.rb +0 -13
  75. data/lib/potassium/assets/config/graphql_playground.rb +0 -20
  76. data/spec/features/graphql_spec.rb +0 -71
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf3d3969e70d29a2f2c15992c48f609ad389a486560fd6a16ea3a74871328a19
4
- data.tar.gz: c1617bc3cba761408d2cba7419fbe4c68cb265a7438ea07b8c9b637944e3271d
3
+ metadata.gz: 81ec8c6408ed21f78421ecb48565bcd42e6478fc0a08a7ca0881035eb8d0c444
4
+ data.tar.gz: 0b925fa5a1344c3f284d91f8fdb092d984d47f8434b4beed51678e4a909e2ada
5
5
  SHA512:
6
- metadata.gz: 61cbdbbced51469867a32a83a97628f8ea4ccfb3290cc2b2e6e8a34f86e53a6e0478609326264b59324266b8db184cd449d921a9f17cc3f5a58be01eddb00e3b
7
- data.tar.gz: '00900211ab3d5dcb75e4f45889778c752cda9f61a7e8d8cd0e264bb1ba678c50f8b9593f8bb98c3afd8b2fa554458cb639bfba202428a978976872cf45d291a5'
6
+ metadata.gz: 8a07cf43e021c0350e84eb0213f5ac513fa2446c16cfd492a0b7947acdd45776b817004d5f4cf42962947137dc988ccaa1e61020f23b89a63040b85d04e61a2e
7
+ data.tar.gz: af4598c990bede9a8be8cbf47dd324f9f13b584b5b0982ab277806f71318b4d97da289e9cad725d45398e66cc7454578bd89fc086b550ebc586286d46d217f98
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.7.0
4
+
5
+ Features
6
+ - Add type checking to reviewdog [#411](https://github.com/platanus/potassium/pull/411)
7
+ - Add initial api files [#412](https://github.com/platanus/potassium/pull/412)
8
+ - Add eslint-plugin-platanus [#415](https://github.com/platanus/potassium/pull/415)
9
+
10
+ Fixes
11
+ - Prepend vips installation [#407](https://github.com/platanus/potassium/pull/407)
12
+ - Fix jest install [#408](https://github.com/platanus/potassium/pull/408)
13
+ - Fix circle ci config. Provide global context to test job [#409](https://github.com/platanus/potassium/pull/409)
14
+ - Fix admin css (arctic_skin) [#413](https://github.com/platanus/potassium/pull/413)
15
+ - Fix tsc check [#414](https://github.com/platanus/potassium/pull/414)
16
+ - Fix monkeyci commenting because of uncovered lines when tests do exist [#416](https://github.com/platanus/potassium/pull/416)
17
+ - Typescript fixes [#417](https://github.com/platanus/potassium/pull/417)
18
+
19
+ ## 6.6.0
20
+ Features
21
+ - Update power api gem to use v2.0.0. Install "internal" API mode [#394](https://github.com/platanus/potassium/pull/394)
22
+ - Updates Webpacker to Shakapacker, upgrading Vue and TailwindCSS to their latest versions [#395](https://github.com/platanus/potassium/pull/395)
23
+ - Add some image handling and processing in shrine file storage option [#398](https://github.com/platanus/potassium/pull/398)
24
+ - Include `--platanus-config` option to skip most of the instalation options [#399](https://github.com/platanus/potassium/pull/399).
25
+ - Add [`rubocop-platanus`](https://github.com/platanus/rubocop-platanus) gem for linting platanus' best practices [#402](https://github.com/platanus/potassium/pull/402).
26
+ - Remove graphql option [#404](https://github.com/platanus/potassium/pull/404)
27
+ - Add frontend testing coverage for Jest [#401](https://github.com/platanus/potassium/pull/401) and associated reviewdog comments [#406](https://github.com/platanus/potassium/pull/406)
28
+ - Add MJML to handle mail templates, with example [#405](https://github.com/platanus/potassium/pull/405)
29
+
30
+ Fixes
31
+ - Add missing vips CI config when selecting shrine [#403](https://github.com/platanus/potassium/pull/403).
32
+ - Fix shakapacker to version 6.2.x to avoid [this bug](https://github.com/shakacode/shakapacker/issues/123) [#404](https://github.com/platanus/potassium/pull/404)
33
+
3
34
  ## 6.5.0
4
35
 
5
36
  Features
@@ -9,9 +40,12 @@ Features
9
40
  - Add SimpleCov recipe [#387](https://github.com/platanus/potassium/pull/387)
10
41
  - Update Rails to 6.1 [#389](https://github.com/platanus/potassium/pull/389) & [#392](https://github.com/platanus/potassium/pull/392)
11
42
  - Include `run_test` as a valid example group [#379](https://github.com/platanus/potassium/pull/379). This was added incorrectly in this [PR](https://github.com/platanus/potassium/pull/379).
43
+ - Add system tests configuration [#388](https://github.com/platanus/potassium/pull/388)
44
+ - Allow CircleCI cache clearing [#383](https://github.com/platanus/potassium/pull/383)
12
45
 
13
46
  Fixes
14
47
  - Remove rails_stdout_logging gem because it is no longer needed after Rails 5 and it was generating a deprecation warning [#325](https://github.com/platanus/potassium/pull/325)
48
+ - Fix default action dissapearance when using `binding.pry` in generated projects [#385](https://github.com/platanus/potassium/pull/385)
15
49
 
16
50
  ## 6.4.0
17
51
 
data/README.md CHANGED
@@ -21,6 +21,34 @@ Use the `potassium create` command to create a new project:
21
21
  > 2. If you feel that it's too slow, you may need to update rubygems: `gem update --system`.
22
22
  > 3. Potassium uses node under the hood, so a check will also be performed to ensure you are running the supported version.
23
23
 
24
+ #### Platanus Configutarion
25
+
26
+ In case you want to use the Platanus Configuration you should use the following command:
27
+
28
+ $ potassium create <project-name> --platanus-config
29
+
30
+ This will create a project with the following configuration:
31
+ 1. `database`: `'postgresql'`
32
+ 2. `local`: `'es-CL'`
33
+ 3. `email_service`: `'sendgrid'`
34
+ 4. `devise`: `true`
35
+ 5. `devise-user-model`: `true`
36
+ 6. `admin`: `true`
37
+ 7. `vue_admin`: `true`
38
+ 8. `pundit`: `true`
39
+ 9. `api`: `true`
40
+ 10. `storage`: `'shrine'`
41
+ 11. `heroku`: `true`
42
+ 12. `background_processor`: `true`
43
+ 13. `draper`: `true`
44
+ 14. `schedule`: `true`
45
+ 15. `sentry`: `true`
46
+ 16. `front_end`: `'vue'`
47
+ 17. `google_tag_manager`: `true`
48
+ 18. `test`: `true`
49
+ 19. `spring`: `true`
50
+
51
+ The remaining question will be asked as usual.
24
52
  ### Adding recipes to an existing project
25
53
 
26
54
  Use the `potassium install` command to add a recipe to a project:
@@ -53,6 +81,7 @@ Potassium Rails apps includes the following gems and technologies:
53
81
  - [Tzinfo-Data](https://github.com/tzinfo/tzinfo-data) for updating timezone information
54
82
  - [Faker](https://github.com/stympy/faker) for creating development data
55
83
  - [Scout](https://github.com/scoutapp/scout_apm_ruby) for monitoring performance
84
+ - [Mjml](https://github.com/sighmon/mjml-rails) for mails style
56
85
 
57
86
  The following optional integrations are also added:
58
87
 
@@ -177,4 +206,4 @@ potassium is maintained by [platanus](http://platan.us).
177
206
 
178
207
  ## License
179
208
 
180
- Potassium is © 2014 Platanus, SPA. It is free software and may be redistributed under the terms specified in the LICENSE file.
209
+ Potassium is © 2014 Platanus, SPA. It is free software and may be redistributed under the terms specified in the [LICENSE](/LICENSE.txt) file.
data/docs/CONTRIBUTING.md CHANGED
@@ -54,7 +54,7 @@ This method is used if you need to ask something to the user before doing someth
54
54
  ```ruby
55
55
  def ask
56
56
  use_banana_split = answer(:banana_split) do
57
- Ask.confirm("Do you wan to use Banana Split?")
57
+ Ask.confirm("Do you want to use Banana Split?")
58
58
  end
59
59
  set(:use_banana_split, true) if use_banana_split
60
60
  end
@@ -103,7 +103,7 @@ For example if you run `portassium install devise` this will use
103
103
  [the recipe template](/lib/potassium/templates/recipe.rb) to load an execute the
104
104
  `install` method for the **devise** recipe.
105
105
 
106
- You can defined the main functionallity of a recipe in a private method and call
106
+ You can define the main functionallity of a recipe in a private method and call
107
107
  it from the `create` and `install` methods.
108
108
 
109
109
  ```ruby
@@ -78,6 +78,13 @@ commands:
78
78
  key: yarn-dependencies-{{ .Environment.YARN_CACHE_VERSION }}-{{ checksum "yarn.lock" }}
79
79
  paths:
80
80
  - node_modules
81
+ <%- if selected?(:storage, :shrine) -%>
82
+ - run:
83
+ name: Install apt and vips buildpack dependencies
84
+ command: |
85
+ xargs -a Aptfile sudo apt-get install
86
+ sudo apt-get install libvips
87
+ <%- end -%>
81
88
 
82
89
  jobs:
83
90
  test:
@@ -109,6 +116,12 @@ jobs:
109
116
  RSPEC_FORMAT_ARGS="-f progress --no-color -p 10"
110
117
  bundle exec rspec spec $RSPEC_FORMAT_ARGS $RSPEC_JUNIT_ARGS
111
118
 
119
+ - run:
120
+ name: Run simplecov
121
+ shell: /bin/bash
122
+ command: |
123
+ cat coverage/coverage.txt | ./bin/reviewdog -reporter=github-pr-review -efm="%f:%l:%c: %m"
124
+
112
125
  - run:
113
126
  name: Run RSpec system tests
114
127
  command: |
@@ -116,16 +129,13 @@ jobs:
116
129
  RSPEC_FORMAT_ARGS="--tag type:system -f progress --no-color -p 10"
117
130
  bundle exec rspec spec $RSPEC_FORMAT_ARGS $RSPEC_JUNIT_ARGS
118
131
 
119
- - run:
120
- name: Run simplecov
121
- shell: /bin/bash
122
- command: |
123
- cat coverage/coverage.txt | ./bin/reviewdog -reporter=github-pr-review -efm="%f:%l:%c: %m"
124
-
125
132
  <%- if selected?(:front_end, :vue) -%>
126
133
  - run:
127
134
  name: Run jest
128
- command: yarn run test
135
+ command: |
136
+ yarn run test > coverage/input_jest.txt
137
+ ./node_modules/.bin/format-coverage coverage/input_jest.txt coverage/output_jest.txt /home/circleci/project/app/javascript
138
+ cat coverage/output_jest.txt | ./bin/reviewdog -reporter=github-pr-review -efm="%f:%l:%c: %m"
129
139
  <%- end -%>
130
140
 
131
141
  - store_test_results:
@@ -154,6 +164,18 @@ jobs:
154
164
  cat tmp/files_to_lint | grep -E '.+\.(js|jsx|vue)$' | xargs yarn run eslint \
155
165
  | ./bin/reviewdog -reporter=github-pr-review -f=eslint
156
166
 
167
+ - run:
168
+ name: Run tsc
169
+ shell: /bin/bash
170
+ command: |
171
+ yarn run tsc --noEmit | ./bin/reviewdog -reporter=github-pr-review -f=tsc
172
+
173
+ - run:
174
+ name: Run vue-tsc
175
+ shell: /bin/bash
176
+ command: |
177
+ yarn run vue-tsc --noEmit | ./bin/reviewdog -reporter=github-pr-review -f=tsc
178
+
157
179
  - run:
158
180
  name: Run stylelint
159
181
  shell: /bin/bash
@@ -164,6 +186,7 @@ jobs:
164
186
  workflows:
165
187
  test_and_lint:
166
188
  jobs:
167
- - test
189
+ - test:
190
+ context: org-global
168
191
  - lint:
169
192
  context: org-global
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "env": {
3
- "es6": true
3
+ "browser": true,
4
+ "es2021": true,
5
+ "node": true,
6
+ "jest/globals": true,
7
+ "vue/setup-compiler-macros": true
4
8
  },
5
9
  "parserOptions": {
6
- "ecmaVersion": 2018,
10
+ "ecmaVersion": 2020,
7
11
  "sourceType": "module"
8
12
  },
9
- "plugins": ["import"],
13
+ "plugins": ["import", "jest", "tailwindcss"],
10
14
  "settings": {
11
15
  "import/resolver": {
12
16
  "node": {
@@ -15,7 +19,11 @@
15
19
  }
16
20
  },
17
21
  "extends": [
18
- "plugin:vue/strongly-recommended"
22
+ "plugin:vue/vue3-recommended",
23
+ "@vue/typescript/recommended",
24
+ "@vue/eslint-config-typescript",
25
+ "plugin:tailwindcss/recommended",
26
+ "plugin:platanus/recommended"
19
27
  ],
20
28
  "rules": {
21
29
  "accessor-pairs": 0,
@@ -338,14 +346,13 @@
338
346
  "vue/max-len": ["error", {
339
347
  "code": 120,
340
348
  "ignoreHTMLAttributeValues": true
341
- }]
349
+ }]
342
350
  },
343
351
  "overrides": [
344
352
  {
345
- "files": ["**/*.js"],
346
- "excludedFiles": "app/**/*.js",
347
- "env": {
348
- "node": true
353
+ "files": ["*.ts", "*.vue"],
354
+ "rules": {
355
+ "no-undef": "off"
349
356
  }
350
357
  }
351
358
  ]
@@ -2,6 +2,7 @@ require:
2
2
  - rubocop-rspec
3
3
  - rubocop-rails
4
4
  - rubocop-performance
5
+ - rubocop-platanus
5
6
  AllCops:
6
7
  Exclude:
7
8
  - "vendor/**/*"
@@ -0,0 +1,5 @@
1
+ libglib2.0-0
2
+ libglib2.0-dev
3
+ libpoppler-glib8
4
+ libwebp-dev
5
+ webp
@@ -27,7 +27,7 @@ readme:
27
27
  body: |
28
28
  For hot-reloading and fast webpacker compilation you need to run webpack's dev server along with the rails server:
29
29
 
30
- $ ./bin/webpack-dev-server
30
+ $ ./bin/webpacker-dev-server
31
31
 
32
32
  Running the dev server will also solve problems with the cache not refreshing between changes and provide better error messages if something fails to compile.
33
33
 
@@ -105,7 +105,34 @@ readme:
105
105
  body: "For managing uploads, this project uses [Active Storage](https://github.com/rails/rails/tree/master/activestorage)."
106
106
  shrine:
107
107
  title: "File Storage"
108
- body: "For managing uploads, this project uses [Shrine](https://github.com/shrinerb/shrine)."
108
+ body: |
109
+ For managing uploads, this project uses [Shrine](https://github.com/shrinerb/shrine). When generated, this project includes the following files and configurations:
110
+
111
+ - `ImageUploader` that includes file type validation
112
+ - `CoverImageUploader`, inheriting from `ImageUploader`. It does a couple of things:
113
+ - Generates derivatives in `jpg` and `webp` format, for three different sizes. For an attachment of name `image`, to get the url for a derivative, let's say `sm`, you would do `record.image_url(:sm)`
114
+ - Saves a [blurhash](https://blurha.sh/) code to the attachment metadata
115
+ - `ImageHandlingUtilities`, a shrine plugin in the initializers folder that is used in the `CoverImageUploader`. Given a model with an attachment of name `image`, it adds the following methods to the model:
116
+ - `image_blurhash`: returns blurhash from metadata
117
+ - `generate_image_derivatives`: It generates all derivatives defined in Uploader. If file already had derivatives, it replaces them with newly generated ones. Associated class method: `generate_all_image_derivatives`
118
+ - `generate_image_metadata`: refreshes all metadata for attachment. Associated class method: `generate_all_image_metadata`
119
+ - `generate_image_derivatives_and_metadata`: does both previous things. Useful because it does so opening the file only once. Associated class method: `generate_all_image_derivatives_and_metadata`
120
+
121
+ Class methods are the same as their instance counterparts, but for collections. They also allow error handling on an individual record by passing a block to handle each error. If no block is given, attachments that throw errors are ignored and the iteration continues
122
+ - `ImageHandlingAttributes` serializer concern. It adds a method `add_image_handling_attributes` to all serializers that inherit from `BaseSerializer`. Considering an attachment of name `image`, this method adds two attributes to the serialized record:
123
+ - `image_blurhash`
124
+ - `image`. This is a hash that includes urls for all derivatives passed to the method. For example:
125
+ ```
126
+ add_image_handling_attributes(attachment_name: :image, derivatives: [:sm, :md], include_original_image: true)
127
+
128
+ # results in the following hash for the image attribute:
129
+ # {
130
+ # sm: { url: 'someurl.com/bla' },
131
+ # md: { url: 'someurl.com/ble' },
132
+ # original: { url: 'someurl.com/ble' }
133
+ # }
134
+ ```
135
+ - `SHRINE_SECRET_KEY` environment variable. It comes witha value set in `.env.development`, but you'll need to set one for it in staging and production. It can be any random value, generating it with `SecureRandom.hex` for instance
109
136
  pundit:
110
137
  title: "Authorization"
111
138
  body: "For defining which parts of the system each user has access to, we have chosen to include the [Pundit](https://github.com/elabs/pundit) gem, by [Elabs](http://elabs.se/)."
@@ -127,16 +154,13 @@ readme:
127
154
  power_api:
128
155
  title: "API Support"
129
156
  body: "This projects uses [Power API](https://github.com/platanus/power_api). It's a Rails engine that gathers a set of gems and configurations designed to build incredible REST APIs."
130
- graphql:
131
- title: "API Support"
132
- body: "This projects uses [graphql-ruby](https://graphql-ruby.org/) to generate a GraphQL API."
133
157
  active_admin:
134
158
  title: "Administration"
135
159
  body: |
136
160
  This project uses [Active Admin](https://github.com/activeadmin/activeadmin) which is a Ruby on Rails framework for creating elegant backends for website administration.
137
161
  <% if get(:vue_admin) %>
138
162
  This project supports Vue inside ActiveAdmin
139
- - The main package is located in `app/javascript/packs/admin_application.js`, here you will declare the components you want to include in your ActiveAdmin views as you would in a normal Vue App.
163
+ - The main package is located in `app/javascript/active_admin.js`, here you will declare the components you want to include in your ActiveAdmin views as you would in a normal Vue App.
140
164
  - Additionally, to be able to use Vue components as [Arbre](https://github.com/activeadmin/arbre) Nodes the component names are also declared in `config/initializers/active_admin.rb`
141
165
  - The generator includes an example component called `admin_component`, you can use this component inside any ActiveAdmin view by just writing `admin_component` as you would with any `html` tag.
142
166
  - For example:
@@ -1,35 +1,27 @@
1
+ <script setup lang="ts">
2
+ interface Props {
3
+ test?: string
4
+ testNumber?: number
5
+ testObject?: {[key: string]: string},
6
+ testList?: number[],
7
+ }
8
+
9
+ const props = withDefaults(
10
+ defineProps<Props>(),
11
+ {
12
+ test: undefined,
13
+ testNumber: 0,
14
+ testObject: undefined,
15
+ testList: undefined,
16
+ },
17
+ );
18
+
19
+ const message = 'Hello World';
20
+ </script>
21
+
1
22
  <template>
2
23
  <div>
3
- I am a Vue Component {{ test }} {{ message }}
24
+ I am a Vue Component {{ props.test }} {{ message }}
4
25
  <slot />
5
26
  </div>
6
27
  </template>
7
-
8
- <script>
9
- export default {
10
- props: {
11
- test: {
12
- type: String,
13
- default: '',
14
- },
15
- testNumber: {
16
- type: Number,
17
- default: 0,
18
- },
19
- testObject: {
20
- type: Object,
21
- default: null,
22
- },
23
- testList: {
24
- type: Array,
25
- default: null,
26
- },
27
- },
28
-
29
- data() {
30
- return {
31
- message: 'Hello World',
32
- };
33
- },
34
- };
35
- </script>
@@ -0,0 +1,55 @@
1
+ import axios, { type AxiosRequestTransformer, type AxiosResponseTransformer } from 'axios';
2
+ import convertKeys from '../utils/case-converter';
3
+
4
+ const api = axios.create({
5
+ transformRequest: [
6
+ (data: any) => convertKeys(data, 'decamelize'),
7
+ ...(axios.defaults.transformRequest as AxiosRequestTransformer[]),
8
+ ],
9
+ transformResponse: [
10
+ ...(axios.defaults.transformResponse as AxiosResponseTransformer[]),
11
+ (data: any) => convertKeys(data, 'camelize'),
12
+ ],
13
+ });
14
+
15
+ export default api;
16
+
17
+ /*
18
+ // Example to use the api object in the path ´app/javascript/api/users.ts´
19
+
20
+ import api from './index';
21
+
22
+ export default {
23
+ index() {
24
+ const path = '/api/internal/users';
25
+
26
+ return api({
27
+ method: 'get',
28
+ url: path,
29
+ });
30
+ },
31
+ create(data: Partial<User>) {
32
+ const path = '/api/internal/users';
33
+
34
+ return api({
35
+ method: 'post',
36
+ url: path,
37
+ data: {
38
+ user: data,
39
+ },
40
+ });
41
+ },
42
+ update(data: Partial<User>) {
43
+ const path = `/api/internal/users/${data.id}`;
44
+
45
+ return api({
46
+ method: 'put',
47
+ url: path,
48
+ data: {
49
+ user: data,
50
+ },
51
+ });
52
+ },
53
+ };
54
+
55
+ */
@@ -1,5 +1,5 @@
1
1
  import { shallowMount } from '@vue/test-utils';
2
- import App from 'app';
2
+ import App from './app.vue';
3
3
 
4
4
  describe('App', () => {
5
5
  test('is a Vue instance', () => {
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ const message = 'Hello Vue!';
3
+ </script>
4
+
5
+ <template>
6
+ <div id="app">
7
+ <p class="text-center text-lg">{{ message }}</p>
8
+ </div>
9
+ </template>
@@ -0,0 +1,5 @@
1
+ declare module '*.vue' {
2
+ import type { DefineComponent } from 'vue'
3
+ const component: DefineComponent<{}, {}, any>
4
+ export default component
5
+ }
@@ -0,0 +1,39 @@
1
+ // From https://github.com/domchristie/humps/issues/51#issuecomment-425113505
2
+ /* eslint-disable complexity */
3
+ /* eslint-disable max-statements */
4
+ import { camelize, decamelize } from 'humps';
5
+
6
+ type objectToConvert = File | FormData | Blob | Record<string, unknown> | Array<objectToConvert>;
7
+
8
+ function convertKeys(
9
+ object: objectToConvert,
10
+ conversion: 'camelize' | 'decamelize',
11
+ ): objectToConvert {
12
+ const converter = {
13
+ camelize,
14
+ decamelize,
15
+ };
16
+ if (object && !(object instanceof File) && !(object instanceof Blob)) {
17
+ if (object instanceof Array) {
18
+ return object.map((item: objectToConvert) => convertKeys(item, conversion));
19
+ }
20
+ if (object instanceof FormData) {
21
+ const formData = new FormData();
22
+ for (const [key, value] of object.entries()) {
23
+ formData.append(converter[conversion](key), value);
24
+ }
25
+
26
+ return formData;
27
+ }
28
+ if (typeof object === 'object') {
29
+ return Object.keys(object).reduce((acc, next) => ({
30
+ ...acc,
31
+ [converter[conversion](next)]: convertKeys(object[next] as objectToConvert, conversion),
32
+ }), {});
33
+ }
34
+ }
35
+
36
+ return object;
37
+ }
38
+
39
+ export default convertKeys;
@@ -0,0 +1,14 @@
1
+ class ShrinePromoteJob < ApplicationJob
2
+ queue_as :default
3
+
4
+ def perform(attacher_class, record_class, record_id, name, file_data)
5
+ attacher_class = Object.const_get(attacher_class)
6
+ record = Object.const_get(record_class).find(record_id)
7
+
8
+ attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
9
+ attacher.create_derivatives
10
+ attacher.atomic_promote
11
+ rescue Shrine::AttachmentChanged, ActiveRecord::RecordNotFound
12
+ # attachment has changed or the record has been deleted, nothing to do
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  class ApplicationMailer < ActionMailer::Base
2
- layout 'mailer'
2
+ layout 'default_mail'
3
3
  end
@@ -0,0 +1,6 @@
1
+ class ExampleMailer < ApplicationMailer
2
+ def example_mail
3
+ @email = params[:email]
4
+ mail(from: 'admin@example.com', to: @email, subject: 'Welcome to Potassium')
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ class BaseSerializer < ActiveModel::Serializer
2
+ include ImageHandlingAttributes
3
+ end
@@ -0,0 +1,20 @@
1
+ module ImageHandlingAttributes
2
+ extend ActiveSupport::Concern
3
+
4
+ class_methods do
5
+ def add_image_handling_attributes(attachment_name:, derivatives:, include_original_image: false)
6
+ attributes attachment_name, "#{attachment_name}_blurhash".to_sym
7
+
8
+ define_method(attachment_name) do
9
+ attachment_hash = derivatives.reduce({}) do |hash, derivative|
10
+ hash[derivative] = { url: object.send("#{attachment_name}_url", derivative) }
11
+ hash
12
+ end
13
+ if include_original_image
14
+ attachment_hash[:original] = { url: object.send("#{attachment_name}_url") }
15
+ end
16
+ attachment_hash
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ require "image_processing/vips"
2
+
3
+ class CoverImageUploader < ImageUploader
4
+ plugin :derivation_endpoint, prefix: "derivations/cover_image"
5
+ plugin :add_metadata
6
+ plugin :image_handling_utilities
7
+
8
+ DERIVATIVES = {
9
+ sm: { size: [426, 240], type: 'jpg' },
10
+ md: { size: [960, 540], type: 'jpg' },
11
+ lg: { size: [1280, 720], type: 'jpg' },
12
+ webp_sm: { size: [426, 240], type: 'webp' },
13
+ webp_md: { size: [960, 540], type: 'webp' },
14
+ webp_lg: { size: [1280, 720], type: 'webp' }
15
+ }
16
+
17
+ Attacher.derivatives do |original|
18
+ vips = ImageProcessing::Vips.source(original)
19
+
20
+ DERIVATIVES.reduce({}) do |derivatives_hash, (name, derivative_info)|
21
+ derivatives_hash[name] = vips.convert(derivative_info[:type]).resize_to_limit!(
22
+ *derivative_info[:size]
23
+ )
24
+ derivatives_hash
25
+ end
26
+ end
27
+
28
+ derivation :thumbnail do |file, width, height|
29
+ ImageProcessing::Vips
30
+ .source(file)
31
+ .resize_to_limit!(width.to_i, height.to_i)
32
+ end
33
+
34
+ Attacher.default_url do |derivative: nil, **|
35
+ file&.derivation_url(:thumbnail, *DERIVATIVES.dig(derivative, :size)) if derivative.present?
36
+ end
37
+
38
+ add_metadata :blurhash do |io, derivative: nil, **|
39
+ if derivative.nil?
40
+ Shrine.with_file(io) do |file|
41
+ image = Vips::Image.new_from_file(file.path, access: :sequential)
42
+ image = image.resize(100.0 / image.width)
43
+ flat_rgb_pixels = []
44
+ image.to_a.each do |row|
45
+ row.each { |pixel| flat_rgb_pixels.concat(pixel[0..2]) }
46
+ end
47
+
48
+ Blurhash.encode(image.width, image.height, flat_rgb_pixels)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,7 @@
1
+ <mj-section>
2
+ <mj-column>
3
+ <mj-text>
4
+ Hello <%= @email %>, welcome to Potassium
5
+ </mj-text>
6
+ </mj-column>
7
+ </mj-section>