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.
- checksums.yaml +7 -0
- data/README.md +42 -0
- data/Rakefile +7 -0
- data/lib/flexi_admin/components/actions/checkbox_component.html.slim +8 -0
- data/lib/flexi_admin/components/actions/checkbox_component.rb +13 -0
- data/lib/flexi_admin/components/actions/select_component.html.slim +11 -0
- data/lib/flexi_admin/components/actions/select_component.rb +17 -0
- data/lib/flexi_admin/components/base_component.rb +19 -0
- data/lib/flexi_admin/components/form/field_component.rb +11 -0
- data/lib/flexi_admin/components/form/label_component.html.slim +2 -0
- data/lib/flexi_admin/components/form/label_component.rb +13 -0
- data/lib/flexi_admin/components/form/rows_component.rb +9 -0
- data/lib/flexi_admin/components/form/text_input_component.html.slim +5 -0
- data/lib/flexi_admin/components/form/text_input_component.rb +17 -0
- data/lib/flexi_admin/components/helpers/action_button_helper.rb +28 -0
- data/lib/flexi_admin/components/helpers/action_helper.rb +12 -0
- data/lib/flexi_admin/components/helpers/icon_helper.rb +11 -0
- data/lib/flexi_admin/components/helpers/link_helper.rb +8 -0
- data/lib/flexi_admin/components/helpers/resource_helper.rb +71 -0
- data/lib/flexi_admin/components/helpers/selectable.rb +11 -0
- data/lib/flexi_admin/components/helpers/url_helper.rb +8 -0
- data/lib/flexi_admin/components/helpers/value_formatter.rb +32 -0
- data/lib/flexi_admin/components/nav/floating_toc_component.html.slim +2 -0
- data/lib/flexi_admin/components/nav/floating_toc_component.rb +6 -0
- data/lib/flexi_admin/components/resource/autocomplete_component.html.slim +30 -0
- data/lib/flexi_admin/components/resource/autocomplete_component.rb +83 -0
- data/lib/flexi_admin/components/resource/button_select_component.html.slim +13 -0
- data/lib/flexi_admin/components/resource/button_select_component.rb +19 -0
- data/lib/flexi_admin/components/resource/form_component.rb +18 -0
- data/lib/flexi_admin/components/resource/form_element_component.html.slim +3 -0
- data/lib/flexi_admin/components/resource/form_element_component.rb +31 -0
- data/lib/flexi_admin/components/resource/form_mixin.rb +287 -0
- data/lib/flexi_admin/components/resource/link_action_component.html.slim +8 -0
- data/lib/flexi_admin/components/resource/link_action_component.rb +16 -0
- data/lib/flexi_admin/components/resource/show_page_component.rb +21 -0
- data/lib/flexi_admin/components/resource/view_component.html.slim +26 -0
- data/lib/flexi_admin/components/resource/view_component.rb +22 -0
- data/lib/flexi_admin/components/resources/bulk_action/button_component.html.slim +7 -0
- data/lib/flexi_admin/components/resources/bulk_action/button_component.rb +29 -0
- data/lib/flexi_admin/components/resources/bulk_action/modal_component.html.slim +32 -0
- data/lib/flexi_admin/components/resources/bulk_action/modal_component.rb +54 -0
- data/lib/flexi_admin/components/resources/grid_view/card_component.html.slim +18 -0
- data/lib/flexi_admin/components/resources/grid_view/card_component.rb +65 -0
- data/lib/flexi_admin/components/resources/grid_view/grid_component.html.slim +10 -0
- data/lib/flexi_admin/components/resources/grid_view/grid_component.rb +16 -0
- data/lib/flexi_admin/components/resources/grid_view_component.rb +89 -0
- data/lib/flexi_admin/components/resources/index_page_component.html.slim +13 -0
- data/lib/flexi_admin/components/resources/index_page_component.rb +19 -0
- data/lib/flexi_admin/components/resources/list_view/cell_component.html.slim +2 -0
- data/lib/flexi_admin/components/resources/list_view/cell_component.rb +26 -0
- data/lib/flexi_admin/components/resources/list_view/table_component.html.slim +17 -0
- data/lib/flexi_admin/components/resources/list_view/table_component.rb +21 -0
- data/lib/flexi_admin/components/resources/list_view_component.rb +80 -0
- data/lib/flexi_admin/components/resources/pagination_component.html.slim +42 -0
- data/lib/flexi_admin/components/resources/pagination_component.rb +64 -0
- data/lib/flexi_admin/components/resources/resources_component.rb +34 -0
- data/lib/flexi_admin/components/resources/switch_view_component.html.slim +16 -0
- data/lib/flexi_admin/components/resources/switch_view_component.rb +45 -0
- data/lib/flexi_admin/components/resources/view_component.html.slim +12 -0
- data/lib/flexi_admin/components/resources/view_component.rb +15 -0
- data/lib/flexi_admin/components/shared/alert_component.html.slim +2 -0
- data/lib/flexi_admin/components/shared/alert_component.rb +11 -0
- data/lib/flexi_admin/components/shared/autocomplete/results_component.html.slim +15 -0
- data/lib/flexi_admin/components/shared/autocomplete/results_component.rb +50 -0
- data/lib/flexi_admin/components/shared/autocomplete.rb +6 -0
- data/lib/flexi_admin/components/shared/datalist_component.html.slim +24 -0
- data/lib/flexi_admin/components/shared/datalist_component.rb +20 -0
- data/lib/flexi_admin/components/shared/link_component.html.slim +3 -0
- data/lib/flexi_admin/components/shared/link_component.rb +15 -0
- data/lib/flexi_admin/components/shared/medium_component.html.slim +7 -0
- data/lib/flexi_admin/components/shared/medium_component.rb +51 -0
- data/lib/flexi_admin/components/shared/table/header_item_component.html.slim +9 -0
- data/lib/flexi_admin/components/shared/table/header_item_component.rb +78 -0
- data/lib/flexi_admin/components/shared/trix_component.html.slim +22 -0
- data/lib/flexi_admin/components/shared/trix_component.rb +21 -0
- data/lib/flexi_admin/components.rb +87 -0
- data/lib/flexi_admin/config.rb +24 -0
- data/lib/flexi_admin/controllers/modals_controller.rb +13 -0
- data/lib/flexi_admin/controllers/resources_controller.rb +240 -0
- data/lib/flexi_admin/controllers.rb +9 -0
- data/lib/flexi_admin/engine.rb +34 -0
- data/lib/flexi_admin/helpers/application_helper.rb +4 -0
- data/lib/flexi_admin/helpers.rb +8 -0
- data/lib/flexi_admin/javascript/controllers/application.js +9 -0
- data/lib/flexi_admin/javascript/controllers/autocomplete_controller.js +142 -0
- data/lib/flexi_admin/javascript/controllers/bulk_action_controller.js +158 -0
- data/lib/flexi_admin/javascript/controllers/button_select_controller.js +32 -0
- data/lib/flexi_admin/javascript/controllers/datalist_controller.js +104 -0
- data/lib/flexi_admin/javascript/controllers/floating_toc_controller.js +39 -0
- data/lib/flexi_admin/javascript/controllers/form_controller.js +17 -0
- data/lib/flexi_admin/javascript/controllers/form_validation_controller.js +86 -0
- data/lib/flexi_admin/javascript/controllers/index.js +44 -0
- data/lib/flexi_admin/javascript/controllers/pagination_controller.js +13 -0
- data/lib/flexi_admin/javascript/controllers/sorting_controller.js +17 -0
- data/lib/flexi_admin/javascript/controllers/switch_view_controller.js +15 -0
- data/lib/flexi_admin/javascript/controllers/toast_controller.js +18 -0
- data/lib/flexi_admin/javascript/controllers/trix_controller.js +32 -0
- data/lib/flexi_admin/javascript/controllers/uploads_controller.js +164 -0
- data/lib/flexi_admin/javascript/flexi_admin.js +4 -0
- data/lib/flexi_admin/javascript/utils.js +26 -0
- data/lib/flexi_admin/models/concerns/application_resource.rb +25 -0
- data/lib/flexi_admin/models/concerns/parentable.rb +17 -0
- data/lib/flexi_admin/models/context_params.rb +127 -0
- data/lib/flexi_admin/models/resources/context.rb +59 -0
- data/lib/flexi_admin/models/struct.rb +29 -0
- data/lib/flexi_admin/models/toast.rb +23 -0
- data/lib/flexi_admin/models.rb +20 -0
- data/lib/flexi_admin/prompts/codegen-system-prompt.md +50 -0
- data/lib/flexi_admin/railtie.rb +78 -0
- data/lib/flexi_admin/routes.rb +15 -0
- data/lib/flexi_admin/services/code_gen/code_export.rb +22 -0
- data/lib/flexi_admin/services/code_gen/gemini.rb +104 -0
- data/lib/flexi_admin/services/code_gen/gpt.rb +68 -0
- data/lib/flexi_admin/services/code_gen/runner.rb +210 -0
- data/lib/flexi_admin/services/code_gen.rb +14 -0
- data/lib/flexi_admin/services/create_resource.rb +32 -0
- data/lib/flexi_admin/services/update_resource.rb +30 -0
- data/lib/flexi_admin/services.rb +10 -0
- data/lib/flexi_admin/version.rb +10 -0
- data/lib/flexi_admin/views/shared/_redirect.slim +2 -0
- data/lib/flexi_admin/views/shared/_reload.slim +2 -0
- data/lib/flexi_admin/views/shared/_toasts.slim +15 -0
- data/lib/flexi_admin/views/shared/not_authorized.slim +11 -0
- data/lib/flexi_admin.rb +58 -0
- data/lib/tasks/flexi_admin.rake +49 -0
- data/lib/tasks/semantic.rake +57 -0
- 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,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
|
data/lib/flexi_admin.rb
ADDED
@@ -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
|