dash_kit 2.0.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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +170 -0
  4. data/Rakefile +18 -0
  5. data/app/assets/builds/dash_kit/dashboard_grid.css +1 -0
  6. data/app/assets/builds/dash_kit/dashboard_grid.js +5 -0
  7. data/app/assets/javascripts/dash_kit/index.js +2 -0
  8. data/app/assets/stylesheets/dash_kit/application.css +15 -0
  9. data/app/controllers/dash_kit/application_controller.rb +6 -0
  10. data/app/controllers/dash_kit/dashboards_controller.rb +139 -0
  11. data/app/controllers/dash_kit/widget_definitions_controller.rb +33 -0
  12. data/app/controllers/dash_kit/widgets_controller.rb +39 -0
  13. data/app/helpers/dash_kit/application_helper.rb +4 -0
  14. data/app/helpers/dash_kit/dashboard_helper.rb +130 -0
  15. data/app/javascript/dash_kit/dashboard_grid.jsx +10 -0
  16. data/app/models/concerns/dash_kit/widget_management.rb +16 -0
  17. data/app/models/dash_kit/application_record.rb +5 -0
  18. data/app/models/dash_kit/dashboard.rb +53 -0
  19. data/app/models/dash_kit/widget_definition.rb +9 -0
  20. data/app/views/dash_kit/dashboards/_widgets.html.erb +1 -0
  21. data/app/views/dash_kit/dashboards/edit.html.erb +21 -0
  22. data/app/views/dash_kit/dashboards/index.html.erb +34 -0
  23. data/app/views/dash_kit/dashboards/new.html.erb +28 -0
  24. data/app/views/dash_kit/widget_definitions/_missing_renderer.html.erb +3 -0
  25. data/app/views/layouts/dash_kit/application.html.erb +17 -0
  26. data/config/importmap.rb +1 -0
  27. data/config/routes.rb +16 -0
  28. data/lib/dash_kit/configuration_backfill.rb +27 -0
  29. data/lib/dash_kit/engine.rb +19 -0
  30. data/lib/dash_kit/reference/guide.md +289 -0
  31. data/lib/dash_kit/reference.rb +11 -0
  32. data/lib/dash_kit/renderer_registry.rb +21 -0
  33. data/lib/dash_kit/the_local/agents/dash_kit-develop.md +298 -0
  34. data/lib/dash_kit/the_local/agents/dash_kit-info.md +298 -0
  35. data/lib/dash_kit/the_local/agents/dash_kit-install.md +298 -0
  36. data/lib/dash_kit/the_local.rb +34 -0
  37. data/lib/dash_kit/version.rb +3 -0
  38. data/lib/dash_kit/widget_registry.rb +69 -0
  39. data/lib/dash_kit.rb +72 -0
  40. data/lib/generators/dash_kit/install_generator.rb +79 -0
  41. data/lib/generators/dash_kit/templates/create_dash_kit_dashboards.rb.tt +20 -0
  42. data/lib/generators/dash_kit/templates/create_dash_kit_widget_definitions.rb.tt +12 -0
  43. data/lib/generators/dash_kit/templates/dash_kit.rb.tt +16 -0
  44. data/lib/tasks/dash_kit_tasks.rake +9 -0
  45. metadata +147 -0
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DashKit
4
+ class WidgetRegistry
5
+ BUILT_WIDGET = :built_widget
6
+ FULL_WIDTH = 12
7
+ ROWS = 4
8
+
9
+ def initialize
10
+ @dashboards = {}
11
+ end
12
+
13
+ def register(dashboard_type, &block)
14
+ builder = DashboardBuilder.new
15
+ block.call(builder)
16
+ @dashboards[dashboard_type.to_sym] = builder.widgets.freeze
17
+ register_block_types(dashboard_type)
18
+ end
19
+
20
+ def widgets_for(dashboard_type)
21
+ @dashboards.fetch(dashboard_type.to_sym)
22
+ end
23
+
24
+ def default_widget_order(dashboard_type)
25
+ widgets_for(dashboard_type)
26
+ .sort_by { |_, v| v[:position] }
27
+ .map { |k, _| k.to_s }
28
+ end
29
+
30
+ def widget_label(dashboard_type, widget_key)
31
+ widgets_for(dashboard_type).dig(widget_key.to_sym, :label)
32
+ end
33
+
34
+ def widget_partial(dashboard_type, widget_key)
35
+ widgets_for(dashboard_type).dig(widget_key.to_sym, :partial)
36
+ end
37
+
38
+ def dashboard_types
39
+ @dashboards.keys
40
+ end
41
+
42
+ private
43
+
44
+ def register_block_types(dashboard_type)
45
+ KsBlocks.block(BUILT_WIDGET, name: "Built widget", kind: dashboard_type.to_sym, width: FULL_WIDTH, height: ROWS, narrow_width: FULL_WIDTH, narrow_height: ROWS)
46
+
47
+ widgets_for(dashboard_type).each do |key, widget|
48
+ KsBlocks.block(key, name: widget[:label], kind: dashboard_type.to_sym,
49
+ width: widget.fetch(:width, FULL_WIDTH), height: widget.fetch(:height, ROWS),
50
+ narrow_width: widget[:narrow_width], narrow_height: widget[:narrow_height],
51
+ once: true, resizable: false)
52
+ end
53
+ end
54
+ end
55
+
56
+ class DashboardBuilder
57
+ attr_reader :widgets
58
+
59
+ def initialize
60
+ @widgets = {}
61
+ @position = 0
62
+ end
63
+
64
+ def widget(key, label:, partial:, **options)
65
+ @position += 1
66
+ @widgets[key.to_sym] = { label: label, partial: partial, position: @position }.merge(options)
67
+ end
68
+ end
69
+ end
data/lib/dash_kit.rb ADDED
@@ -0,0 +1,72 @@
1
+ require "keystone_ui-blocks"
2
+ require "dash_kit/version"
3
+ require "dash_kit/widget_registry"
4
+ require "dash_kit/renderer_registry"
5
+ require "dash_kit/configuration_backfill"
6
+
7
+ module DashKit
8
+ class Error < StandardError; end
9
+
10
+ mattr_accessor :parent_controller, default: "DashKit::ApplicationController"
11
+ mattr_accessor :current_owner_method, default: nil
12
+ mattr_accessor :current_viewer_method, default: nil
13
+
14
+ OWNER_EQUALITY = ->(dashboard, viewer) { dashboard.owner == viewer }
15
+ NO_SOURCES = ->(_viewer) { [] }
16
+
17
+ mattr_accessor :viewable_by, default: OWNER_EQUALITY
18
+ mattr_accessor :editable_by, default: OWNER_EQUALITY
19
+ mattr_accessor :shareable_by, default: OWNER_EQUALITY
20
+ mattr_accessor :available_sources_for, default: NO_SOURCES
21
+
22
+ def self.available_sources(viewer)
23
+ available_sources_for.call(viewer)
24
+ end
25
+
26
+ def self.viewable?(dashboard, viewer)
27
+ viewable_by.call(dashboard, viewer)
28
+ end
29
+
30
+ def self.editable?(dashboard, viewer)
31
+ editable_by.call(dashboard, viewer)
32
+ end
33
+
34
+ def self.shareable?(dashboard, viewer)
35
+ shareable_by.call(dashboard, viewer)
36
+ end
37
+
38
+ def self.registry
39
+ @registry ||= WidgetRegistry.new
40
+ end
41
+
42
+ def self.configure
43
+ yield registry
44
+ end
45
+
46
+ def self.reset_registry!
47
+ @registry = WidgetRegistry.new
48
+ end
49
+
50
+ def self.renderers
51
+ @renderers ||= RendererRegistry.new
52
+ end
53
+
54
+ def self.register_renderer(visualization, partial:)
55
+ renderers.register(visualization, partial: partial)
56
+ end
57
+
58
+ def self.renderer_for(visualization)
59
+ renderers.renderer_for(visualization)
60
+ end
61
+
62
+ def self.visualizations
63
+ renderers.visualizations
64
+ end
65
+
66
+ def self.reset_renderers!
67
+ @renderers = RendererRegistry.new
68
+ end
69
+ end
70
+
71
+ require "dash_kit/engine" if defined?(Rails::Engine)
72
+ require "dash_kit/the_local"
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module DashKit
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ include ActiveRecord::Generators::Migration
10
+
11
+ source_root File.expand_path("templates", __dir__)
12
+
13
+ desc "Install DashKit dashboard engine"
14
+
15
+ def copy_migration
16
+ migration_template "create_dash_kit_dashboards.rb.tt", "db/migrate/create_dash_kit_dashboards.rb"
17
+ end
18
+
19
+ def copy_widget_definitions_migration
20
+ migration_template "create_dash_kit_widget_definitions.rb.tt", "db/migrate/create_dash_kit_widget_definitions.rb"
21
+ end
22
+
23
+ def copy_initializer
24
+ template "dash_kit.rb.tt", "config/initializers/dash_kit.rb"
25
+ end
26
+
27
+ def mount_engine
28
+ route 'mount DashKit::Engine => "/dash_kit"'
29
+ end
30
+
31
+ IMPORTMAP_PATH = "config/importmap.rb"
32
+ STIMULUS_INDEX_PATH = "app/javascript/controllers/index.js"
33
+
34
+ def register_dash_kit_controllers
35
+ return unless host_file?(STIMULUS_INDEX_PATH)
36
+ return if host_file_includes?(STIMULUS_INDEX_PATH, "registerDashKitControllers")
37
+
38
+ append_to_file STIMULUS_INDEX_PATH, <<~JS
39
+
40
+ import { registerControllers as registerDashKitControllers } from "dash_kit/index"
41
+ registerDashKitControllers(application)
42
+ JS
43
+ end
44
+
45
+ def print_instructions
46
+ say ""
47
+ say "DashKit installed successfully!", :green
48
+ say ""
49
+ say "Registered DashKit's Stimulus controllers for you", :green
50
+ say "(where app/javascript/controllers/index.js exists)."
51
+ say ""
52
+ say "Next steps:", :yellow
53
+ say ""
54
+ say " 1. Run migrations:"
55
+ say " rails db:migrate"
56
+ say ""
57
+ say " 2. Add the association to your owner model (e.g. Account):"
58
+ say " has_many :dash_kit_dashboards, class_name: \"DashKit::Dashboard\","
59
+ say " as: :owner, dependent: :destroy"
60
+ say ""
61
+ say " 3. Configure parent_controller and current_owner_method in"
62
+ say " config/initializers/dash_kit.rb"
63
+ say ""
64
+ say " 4. Register your dashboards and widgets in the initializer"
65
+ say ""
66
+ end
67
+
68
+ private
69
+
70
+ def host_file?(path)
71
+ File.exist?(File.expand_path(path, destination_root))
72
+ end
73
+
74
+ def host_file_includes?(path, snippet)
75
+ File.read(File.expand_path(path, destination_root)).include?(snippet)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,20 @@
1
+ class CreateDashKitDashboards < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :dash_kit_dashboards do |t|
4
+ t.references :owner, polymorphic: true, null: false
5
+ t.bigint :account_id
6
+ t.string :name
7
+ t.string :dashboard_type, null: false
8
+ t.jsonb :blocks, default: []
9
+ t.jsonb :widget_settings, default: {}
10
+ t.jsonb :filter_state, default: {}
11
+ t.string :visibility, null: false, default: "private"
12
+ t.string :role_default_for
13
+ t.boolean :active, null: false, default: false
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :dash_kit_dashboards, :account_id
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ class CreateDashKitWidgetDefinitions < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :dash_kit_widget_definitions do |t|
4
+ t.references :dashboard, null: false, foreign_key: { to_table: :dash_kit_dashboards }
5
+ t.string :source
6
+ t.string :visualization
7
+ t.jsonb :options, default: {}
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ # Set the parent controller for DashKit's controllers to inherit from.
2
+ # This gives DashKit access to authentication and helper methods.
3
+ DashKit.parent_controller = "ApplicationController"
4
+
5
+ # Set the method DashKit uses to find the current owner (e.g. account or user).
6
+ # This scopes dashboard configurations to the correct owner.
7
+ DashKit.current_owner_method = :current_account
8
+
9
+ DashKit.configure do |config|
10
+ # Register your dashboards and widgets here.
11
+ #
12
+ # config.register(:home) do |d|
13
+ # d.widget :on_deck, label: "On Deck", partial: "widgets/home/on_deck"
14
+ # d.widget :tasks, label: "Tasks", partial: "widgets/home/tasks"
15
+ # end
16
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :dash_kit do
4
+ desc "Backfill a Dashboard for each legacy Configuration"
5
+ task backfill_dashboards: :environment do
6
+ DashKit::ConfigurationBackfill.run
7
+ puts "DashKit backfilled Dashboards from Configurations"
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dash_kit
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Schneider
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-09-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: turbo-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: keystone_ui
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.11.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.11.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: keystone_ui-blocks
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.2.2
69
+ description: DashKit provides a presentation layer for building reusable dashboards.
70
+ Register widgets, persist user configuration, and render dashboards without coupling
71
+ to any specific data backend.
72
+ email:
73
+ - tylercschneider@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - MIT-LICENSE
79
+ - README.md
80
+ - Rakefile
81
+ - app/assets/builds/dash_kit/dashboard_grid.css
82
+ - app/assets/builds/dash_kit/dashboard_grid.js
83
+ - app/assets/javascripts/dash_kit/index.js
84
+ - app/assets/stylesheets/dash_kit/application.css
85
+ - app/controllers/dash_kit/application_controller.rb
86
+ - app/controllers/dash_kit/dashboards_controller.rb
87
+ - app/controllers/dash_kit/widget_definitions_controller.rb
88
+ - app/controllers/dash_kit/widgets_controller.rb
89
+ - app/helpers/dash_kit/application_helper.rb
90
+ - app/helpers/dash_kit/dashboard_helper.rb
91
+ - app/javascript/dash_kit/dashboard_grid.jsx
92
+ - app/models/concerns/dash_kit/widget_management.rb
93
+ - app/models/dash_kit/application_record.rb
94
+ - app/models/dash_kit/dashboard.rb
95
+ - app/models/dash_kit/widget_definition.rb
96
+ - app/views/dash_kit/dashboards/_widgets.html.erb
97
+ - app/views/dash_kit/dashboards/edit.html.erb
98
+ - app/views/dash_kit/dashboards/index.html.erb
99
+ - app/views/dash_kit/dashboards/new.html.erb
100
+ - app/views/dash_kit/widget_definitions/_missing_renderer.html.erb
101
+ - app/views/layouts/dash_kit/application.html.erb
102
+ - config/importmap.rb
103
+ - config/routes.rb
104
+ - lib/dash_kit.rb
105
+ - lib/dash_kit/configuration_backfill.rb
106
+ - lib/dash_kit/engine.rb
107
+ - lib/dash_kit/reference.rb
108
+ - lib/dash_kit/reference/guide.md
109
+ - lib/dash_kit/renderer_registry.rb
110
+ - lib/dash_kit/the_local.rb
111
+ - lib/dash_kit/the_local/agents/dash_kit-develop.md
112
+ - lib/dash_kit/the_local/agents/dash_kit-info.md
113
+ - lib/dash_kit/the_local/agents/dash_kit-install.md
114
+ - lib/dash_kit/version.rb
115
+ - lib/dash_kit/widget_registry.rb
116
+ - lib/generators/dash_kit/install_generator.rb
117
+ - lib/generators/dash_kit/templates/create_dash_kit_dashboards.rb.tt
118
+ - lib/generators/dash_kit/templates/create_dash_kit_widget_definitions.rb.tt
119
+ - lib/generators/dash_kit/templates/dash_kit.rb.tt
120
+ - lib/tasks/dash_kit_tasks.rake
121
+ homepage: https://github.com/DYB-Development/dash_kit
122
+ licenses:
123
+ - MIT
124
+ metadata:
125
+ homepage_uri: https://github.com/DYB-Development/dash_kit
126
+ source_code_uri: https://github.com/DYB-Development/dash_kit
127
+ changelog_uri: https://github.com/DYB-Development/dash_kit/blob/main/CHANGELOG.md
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 3.3.0
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubygems_version: 3.5.16
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: A Rails engine for composable, configurable dashboards and widgets.
147
+ test_files: []