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,32 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
// Connects to data-controller="trix"
|
4
|
+
export default class extends Controller {
|
5
|
+
static values = { disabled: Boolean, collapsed: Boolean };
|
6
|
+
static targets = ["editor", "trigger", "container"];
|
7
|
+
|
8
|
+
connect() {
|
9
|
+
if (this.disabledValue === false) {
|
10
|
+
// Set background color to white
|
11
|
+
this.editorTarget.style.backgroundColor = "white";
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
toggleCollapse() {
|
16
|
+
if (this.collapsedValue === true) {
|
17
|
+
this.containerTarget.classList.remove("collapsed");
|
18
|
+
this.containerTarget.classList.add("expanded");
|
19
|
+
this.collapsedValue = false;
|
20
|
+
} else {
|
21
|
+
this.containerTarget.classList.remove("expanded");
|
22
|
+
this.containerTarget.classList.add("collapsed");
|
23
|
+
this.collapsedValue = true;
|
24
|
+
}
|
25
|
+
|
26
|
+
if (this.triggerTarget.innerHTML === "rozbalit") {
|
27
|
+
this.triggerTarget.innerHTML = "skrýt";
|
28
|
+
} else {
|
29
|
+
this.triggerTarget.innerHTML = "rozbalit";
|
30
|
+
}
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
import { CSRFToken } from "../utils";
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
static targets = [
|
6
|
+
"form",
|
7
|
+
"list",
|
8
|
+
"globalProgress",
|
9
|
+
"globalProgressBar",
|
10
|
+
"resetButton",
|
11
|
+
"filesInput",
|
12
|
+
];
|
13
|
+
|
14
|
+
connect() {
|
15
|
+
this.element.addEventListener("direct-uploads:start", (event) => {
|
16
|
+
this._initGlobalProgress();
|
17
|
+
});
|
18
|
+
|
19
|
+
this.element.addEventListener("direct-upload:initialize", (event) => {
|
20
|
+
const { id, file } = event.detail;
|
21
|
+
this._initializeFileCard(id, file);
|
22
|
+
});
|
23
|
+
|
24
|
+
this.element.addEventListener("direct-upload:progress", (event) => {
|
25
|
+
const { id, file, progress } = event.detail;
|
26
|
+
this._updateImageProgress(id, progress);
|
27
|
+
});
|
28
|
+
|
29
|
+
this.element.addEventListener("direct-upload:end", (event) => {
|
30
|
+
const { id, file } = event.detail;
|
31
|
+
this._reportCompletion(file, id);
|
32
|
+
this._updateImageProgress(id, 100);
|
33
|
+
this._updateGlobalProgress();
|
34
|
+
});
|
35
|
+
|
36
|
+
this.element.addEventListener("direct-uploads:end", (event) => {
|
37
|
+
this.resetButtonTarget.classList.remove("d-none");
|
38
|
+
});
|
39
|
+
|
40
|
+
this.element.addEventListener("direct-upload:error", (event) => {
|
41
|
+
const { id } = event.detail;
|
42
|
+
this._setErrorProgress(id);
|
43
|
+
});
|
44
|
+
}
|
45
|
+
|
46
|
+
resetForm() {
|
47
|
+
this.formTarget.reset();
|
48
|
+
// hide global progress
|
49
|
+
this.globalProgressTarget.classList.remove("show");
|
50
|
+
// hide reset button
|
51
|
+
this.resetButtonTarget.classList.add("d-none");
|
52
|
+
// reset counters
|
53
|
+
this.totalCount = 0;
|
54
|
+
this.currentCount = 0;
|
55
|
+
// clear list
|
56
|
+
this.listTarget.innerHTML = "";
|
57
|
+
// enable the input field
|
58
|
+
this.filesInputTarget.disabled = false;
|
59
|
+
}
|
60
|
+
|
61
|
+
_initGlobalProgress(totalCount) {
|
62
|
+
const filesInput = this.filesInputTarget;
|
63
|
+
this.totalCount = filesInput.files.length;
|
64
|
+
this.currentCount = 0;
|
65
|
+
|
66
|
+
this.globalProgressTarget.classList.add("show");
|
67
|
+
this.globalProgressBarTarget.style.width = `${0}%`;
|
68
|
+
this.globalProgressBarTarget.setAttribute("aria-valuenow", 0);
|
69
|
+
this.globalProgressBarTarget.textContent = `0/${totalCount}`;
|
70
|
+
}
|
71
|
+
|
72
|
+
_updateGlobalProgress() {
|
73
|
+
const globalProgressBar = this.globalProgressBarTarget;
|
74
|
+
this.currentCount += 1;
|
75
|
+
|
76
|
+
const perCent = (this.currentCount / this.totalCount) * 100;
|
77
|
+
globalProgressBar.style.width = `${perCent}%`;
|
78
|
+
globalProgressBar.setAttribute("aria-valuenow", perCent);
|
79
|
+
globalProgressBar.textContent = `${this.currentCount}/${this.totalCount}`;
|
80
|
+
}
|
81
|
+
|
82
|
+
_setErrorProgress(id) {
|
83
|
+
const element = document.getElementById(`upload-${id}`);
|
84
|
+
const progressBar = element.querySelector(".progress-bar");
|
85
|
+
progressBar.classList.add("bg-danger");
|
86
|
+
progressBar.style.width = "100%";
|
87
|
+
progressBar.setAttribute("aria-valuenow", 100);
|
88
|
+
}
|
89
|
+
|
90
|
+
_updateImageProgress(id, progress) {
|
91
|
+
const element = document.getElementById(`upload-${id}`);
|
92
|
+
const progressBar = element.querySelector(".progress-bar");
|
93
|
+
progressBar.style.width = `${progress}%`;
|
94
|
+
progressBar.setAttribute("aria-valuenow", progress);
|
95
|
+
}
|
96
|
+
|
97
|
+
_switchToVideo(id, url) {
|
98
|
+
const element = document.getElementById(`upload-${id}`);
|
99
|
+
const videoContainer = element.querySelector(".upload-video");
|
100
|
+
const video = element.querySelector(".upload-video video");
|
101
|
+
const icon = element.querySelector(".upload-icon");
|
102
|
+
video.src = url;
|
103
|
+
icon.classList.add("d-none");
|
104
|
+
videoContainer.classList.add("show");
|
105
|
+
}
|
106
|
+
|
107
|
+
_switchToImage(id, url) {
|
108
|
+
const element = document.getElementById(`upload-${id}`);
|
109
|
+
const imageContainer = element.querySelector(".upload-image");
|
110
|
+
const image = element.querySelector(".upload-image img");
|
111
|
+
const icon = element.querySelector(".upload-icon");
|
112
|
+
image.src = url;
|
113
|
+
icon.classList.add("d-none");
|
114
|
+
imageContainer.classList.add("show");
|
115
|
+
}
|
116
|
+
|
117
|
+
_reportCompletion(file, id) {
|
118
|
+
const name = file.name;
|
119
|
+
const size = file.size;
|
120
|
+
|
121
|
+
fetch("/uploads/soft_completed", {
|
122
|
+
method: "POST",
|
123
|
+
headers: {
|
124
|
+
"Content-Type": "application/json",
|
125
|
+
"X-CSRF-Token": CSRFToken(),
|
126
|
+
Accept: "application/json",
|
127
|
+
},
|
128
|
+
body: JSON.stringify({ name, size }),
|
129
|
+
})
|
130
|
+
.then((response) => response.json())
|
131
|
+
.then((data) => {
|
132
|
+
const { url, kind } = data;
|
133
|
+
if (url) {
|
134
|
+
if (kind === "video") {
|
135
|
+
this._switchToVideo(id, url);
|
136
|
+
} else {
|
137
|
+
this._switchToImage(id, url);
|
138
|
+
}
|
139
|
+
}
|
140
|
+
})
|
141
|
+
.catch((error) => console.error("Error:", error));
|
142
|
+
}
|
143
|
+
|
144
|
+
_initializeFileCard(id, file) {
|
145
|
+
const name = file.name;
|
146
|
+
const size = file.size;
|
147
|
+
const contentType = file.type;
|
148
|
+
|
149
|
+
fetch("/uploads/initialize_upload", {
|
150
|
+
method: "POST",
|
151
|
+
headers: {
|
152
|
+
"Content-Type": "application/json",
|
153
|
+
"X-CSRF-Token": CSRFToken(),
|
154
|
+
Accept: "text/html",
|
155
|
+
},
|
156
|
+
body: JSON.stringify({ id, name, size, contentType }),
|
157
|
+
})
|
158
|
+
.then((response) => response.text())
|
159
|
+
.then((html) => {
|
160
|
+
this.listTarget.insertAdjacentHTML("afterbegin", html);
|
161
|
+
})
|
162
|
+
.catch((error) => console.error("Error:", error));
|
163
|
+
}
|
164
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
export function CSRFToken() {
|
2
|
+
const metaTag = document.querySelector('meta[name="csrf-token"]');
|
3
|
+
return metaTag ? metaTag.getAttribute("content") : null;
|
4
|
+
}
|
5
|
+
|
6
|
+
export function fetchTurboContent(event, path) {
|
7
|
+
event.preventDefault();
|
8
|
+
|
9
|
+
fetch(path, {
|
10
|
+
headers: {
|
11
|
+
Accept: "text/vnd.turbo-stream.html",
|
12
|
+
},
|
13
|
+
})
|
14
|
+
.then((response) => response.text())
|
15
|
+
.then((html) => {
|
16
|
+
Turbo.renderStreamMessage(html);
|
17
|
+
})
|
18
|
+
.catch((error) => {
|
19
|
+
console.error("Error fetching content:", error);
|
20
|
+
});
|
21
|
+
}
|
22
|
+
|
23
|
+
export function markValid(event) {
|
24
|
+
event.target.setCustomValidity("");
|
25
|
+
event.target.checkValidity();
|
26
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Models::Concerns::ApplicationResource
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
include FlexiAdmin::Models::Concerns::Parentable
|
6
|
+
|
7
|
+
def identifier
|
8
|
+
"#{self.class.name.underscore}_#{id}"
|
9
|
+
end
|
10
|
+
alias frame_id identifier
|
11
|
+
|
12
|
+
def form_id
|
13
|
+
"#{identifier}_form"
|
14
|
+
end
|
15
|
+
|
16
|
+
def gid_param
|
17
|
+
gid = to_gid
|
18
|
+
|
19
|
+
URI.encode_www_form_component(gid)
|
20
|
+
end
|
21
|
+
|
22
|
+
def raw(attribute)
|
23
|
+
read_attribute_before_type_cast(attribute)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Models::Concerns::Parentable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
scope :with_parent, lambda { |parent_instance|
|
8
|
+
return all if parent_instance.blank?
|
9
|
+
|
10
|
+
plural_name = parent_instance.class.model_name.plural
|
11
|
+
|
12
|
+
association_name = model.reflect_on_all_associations.find { |a| a.plural_name == plural_name }.name
|
13
|
+
|
14
|
+
joins(association_name).where(association_name => { id: parent_instance.id })
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Models
|
4
|
+
class ContextParams
|
5
|
+
MAP = {
|
6
|
+
scope: 'fa_scope',
|
7
|
+
page: 'fa_page',
|
8
|
+
per_page: 'fa_per_page',
|
9
|
+
parent: 'fa_parent',
|
10
|
+
frame: 'fa_frame', # target turbolinks frame
|
11
|
+
sort: 'fa_sort',
|
12
|
+
order: 'fa_order',
|
13
|
+
form_disabled: 'fa_form_disabled',
|
14
|
+
view: 'fa_view',
|
15
|
+
ac_action: 'ac_action', # autocomplete action
|
16
|
+
ac_fields: { 'ac_fields': [] }, # autocomplete result fields
|
17
|
+
ac_path: 'ac_path' # autocomplete path for opening resource in new window
|
18
|
+
}
|
19
|
+
|
20
|
+
def self.permitted_params_keys
|
21
|
+
MAP.values
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.permitted_keys
|
25
|
+
MAP.keys.map(&:to_sym)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.params_map
|
29
|
+
MAP.each_with_object({}) do |(key, value), acc|
|
30
|
+
acc[key] = value.is_a?(Hash) ? value.keys.first.to_s : value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :params
|
35
|
+
|
36
|
+
def initialize(params)
|
37
|
+
@params = params.to_h.with_indifferent_access.each_with_object({}) do |(key, value), acc|
|
38
|
+
acc[self.class.params_map.invert[key.to_s]] = value
|
39
|
+
end.with_indifferent_access
|
40
|
+
end
|
41
|
+
|
42
|
+
def [](key)
|
43
|
+
@params[key]
|
44
|
+
end
|
45
|
+
|
46
|
+
def merge(params)
|
47
|
+
new_params = @params.dup.merge(params.to_h.with_indifferent_access)
|
48
|
+
|
49
|
+
if params.keys.any? { |key| !self.class.permitted_keys.include?(key.to_sym) }
|
50
|
+
msg = "ContextParams: invalid params: "
|
51
|
+
msg += params.keys.select { |key| !self.class.permitted_keys.include?(key.to_sym) }.join(", ")
|
52
|
+
Rails.logger.warn msg
|
53
|
+
end
|
54
|
+
|
55
|
+
new_params = new_params.transform_keys { |key| self.class.params_map[key.to_sym] || key.to_sym }
|
56
|
+
|
57
|
+
self.class.new(new_params)
|
58
|
+
end
|
59
|
+
|
60
|
+
def with_parent(parent_instance)
|
61
|
+
return self if parent_instance.blank?
|
62
|
+
|
63
|
+
merge(parent: parent_instance.gid_param)
|
64
|
+
end
|
65
|
+
|
66
|
+
def with_parent!(parent_instance)
|
67
|
+
params[:parent] = parent_instance.gid_param
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def except(*keys)
|
72
|
+
new_params = @params.dup.except(*keys)
|
73
|
+
new_params = new_params.transform_keys { |key| self.class.params_map.invert[key.to_s] }
|
74
|
+
self.class.new(new_params)
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_params
|
78
|
+
self.class.params_map.map { |k, v| [v, params[k]] }
|
79
|
+
.reject { |_k, v| v.blank? }.to_h
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_path(path)
|
83
|
+
path + "?" + to_params.to_query
|
84
|
+
end
|
85
|
+
|
86
|
+
def parent
|
87
|
+
params[:parent]
|
88
|
+
end
|
89
|
+
|
90
|
+
def per_page
|
91
|
+
params[:per_page] || 13
|
92
|
+
end
|
93
|
+
|
94
|
+
def page
|
95
|
+
params[:page] || 1
|
96
|
+
end
|
97
|
+
|
98
|
+
def frame
|
99
|
+
params[:frame] || '_top'
|
100
|
+
end
|
101
|
+
|
102
|
+
# Not sure if this is needed
|
103
|
+
def scope
|
104
|
+
params[:scope]
|
105
|
+
end
|
106
|
+
|
107
|
+
def form_disabled
|
108
|
+
params[:form_disabled] || false
|
109
|
+
end
|
110
|
+
|
111
|
+
def current_view
|
112
|
+
params[:view]
|
113
|
+
end
|
114
|
+
|
115
|
+
def pagination
|
116
|
+
{ page:, per_page: }
|
117
|
+
end
|
118
|
+
|
119
|
+
def sort
|
120
|
+
params[:sort]
|
121
|
+
end
|
122
|
+
|
123
|
+
def order
|
124
|
+
params[:order]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Models::Resources
|
4
|
+
class Context
|
5
|
+
attr_reader :resources, :scope, :params, :options
|
6
|
+
|
7
|
+
def initialize(resources, scope, params, options)
|
8
|
+
@resources = resources
|
9
|
+
@scope = scope
|
10
|
+
@params = params
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource
|
15
|
+
resources
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.build(resource: nil, scope: nil, params: FlexiAdmin::Models::ContextParams.new({}), **options)
|
19
|
+
new(resource, scope, params, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.from_params(context_params, resources = nil)
|
23
|
+
parent = load_parent(context_params)
|
24
|
+
|
25
|
+
new(
|
26
|
+
resources,
|
27
|
+
context_params.scope,
|
28
|
+
context_params,
|
29
|
+
{}.merge(parent:)
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.load_parent(context_params)
|
34
|
+
return nil if context_params.parent.blank?
|
35
|
+
|
36
|
+
gid = URI.decode_www_form_component(context_params.parent)
|
37
|
+
|
38
|
+
GlobalID::Locator.locate(gid)
|
39
|
+
end
|
40
|
+
|
41
|
+
def views
|
42
|
+
options[:views] || %w[list]
|
43
|
+
end
|
44
|
+
|
45
|
+
def paginate?
|
46
|
+
options.key?(:paginate) || true
|
47
|
+
end
|
48
|
+
|
49
|
+
def parent
|
50
|
+
options[:parent]
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_params
|
54
|
+
params.merge(scope:)
|
55
|
+
.with_parent(parent)
|
56
|
+
.to_params
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Models
|
4
|
+
class Struct
|
5
|
+
def self.new(*positional_attrs, **keyword_attrs)
|
6
|
+
Class.new do
|
7
|
+
attr_reader(*positional_attrs, *keyword_attrs.keys)
|
8
|
+
|
9
|
+
define_method :initialize do |*args, **kwargs|
|
10
|
+
if args.size != positional_attrs.size
|
11
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected #{positional_attrs.size})"
|
12
|
+
end
|
13
|
+
|
14
|
+
unknown_kwargs = kwargs.keys - keyword_attrs.keys
|
15
|
+
raise ArgumentError, "unknown keywords: #{unknown_kwargs.join(", ")}" unless unknown_kwargs.empty?
|
16
|
+
|
17
|
+
positional_attrs.zip(args).each do |attr, value|
|
18
|
+
instance_variable_set("@#{attr}", value)
|
19
|
+
end
|
20
|
+
|
21
|
+
keyword_attrs.each do |attr, default|
|
22
|
+
value = kwargs.key?(attr) ? kwargs[attr] : default
|
23
|
+
instance_variable_set("@#{attr}", value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin::Models
|
4
|
+
class Toast
|
5
|
+
DELAY = 4
|
6
|
+
attr_reader :message, :options, :autohide, :delay_sec
|
7
|
+
|
8
|
+
def initialize(message, **options)
|
9
|
+
@message = message
|
10
|
+
@options = options
|
11
|
+
@autohide = options.fetch(:autohide, true)
|
12
|
+
@delay_sec = options.fetch(:delay, DELAY)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
message
|
17
|
+
end
|
18
|
+
|
19
|
+
def delay
|
20
|
+
delay_sec * 1000
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin
|
4
|
+
module Models
|
5
|
+
module Concerns; end
|
6
|
+
module Resources; end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Core
|
11
|
+
require_relative "models/context_params"
|
12
|
+
require_relative "models/struct"
|
13
|
+
require_relative "models/toast"
|
14
|
+
|
15
|
+
# Concerns
|
16
|
+
require_relative "models/concerns/parentable"
|
17
|
+
require_relative "models/concerns/application_resource"
|
18
|
+
|
19
|
+
# Resources
|
20
|
+
require_relative "models/resources/context"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Act as a Code Generation Assistant
|
2
|
+
|
3
|
+
- **You are** an advanced **Code Generation Assistant** skilled in generating structured code based on provided application architecture patterns in the following technologies: Ruby on Rails, Javascript (Stimulus JS) and Bootstrap.
|
4
|
+
- follow instructions in the <Task> section.
|
5
|
+
|
6
|
+
## Objective
|
7
|
+
|
8
|
+
Your objective is to:
|
9
|
+
|
10
|
+
1. **Identify** which files need to be created based on the <Task> description, <CodeSamples> and known Rails file conventions.
|
11
|
+
2. **Generate** code for each file with patterns similar to the provided examples in <CodeSamples> section, following naming conventions, structural organization and class inheritance.
|
12
|
+
|
13
|
+
## Task Requirements
|
14
|
+
|
15
|
+
1. **Adhere** to comments provided in the file samples in <CodeSamples> section, tagged with "CodeGen:"
|
16
|
+
2. **Omit** any comments marked as "CodeGen:" in the final output.
|
17
|
+
3. **Return** a array of JSON objects, where each object always includes:
|
18
|
+
- **filename**: the determined filename for the generated code.
|
19
|
+
- **code**: the generated code as per the task requirements.
|
20
|
+
|
21
|
+
## Output schema
|
22
|
+
|
23
|
+
```json
|
24
|
+
{
|
25
|
+
"files": [
|
26
|
+
{
|
27
|
+
"filename": "string",
|
28
|
+
"code": "string"
|
29
|
+
}
|
30
|
+
]
|
31
|
+
}
|
32
|
+
```
|
33
|
+
|
34
|
+
---
|
35
|
+
|
36
|
+
<CodeSamples>
|
37
|
+
|
38
|
+
```plaintext
|
39
|
+
{{sample_files}}
|
40
|
+
```
|
41
|
+
|
42
|
+
</CodeSamples>
|
43
|
+
|
44
|
+
---
|
45
|
+
|
46
|
+
<Task>
|
47
|
+
|
48
|
+
{{task}}
|
49
|
+
|
50
|
+
</Task>
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
# Don't need this for now
|
4
|
+
# require "flexi_admin/engine"
|
5
|
+
|
6
|
+
module FlexiAdmin
|
7
|
+
class Railtie < Rails::Railtie
|
8
|
+
rake_tasks do
|
9
|
+
load "tasks/flexi_admin.rake"
|
10
|
+
end
|
11
|
+
|
12
|
+
initializer "flexi_admin.asset_paths" do |_app|
|
13
|
+
# This enables
|
14
|
+
setup_node_path
|
15
|
+
setup_sass_path
|
16
|
+
end
|
17
|
+
|
18
|
+
initializer "flexi_admin.configure" do |app|
|
19
|
+
# Add any additional configuration here
|
20
|
+
end
|
21
|
+
|
22
|
+
initializer "flexi_admin.assets" do |app|
|
23
|
+
# Add asset paths to host application
|
24
|
+
app.config.assets.paths << absolute_gem_path("lib/flexi_admin/javascript")
|
25
|
+
app.config.assets.paths << absolute_gem_path("app/assets/stylesheets")
|
26
|
+
end
|
27
|
+
|
28
|
+
# # Configure importmap if using it
|
29
|
+
# initializer "flexi_admin.importmap", before: "importmap" do |app|
|
30
|
+
# if app.config.respond_to?(:importmap)
|
31
|
+
# app.config.importmap.paths << absolute_gem_path("app/flexi_admin/javascript")
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
|
35
|
+
# initializer "flexi_admin.helpers" do
|
36
|
+
# ActiveSupport.on_load(:action_controller) do
|
37
|
+
# include FlexiAdmin::Helpers::ApplicationHelper
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
|
41
|
+
initializer "flexi_admin.add_view_paths" do |_app|
|
42
|
+
# Assuming your gem has a `app/views` directory
|
43
|
+
custom_views_path = File.expand_path("../flexi_admin/views", __dir__)
|
44
|
+
|
45
|
+
# Add the path to the application's view paths
|
46
|
+
ActiveSupport.on_load(:action_controller) do
|
47
|
+
ActionController::Base.prepend_view_path(custom_views_path)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def absolute_gem_path(path)
|
52
|
+
[Gem::Specification.find_by_name("flexi_admin").gem_dir, path].join("/")
|
53
|
+
end
|
54
|
+
|
55
|
+
def setup_node_path
|
56
|
+
node_paths ||= []
|
57
|
+
node_paths << "./node_modules"
|
58
|
+
node_paths << absolute_gem_path("lib/flexi_admin/javascript")
|
59
|
+
ENV["NODE_PATH"] = node_paths.join(":")
|
60
|
+
|
61
|
+
# Set the NODE_PATH for the current bash session
|
62
|
+
# https://nodejs.org/api/modules.html#loading-from-the-global-folders
|
63
|
+
system("export NODE_PATH=#{ENV["NODE_PATH"]}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup_sass_path
|
67
|
+
sass_paths ||= []
|
68
|
+
sass_paths << "./node_modules"
|
69
|
+
sass_paths << absolute_gem_path("app/assets/stylesheets")
|
70
|
+
sass_paths << absolute_gem_path("app/assets/stylesheets/components")
|
71
|
+
ENV["SASS_PATH"] = sass_paths.join(":")
|
72
|
+
|
73
|
+
# Set the SASS_PATH for the current bash session
|
74
|
+
# https://sass-lang.com/documentation/cli/ruby-sass/#load-path
|
75
|
+
system("export SASS_PATH=#{ENV["SASS_PATH"]}")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FlexiAdmin
|
4
|
+
module Routes
|
5
|
+
def self.extended(router)
|
6
|
+
router.instance_eval do
|
7
|
+
concern :flexi_admin_resourceful do
|
8
|
+
post :bulk_action, on: :collection
|
9
|
+
get :datalist, on: :collection
|
10
|
+
get :autocomplete, on: :collection
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|