studio-engine 0.137.0 → 0.138.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +27 -1
  4. data/app/assets/tailwind/studio_engine/engine.css +228 -0
  5. data/app/controllers/concerns/studio/connection_flow.rb +1 -1
  6. data/app/controllers/sessions_controller.rb +12 -3
  7. data/app/controllers/studio/integrations_controller.rb +43 -0
  8. data/app/controllers/studio/local_reviews_controller.rb +12 -0
  9. data/app/javascript/studio/carousel.js +66 -0
  10. data/app/javascript/studio/controllers/carousel_controller.js +203 -1
  11. data/app/models/concerns/studio/account.rb +143 -0
  12. data/app/models/concerns/studio/omniauth_user.rb +9 -17
  13. data/app/models/error_log.rb +14 -5
  14. data/app/views/studio/_carousel.html.erb +58 -14
  15. data/app/views/studio/integrations/_card.html.erb +50 -0
  16. data/app/views/studio/integrations/index.html.erb +22 -0
  17. data/app/views/studio/integrations/show.html.erb +24 -0
  18. data/app/views/style/_tricks.html.erb +15 -0
  19. data/config/studio_tricks.yml +7 -0
  20. data/db/migrate/20261006120001_ensure_error_logs_table.rb +3 -1
  21. data/db/migrate/20261006120002_ensure_theme_settings_table.rb +3 -2
  22. data/db/migrate/20261108160000_require_slugs_on_engine_tables.rb +119 -0
  23. data/db/migrate/20261108160001_add_engine_state_checks.rb +94 -0
  24. data/db/migrate/20261108170000_add_users_role_known_check.rb +69 -0
  25. data/lib/generators/studio/connections/connections_generator.rb +10 -0
  26. data/lib/studio/connections.rb +53 -12
  27. data/lib/studio/integrations/egnyte.rb +69 -0
  28. data/lib/studio/integrations/microsoft_365.rb +63 -0
  29. data/lib/studio/integrations/quickbooks.rb +86 -0
  30. data/lib/studio/integrations.rb +265 -0
  31. data/lib/studio/node_tooling/README.md +9 -1
  32. data/lib/studio/node_tooling/e2e_helpers.js +93 -1
  33. data/lib/studio/node_tooling/playwright_base.js +51 -4
  34. data/lib/studio/roles.rb +17 -0
  35. data/lib/studio/version.rb +1 -1
  36. data/lib/studio.rb +59 -1
  37. metadata +15 -2
data/lib/studio.rb CHANGED
@@ -12,6 +12,7 @@ require "active_support/core_ext/module/attribute_accessors"
12
12
  require "active_support/core_ext/numeric/time"
13
13
  require "active_support/core_ext/integer/time"
14
14
  require "studio/version"
15
+ require "studio/roles"
15
16
  require "studio/local_path"
16
17
  require "studio/public_file_version"
17
18
  require "studio/component_gallery"
@@ -77,6 +78,10 @@ require "studio/redis"
77
78
  require "studio/cable"
78
79
  require "studio/connections"
79
80
  require "studio/connections/stand_in"
81
+ require "studio/integrations"
82
+ require "studio/integrations/quickbooks"
83
+ require "studio/integrations/egnyte"
84
+ require "studio/integrations/microsoft_365"
80
85
  require "studio/survey"
81
86
  require "studio/survey/breakdown"
82
87
  require "studio/survey/export"
@@ -1203,7 +1208,8 @@ module Studio
1203
1208
 
1204
1209
  # ---- Connections (docs/CONNECTIONS.md) ------------------------------------
1205
1210
  #
1206
- # The generic OAuth 2.0 connection tooling. The engine names no provider: a
1211
+ # The generic OAuth 2.0 connection tooling. The tooling names no provider (the
1212
+ # engine's own definitions are Studio::Integrations, below): a
1207
1213
  # host declares each in an initializer and draws its routes.
1208
1214
  #
1209
1215
  # Studio.define_connection :files, label: "Acme Files", env: {...}, ...
@@ -1259,6 +1265,58 @@ module Studio
1259
1265
  end
1260
1266
  end
1261
1267
 
1268
+ # ---- Integrations (docs/INTEGRATIONS.md) -----------------------------------
1269
+ #
1270
+ # The engine's own connection definitions (Studio::Integrations): QuickBooks,
1271
+ # Egnyte and Microsoft 365. Connection only; a host writes its readers.
1272
+ #
1273
+ # # config/initializers/studio_integrations.rb
1274
+ # Studio.enable_integration :quickbooks,
1275
+ # env: { client_id: "INTUIT_CLIENT_ID", client_secret: "INTUIT_CLIENT_SECRET", environment: "INTUIT_ENVIRONMENT" },
1276
+ # panel: "admin/integrations/quickbooks_panel"
1277
+ # # config/routes.rb
1278
+ # Studio.draw_integrations_routes(self)
1279
+ #
1280
+ # env: names the host's env vars (never values); the integration stays off
1281
+ # until its client id and secret are set. panel: a host partial rendered on
1282
+ # the integration's page with locals integration: and connections:.
1283
+ def self.enable_integration(key, env:, panel: nil, label: nil, scopes: nil)
1284
+ Integrations.enable(key, env:, panel:, label:, scopes:)
1285
+ end
1286
+
1287
+ def self.integration(key)
1288
+ Integrations.fetch(key)
1289
+ end
1290
+
1291
+ def self.integrations
1292
+ Integrations.all
1293
+ end
1294
+
1295
+ # Draws the admin integrations page and, for every enabled integration, its
1296
+ # page and connection routes (Studio.draw_connection_routes), all served by
1297
+ # Studio::IntegrationsController unless the host names its own:
1298
+ #
1299
+ # GET /<path> <as> the list
1300
+ # GET /<path>/<key> <as>_<key> one integration's page
1301
+ # POST /<path>/<key>/connect <as>_<key>_connect (also GET when it takes no account at Connect)
1302
+ # GET /<path>/<key>/callback <as>_<key>_callback the redirect URI to register
1303
+ # DELETE /<path>/<key>/connections/:id <as>_<key>_disconnect
1304
+ #
1305
+ # path: defaults to admin/integrations, so QuickBooks's redirect URI is
1306
+ # /admin/integrations/quickbooks/callback. Call it after every
1307
+ # enable_integration (an initializer runs before the routes load).
1308
+ def self.draw_integrations_routes(router, path: "admin/integrations", controller: "studio/integrations", as: nil)
1309
+ path = path.to_s.delete_prefix("/").delete_suffix("/")
1310
+ controller = controller.to_s.delete_prefix("/")
1311
+ as = (as || path.tr("/-", "__")).to_s
1312
+ Integrations.mount_path = path
1313
+ router.instance_exec { get path, to: "#{controller}#index", as: as }
1314
+ Integrations.all.each do |integration|
1315
+ draw_connection_routes(router, integration.key, path: "#{path}/#{integration.key}", controller:, as: "#{as}_#{integration.key}",
1316
+ show: true, return_to: ["/#{path}/#{integration.key}", "/#{path}"])
1317
+ end
1318
+ end
1319
+
1262
1320
  # Define a survey in app code. See Studio::Survey for the DSL.
1263
1321
  def self.define_survey(slug, &block)
1264
1322
  Survey.define(slug, &block)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: studio-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.137.0
4
+ version: 0.138.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McRitchie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-11-08 00:00:00.000000000 Z
11
+ date: 2026-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -468,6 +468,7 @@ files:
468
468
  - app/controllers/studio/geo_settings_controller.rb
469
469
  - app/controllers/studio/google_setup_requests_controller.rb
470
470
  - app/controllers/studio/health_reports_controller.rb
471
+ - app/controllers/studio/integrations_controller.rb
471
472
  - app/controllers/studio/knowledge_docs_controller.rb
472
473
  - app/controllers/studio/links_controller.rb
473
474
  - app/controllers/studio/local_emails_controller.rb
@@ -596,6 +597,7 @@ files:
596
597
  - app/mailers/studio/profile_mailer.rb
597
598
  - app/mailers/user_mailer.rb
598
599
  - app/models/concerns/sluggable.rb
600
+ - app/models/concerns/studio/account.rb
599
601
  - app/models/concerns/studio/board/rankable.rb
600
602
  - app/models/concerns/studio/omniauth_user.rb
601
603
  - app/models/current.rb
@@ -716,6 +718,9 @@ files:
716
718
  - app/views/studio/google_sign_in/_setup_modal.html.erb
717
719
  - app/views/studio/health_report_mailer/daily.html.erb
718
720
  - app/views/studio/health_report_mailer/daily.text.erb
721
+ - app/views/studio/integrations/_card.html.erb
722
+ - app/views/studio/integrations/index.html.erb
723
+ - app/views/studio/integrations/show.html.erb
719
724
  - app/views/studio/knowledge_docs/_access_chips.html.erb
720
725
  - app/views/studio/knowledge_docs/_browser.html.erb
721
726
  - app/views/studio/knowledge_docs/_chip_styles.html.erb
@@ -882,6 +887,9 @@ files:
882
887
  - db/migrate/20261103120000_create_studio_user_sessions.rb
883
888
  - db/migrate/20261108120000_add_device_revocation_to_studio_user_sessions.rb
884
889
  - db/migrate/20261108130000_create_studio_connections.rb
890
+ - db/migrate/20261108160000_require_slugs_on_engine_tables.rb
891
+ - db/migrate/20261108160001_add_engine_state_checks.rb
892
+ - db/migrate/20261108170000_add_users_role_known_check.rb
885
893
  - docs/BOOKING.md
886
894
  - docs/SITE_FOOTER.md
887
895
  - lib/active_storage/service/studio_trash_s3_service.rb
@@ -932,6 +940,10 @@ files:
932
940
  - lib/studio/icons/lucide/rocket.svg
933
941
  - lib/studio/icons/lucide/user.svg
934
942
  - lib/studio/image_cache.rb
943
+ - lib/studio/integrations.rb
944
+ - lib/studio/integrations/egnyte.rb
945
+ - lib/studio/integrations/microsoft_365.rb
946
+ - lib/studio/integrations/quickbooks.rb
935
947
  - lib/studio/ip_locations.rb
936
948
  - lib/studio/js_identifier.rb
937
949
  - lib/studio/js_literal.rb
@@ -975,6 +987,7 @@ files:
975
987
  - lib/studio/public_file_version.rb
976
988
  - lib/studio/public_user.rb
977
989
  - lib/studio/redis.rb
990
+ - lib/studio/roles.rb
978
991
  - lib/studio/s3.rb
979
992
  - lib/studio/s3/multipart.rb
980
993
  - lib/studio/s3/trash.rb