meta_workflows 0.8.24 → 0.9.1
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 +4 -4
- data/README.md +33 -2
- data/app/assets/stylesheets/meta_workflows/application.css +239 -153
- data/app/controllers/meta_workflows/base_debug_controller.rb +46 -0
- data/app/controllers/meta_workflows/debug_controller.rb +1 -42
- data/app/controllers/meta_workflows/workflow_imports_controller.rb +85 -0
- data/app/services/meta_workflows/application_service.rb +38 -0
- data/app/services/meta_workflows/workflow_import_service.rb +116 -0
- data/app/views/layouts/meta_workflows/application.html.erb +60 -6
- data/app/views/meta_workflows/_lexi_chat_alpha_tray.html.erb +2 -2
- data/app/views/meta_workflows/_lexi_chat_right_tray.html.erb +3 -3
- data/app/views/meta_workflows/_response_form_lexi.html.erb +2 -2
- data/app/views/meta_workflows/_response_lexi.html.erb +3 -3
- data/app/views/meta_workflows/debug/workflows.html.erb +23 -10
- data/app/views/meta_workflows/workflow_imports/new.html.erb +171 -0
- data/config/routes.rb +7 -0
- data/lib/meta_workflows/version.rb +2 -2
- data/lib/services/meta_workflows/asset_installer_service.rb +95 -0
- data/lib/tasks/asset_installer_tasks.rake +12 -0
- data/lib/tasks/meta_workflows_tasks.rake +23 -136
- metadata +9 -3
- data/app/views/layouts/meta_workflows/debug.html.erb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50ae604291373e74675fbac7838bb9cbbdcef8beb635a07ac40f06c89f784a75
|
4
|
+
data.tar.gz: cefff5fe7d2a949941dee57e2a642e7eb54d2eaec220a489e252799fb8888f1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec4974b30bfe8c3c17fbd779228e2bdf469ba86fd808fcfdfa792b4bad5419591e919d23570a42c70aedc06c68021321174a33d91faaf1b935eced1aa5504072
|
7
|
+
data.tar.gz: 940604b1494c067ead7d9dbf6da6be88b10538e59bba4551e90a575ac070ff6fe882134a170e0f1d4f2045d2a9cffb75a3116fc010d3591361bbd74666e4efb5
|
data/README.md
CHANGED
@@ -518,13 +518,44 @@ For development contributions:
|
|
518
518
|
|
519
519
|
For detailed information about the MetaWorkflows system:
|
520
520
|
- [Setup Guide](https://strongmind.atlassian.net/wiki/spaces/MW/pages/3929833507) - Configuration and workflow setup
|
521
|
-
- [File Structure Guide](https://strongmind.atlassian.net/wiki/spaces/MW/pages/3930521627) - Complete file organization reference
|
522
|
-
- [Dummy App Guide](https://strongmind.atlassian.net/wiki/spaces/MW/pages/3941072927) - Test application documentation
|
523
521
|
|
524
522
|
## License
|
525
523
|
|
526
524
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
527
525
|
|
526
|
+
## Styling Setup
|
527
|
+
|
528
|
+
To apply or customize the styles for the `meta_workflows` engine, follow these steps:
|
529
|
+
|
530
|
+
### 1. Where to Add Your Styles
|
531
|
+
|
532
|
+
- All styles should be placed in this file:
|
533
|
+
`app/assets/stylesheets/meta_workflows/application.css`
|
534
|
+
|
535
|
+
### 2. How to Copy the Stylesheet
|
536
|
+
|
537
|
+
- To bring the stylesheet into your app (host app or dummy app), run this command from your terminal:
|
538
|
+
|
539
|
+
```bash
|
540
|
+
rails meta_workflows:install:assets
|
541
|
+
```
|
542
|
+
|
543
|
+
### 3. Location in Dummy App
|
544
|
+
|
545
|
+
- If you're using the dummy app (located at `spec/dummy`), the stylesheet will be copied to:
|
546
|
+
`spec/dummy/app/assets/stylesheets/meta_workflows/application.css`.
|
547
|
+
|
548
|
+
### 4. ⚠️ Important Note
|
549
|
+
|
550
|
+
- Do not edit the copied stylesheet in the dummy app (spec/dummy/...) directly.
|
551
|
+
- Changes made there will not carry over to the host app and will be overwritten if you re-run the install:assets task.
|
552
|
+
|
553
|
+
### 5. Avoid Using Tailwind's Custom Properties
|
554
|
+
|
555
|
+
- **Do not use Tailwind’s custom properties (CSS variables)** in your styles.
|
556
|
+
- These properties **won’t be compiled** because the layout files are accessed directly from the engine.
|
557
|
+
- As a result, the host app doesn’t recognize that it needs to compile them, and the styles will not work as expected.
|
558
|
+
|
528
559
|
## Tray System (Sidebar, Bottom, and Main Content Trays)
|
529
560
|
|
530
561
|
MetaWorkflows provides a flexible tray system for building modern, multi-pane layouts. The tray system supports left (Beta), right (Gamma), and bottom (Delta) trays, as well as a main content area (Alpha). Each tray can be shown, hidden, or made collapsible on a per-controller or per-page basis.
|
@@ -1,165 +1,200 @@
|
|
1
|
-
/*
|
1
|
+
/* Meta Workflows Styles Installed in Main App */
|
2
2
|
.meta-workflows.chat {
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
display: flex;
|
4
|
+
flex-direction: column;
|
5
|
+
gap: 1.5rem;
|
6
|
+
color: var(--slate-800);
|
7
|
+
font-size: 1.125rem;
|
8
|
+
line-height: 1.75;
|
9
|
+
|
10
|
+
h1 {
|
11
|
+
color: var(--slate-800);
|
12
|
+
font-weight: 600;
|
13
|
+
margin-bottom: 0.5rem;
|
14
|
+
font-size: 1.875rem;
|
15
|
+
line-height: 1.25;
|
16
|
+
}
|
17
|
+
|
18
|
+
h2 {
|
6
19
|
color: var(--slate-800);
|
20
|
+
font-weight: 600;
|
21
|
+
margin-bottom: 0.5rem;
|
22
|
+
font-size: 1.5rem;
|
23
|
+
line-height: 1.25;
|
24
|
+
}
|
25
|
+
|
26
|
+
h3 {
|
27
|
+
color: var(--slate-800);
|
28
|
+
font-weight: 600;
|
29
|
+
margin-bottom: 0.5rem;
|
30
|
+
font-size: 1.25rem;
|
31
|
+
line-height: 1.25;
|
32
|
+
}
|
33
|
+
|
34
|
+
h4 {
|
35
|
+
color: var(--slate-800);
|
36
|
+
font-weight: 600;
|
37
|
+
margin-bottom: 0.5rem;
|
7
38
|
font-size: 1.125rem;
|
8
|
-
line-height: 1.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
39
|
+
line-height: 1.25;
|
40
|
+
}
|
41
|
+
|
42
|
+
h5 {
|
43
|
+
color: var(--slate-800);
|
44
|
+
font-weight: 600;
|
45
|
+
margin-bottom: 0.5rem;
|
46
|
+
font-size: 1rem;
|
47
|
+
line-height: 1.25;
|
48
|
+
}
|
49
|
+
|
50
|
+
h6 {
|
51
|
+
color: var(--slate-800);
|
52
|
+
font-weight: 600;
|
53
|
+
margin-bottom: 0.5rem;
|
54
|
+
font-size: 0.875rem;
|
55
|
+
line-height: 1.25;
|
56
|
+
}
|
57
|
+
|
58
|
+
/* combined list styles */
|
59
|
+
ul,
|
60
|
+
ol {
|
61
|
+
display: flex;
|
62
|
+
flex-direction: column;
|
63
|
+
gap: .5rem;
|
64
|
+
padding-left: 0;
|
65
|
+
list-style-type: none;
|
66
|
+
|
67
|
+
li {
|
68
|
+
display: flex;
|
69
|
+
padding: 1rem 1.375rem;
|
70
|
+
border: 1px solid var(--slate-300);
|
71
|
+
border-radius: 0.875rem;
|
72
|
+
background-color: white;
|
30
73
|
font-size: 1.25rem;
|
31
|
-
line-height: 1.25;
|
32
|
-
}
|
33
|
-
|
34
|
-
h4 {
|
35
|
-
color: var(--slate-800);
|
36
|
-
font-weight: 600;
|
37
|
-
margin-bottom: 0.5rem;
|
38
|
-
font-size: 1.125rem;
|
39
|
-
line-height: 1.25;
|
40
|
-
}
|
41
|
-
|
42
|
-
h5 {
|
43
|
-
color: var(--slate-800);
|
44
|
-
font-weight: 600;
|
45
|
-
margin-bottom: 0.5rem;
|
46
|
-
font-size: 1rem;
|
47
|
-
line-height: 1.25;
|
48
|
-
}
|
49
|
-
|
50
|
-
h6 {
|
51
|
-
color: var(--slate-800);
|
52
74
|
font-weight: 600;
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
/* Combined list styles */
|
59
|
-
ul,
|
60
|
-
ol {
|
61
|
-
display: flex;
|
62
|
-
flex-direction: column;
|
63
|
-
gap: .5rem;
|
64
|
-
padding-left: 0;
|
65
|
-
list-style-type: none;
|
66
|
-
|
67
|
-
li {
|
68
|
-
display: flex;
|
69
|
-
padding: 1rem 1.375rem;
|
70
|
-
border: 1px solid var(--slate-300);
|
71
|
-
border-radius: 0.875rem;
|
72
|
-
background-color: white;
|
73
|
-
font-size: 1.25rem;
|
74
|
-
font-weight: 600;
|
75
|
-
line-height: 1.375;
|
76
|
-
|
77
|
-
&::before {
|
78
|
-
display: none;
|
79
|
-
}
|
80
|
-
}
|
81
|
-
}
|
82
|
-
|
83
|
-
/* Ordered list specific styles */
|
84
|
-
ol {
|
85
|
-
counter-reset: list-counter;
|
86
|
-
|
87
|
-
li::before {
|
88
|
-
content: counter(list-counter) ".";
|
89
|
-
counter-increment: list-counter;
|
90
|
-
display: inline-block;
|
91
|
-
width: 1.5em;
|
92
|
-
margin-right: 0.5em;
|
93
|
-
color: var(--slate-400);
|
94
|
-
}
|
95
|
-
}
|
96
|
-
|
97
|
-
a {
|
98
|
-
color: #2563eb;
|
99
|
-
text-decoration: underline;
|
100
|
-
|
101
|
-
&:hover {
|
102
|
-
color: #1d4ed8;
|
75
|
+
line-height: 1.375;
|
76
|
+
|
77
|
+
&::before {
|
78
|
+
display: none;
|
103
79
|
}
|
104
80
|
}
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
font-size: 0.875rem;
|
119
|
-
font-family: ui-monospace, monospace;
|
120
|
-
}
|
121
|
-
|
122
|
-
blockquote {
|
123
|
-
border-left: 4px solid #e5e7eb;
|
124
|
-
padding-left: 1rem;
|
125
|
-
font-style: italic;
|
126
|
-
color: #374151;
|
127
|
-
margin: 1rem 0;
|
128
|
-
}
|
129
|
-
|
130
|
-
table {
|
131
|
-
width: 100%;
|
132
|
-
border-collapse: collapse;
|
133
|
-
margin: 1rem 0;
|
134
|
-
}
|
135
|
-
|
136
|
-
th,
|
137
|
-
td {
|
138
|
-
border: 1px solid #e5e7eb;
|
139
|
-
padding: 0.5rem;
|
140
|
-
text-align: left;
|
141
|
-
}
|
142
|
-
|
143
|
-
th {
|
144
|
-
background-color: #f9fafb;
|
145
|
-
font-weight: 600;
|
146
|
-
}
|
147
|
-
|
148
|
-
img {
|
149
|
-
border-radius: 0.5rem;
|
150
|
-
margin: 1rem 0;
|
151
|
-
}
|
152
|
-
|
153
|
-
strong {
|
154
|
-
font-weight: 600;
|
155
|
-
color: var(--slate-800);
|
81
|
+
}
|
82
|
+
|
83
|
+
/* ordered list specific styles */
|
84
|
+
ol {
|
85
|
+
counter-reset: list-counter;
|
86
|
+
|
87
|
+
li::before {
|
88
|
+
content: counter(list-counter) ".";
|
89
|
+
counter-increment: list-counter;
|
90
|
+
display: inline-block;
|
91
|
+
width: 1.5em;
|
92
|
+
margin-right: 0.5em;
|
93
|
+
color: var(--slate-400);
|
156
94
|
}
|
157
|
-
|
158
|
-
|
159
|
-
|
95
|
+
}
|
96
|
+
|
97
|
+
a {
|
98
|
+
color: #2563eb;
|
99
|
+
text-decoration: underline;
|
100
|
+
|
101
|
+
&:hover {
|
102
|
+
color: #1d4ed8;
|
160
103
|
}
|
161
104
|
}
|
162
105
|
|
106
|
+
pre {
|
107
|
+
background-color: #f9fafb;
|
108
|
+
padding: 1rem;
|
109
|
+
border-radius: 0.5rem;
|
110
|
+
overflow-x: auto;
|
111
|
+
margin: 1rem 0;
|
112
|
+
}
|
113
|
+
|
114
|
+
code {
|
115
|
+
background-color: #f9fafb;
|
116
|
+
padding: 0.125rem 0.375rem;
|
117
|
+
border-radius: 0.25rem;
|
118
|
+
font-size: 0.875rem;
|
119
|
+
font-family: ui-monospace, monospace;
|
120
|
+
}
|
121
|
+
|
122
|
+
blockquote {
|
123
|
+
border-left: 4px solid #e5e7eb;
|
124
|
+
padding-left: 1rem;
|
125
|
+
font-style: italic;
|
126
|
+
color: #374151;
|
127
|
+
margin: 1rem 0;
|
128
|
+
}
|
129
|
+
|
130
|
+
table {
|
131
|
+
width: 100%;
|
132
|
+
border-collapse: collapse;
|
133
|
+
margin: 1rem 0;
|
134
|
+
}
|
135
|
+
|
136
|
+
th,
|
137
|
+
td {
|
138
|
+
border: 1px solid #e5e7eb;
|
139
|
+
padding: 0.5rem;
|
140
|
+
text-align: left;
|
141
|
+
}
|
142
|
+
|
143
|
+
th {
|
144
|
+
background-color: #f9fafb;
|
145
|
+
font-weight: 600;
|
146
|
+
}
|
147
|
+
|
148
|
+
img {
|
149
|
+
border-radius: 0.5rem;
|
150
|
+
margin: 1rem 0;
|
151
|
+
}
|
152
|
+
|
153
|
+
strong {
|
154
|
+
font-weight: 600;
|
155
|
+
color: var(--slate-800);
|
156
|
+
}
|
157
|
+
|
158
|
+
em {
|
159
|
+
font-style: italic;
|
160
|
+
}
|
161
|
+
}
|
162
|
+
|
163
|
+
|
164
|
+
/* Lexi Chat Component Heights */
|
165
|
+
.lexi-chat-container {
|
166
|
+
height: 95vh;
|
167
|
+
}
|
168
|
+
|
169
|
+
.lexi-chat-container-full {
|
170
|
+
height: 100vh;
|
171
|
+
}
|
172
|
+
|
173
|
+
.lexi-avatar-large {
|
174
|
+
height: 375px;
|
175
|
+
}
|
176
|
+
|
177
|
+
.lexi-avatar-medium {
|
178
|
+
height: 300px;
|
179
|
+
}
|
180
|
+
|
181
|
+
.lexi-input-container {
|
182
|
+
height: 335px;
|
183
|
+
}
|
184
|
+
|
185
|
+
/* Lexi Chat Component Constraints */
|
186
|
+
.lexi-input-max-height {
|
187
|
+
max-height: 200px;
|
188
|
+
}
|
189
|
+
|
190
|
+
.lexi-textarea-min-height {
|
191
|
+
min-height: 35px;
|
192
|
+
}
|
193
|
+
|
194
|
+
.lexi-message-max-width {
|
195
|
+
max-width: 80%;
|
196
|
+
}
|
197
|
+
|
163
198
|
/* Tray Animations */
|
164
199
|
.tray-container {
|
165
200
|
transition: all 500ms ease-in-out;
|
@@ -212,7 +247,58 @@
|
|
212
247
|
|
213
248
|
/* Common content transitions */
|
214
249
|
.tray-content {
|
215
|
-
transition: opacity
|
250
|
+
transition: opacity 300ms ease-in-out, transform 500ms ease-in-out;
|
216
251
|
opacity: 1;
|
217
252
|
transform: translate(0);
|
218
|
-
}
|
253
|
+
}
|
254
|
+
|
255
|
+
/* Lexi Tray Overrides */
|
256
|
+
.gamma-tray.lexi-tray.collapsed {
|
257
|
+
width: 0px; /* Completely hide the tray */
|
258
|
+
border: none; /* Remove border when collapsed */
|
259
|
+
overflow: visible; /* Allow avatar to show outside tray bounds */
|
260
|
+
}
|
261
|
+
|
262
|
+
.gamma-tray.lexi-tray.collapsed .tray-content {
|
263
|
+
opacity: 0;
|
264
|
+
transform: translateX(-1rem);
|
265
|
+
pointer-events: none;
|
266
|
+
}
|
267
|
+
|
268
|
+
/* Fast fade out when collapsing */
|
269
|
+
.gamma-tray.lexi-tray.collapsed .tray-content {
|
270
|
+
transition: opacity 200ms ease-in-out, transform 500ms ease-in-out;
|
271
|
+
}
|
272
|
+
|
273
|
+
/* Delayed fade in when expanding - wait for width animation to mostly complete */
|
274
|
+
.gamma-tray.lexi-tray:not(.collapsed) .tray-content {
|
275
|
+
transition: opacity 200ms ease-in-out 300ms, transform 500ms ease-in-out;
|
276
|
+
}
|
277
|
+
|
278
|
+
/* Hide standard collapse button when Lexi tray is collapsed */
|
279
|
+
.gamma-tray.lexi-tray.collapsed > button[data-action="click->tray#toggle"]:not(.lexi-floating-avatar) {
|
280
|
+
display: none;
|
281
|
+
}
|
282
|
+
|
283
|
+
/* Show floating Lexi avatar button when collapsed - with delay to avoid overlap */
|
284
|
+
.gamma-tray.lexi-tray.collapsed .lexi-floating-avatar {
|
285
|
+
display: block !important;
|
286
|
+
opacity: 0;
|
287
|
+
animation: lexi-avatar-appear 200ms ease-in-out 400ms forwards;
|
288
|
+
}
|
289
|
+
|
290
|
+
@keyframes lexi-avatar-appear {
|
291
|
+
from {
|
292
|
+
opacity: 0;
|
293
|
+
transform: scale(0.8);
|
294
|
+
}
|
295
|
+
to {
|
296
|
+
opacity: 1;
|
297
|
+
transform: scale(1);
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
/* Hide floating avatar when tray is expanded */
|
302
|
+
.gamma-tray.lexi-tray:not(.collapsed) .lexi-floating-avatar {
|
303
|
+
display: none !important;
|
304
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MetaWorkflows
|
4
|
+
class BaseDebugController < MetaWorkflows::ApplicationController
|
5
|
+
include MetaWorkflows::DebugHelper
|
6
|
+
|
7
|
+
layout 'meta_workflows/application'
|
8
|
+
|
9
|
+
# Apply authentication only in production environment
|
10
|
+
before_action :authenticate_with_basic_auth, if: :production_environment?
|
11
|
+
|
12
|
+
# Skip CSRF protection for this debug interface
|
13
|
+
skip_before_action :verify_authenticity_token
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def authenticate_with_basic_auth
|
18
|
+
return unless production_environment?
|
19
|
+
return unless authentication_required?
|
20
|
+
|
21
|
+
authenticate_or_request_with_http_basic do |username, password|
|
22
|
+
username == ENV.fetch('SIDEKIQ_USER', nil) &&
|
23
|
+
password == ENV.fetch('SIDEKIQ_PASSWORD', nil)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def production_environment?
|
30
|
+
Rails.env.production?
|
31
|
+
end
|
32
|
+
|
33
|
+
def authentication_required?
|
34
|
+
ENV['SIDEKIQ_USER'].present? && ENV['SIDEKIQ_PASSWORD'].present?
|
35
|
+
end
|
36
|
+
|
37
|
+
def paginate_collection(collection)
|
38
|
+
# Use Kaminari if available, otherwise limit to 25 records
|
39
|
+
if defined?(Kaminari) && collection.respond_to?(:page)
|
40
|
+
collection.page(params[:page]).per(25)
|
41
|
+
else
|
42
|
+
collection.limit(25).offset(((params[:page]&.to_i || 1) - 1) * 25)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,17 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module MetaWorkflows
|
4
|
-
class DebugController < MetaWorkflows::
|
5
|
-
include MetaWorkflows::DebugHelper
|
6
|
-
|
7
|
-
layout 'meta_workflows/debug'
|
8
|
-
|
9
|
-
# Apply authentication only in production environment
|
10
|
-
before_action :authenticate_with_basic_auth, if: :production_environment?
|
11
|
-
|
12
|
-
# Skip CSRF protection for this debug interface
|
13
|
-
skip_before_action :verify_authenticity_token
|
14
|
-
|
4
|
+
class DebugController < MetaWorkflows::BaseDebugController
|
15
5
|
def index
|
16
6
|
redirect_to workflows_path
|
17
7
|
end
|
@@ -66,36 +56,5 @@ module MetaWorkflows
|
|
66
56
|
format.html { redirect_to execution_path(@execution), alert: t('meta_workflows.export_only_json') }
|
67
57
|
end
|
68
58
|
end
|
69
|
-
|
70
|
-
protected
|
71
|
-
|
72
|
-
def authenticate_with_basic_auth
|
73
|
-
return unless production_environment?
|
74
|
-
return unless authentication_required?
|
75
|
-
|
76
|
-
authenticate_or_request_with_http_basic do |username, password|
|
77
|
-
username == ENV.fetch('SIDEKIQ_USER', nil) &&
|
78
|
-
password == ENV.fetch('SIDEKIQ_PASSWORD', nil)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
private
|
83
|
-
|
84
|
-
def production_environment?
|
85
|
-
Rails.env.production?
|
86
|
-
end
|
87
|
-
|
88
|
-
def authentication_required?
|
89
|
-
ENV['SIDEKIQ_USER'].present? && ENV['SIDEKIQ_PASSWORD'].present?
|
90
|
-
end
|
91
|
-
|
92
|
-
def paginate_collection(collection)
|
93
|
-
# Use Kaminari if available, otherwise limit to 25 records
|
94
|
-
if defined?(Kaminari) && collection.respond_to?(:page)
|
95
|
-
collection.page(params[:page]).per(25)
|
96
|
-
else
|
97
|
-
collection.limit(25).offset(((params[:page]&.to_i || 1) - 1) * 25)
|
98
|
-
end
|
99
|
-
end
|
100
59
|
end
|
101
60
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MetaWorkflows
|
4
|
+
class WorkflowImportsController < MetaWorkflows::BaseDebugController
|
5
|
+
def new
|
6
|
+
# Show the import form
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
result = perform_import
|
11
|
+
return unless result
|
12
|
+
|
13
|
+
handle_import_result(result)
|
14
|
+
end
|
15
|
+
|
16
|
+
def bulk
|
17
|
+
import_service = MetaWorkflows::WorkflowImportService.new
|
18
|
+
result = import_service.import_from_directory
|
19
|
+
|
20
|
+
if result.success?
|
21
|
+
data = result.data
|
22
|
+
flash[:notice] = data[:message]
|
23
|
+
else
|
24
|
+
flash[:alert] = result.error
|
25
|
+
end
|
26
|
+
|
27
|
+
redirect_to workflows_path
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def perform_import
|
33
|
+
import_service = MetaWorkflows::WorkflowImportService.new
|
34
|
+
|
35
|
+
case params[:import_type]
|
36
|
+
when 'file'
|
37
|
+
handle_file_import(import_service)
|
38
|
+
when 'text'
|
39
|
+
handle_text_import(import_service)
|
40
|
+
when 'directory'
|
41
|
+
import_service.import_from_directory
|
42
|
+
else
|
43
|
+
flash[:alert] = 'Please provide either a file, YAML text, or select directory import'
|
44
|
+
render :new
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def handle_file_import(import_service)
|
50
|
+
if params[:workflow_file].present?
|
51
|
+
import_service.import_from_file(params[:workflow_file])
|
52
|
+
else
|
53
|
+
flash[:alert] = 'Please provide either a file, YAML text, or select directory import'
|
54
|
+
render :new
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_text_import(import_service)
|
60
|
+
if params[:workflow_name].present? && params[:yaml_content].present?
|
61
|
+
import_service.import_from_yaml_text(params[:workflow_name], params[:yaml_content])
|
62
|
+
else
|
63
|
+
flash[:alert] = 'Please provide either a file, YAML text, or select directory import'
|
64
|
+
render :new
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_import_result(result)
|
70
|
+
if result.success?
|
71
|
+
import_result = result.data
|
72
|
+
flash[:notice] = success_message(import_result)
|
73
|
+
redirect_to workflows_path
|
74
|
+
else
|
75
|
+
flash[:alert] = result.error
|
76
|
+
render :new
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def success_message(import_result)
|
81
|
+
action = import_result[:action] == 'created' ? 'imported' : 'updated'
|
82
|
+
"Workflow '#{import_result[:workflow_name]}' #{action} successfully!"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MetaWorkflows
|
4
|
+
class ApplicationService
|
5
|
+
def self.call(...)
|
6
|
+
new(...).call
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def success(data = nil)
|
12
|
+
ServiceResult.new(success: true, data: data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure(error = nil)
|
16
|
+
ServiceResult.new(success: false, error: error)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Simple result object for service responses
|
21
|
+
class ServiceResult
|
22
|
+
attr_reader :data, :error
|
23
|
+
|
24
|
+
def initialize(success:, data: nil, error: nil)
|
25
|
+
@success = success
|
26
|
+
@data = data
|
27
|
+
@error = error
|
28
|
+
end
|
29
|
+
|
30
|
+
def success?
|
31
|
+
@success
|
32
|
+
end
|
33
|
+
|
34
|
+
def failure?
|
35
|
+
!@success
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|