decidim-toggle 0.1.3

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 (151) hide show
  1. checksums.yaml +7 -0
  2. data/.erb-lint.yml +2134 -0
  3. data/.github/workflows/website.yml +57 -0
  4. data/.gitignore +13 -0
  5. data/.gitlab-ci.yml +165 -0
  6. data/.node-version +1 -0
  7. data/.rspec +1 -0
  8. data/.rubocop.yml +2 -0
  9. data/.ruby-version +1 -0
  10. data/.simplecov +18 -0
  11. data/CONTRIBUTING.md +17 -0
  12. data/Gemfile +33 -0
  13. data/Gemfile.lock +843 -0
  14. data/LICENSE.md +661 -0
  15. data/README.md +90 -0
  16. data/Rakefile +38 -0
  17. data/app/commands/decidim/toggle/update_authorizations_command.rb +31 -0
  18. data/app/commands/decidim/toggle/update_emails_command.rb +30 -0
  19. data/app/commands/decidim/toggle/update_file_upload_settings_command.rb +31 -0
  20. data/app/commands/decidim/toggle/update_locale_command.rb +47 -0
  21. data/app/commands/decidim/toggle/update_module_config_command.rb +31 -0
  22. data/app/commands/decidim/toggle/update_name_command.rb +31 -0
  23. data/app/commands/decidim/toggle/update_omniauth_command.rb +30 -0
  24. data/app/commands/decidim/toggle/update_security_command.rb +31 -0
  25. data/app/controllers/decidim_toggle/system/settings_tab_controller.rb +64 -0
  26. data/app/forms/decidim/toggle/update_authorizations_form.rb +54 -0
  27. data/app/forms/decidim/toggle/update_emails_form.rb +28 -0
  28. data/app/forms/decidim/toggle/update_file_upload_settings_form.rb +26 -0
  29. data/app/forms/decidim/toggle/update_locale_form.rb +116 -0
  30. data/app/forms/decidim/toggle/update_name_form.rb +63 -0
  31. data/app/forms/decidim/toggle/update_omniauth_form.rb +37 -0
  32. data/app/forms/decidim/toggle/update_security_form.rb +65 -0
  33. data/app/helpers/decidim/toggle/javascript_config_helper.rb +11 -0
  34. data/app/helpers/decidim/toggle/system_settings_tab_helper.rb +59 -0
  35. data/app/models/decidim/toggle/organization_module_config.rb +15 -0
  36. data/app/overrides/add_toggle_javascript_admin.rb +11 -0
  37. data/app/overrides/add_toggle_javascript_public.rb +11 -0
  38. data/app/packs/entrypoints/decidim_toggle.js +3 -0
  39. data/app/packs/src/decidim/toggle/organization_settings_tabs.js +114 -0
  40. data/app/packs/stylesheets/decidim/toggle/organization_settings.scss +160 -0
  41. data/app/views/decidim/system/organizations/edit.html.erb +20 -0
  42. data/app/views/decidim_toggle/system/organizations/_default_form_tab.html.erb +5 -0
  43. data/app/views/decidim_toggle/system/organizations/_encryption_not_configured_callout.html.erb +6 -0
  44. data/app/views/decidim_toggle/system/organizations/_settings_tab_active_tab_field.html.erb +1 -0
  45. data/app/views/decidim_toggle/system/organizations/_settings_tab_submit.html.erb +4 -0
  46. data/app/views/decidim_toggle/system/organizations/_settings_tabs.html.erb +31 -0
  47. data/app/views/decidim_toggle/system/organizations/tabs/_authorizations_tab.html.erb +9 -0
  48. data/app/views/decidim_toggle/system/organizations/tabs/_emails_tab.html.erb +5 -0
  49. data/app/views/decidim_toggle/system/organizations/tabs/_file_upload_tab.html.erb +5 -0
  50. data/app/views/decidim_toggle/system/organizations/tabs/_language_tab.html.erb +35 -0
  51. data/app/views/decidim_toggle/system/organizations/tabs/_omniauth_tab.html.erb +5 -0
  52. data/app/views/decidim_toggle/system/organizations/tabs/_security_tab.html.erb +20 -0
  53. data/app/views/layouts/decidim/toggle/_javascript_config.html.erb +3 -0
  54. data/bin/check +10 -0
  55. data/bin/i18n-tasks +27 -0
  56. data/bin/postversion +14 -0
  57. data/config/assets.rb +8 -0
  58. data/config/locales/decidim_toggle_en.yml +58 -0
  59. data/crowdin.yml +15 -0
  60. data/db/migrate/20260321120000_create_decidim_toggle_organization_module_configs.rb +20 -0
  61. data/decidim-toggle.gemspec +35 -0
  62. data/docker-compose.yml +41 -0
  63. data/lib/decidim/toggle/engine.rb +62 -0
  64. data/lib/decidim/toggle/expose_attributes_to_js.rb +26 -0
  65. data/lib/decidim/toggle/expose_attributes_to_js_validator.rb +32 -0
  66. data/lib/decidim/toggle/gem_registry.rb +15 -0
  67. data/lib/decidim/toggle/informative_callouts.rb +76 -0
  68. data/lib/decidim/toggle/javascript_config.rb +87 -0
  69. data/lib/decidim/toggle/module_config.rb +64 -0
  70. data/lib/decidim/toggle/module_config_form.rb +41 -0
  71. data/lib/decidim/toggle/module_config_i18n.rb +44 -0
  72. data/lib/decidim/toggle/module_configuration_presenter.rb +55 -0
  73. data/lib/decidim/toggle/organization_settings_tabs.rb +69 -0
  74. data/lib/decidim/toggle/settings_form_builder.rb +200 -0
  75. data/lib/decidim/toggle/settings_tab_item.rb +37 -0
  76. data/lib/decidim/toggle/settings_tab_registry.rb +109 -0
  77. data/lib/decidim/toggle/settings_tabs.rb +56 -0
  78. data/lib/decidim/toggle/tab_form.rb +20 -0
  79. data/lib/decidim/toggle/version.rb +14 -0
  80. data/lib/decidim/toggle.rb +36 -0
  81. data/lib/tasks/decidim/toggle/toggle_upgrade.rake +13 -0
  82. data/lib/tasks/decidim/toggle/toggle_webpacker.rake +60 -0
  83. data/log/.gitignore +2 -0
  84. data/package.json +18 -0
  85. data/prettier.config.js +15 -0
  86. data/spec/commands/decidim/toggle/update_authorizations_command_spec.rb +41 -0
  87. data/spec/commands/decidim/toggle/update_emails_command_spec.rb +84 -0
  88. data/spec/commands/decidim/toggle/update_file_upload_settings_command_spec.rb +28 -0
  89. data/spec/commands/decidim/toggle/update_locale_command_spec.rb +53 -0
  90. data/spec/commands/decidim/toggle/update_module_config_command_spec.rb +38 -0
  91. data/spec/commands/decidim/toggle/update_name_command_spec.rb +49 -0
  92. data/spec/commands/decidim/toggle/update_omniauth_command_spec.rb +80 -0
  93. data/spec/commands/decidim/toggle/update_security_command_spec.rb +25 -0
  94. data/spec/decidim/toggle/settings_tab_item_spec.rb +34 -0
  95. data/spec/decidim/toggle/settings_tab_registry_spec.rb +66 -0
  96. data/spec/decidim/toggle/settings_tabs_spec.rb +60 -0
  97. data/spec/forms/concerns/decidim/toggle/informative_callouts_spec.rb +48 -0
  98. data/spec/forms/decidim/toggle/update_authorizations_form_spec.rb +40 -0
  99. data/spec/forms/decidim/toggle/update_emails_form_spec.rb +35 -0
  100. data/spec/forms/decidim/toggle/update_file_upload_settings_form_spec.rb +20 -0
  101. data/spec/forms/decidim/toggle/update_locale_form_spec.rb +64 -0
  102. data/spec/forms/decidim/toggle/update_name_form_spec.rb +57 -0
  103. data/spec/forms/decidim/toggle/update_omniauth_form_spec.rb +56 -0
  104. data/spec/forms/decidim/toggle/update_security_form_spec.rb +32 -0
  105. data/spec/helpers/decidim/toggle/system_settings_tab_helper_spec.rb +99 -0
  106. data/spec/lib/decidim/toggle/expose_attributes_to_js_spec.rb +31 -0
  107. data/spec/lib/decidim/toggle/expose_attributes_to_js_validator_spec.rb +30 -0
  108. data/spec/lib/decidim/toggle/gem_registry_spec.rb +30 -0
  109. data/spec/lib/decidim/toggle/javascript_config_spec.rb +169 -0
  110. data/spec/lib/decidim/toggle/module_config_form_spec.rb +45 -0
  111. data/spec/lib/decidim/toggle/module_config_spec.rb +74 -0
  112. data/spec/lib/decidim/toggle/module_configuration_presenter_spec.rb +53 -0
  113. data/spec/lib/decidim/toggle/settings_form_builder_spec.rb +115 -0
  114. data/spec/requests/decidim_toggle/system/settings_tab_spec.rb +144 -0
  115. data/spec/spec_helper.rb +12 -0
  116. data/spec/support/decidim_factories.rb +3 -0
  117. data/spec/support/devise.rb +5 -0
  118. data/spec/system/decidim_toggle/javascript_config_spec.rb +56 -0
  119. data/website/.gitignore +4 -0
  120. data/website/docs/developer/_category_.json +8 -0
  121. data/website/docs/developer/code-of-conduct.md +99 -0
  122. data/website/docs/developer/contribute.md +50 -0
  123. data/website/docs/developer/deface-usage.md +37 -0
  124. data/website/docs/developer/documentation.md +58 -0
  125. data/website/docs/developer/error-handling.md +51 -0
  126. data/website/docs/developer/tab-registry.md +51 -0
  127. data/website/docs/developer/view-customization.md +49 -0
  128. data/website/docs/index.md +80 -0
  129. data/website/docs/integrate/_category_.json +8 -0
  130. data/website/docs/integrate/attributes.md +121 -0
  131. data/website/docs/integrate/customize-views.md +62 -0
  132. data/website/docs/integrate/index.md +38 -0
  133. data/website/docs/integrate/informative_callout.md +80 -0
  134. data/website/docs/integrate/javascript.md +84 -0
  135. data/website/docs/integrate/labels.md +91 -0
  136. data/website/docs/integrate/quickstart.md +77 -0
  137. data/website/docusaurus.config.ts +100 -0
  138. data/website/package.json +31 -0
  139. data/website/sidebars.ts +7 -0
  140. data/website/src/css/custom.css +37 -0
  141. data/website/static/img/logo.svg +1 -0
  142. data/website/static/img/schema_overview.png +0 -0
  143. data/website/static/img/screenshot_informative_callouts.png +0 -0
  144. data/website/static/img/screenshot_saved_flash.png +0 -0
  145. data/website/static/img/screenshots_locale_tab.png +0 -0
  146. data/website/static/img/screenshots_name_tab.png +0 -0
  147. data/website/static/img/screenshots_security_tab.png +0 -0
  148. data/website/tsconfig.json +6 -0
  149. data/website/yarn.lock +8336 -0
  150. data/yarn.lock +13 -0
  151. metadata +249 -0
@@ -0,0 +1,62 @@
1
+ ---
2
+ sidebar_position: 6
3
+ title: Customize views
4
+ description: form_layout_partial for custom settings tab layouts
5
+ ---
6
+
7
+ # Customize views
8
+
9
+ Without `form_layout_partial:`, decidim-toggle renders every form attribute through the default shell (`all_fields` + submit). For custom markup, provide a full tab layout partial.
10
+
11
+ ## Default vs custom
12
+
13
+ | | Default | `form_layout_partial:` |
14
+ |---|---------|------------------------|
15
+ | When | Simple JSON-backed settings | Tables, fieldsets, reused decidim-system partials, mixed markup |
16
+ | Locals | — | `tab`, `organization` |
17
+ | You render | Nothing — toggle uses `all_fields` | Entire tab inside `decidim_toggle_settings_tab_form` |
18
+
19
+ Built-in examples: `lib/decidim/toggle/organization_settings_tabs.rb` and `app/views/decidim_toggle/system/organizations/tabs/`.
20
+
21
+ ## Custom tab layout
22
+
23
+ ```erb
24
+ <%# app/views/decidim/my_module/admin/_organization_settings_tab.html.erb %>
25
+ <%= decidim_toggle_settings_tab_form(organization, tab) do |tf| %>
26
+ <fieldset>
27
+ <legend class="form-legend">My module</legend>
28
+ <%= tf.fields_for_names(:enabled) %>
29
+ </fieldset>
30
+ <% end %>
31
+ ```
32
+
33
+ ```ruby
34
+ tabs.add_tab :my_module,
35
+ "My module",
36
+ form: MyModule::AdminConfigForm,
37
+ command: Decidim::Toggle::UpdateModuleConfigCommand,
38
+ module_name: :my_module,
39
+ form_layout_partial: "decidim/my_module/admin/organization_settings_tab"
40
+ ```
41
+
42
+ `decidim_toggle_settings_tab_form` provides the PATCH form, hidden active-tab field, informative callouts, and save/cancel buttons. Do not drop the hidden `decidim_toggle_active_tab` field.
43
+
44
+ Use `tf` (`Decidim::Toggle::SettingsFormBuilder`) for fields — `tf.all_fields`, `tf.fields_for_names(:enabled)`, or pass `f: tf` to existing partials.
45
+
46
+ ## Reuse decidim-system partials
47
+
48
+ ```erb
49
+ <%= decidim_toggle_settings_tab_form(organization, tab) do |tf| %>
50
+ <%= render "decidim/system/organizations/smtp_settings", f: tf %>
51
+ <% end %>
52
+ ```
53
+
54
+ See `tabs/_emails_tab.html.erb` and `tabs/_file_upload_tab.html.erb` in this gem.
55
+
56
+ ## See also
57
+
58
+ - [Attributes](./attributes.md) — `fields_for_names`, helptext
59
+ - [Informative callouts](./informative_callout.md)
60
+ - [Add a settings tab](./quickstart.md)
61
+ - [JavaScript](./javascript.md)
62
+ - [View customization (contributor)](../developer/view-customization.md) — internal gem views
@@ -0,0 +1,38 @@
1
+ ---
2
+ sidebar_position: 1
3
+ title: Integrate
4
+ description: Add organization settings from your Decidim module
5
+ ---
6
+
7
+ # Integrate your module
8
+ Three steps to ship a settings tab: register the tab, declare form attributes, optionally customize the view.
9
+
10
+ ## 1. Add a tab
11
+
12
+ Register a form and command in your engine after `decidim_toggle.organization_settings_tabs`.
13
+
14
+ → [Add a settings tab](./quickstart.md)
15
+
16
+ ## 2. Define attributes and validation
17
+
18
+ Declare fields on your `Decidim::Form` — booleans, collections, translatable fields. Field labels live under `decidim_toggle.system.<module_config_name>` — see [Labels](./labels.md).
19
+
20
+ → [Attributes](./attributes.md) · [Labels](./labels.md) · [Informative callouts](./informative_callout.md) (optional)
21
+
22
+ ## 3. Customize the form view (optional)
23
+
24
+ Default rendering uses `all_fields`. Override with `form_layout_partial:` when you need custom markup.
25
+
26
+ → [Customize views](./customize-views.md)
27
+
28
+ ## Optional: JavaScript exposure
29
+
30
+ Expose selected settings to `window.DecidimToggle` on the participant and admin frontends.
31
+
32
+ → [JavaScript](./javascript.md)
33
+
34
+ ## See also
35
+
36
+ - [Overview](../index.md)
37
+ - [Contribute](../developer/contribute.md) — hacking the gem itself
38
+ - [GitLab issues](https://git.octree.ch/decidim/vocacity/decidim-modules/decidim-toggle/-/issues)
@@ -0,0 +1,80 @@
1
+ ---
2
+ sidebar_position: 5
3
+ title: Informative callouts
4
+ description: info, warning, and danger callouts on settings tab forms
5
+ ---
6
+
7
+ # Informative callouts
8
+
9
+ Show info, warning, or danger banners **above** the tab field body, inside the shared form shell (submit + active-tab field unchanged).
10
+
11
+ ![Informative Callouts](/img/screenshot_informative_callouts.png)
12
+
13
+ ## Setup
14
+
15
+ Include `Decidim::Toggle::TabForm` (recommended) or `Decidim::Toggle::InformativeCallouts` on the form class:
16
+
17
+ ```ruby
18
+ module MyModule
19
+ class AdminConfigForm < Decidim::Form
20
+ include Decidim::Toggle::TabForm
21
+ include Decidim::Toggle::ModuleConfigForm
22
+
23
+ self.module_config_name = "my_module"
24
+ mimic :organization
25
+
26
+ attribute :enabled, :boolean
27
+
28
+ info :defaults_callout
29
+
30
+ info :installed_modules_callout,
31
+ if_predicate: ->(form) { form.missing_modules.any? }
32
+
33
+ warning :disable_warning_callout,
34
+ if_predicate: ->(form) { form.enabled == false }
35
+
36
+ danger :other_gem_required_callout,
37
+ if_predicate: ->(*) { Decidim::Toggle.gem_present?("decidim-other") }
38
+
39
+ def defaults_callout
40
+ "Defaults apply to new organizations only."
41
+ end
42
+
43
+ def installed_modules_callout
44
+ I18n.t("my_module.admin.missing_modules", missing: missing_modules.join(", "))
45
+ end
46
+
47
+ def disable_warning_callout
48
+ "Disabling removes public access to #{module_label}."
49
+ end
50
+
51
+ def other_gem_required_callout
52
+ "Requires decidim-other in the Gemfile."
53
+ end
54
+ end
55
+ end
56
+ ```
57
+
58
+ ## Macros
59
+
60
+ | Macro | Style | When to use |
61
+ |-------|-------|-------------|
62
+ | `info :method_name` | Info (blue) | Context from a form instance method (HTML allowed) |
63
+ | `warning :method_name, if_predicate:` | Warning (yellow) | Reversible caution before save |
64
+ | `danger :method_name, if_predicate:` | Alert (red) | Strong caution, destructive or risky change |
65
+
66
+ The first argument is a **Symbol** naming a method on the form (`form.public_send(symbol)`).
67
+
68
+ `if_predicate` receives the form instance; omit it to always show the callout.
69
+
70
+ ## Rendering
71
+
72
+ Callouts render via `SettingsFormBuilder#informative_callouts` inside `decidim_toggle_settings_tab_form` — **above** the field body.
73
+
74
+ They appear in `form_layout_partial:` tabs when you wrap fields with `decidim_toggle_settings_tab_form`.
75
+
76
+ ## See also
77
+
78
+ - [Attributes](./attributes.md)
79
+ - [Customize views](./customize-views.md)
80
+ - [Add a settings tab](./quickstart.md)
@@ -0,0 +1,84 @@
1
+ ---
2
+ sidebar_position: 7
3
+ title: JavaScript
4
+ description: Expose organization settings to window.DecidimToggle
5
+ ---
6
+
7
+ # JavaScript
8
+
9
+ Opt in per attribute to expose config on `window.DecidimToggle`. By default, settings stay server-side (`Decidim::Toggle.config_for`).
10
+
11
+ ## Opt in on the form
12
+
13
+ Include `Decidim::Toggle::ExposeAttributesToJs` and list attributes explicitly — secrets are **not** exposed unless you add them.
14
+
15
+ ```ruby
16
+ module MyModule
17
+ class AdminConfigForm < Decidim::Form
18
+ include Decidim::Toggle::TabForm
19
+ include Decidim::Toggle::ModuleConfigForm
20
+ include Decidim::Toggle::ExposeAttributesToJs
21
+
22
+ self.module_config_name = "my_module"
23
+ mimic :organization
24
+
25
+ attribute :enabled, :boolean
26
+ attribute :search_bar, :boolean
27
+ attribute :api_key, :string
28
+
29
+ expose_to_javascript :enabled, :search_bar
30
+ # api_key is intentionally omitted
31
+ end
32
+ end
33
+ ```
34
+
35
+ | Macro | Role |
36
+ |-------|------|
37
+ | `expose_to_javascript :attr, ...` | Registers attribute names for the current organization's config |
38
+
39
+ The tab must be registered with `module_name:` matching `module_config_name` so `config_for` can resolve values.
40
+
41
+ ## Key format
42
+
43
+ Flat string keys: `"<module_config_name>.<attribute_name>"`.
44
+
45
+ ```js
46
+ if (window.DecidimToggle["my_module.enabled"]) {
47
+ document.querySelector(".search-bar")?.classList.remove("hidden");
48
+ }
49
+ ```
50
+
51
+ ## Supported value types
52
+
53
+ Serialized into JSON-safe values:
54
+
55
+ | Type | Exposed as |
56
+ |------|------------|
57
+ | boolean | `true` / `false` |
58
+ | string, integer, float | scalar |
59
+ | array | JSON array (elements stringified when needed) |
60
+ | hash | plain object (keys stringified) |
61
+ | translatable attribute | raw locale hash (`{ "en": "...", "ca": "..." }`) |
62
+
63
+ Unsupported types are skipped (development/test may log a warning via `ExposeAttributesToJsValidator`).
64
+
65
+ ## Server-side read
66
+
67
+ Browser and server use the same underlying config:
68
+
69
+ ```ruby
70
+ Decidim::Toggle.config_for(organization, :my_module)[:enabled]
71
+ Decidim::Toggle.javascript_config_for(organization) # => { "my_module.enabled" => true, ... }
72
+ ```
73
+
74
+ `javascript_config_for` aggregates every registered form that includes `ExposeAttributesToJs`.
75
+
76
+ ## How it reaches the page
77
+
78
+ Deface overrides insert `layouts/decidim/toggle/javascript_config` into decidim-core layouts.
79
+
80
+ ## See also
81
+
82
+ - [Attributes](./attributes.md)
83
+ - [Add a settings tab](./quickstart.md)
84
+ - [Deface usage](../developer/deface-usage.md)
@@ -0,0 +1,91 @@
1
+ ---
2
+ sidebar_position: 4
3
+ title: Labels
4
+ description: Field labels and helptext for module config tabs
5
+ ---
6
+
7
+ # Labels
8
+
9
+ Forms that include `Decidim::Toggle::ModuleConfigForm` resolve **field labels**, **helptext**, and the **tab title** from `decidim_toggle.system.<module_name>`.
10
+
11
+ ## Module name
12
+
13
+ Define one constant in your module and reuse it everywhere:
14
+
15
+ ```ruby
16
+ # lib/decidim/my_module.rb
17
+ module Decidim
18
+ module MyModule
19
+ MODULE_NAME = "my_module"
20
+ end
21
+ end
22
+ ```
23
+
24
+ ```ruby
25
+ # app/forms/my_module/admin_config_form.rb
26
+ self.module_config_name = Decidim::MyModule::MODULE_NAME
27
+
28
+ # lib/decidim/my_module/engine.rb
29
+ tabs.add_tab :my_module,
30
+ I18n.t("decidim_toggle.system.#{Decidim::MyModule::MODULE_NAME}.tab"),
31
+ form: MyModule::AdminConfigForm,
32
+ command: Decidim::Toggle::UpdateModuleConfigCommand,
33
+ module_name: Decidim::MyModule::MODULE_NAME
34
+ ```
35
+
36
+ `module_config_name`, `module_name:` on `add_tab`, and the locale path must all match.
37
+
38
+ ## Locale files
39
+
40
+ Keep toggle strings in dedicated files — one per locale:
41
+
42
+ ```
43
+ config/locales/decidim_toggle.en.yml
44
+ config/locales/decidim_toggle.fr.yml
45
+ ```
46
+
47
+ ```yaml
48
+ # config/locales/decidim_toggle.en.yml
49
+ en:
50
+ decidim_toggle:
51
+ system:
52
+ my_module:
53
+ tab: My module
54
+ enabled: Enable my module
55
+ helptext:
56
+ enabled: Applies to this organization only.
57
+ ```
58
+
59
+ | Key | Use |
60
+ |-----|-----|
61
+ | `tab` | Tab button label (`I18n.t("decidim_toggle.system.<module_name>.tab")`) |
62
+ | `<attribute>` | Field label (via `ModuleConfigForm`) |
63
+ | `helptext.<attribute>` | Optional help copy under a field |
64
+
65
+ Field labels use:
66
+
67
+ `decidim_toggle.system.<module_name>.<attribute>`
68
+
69
+ ## Helptext
70
+
71
+ Optional copy under a field uses a `helptext` sub-key in the same module scope:
72
+
73
+ `decidim_toggle.system.<module_name>.helptext.<attribute>`
74
+
75
+ ## Custom labels
76
+
77
+ Override only when you need an exception:
78
+
79
+ ```ruby
80
+ def self.human_attribute_name(attr, options = {})
81
+ return "Special case" if attr == :legacy_flag
82
+
83
+ super
84
+ end
85
+ ```
86
+
87
+ ## See also
88
+
89
+ - [Add a settings tab](./quickstart.md)
90
+ - [Attributes](./attributes.md)
91
+ - [Customize views](./customize-views.md)
@@ -0,0 +1,77 @@
1
+ ---
2
+ sidebar_position: 2
3
+ title: Add a settings tab
4
+ description: Form, engine registration, verify
5
+ ---
6
+
7
+ # Add a settings tab
8
+
9
+ Register a form and command, then verify persistence.
10
+
11
+ ## 1. Form
12
+
13
+ ```ruby
14
+ # app/forms/my_module/admin_config_form.rb
15
+ module MyModule
16
+ class AdminConfigForm < Decidim::Form
17
+ include Decidim::Toggle::ModuleConfigForm
18
+
19
+ self.module_config_name = Decidim::MyModule::MODULE_NAME
20
+
21
+ mimic :organization
22
+
23
+ attribute :enabled, :boolean
24
+ end
25
+ end
26
+ ```
27
+
28
+ ## 2. Register tab
29
+
30
+ In your module engine, **after** `decidim_toggle.organization_settings_tabs`:
31
+
32
+ ```ruby
33
+ # lib/decidim/my_module/engine.rb
34
+ initializer "decidim_my_module.organization_settings_tab", after: "decidim_toggle.organization_settings_tabs" do
35
+ Decidim::Toggle.settings_tabs :organization_settings do |tabs|
36
+ tabs.add_tab :my_module,
37
+ I18n.t("decidim_toggle.system.#{Decidim::MyModule::MODULE_NAME}.tab"),
38
+ form: MyModule::AdminConfigForm,
39
+ command: Decidim::Toggle::UpdateModuleConfigCommand,
40
+ module_name: Decidim::MyModule::MODULE_NAME,
41
+ position: 10
42
+ end
43
+ end
44
+ ```
45
+
46
+ | Option | Role |
47
+ |--------|------|
48
+ | `module_name:` | JSON row key; must match `module_config_name` on the form |
49
+ | `position:` | Tab order (default: append) |
50
+ | `open:` | Open this panel by default |
51
+ | `if:` | Hide tab when false |
52
+ | `form_layout_partial:` | Custom tab layout — [Customize views](./customize-views.md) |
53
+
54
+ ## 3. Verify
55
+
56
+ 1. Boot the host app.
57
+ 2. **System → Organizations → Edit** → open **My module**.
58
+ 3. Toggle **enabled**, save.
59
+ 4. Console: `Decidim::Toggle.config_for(organization, :my_module)[:enabled]`
60
+
61
+ ## Read / write config
62
+
63
+ ```ruby
64
+ Decidim::Toggle.config_for(organization, :my_module)
65
+ Decidim::Toggle.save_config!(organization, :my_module, { "enabled" => true })
66
+ ```
67
+
68
+ ## Organization columns
69
+
70
+ When settings live on `Decidim::Organization` (SMTP, host, locales, …), use a custom `Decidim::Form` + custom `Decidim::Command` with the same `add_tab` contract. See built-in tabs in `lib/decidim/toggle/organization_settings_tabs.rb`.
71
+
72
+ ## See also
73
+
74
+ - [Integrate](./index.md)
75
+ - [Attributes](./attributes.md)
76
+ - [Informative callouts](./informative_callout.md)
77
+ - [Customize views](./customize-views.md)
@@ -0,0 +1,100 @@
1
+ import {themes as prismThemes} from 'prism-react-renderer';
2
+ import type {Config} from '@docusaurus/types';
3
+ import type * as Preset from '@docusaurus/preset-classic';
4
+
5
+ const config: Config = {
6
+ title: 'Decidim Toggle',
7
+ tagline: 'Tabbed System administration — register org settings from your Decidim module',
8
+ favicon: 'img/logo.svg',
9
+
10
+ url: 'https://octree.ch',
11
+ baseUrl: '/decidim-toggle/',
12
+ trailingSlash: false,
13
+
14
+ organizationName: 'octree-gva',
15
+ projectName: 'decidim-toggle',
16
+
17
+ onBrokenLinks: 'throw',
18
+ onBrokenMarkdownLinks: 'warn',
19
+
20
+ i18n: {
21
+ defaultLocale: 'en',
22
+ locales: ['en'],
23
+ },
24
+
25
+ presets: [
26
+ [
27
+ 'classic',
28
+ {
29
+ docs: {
30
+ sidebarPath: './sidebars.ts',
31
+ routeBasePath: '/',
32
+ },
33
+ theme: {
34
+ customCss: './src/css/custom.css',
35
+ },
36
+ } satisfies Preset.Options,
37
+ ],
38
+ ],
39
+
40
+ themeConfig: {
41
+ navbar: {
42
+ title: 'Decidim Toggle',
43
+ items: [
44
+ {
45
+ type: 'docSidebar',
46
+ sidebarId: 'tutorialSidebar',
47
+ position: 'left',
48
+ label: 'Documentation',
49
+ },
50
+ {
51
+ href: 'https://git.octree.ch/decidim/vocacity/decidim-modules/decidim-toggle',
52
+ label: 'GitLab',
53
+ position: 'right',
54
+ },
55
+ ],
56
+ },
57
+ footer: {
58
+ style: 'dark',
59
+ links: [
60
+ {
61
+ title: 'Docs',
62
+ items: [
63
+ {
64
+ label: 'Overview',
65
+ to: '/',
66
+ },
67
+ {
68
+ label: 'Integrate',
69
+ to: '/integrate',
70
+ },
71
+ {
72
+ label: 'Contribute',
73
+ to: '/contributing',
74
+ },
75
+ {
76
+ label: 'Code of conduct',
77
+ to: '/code-of-conduct',
78
+ },
79
+ ],
80
+ },
81
+ {
82
+ title: 'More',
83
+ items: [
84
+ {
85
+ label: 'GitLab',
86
+ href: 'https://git.octree.ch/decidim/vocacity/decidim-modules/decidim-toggle',
87
+ },
88
+ ],
89
+ },
90
+ ],
91
+ copyright: 'Built with Docusaurus. Powered by <a href="https://voca.city">Voca</a>.',
92
+ },
93
+ prism: {
94
+ theme: prismThemes.github,
95
+ darkTheme: prismThemes.dracula,
96
+ },
97
+ } satisfies Preset.ThemeConfig,
98
+ };
99
+
100
+ export default config;
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "decidim-toggle-website",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "docusaurus": "docusaurus",
7
+ "start": "docusaurus start",
8
+ "build": "docusaurus build",
9
+ "clear": "docusaurus clear",
10
+ "serve": "docusaurus serve",
11
+ "typecheck": "tsc"
12
+ },
13
+ "dependencies": {
14
+ "@docusaurus/core": "3.5.2",
15
+ "@docusaurus/preset-classic": "3.5.2",
16
+ "@mdx-js/react": "^3.0.0",
17
+ "clsx": "^2.0.0",
18
+ "prism-react-renderer": "^2.3.0",
19
+ "react": "^18.0.0",
20
+ "react-dom": "^18.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "@docusaurus/module-type-aliases": "3.5.2",
24
+ "@docusaurus/tsconfig": "3.5.2",
25
+ "@docusaurus/types": "3.5.2",
26
+ "typescript": "~5.5.2"
27
+ },
28
+ "engines": {
29
+ "node": ">=18.0"
30
+ }
31
+ }
@@ -0,0 +1,7 @@
1
+ import type {SidebarsConfig} from '@docusaurus/plugin-content-docs';
2
+
3
+ const sidebars: SidebarsConfig = {
4
+ tutorialSidebar: [{type: 'autogenerated', dirName: '.'}],
5
+ };
6
+
7
+ export default sidebars;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Any CSS included here will be global. The classic template
3
+ * bundles Infima by default. Infima is a CSS framework designed to
4
+ * work well for content-centric websites.
5
+ */
6
+
7
+ /* You can override the default Infima variables here. */
8
+ :root {
9
+ --ifm-color-primary: #2e8555;
10
+ --ifm-color-primary-dark: #29784c;
11
+ --ifm-color-primary-darker: #277148;
12
+ --ifm-color-primary-darkest: #205d3b;
13
+ --ifm-color-primary-light: #33925d;
14
+ --ifm-color-primary-lighter: #359962;
15
+ --ifm-color-primary-lightest: #3cad6e;
16
+ --ifm-code-font-size: 95%;
17
+ --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
18
+ }
19
+
20
+ /* For readability concerns, you should choose a lighter palette in dark mode. */
21
+ [data-theme='dark'] {
22
+ --ifm-color-primary: #25c2a0;
23
+ --ifm-color-primary-dark: #21af90;
24
+ --ifm-color-primary-darker: #1fa588;
25
+ --ifm-color-primary-darkest: #1a8870;
26
+ --ifm-color-primary-light: #29d5b0;
27
+ --ifm-color-primary-lighter: #32d8b4;
28
+ --ifm-color-primary-lightest: #4fddbf;
29
+ --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
30
+ }
31
+
32
+ img{
33
+ max-width:520px;
34
+ }
35
+ .full > p > img {
36
+ max-width: 100%;;
37
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8.00008 6V9H5.00008V6H8.00008ZM3.00008 4V11H10.0001V4H3.00008ZM13.0001 4H21.0001V6H13.0001V4ZM13.0001 11H21.0001V13H13.0001V11ZM13.0001 18H21.0001V20H13.0001V18ZM10.7072 16.2071L9.29297 14.7929L6.00008 18.0858L4.20718 16.2929L2.79297 17.7071L6.00008 20.9142L10.7072 16.2071Z"></path></svg>
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "@docusaurus/tsconfig",
3
+ "compilerOptions": {
4
+ "baseUrl": "."
5
+ }
6
+ }