flexi_admin 0.0.5

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 (127) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +42 -0
  3. data/Rakefile +7 -0
  4. data/lib/flexi_admin/components/actions/checkbox_component.html.slim +8 -0
  5. data/lib/flexi_admin/components/actions/checkbox_component.rb +13 -0
  6. data/lib/flexi_admin/components/actions/select_component.html.slim +11 -0
  7. data/lib/flexi_admin/components/actions/select_component.rb +17 -0
  8. data/lib/flexi_admin/components/base_component.rb +19 -0
  9. data/lib/flexi_admin/components/form/field_component.rb +11 -0
  10. data/lib/flexi_admin/components/form/label_component.html.slim +2 -0
  11. data/lib/flexi_admin/components/form/label_component.rb +13 -0
  12. data/lib/flexi_admin/components/form/rows_component.rb +9 -0
  13. data/lib/flexi_admin/components/form/text_input_component.html.slim +5 -0
  14. data/lib/flexi_admin/components/form/text_input_component.rb +17 -0
  15. data/lib/flexi_admin/components/helpers/action_button_helper.rb +28 -0
  16. data/lib/flexi_admin/components/helpers/action_helper.rb +12 -0
  17. data/lib/flexi_admin/components/helpers/icon_helper.rb +11 -0
  18. data/lib/flexi_admin/components/helpers/link_helper.rb +8 -0
  19. data/lib/flexi_admin/components/helpers/resource_helper.rb +71 -0
  20. data/lib/flexi_admin/components/helpers/selectable.rb +11 -0
  21. data/lib/flexi_admin/components/helpers/url_helper.rb +8 -0
  22. data/lib/flexi_admin/components/helpers/value_formatter.rb +32 -0
  23. data/lib/flexi_admin/components/nav/floating_toc_component.html.slim +2 -0
  24. data/lib/flexi_admin/components/nav/floating_toc_component.rb +6 -0
  25. data/lib/flexi_admin/components/resource/autocomplete_component.html.slim +30 -0
  26. data/lib/flexi_admin/components/resource/autocomplete_component.rb +83 -0
  27. data/lib/flexi_admin/components/resource/button_select_component.html.slim +13 -0
  28. data/lib/flexi_admin/components/resource/button_select_component.rb +19 -0
  29. data/lib/flexi_admin/components/resource/form_component.rb +18 -0
  30. data/lib/flexi_admin/components/resource/form_element_component.html.slim +3 -0
  31. data/lib/flexi_admin/components/resource/form_element_component.rb +31 -0
  32. data/lib/flexi_admin/components/resource/form_mixin.rb +287 -0
  33. data/lib/flexi_admin/components/resource/link_action_component.html.slim +8 -0
  34. data/lib/flexi_admin/components/resource/link_action_component.rb +16 -0
  35. data/lib/flexi_admin/components/resource/show_page_component.rb +21 -0
  36. data/lib/flexi_admin/components/resource/view_component.html.slim +26 -0
  37. data/lib/flexi_admin/components/resource/view_component.rb +22 -0
  38. data/lib/flexi_admin/components/resources/bulk_action/button_component.html.slim +7 -0
  39. data/lib/flexi_admin/components/resources/bulk_action/button_component.rb +29 -0
  40. data/lib/flexi_admin/components/resources/bulk_action/modal_component.html.slim +32 -0
  41. data/lib/flexi_admin/components/resources/bulk_action/modal_component.rb +54 -0
  42. data/lib/flexi_admin/components/resources/grid_view/card_component.html.slim +18 -0
  43. data/lib/flexi_admin/components/resources/grid_view/card_component.rb +65 -0
  44. data/lib/flexi_admin/components/resources/grid_view/grid_component.html.slim +10 -0
  45. data/lib/flexi_admin/components/resources/grid_view/grid_component.rb +16 -0
  46. data/lib/flexi_admin/components/resources/grid_view_component.rb +89 -0
  47. data/lib/flexi_admin/components/resources/index_page_component.html.slim +13 -0
  48. data/lib/flexi_admin/components/resources/index_page_component.rb +19 -0
  49. data/lib/flexi_admin/components/resources/list_view/cell_component.html.slim +2 -0
  50. data/lib/flexi_admin/components/resources/list_view/cell_component.rb +26 -0
  51. data/lib/flexi_admin/components/resources/list_view/table_component.html.slim +17 -0
  52. data/lib/flexi_admin/components/resources/list_view/table_component.rb +21 -0
  53. data/lib/flexi_admin/components/resources/list_view_component.rb +80 -0
  54. data/lib/flexi_admin/components/resources/pagination_component.html.slim +42 -0
  55. data/lib/flexi_admin/components/resources/pagination_component.rb +64 -0
  56. data/lib/flexi_admin/components/resources/resources_component.rb +34 -0
  57. data/lib/flexi_admin/components/resources/switch_view_component.html.slim +16 -0
  58. data/lib/flexi_admin/components/resources/switch_view_component.rb +45 -0
  59. data/lib/flexi_admin/components/resources/view_component.html.slim +12 -0
  60. data/lib/flexi_admin/components/resources/view_component.rb +15 -0
  61. data/lib/flexi_admin/components/shared/alert_component.html.slim +2 -0
  62. data/lib/flexi_admin/components/shared/alert_component.rb +11 -0
  63. data/lib/flexi_admin/components/shared/autocomplete/results_component.html.slim +15 -0
  64. data/lib/flexi_admin/components/shared/autocomplete/results_component.rb +50 -0
  65. data/lib/flexi_admin/components/shared/autocomplete.rb +6 -0
  66. data/lib/flexi_admin/components/shared/datalist_component.html.slim +24 -0
  67. data/lib/flexi_admin/components/shared/datalist_component.rb +20 -0
  68. data/lib/flexi_admin/components/shared/link_component.html.slim +3 -0
  69. data/lib/flexi_admin/components/shared/link_component.rb +15 -0
  70. data/lib/flexi_admin/components/shared/medium_component.html.slim +7 -0
  71. data/lib/flexi_admin/components/shared/medium_component.rb +51 -0
  72. data/lib/flexi_admin/components/shared/table/header_item_component.html.slim +9 -0
  73. data/lib/flexi_admin/components/shared/table/header_item_component.rb +78 -0
  74. data/lib/flexi_admin/components/shared/trix_component.html.slim +22 -0
  75. data/lib/flexi_admin/components/shared/trix_component.rb +21 -0
  76. data/lib/flexi_admin/components.rb +87 -0
  77. data/lib/flexi_admin/config.rb +24 -0
  78. data/lib/flexi_admin/controllers/modals_controller.rb +13 -0
  79. data/lib/flexi_admin/controllers/resources_controller.rb +240 -0
  80. data/lib/flexi_admin/controllers.rb +9 -0
  81. data/lib/flexi_admin/engine.rb +34 -0
  82. data/lib/flexi_admin/helpers/application_helper.rb +4 -0
  83. data/lib/flexi_admin/helpers.rb +8 -0
  84. data/lib/flexi_admin/javascript/controllers/application.js +9 -0
  85. data/lib/flexi_admin/javascript/controllers/autocomplete_controller.js +142 -0
  86. data/lib/flexi_admin/javascript/controllers/bulk_action_controller.js +158 -0
  87. data/lib/flexi_admin/javascript/controllers/button_select_controller.js +32 -0
  88. data/lib/flexi_admin/javascript/controllers/datalist_controller.js +104 -0
  89. data/lib/flexi_admin/javascript/controllers/floating_toc_controller.js +39 -0
  90. data/lib/flexi_admin/javascript/controllers/form_controller.js +17 -0
  91. data/lib/flexi_admin/javascript/controllers/form_validation_controller.js +86 -0
  92. data/lib/flexi_admin/javascript/controllers/index.js +44 -0
  93. data/lib/flexi_admin/javascript/controllers/pagination_controller.js +13 -0
  94. data/lib/flexi_admin/javascript/controllers/sorting_controller.js +17 -0
  95. data/lib/flexi_admin/javascript/controllers/switch_view_controller.js +15 -0
  96. data/lib/flexi_admin/javascript/controllers/toast_controller.js +18 -0
  97. data/lib/flexi_admin/javascript/controllers/trix_controller.js +32 -0
  98. data/lib/flexi_admin/javascript/controllers/uploads_controller.js +164 -0
  99. data/lib/flexi_admin/javascript/flexi_admin.js +4 -0
  100. data/lib/flexi_admin/javascript/utils.js +26 -0
  101. data/lib/flexi_admin/models/concerns/application_resource.rb +25 -0
  102. data/lib/flexi_admin/models/concerns/parentable.rb +17 -0
  103. data/lib/flexi_admin/models/context_params.rb +127 -0
  104. data/lib/flexi_admin/models/resources/context.rb +59 -0
  105. data/lib/flexi_admin/models/struct.rb +29 -0
  106. data/lib/flexi_admin/models/toast.rb +23 -0
  107. data/lib/flexi_admin/models.rb +20 -0
  108. data/lib/flexi_admin/prompts/codegen-system-prompt.md +50 -0
  109. data/lib/flexi_admin/railtie.rb +78 -0
  110. data/lib/flexi_admin/routes.rb +15 -0
  111. data/lib/flexi_admin/services/code_gen/code_export.rb +22 -0
  112. data/lib/flexi_admin/services/code_gen/gemini.rb +104 -0
  113. data/lib/flexi_admin/services/code_gen/gpt.rb +68 -0
  114. data/lib/flexi_admin/services/code_gen/runner.rb +210 -0
  115. data/lib/flexi_admin/services/code_gen.rb +14 -0
  116. data/lib/flexi_admin/services/create_resource.rb +32 -0
  117. data/lib/flexi_admin/services/update_resource.rb +30 -0
  118. data/lib/flexi_admin/services.rb +10 -0
  119. data/lib/flexi_admin/version.rb +10 -0
  120. data/lib/flexi_admin/views/shared/_redirect.slim +2 -0
  121. data/lib/flexi_admin/views/shared/_reload.slim +2 -0
  122. data/lib/flexi_admin/views/shared/_toasts.slim +15 -0
  123. data/lib/flexi_admin/views/shared/not_authorized.slim +11 -0
  124. data/lib/flexi_admin.rb +58 -0
  125. data/lib/tasks/flexi_admin.rake +49 -0
  126. data/lib/tasks/semantic.rake +57 -0
  127. metadata +333 -0
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiAdmin::Services::CodeGen
4
+ class CodeExport
5
+ def self.export_codebase
6
+ exclusions = [
7
+ "app/assets/builds/"
8
+ ]
9
+ File.open("tmp/codebase.txt", "w") do |file|
10
+ Dir.glob("lib/flexi_admin/*.rb").each do |filename|
11
+ next if exclusions.any? { |exclusion| filename.include?(exclusion) }
12
+
13
+ next unless File.file?(filename)
14
+
15
+ file.puts "#filecontent: #{filename}"
16
+ file.puts File.read(filename)
17
+ file.puts "\n"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,104 @@
1
+ require "gemini-ai"
2
+
3
+ # frozen_string_literal: true
4
+
5
+ module FlexiAdmin::Services::CodeGen
6
+ class Gemini
7
+ # Gemini 1.5 Models (Latest)
8
+ MODELS = {
9
+ # Gemini 1.5 Models (Latest)
10
+ gemini_pro: "gemini-1.5-pro-001",
11
+ gemini_pro_latest: "gemini-1.5-pro-002",
12
+ gemini_flash: "gemini-1.5-flash-001",
13
+ gemini_flash_latest: "gemini-1.5-flash-002",
14
+
15
+ # Gemini 1.0 Models
16
+ gemini_1_0_pro: "gemini-1.0-pro",
17
+ gemini_1_0_pro_001: "gemini-1.0-pro-001",
18
+ gemini_1_0_pro_002: "gemini-1.0-pro-002",
19
+
20
+ # Vision Models
21
+ gemini_pro_vision: "gemini-1.0-pro-vision-001"
22
+ }.freeze
23
+
24
+ class Response
25
+ attr_reader :response
26
+
27
+ def initialize(response, format:)
28
+ @response = response
29
+ @format = format
30
+ end
31
+
32
+ def text
33
+ response.map { |r| r["candidates"].first["content"]["parts"].first["text"] }.join
34
+ end
35
+
36
+ def to_h
37
+ JSON.parse(text)
38
+ rescue StandardError
39
+ puts "Error parsing JSON: #{text}"
40
+ {}
41
+ end
42
+ alias as_json to_h
43
+
44
+ def usage
45
+ response.usage&.total_tokens
46
+ end
47
+ end
48
+
49
+ attr_reader :client
50
+
51
+ def build_client(model)
52
+ @client = ::Gemini.new(
53
+ credentials: {
54
+ service: "vertex-ai-api",
55
+ region: "europe-west4",
56
+ file_path: ENV["GOOGLE_APPLICATION_CREDENTIALS"]
57
+ },
58
+ options: { model: MODELS.fetch(model), server_sent_events: true }
59
+ )
60
+ end
61
+
62
+ def chat(message, format: "text", model: :gemini_pro, temperature: 0.8, system_prompt: nil)
63
+ request_body = request_body(message, format, system_prompt, temperature)
64
+
65
+ response = build_client(model).stream_generate_content(request_body)
66
+ Response.new(response, format: format)
67
+ rescue StandardError => e
68
+ binding.pry if Rails.env.development?
69
+ raise e
70
+ end
71
+
72
+ def request_body(message, format, system_prompt = nil, temperature = nil)
73
+ body = {
74
+ contents: [{
75
+ role: "user",
76
+ parts: [{
77
+ text: message
78
+ }]
79
+ }]
80
+ }
81
+
82
+ if format.to_s == "json"
83
+ body[:generation_config] = {
84
+ response_mime_type: "application/json"
85
+ }
86
+ end
87
+
88
+ # Add optional configurations if provided
89
+ if system_prompt
90
+ body[:system_instruction] = {
91
+ role: "system",
92
+ parts: [{
93
+ text: system_prompt
94
+ }]
95
+ }
96
+ end
97
+
98
+ body[:generation_config] ||= {}
99
+ body[:generation_config][:temperature] = temperature if temperature
100
+
101
+ body
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiAdmin::Services::CodeGen
4
+ class Gpt
5
+ GPT_3_5 = 'gpt-3.5-turbo'
6
+ GPT_3_5_16 = 'gpt-3.5-turbo-16k'
7
+ GPT_4 = 'gpt-4-turbo-2024-04-09'
8
+ GPT_4o = 'gpt-4o'
9
+ GPT_4o_mini = 'gpt-4o-mini'
10
+ GPT_o1 = 'gpt-o1'
11
+ GPT_o1_mini = 'o1-mini'
12
+
13
+ class Response
14
+ attr_reader :response
15
+
16
+ def initialize(response, format:)
17
+ @response = response
18
+ @format = format
19
+ end
20
+
21
+ def text
22
+ response.dig('choices', 0, 'message', 'content')
23
+ end
24
+
25
+ def to_h
26
+ JSON.parse(response.dig('choices', 0, 'message', 'content'))
27
+ rescue StandardError
28
+ puts "Error parsing JSON: #{text}"
29
+ {}
30
+ end
31
+ alias as_json to_h
32
+
33
+ def usage
34
+ response.dig('usage', 'total_tokens')
35
+ end
36
+ end
37
+
38
+ attr_reader :client
39
+
40
+ def initialize
41
+ @client = OpenAI::Client.new log_errors: true
42
+ end
43
+
44
+ def chat(message, format: 'text', model: GPT_4o, temperature: nil)
45
+ temperature ||= resolve_temperature(model)
46
+
47
+ response = client.chat(
48
+ parameters: {
49
+ model: model,
50
+ response_format: { type: format.to_s == 'json' ? 'json_object' : 'text' },
51
+ messages: [{ role: 'user', content: message }],
52
+ temperature: temperature
53
+ }
54
+ )
55
+
56
+ Response.new(response, format:)
57
+ end
58
+
59
+ def resolve_temperature(model)
60
+ case model
61
+ when GPT_o1, GPT_o1_mini
62
+ 1
63
+ else
64
+ 0.7
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiAdmin::Services::CodeGen
4
+ EXAMPLES_DIR = 'examples'
5
+
6
+ class Runner
7
+ SYSTEM_PROMPT_FILENAME = 'prompts/codegen-system-prompt.md'
8
+ OUTPUT_PROMPT_FILE = 'tmp/code_gen_prompt.md'
9
+ OUTPUT_CODE_FILE = 'tmp/code_gen_parsed_response.json'
10
+
11
+ attr_reader :client, :model
12
+
13
+ def initialize(client: :gemini, model: :gemini_flash)
14
+ @client = resolve_client(client)
15
+ @model = model
16
+ end
17
+
18
+ def execute(text)
19
+ prompt = prompt(text)
20
+ File.write OUTPUT_PROMPT_FILE, prompt
21
+
22
+ result = client.new.chat prompt, format: :json, model: model
23
+ File.write OUTPUT_CODE_FILE, result.as_json.to_json
24
+ execute_response(result.as_json.dig('files'))
25
+
26
+ result
27
+ rescue StandardError => e
28
+ binding.pry if Rails.env.development?
29
+ raise e
30
+ end
31
+
32
+ def execute_response(array_of_hashes)
33
+ raise "Array of hashes, expected, got #{array_of_hashes.inspect}" if !array_of_hashes.is_a?(Array)
34
+
35
+ array_of_hashes.each do |hash|
36
+ FileUtils.mkdir_p File.dirname(hash['filename'])
37
+ File.write hash['filename'], hash['code']
38
+ end
39
+ end
40
+
41
+ def export_codebase(output_file = 'codebase_export.txt', exclude_patterns = [])
42
+ exclude_patterns = ['tmp/**', 'templates/**', 'examples/**', 'storage/**', 'bin/**', 'db/**', 'vendor/**', 'node_modules/**', 'public/**',
43
+ '*.png', '*.jpg', '*.jpeg', '*.gif', '*.lock', '*.log', '*.pid', '*.pid.lock',
44
+ '*.map', '*.gz', '*.swp', '*.swo', '*.DS_Store']
45
+
46
+ File.open(output_file, 'w') do |file|
47
+ Dir.glob('**/*').each do |path|
48
+ next if exclude_patterns.any? { |pattern| File.fnmatch?(pattern, path) }
49
+ next if File.directory?(path)
50
+ next if File.size(path) > 100 * 1024 # Skip files larger than 100KB
51
+
52
+ file.puts "# #{path}"
53
+ file.puts File.read(path)
54
+ file.puts "\n\n"
55
+ end
56
+ end
57
+ end
58
+
59
+ def system_prompt
60
+ File.read(resolve_file_path(SYSTEM_PROMPT_FILENAME))
61
+ end
62
+
63
+ def gem_info
64
+ @gem_info ||= Gem::Specification.find_by_name('flexi_admin')
65
+ end
66
+
67
+ def prompt(text)
68
+ prompt = system_prompt.gsub('{{task}}', text)
69
+ prompt.gsub('{{sample_files}}', inject_all_files)
70
+ end
71
+
72
+ def inject_files_and_descriptions(*objects)
73
+ result = String.new
74
+ objects.each do |object|
75
+ result << "# Description\n"
76
+ result << "#{object.description}\n\n# Files\n"
77
+ object.files.each do |example_file|
78
+ real_path = example_file.gsub(EXAMPLES_DIR + '/', '')
79
+ result << "/# #{real_path}\n"
80
+ result << "#{File.read(example_file)}\n\n" # Fetch from examples/ directory
81
+ end
82
+ end
83
+ result
84
+ end
85
+
86
+ def inject_all_files
87
+ inject_files_and_descriptions(show_view_files, index_view_files, bulk_action_view_files,
88
+ model_files,
89
+ controller_files,
90
+ config_files)
91
+ end
92
+
93
+ def resolve_file_path(file)
94
+ local_path = gem_info.full_gem_path
95
+ full_path = gem_info.files.find { |f| f.include?(file) }
96
+ File.expand_path(full_path, local_path)
97
+ end
98
+
99
+ def resource_files
100
+ {
101
+ show_views: [
102
+ "#{EXAMPLES_DIR}/app/components/admin/observation/show/edit_form_component.html.slim",
103
+ "#{EXAMPLES_DIR}/app/components/admin/observation/show/edit_form_component.rb",
104
+ "#{EXAMPLES_DIR}/app/components/admin/observation/show/page_component.html.slim",
105
+ "#{EXAMPLES_DIR}/app/components/admin/observation/show/page_component.rb",
106
+ "#{EXAMPLES_DIR}/app/views/admin/observations/show.html.slim"
107
+
108
+ ],
109
+ index_views: [
110
+ "#{EXAMPLES_DIR}/app/components/admin/observation/index_page_component.html.slim",
111
+ "#{EXAMPLES_DIR}/app/components/admin/observation/index_page_component.rb",
112
+ "#{EXAMPLES_DIR}/app/components/admin/observation/resources_component.html.slim",
113
+ "#{EXAMPLES_DIR}/app/components/admin/observation/resources_component.rb",
114
+ "#{EXAMPLES_DIR}/app/components/admin/observation/view/grid_view_component.html.slim",
115
+ "#{EXAMPLES_DIR}/app/components/admin/observation/view/grid_view_component.rb",
116
+ "#{EXAMPLES_DIR}/app/components/admin/observation/view/list_view_component.html.slim",
117
+ "#{EXAMPLES_DIR}/app/components/admin/observation/view/list_view_component.rb",
118
+ "#{EXAMPLES_DIR}/app/views/admin/observations/index.html.slim",
119
+ "#{EXAMPLES_DIR}/app/components/admin/nav/navbar_component.rb"
120
+ ],
121
+ bulk_actions: [
122
+ "#{EXAMPLES_DIR}/app/components/admin/observation_image/action/delete_image.html.slim",
123
+ "#{EXAMPLES_DIR}/app/components/admin/observation_image/action/delete_image.rb"
124
+ ],
125
+ models: [
126
+ "#{EXAMPLES_DIR}/app/models/observation.rb"
127
+ ],
128
+ controllers: [
129
+ "#{EXAMPLES_DIR}/app/controllers/admin/observations_controller.rb"
130
+ ],
131
+ config: [
132
+ "#{EXAMPLES_DIR}/db/schema.rb",
133
+ "#{EXAMPLES_DIR}/config/routes.rb"
134
+ ]
135
+ }
136
+ end
137
+
138
+ def update_resource_examples
139
+ resource_files.each do |_type, files|
140
+ files.each do |file|
141
+ source = file.gsub(EXAMPLES_DIR + '/', '')
142
+ destination = file
143
+ dirname = File.dirname(destination)
144
+
145
+ FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
146
+ FileUtils.cp(source, destination)
147
+ end
148
+ end
149
+ end
150
+
151
+ def show_view_files
152
+ description = <<~DESCRIPTION
153
+ These are files that comprise show views of an application resource.
154
+ DESCRIPTION
155
+
156
+ OpenStruct.new(description:, files: resource_files[:show_views])
157
+ end
158
+
159
+ def index_view_files
160
+ description = <<~DESCRIPTION
161
+ These are files that comprise index views of an application resource.
162
+ DESCRIPTION
163
+
164
+ OpenStruct.new(description:, files: resource_files[:index_views])
165
+ end
166
+
167
+ def bulk_action_view_files
168
+ description = <<~DESCRIPTION
169
+ These are files that comprise components to build bulk actions.
170
+ DESCRIPTION
171
+
172
+ OpenStruct.new(description:, files: resource_files[:bulk_actions])
173
+ end
174
+
175
+ def model_files
176
+ description = <<~DESCRIPTION
177
+ These are files that comprise models of an application resource.
178
+ DESCRIPTION
179
+
180
+ OpenStruct.new(description:, files: resource_files[:models])
181
+ end
182
+
183
+ def controller_files
184
+ description = <<~DESCRIPTION
185
+ These are files that comprise controllers of an application resource.
186
+ DESCRIPTION
187
+
188
+ OpenStruct.new(description:, files: resource_files[:controllers])
189
+ end
190
+
191
+ def config_files
192
+ description = <<~DESCRIPTION
193
+ Various files describing the system setup. Current time is #{Time.now.strftime('%Y%m%d%H%M%S')}.
194
+ DESCRIPTION
195
+
196
+ OpenStruct.new(description:, files: resource_files[:config])
197
+ end
198
+
199
+ def resolve_client(client)
200
+ case client
201
+ when :gpt
202
+ FlexiAdmin::Services::CodeGen::Gpt
203
+ when :gemini
204
+ FlexiAdmin::Services::CodeGen::Gemini
205
+ else
206
+ raise "Unknown client: #{client}, expected :gpt or :gemini"
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiAdmin::Services::CodeGen
4
+ class << self
5
+ def execute(prompt)
6
+ FlexiAdmin::Services::CodeGen::Runner.new.execute(prompt)
7
+ end
8
+ end
9
+ end
10
+
11
+ require_relative "code_gen/runner"
12
+ require_relative "code_gen/code_export"
13
+ require_relative "code_gen/gpt"
14
+ require_relative "code_gen/gemini"
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FlexiAdmin::Services::CreateResource
4
+ attr_reader :params, :resource_class, :errors
5
+
6
+ def initialize(params:, resource_class:)
7
+ @params = params
8
+ @resource_class = resource_class
9
+ @errors = {}
10
+ end
11
+
12
+ def self.run(params:, resource_class:)
13
+ new(params:, resource_class:).run
14
+ end
15
+
16
+ def run
17
+ resource = resource_class.new(params)
18
+
19
+ if resource.save
20
+ resource
21
+ else
22
+ @errors.merge!(resource.errors)
23
+ nil
24
+ end
25
+
26
+ self
27
+ end
28
+
29
+ def valid?
30
+ resource.present? && errors.valid?
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FlexiAdmin::Services::UpdateResource
4
+ attr_reader :resource, :params, :errors
5
+
6
+ def initialize(resource:, params:)
7
+ @resource = resource
8
+ @params = params
9
+ @errors = {}
10
+ end
11
+
12
+ def self.run(resource:, params:)
13
+ new(resource:, params:).run
14
+ end
15
+
16
+ def run
17
+ if resource.update(params)
18
+ resource
19
+ else
20
+ @errors.merge!(resource.errors)
21
+ nil
22
+ end
23
+
24
+ self
25
+ end
26
+
27
+ def valid?
28
+ resource.present? && resource.valid?
29
+ end
30
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiAdmin
4
+ module Services
5
+ end
6
+ end
7
+
8
+ require_relative "services/code_gen"
9
+ require_relative "services/update_resource"
10
+ require_relative "services/create_resource"
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlexiAdmin
4
+ VERSION_FILE = ".gem-version"
5
+ VERSION = "0.0.5"
6
+
7
+ def self.version
8
+ VERSION
9
+ end
10
+ end
@@ -0,0 +1,2 @@
1
+ javascript:
2
+ window.location.href = "#{path.html_safe}";
@@ -0,0 +1,2 @@
1
+ javascript:
2
+ window.location.reload();
@@ -0,0 +1,15 @@
1
+ = turbo_frame_tag 'toasts'
2
+ .toast-container.top-0.end-0.p-3
3
+ - flash.each_with_index do |(type, object), i|
4
+ - object = object if object.is_a?(FlexiAdmin::Models::Toast)
5
+ - object = FlexiAdmin::Models::Toast.new(object) if object.is_a?(String)
6
+ - object = FlexiAdmin::Models::Toast.new(object['message'], delay: object['delay'] || FlexiAdmin::Models::Toast::DELAY) if object.is_a?(Hash)
7
+
8
+ .toast.show.align-items-center.text-bg-primary.border-0.opacity-75 [role="alert"
9
+ aria-live="assertive"
10
+ aria-atomic="true"
11
+ data-controller="toast"
12
+ class="#{toast_class(type)}"]
13
+ .d-flex
14
+ .toast-body = object.to_s.html_safe
15
+ button.btn-close.btn-close-white.me-2.m-auto data-bs-dismiss="toast" aria-label="Close" data-action="click->toast#hide"
@@ -0,0 +1,11 @@
1
+ .container.min-vh-100.d-flex.align-items-center.justify-content-center
2
+ .text-center
3
+ h1.mb-4.text-danger
4
+ | Nemáte oprávnění k zobrazení této stránky
5
+ p.lead.mb-4
6
+ | Pro přístup k této části aplikace potřebujete příslušná oprávnění.
7
+ p.text-muted
8
+ | Pokud si myslíte, že by vám měl být udělen přístup, kontaktujte prosím administrátora.
9
+ .mt-4
10
+ a.btn.btn-primary.btn-lg href="/"
11
+ | Zpět na hlavní stránku
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Gems
4
+ require "slim-rails"
5
+ require "view_component"
6
+ require "will_paginate"
7
+ require "will_paginate-bootstrap-style"
8
+
9
+ # Rails modules
10
+ require "action_view"
11
+ require "active_support"
12
+ require "active_support/core_ext"
13
+
14
+ # Version
15
+ require_relative "flexi_admin/version"
16
+
17
+ # Config
18
+ require_relative "flexi_admin/config"
19
+
20
+ # Helpers
21
+ require_relative "flexi_admin/helpers"
22
+
23
+ # Core modules
24
+ require_relative "flexi_admin/controllers"
25
+ require_relative "flexi_admin/components"
26
+ require_relative "flexi_admin/models"
27
+ require_relative "flexi_admin/services"
28
+
29
+ begin
30
+ # Railtie
31
+ require "flexi_admin/railtie" if defined?(Rails)
32
+ rescue LoadError
33
+ puts "FlexiAdmin::Railtie not loaded"
34
+ end
35
+
36
+ begin
37
+ # Routes
38
+ require "flexi_admin/routes"
39
+ rescue LoadError
40
+ puts "FlexiAdmin::Routes not loaded"
41
+ end
42
+
43
+ module FlexiAdmin
44
+ # Temporary fix to solve admin files namespaced in Admin namespace
45
+ NAMESPACE = "Admin"
46
+
47
+ class Error < StandardError; end
48
+
49
+ class << self
50
+ def configure(&block)
51
+ FlexiAdmin::Config.configure(&block)
52
+ end
53
+
54
+ def configuration
55
+ FlexiAdmin::Config.configuration
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ namespace :flexi_admin do
2
+ desc "Generate code for a given entity"
3
+ task :codegen, [:prompt] => :environment do |_t, _args|
4
+ prompt = ENV["prompt"]
5
+
6
+ abort "prompt is required" if prompt.nil? || prompt.strip.empty?
7
+
8
+ FlexiAdmin::Services::CodeGen::Runner.new(model: :gemini_flash).execute(prompt)
9
+ end
10
+
11
+ task :update_code_examples do
12
+ FlexiAdmin::Services::CodeGen::Runner.new.update_resource_examples
13
+ end
14
+
15
+ desc "Setup SASS path"
16
+ task :sass_path do
17
+ # !/usr/bin/env ruby
18
+
19
+ # Define the array of paths
20
+ sass_paths = []
21
+ sass_paths << "./node_modules"
22
+
23
+ # Get the absolute path of the gem
24
+ gem_path = Gem::Specification.find_by_name("flexi_admin").gem_dir
25
+
26
+ if gem_path.empty?
27
+ warn "Error: Unable to find gem path for #{gem_name}"
28
+ exit 1
29
+ end
30
+
31
+ # Add gem-related paths
32
+ sass_paths << "#{gem_path}/app/assets/stylesheets"
33
+ sass_paths << "#{gem_path}/app/assets/stylesheets/components"
34
+
35
+ # Join paths with ':' and return the joined path
36
+ puts sass_paths.join(":")
37
+ end
38
+
39
+ desc "Setup node path"
40
+ task :node_path do
41
+ gem_path = Gem::Specification.find_by_name("flexi_admin").gem_dir
42
+
43
+ node_paths ||= []
44
+ node_paths << "./node_modules"
45
+ node_paths << "#{gem_path}/lib/flexi_admin/javascript"
46
+
47
+ puts node_paths.join(":")
48
+ end
49
+ end