completion-kit 0.26.2 → 0.26.4
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/app/assets/javascripts/completion_kit/application.js +72 -0
- data/app/assets/stylesheets/completion_kit/application.css +22 -8
- data/app/helpers/completion_kit/application_helper.rb +15 -0
- data/app/models/completion_kit/provider_credential.rb +0 -1
- data/app/services/completion_kit/azure_foundry_client.rb +11 -3
- data/app/services/completion_kit/model_discovery_service.rb +17 -6
- data/app/views/completion_kit/datasets/_form.html.erb +12 -8
- data/app/views/completion_kit/metric_groups/_form.html.erb +11 -5
- data/app/views/completion_kit/metrics/_form.html.erb +56 -50
- data/app/views/completion_kit/prompts/_form.html.erb +12 -8
- data/app/views/completion_kit/provider_credentials/_form.html.erb +17 -9
- data/app/views/completion_kit/runs/_actions.html.erb +1 -1
- data/app/views/completion_kit/shared/_delete_form.html.erb +2 -0
- data/app/views/completion_kit/tags/_form.html.erb +11 -7
- data/app/views/layouts/completion_kit/application.html.erb +17 -0
- data/lib/completion_kit/version.rb +1 -1
- metadata +2 -2
- data/app/views/completion_kit/shared/_delete_action.html.erb +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c296e624ff4313d1e4f4804cf902cce88ac7e5eee95deccefec8ff69241ff89d
|
|
4
|
+
data.tar.gz: 6f0c48e6efaa5fd65c23e07656687de56031f6c3634593d1a44cf9b40b560c11
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b4d0c20a2c591456cb9d7def96f8bd01ea143b66c3cbb678a10e6a68c5310e40a6bf8b69cc547b3c5e802905b31e4b741dcff5c2a6fb110d652ceb363a03548b
|
|
7
|
+
data.tar.gz: 58a03c4e699a33193dfe2cfaed23a3913cd0b1b2819a79beaca2559d38016c0c131e0cf0817b97a9c50651dc92a717d0146986d015065f588327cc63d075c7dc
|
|
@@ -290,6 +290,30 @@ document.addEventListener("change", function(e) {
|
|
|
290
290
|
}
|
|
291
291
|
});
|
|
292
292
|
|
|
293
|
+
function ckApplyProviderFields(scope) {
|
|
294
|
+
if (!scope) return;
|
|
295
|
+
var select = scope.querySelector("[data-ck-provider-select]");
|
|
296
|
+
if (!select) return;
|
|
297
|
+
var provider = select.value;
|
|
298
|
+
scope.querySelectorAll("[data-ck-provider-field]").forEach(function(field) {
|
|
299
|
+
var wanted = (field.getAttribute("data-ck-provider-field") || "").split(",");
|
|
300
|
+
field.hidden = wanted.indexOf(provider) === -1;
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
document.addEventListener("turbo:load", function() {
|
|
305
|
+
document.querySelectorAll("[data-ck-provider-select]").forEach(function(select) {
|
|
306
|
+
ckApplyProviderFields(select.closest("form") || document);
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
document.addEventListener("change", function(e) {
|
|
311
|
+
var target = e.target;
|
|
312
|
+
if (target && target.matches && target.matches("[data-ck-provider-select]")) {
|
|
313
|
+
ckApplyProviderFields(target.closest("form") || document);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
293
317
|
document.addEventListener("click", function(e) {
|
|
294
318
|
var btn = e.target.closest("[data-ck-apply]");
|
|
295
319
|
if (!btn) return;
|
|
@@ -378,3 +402,51 @@ document.addEventListener("keydown", function(e) {
|
|
|
378
402
|
else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); if (options[idx]) ckSelectChoose(sel, options[idx]); }
|
|
379
403
|
else if (e.key === "Escape") { e.preventDefault(); ckSelectClose(sel); trigger.focus(); }
|
|
380
404
|
});
|
|
405
|
+
|
|
406
|
+
function ckConfirmModal(message, formEl, submitter) {
|
|
407
|
+
var dialog = document.getElementById("ck-confirm-modal");
|
|
408
|
+
if (!dialog || typeof dialog.showModal !== "function") {
|
|
409
|
+
return Promise.resolve(window.confirm(message));
|
|
410
|
+
}
|
|
411
|
+
var messageEl = dialog.querySelector("#ck-confirm-message");
|
|
412
|
+
var acceptBtn = dialog.querySelector("[data-ck-confirm-accept]");
|
|
413
|
+
var cancelBtn = dialog.querySelector("[data-ck-confirm-cancel]");
|
|
414
|
+
if (messageEl) messageEl.textContent = message || "Are you sure?";
|
|
415
|
+
var label = (submitter && submitter.getAttribute("data-ck-confirm-label")) || "Confirm";
|
|
416
|
+
var tone = (submitter && submitter.getAttribute("data-ck-confirm-tone")) || "";
|
|
417
|
+
if (acceptBtn) {
|
|
418
|
+
acceptBtn.textContent = label;
|
|
419
|
+
acceptBtn.className = "ck-button " + (tone === "danger" ? "ck-button--danger" : "ck-button--primary");
|
|
420
|
+
}
|
|
421
|
+
return new Promise(function(resolve) {
|
|
422
|
+
function onClose() {
|
|
423
|
+
dialog.removeEventListener("close", onClose);
|
|
424
|
+
acceptBtn.removeEventListener("click", onAccept);
|
|
425
|
+
cancelBtn.removeEventListener("click", onCancel);
|
|
426
|
+
dialog.removeEventListener("click", onBackdrop);
|
|
427
|
+
resolve(dialog.returnValue === "accept");
|
|
428
|
+
}
|
|
429
|
+
function onAccept() { dialog.close("accept"); }
|
|
430
|
+
function onCancel() { dialog.close("cancel"); }
|
|
431
|
+
function onBackdrop(e) { if (e.target === dialog) dialog.close("cancel"); }
|
|
432
|
+
dialog.addEventListener("close", onClose);
|
|
433
|
+
acceptBtn.addEventListener("click", onAccept);
|
|
434
|
+
cancelBtn.addEventListener("click", onCancel);
|
|
435
|
+
dialog.addEventListener("click", onBackdrop);
|
|
436
|
+
dialog.returnValue = "";
|
|
437
|
+
dialog.showModal();
|
|
438
|
+
var focusTarget = (tone === "danger" ? cancelBtn : acceptBtn);
|
|
439
|
+
if (focusTarget) focusTarget.focus();
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function ckInstallConfirm() {
|
|
444
|
+
if (!window.Turbo) return;
|
|
445
|
+
if (Turbo.config && Turbo.config.forms) {
|
|
446
|
+
Turbo.config.forms.confirm = ckConfirmModal;
|
|
447
|
+
} else if (typeof Turbo.setConfirmMethod === "function") {
|
|
448
|
+
Turbo.setConfirmMethod(ckConfirmModal);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
document.addEventListener("turbo:load", ckInstallConfirm);
|
|
452
|
+
ckInstallConfirm();
|
|
@@ -2259,16 +2259,19 @@ label.ck-checkbox[hidden] {
|
|
|
2259
2259
|
outline-offset: 2px;
|
|
2260
2260
|
}
|
|
2261
2261
|
|
|
2262
|
-
.ck-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
flex-direction: column;
|
|
2266
|
-
align-items: flex-start;
|
|
2267
|
-
gap: 0.5rem;
|
|
2262
|
+
.ck-icon-btn:disabled {
|
|
2263
|
+
opacity: 0.4;
|
|
2264
|
+
cursor: not-allowed;
|
|
2268
2265
|
}
|
|
2269
2266
|
|
|
2270
|
-
.ck-
|
|
2271
|
-
|
|
2267
|
+
.ck-icon-btn:disabled:hover {
|
|
2268
|
+
background: none;
|
|
2269
|
+
border-color: transparent;
|
|
2270
|
+
color: var(--ck-dim);
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
.ck-delete-form {
|
|
2274
|
+
display: contents;
|
|
2272
2275
|
}
|
|
2273
2276
|
|
|
2274
2277
|
.ck-icon-btn--spinning svg {
|
|
@@ -2723,6 +2726,17 @@ select.ck-input {
|
|
|
2723
2726
|
backdrop-filter: blur(4px);
|
|
2724
2727
|
}
|
|
2725
2728
|
|
|
2729
|
+
.ck-modal--sm {
|
|
2730
|
+
max-width: min(92vw, 440px);
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
.ck-confirm__message {
|
|
2734
|
+
margin: 0;
|
|
2735
|
+
color: var(--ck-muted);
|
|
2736
|
+
font-size: 0.95rem;
|
|
2737
|
+
line-height: 1.55;
|
|
2738
|
+
}
|
|
2739
|
+
|
|
2726
2740
|
.ck-modal[open] {
|
|
2727
2741
|
animation: ck-modal-in 0.18s ease-out;
|
|
2728
2742
|
}
|
|
@@ -29,6 +29,21 @@ module CompletionKit
|
|
|
29
29
|
"#{base} #{styles}"
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
def ck_delete_trigger(form_id:, label:, confirm: nil, disabled: false, title: nil)
|
|
33
|
+
content_tag(
|
|
34
|
+
:button,
|
|
35
|
+
type: "submit",
|
|
36
|
+
form: (disabled ? nil : form_id),
|
|
37
|
+
class: "ck-icon-btn",
|
|
38
|
+
title: title || label,
|
|
39
|
+
"aria-label": label,
|
|
40
|
+
disabled: disabled,
|
|
41
|
+
data: (disabled ? {} : {turbo_confirm: confirm, ck_confirm_label: "Delete", ck_confirm_tone: "danger"})
|
|
42
|
+
) do
|
|
43
|
+
heroicon_tag "trash", variant: :outline, size: 16, "aria-hidden": "true"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
32
47
|
def ck_badge_classes(kind)
|
|
33
48
|
case kind.to_s
|
|
34
49
|
when "high"
|
|
@@ -26,7 +26,6 @@ module CompletionKit
|
|
|
26
26
|
validates :provider, presence: true, inclusion: { in: PROVIDERS }
|
|
27
27
|
validates :provider, tenant_scoped_uniqueness: true
|
|
28
28
|
validates :api_endpoint, presence: true, if: :azure_foundry?
|
|
29
|
-
validates :api_version, presence: true, if: :azure_foundry?
|
|
30
29
|
validate :api_endpoint_not_internal
|
|
31
30
|
|
|
32
31
|
after_save :enqueue_discovery
|
|
@@ -49,7 +49,7 @@ module CompletionKit
|
|
|
49
49
|
return [] unless configured?
|
|
50
50
|
return [] unless ProviderEndpoint.safe?(api_endpoint)
|
|
51
51
|
|
|
52
|
-
response = build_connection(azure_base_url).get(
|
|
52
|
+
response = build_connection(azure_base_url).get(models_path) do |req|
|
|
53
53
|
req.headers["api-key"] = api_key
|
|
54
54
|
end
|
|
55
55
|
return [] unless response.success?
|
|
@@ -67,7 +67,6 @@ module CompletionKit
|
|
|
67
67
|
errors = []
|
|
68
68
|
errors << "Azure endpoint is not configured" if api_endpoint.blank?
|
|
69
69
|
errors << "Azure API key is not configured" if api_key.blank?
|
|
70
|
-
errors << "Azure api-version is not configured" if api_version.blank?
|
|
71
70
|
errors
|
|
72
71
|
end
|
|
73
72
|
|
|
@@ -89,12 +88,21 @@ module CompletionKit
|
|
|
89
88
|
api_endpoint.to_s.strip.delete_suffix("/")
|
|
90
89
|
end
|
|
91
90
|
|
|
91
|
+
def v1_mode?
|
|
92
|
+
api_version.blank?
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def models_path
|
|
96
|
+
v1_mode? ? "/openai/v1/models" : "/openai/deployments?api-version=#{api_version}"
|
|
97
|
+
end
|
|
98
|
+
|
|
92
99
|
def post_chat(model:, prompt:, max_tokens:, temperature:)
|
|
93
100
|
body = { messages: [{ role: "user", content: prompt }], max_tokens: max_tokens }
|
|
101
|
+
body[:model] = model if v1_mode?
|
|
94
102
|
body[:temperature] = temperature unless temperature.nil?
|
|
95
103
|
|
|
96
104
|
build_connection(azure_base_url, timeout: 30, open_timeout: 5).post do |req|
|
|
97
|
-
req.url "/openai/deployments/#{model}/chat/completions?api-version=#{api_version}"
|
|
105
|
+
req.url(v1_mode? ? "/openai/v1/chat/completions" : "/openai/deployments/#{model}/chat/completions?api-version=#{api_version}")
|
|
98
106
|
req.headers["Content-Type"] = "application/json"
|
|
99
107
|
req.headers["api-key"] = api_key
|
|
100
108
|
req.body = body.to_json
|
|
@@ -133,7 +133,7 @@ module CompletionKit
|
|
|
133
133
|
def custom_endpoint_404_message
|
|
134
134
|
message = "No OpenAI-compatible model list was found at #{custom_endpoint_host}/v1/models (404). Check that the base URL is correct."
|
|
135
135
|
return message unless azure_custom_host?
|
|
136
|
-
"#{message} This looks like an Azure endpoint; add it with the Azure AI Foundry provider
|
|
136
|
+
"#{message} This looks like an Azure endpoint; add it with the Azure AI Foundry provider."
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
def with_detail(message, detail)
|
|
@@ -155,22 +155,31 @@ module CompletionKit
|
|
|
155
155
|
|
|
156
156
|
def fetch_azure_foundry_models
|
|
157
157
|
raise DiscoveryError, "An Azure endpoint URL is required." if @api_endpoint.blank?
|
|
158
|
-
raise DiscoveryError, "An Azure api-version is required." if @api_version.blank?
|
|
159
158
|
|
|
160
|
-
response = fetch_connection(azure_base_url).get(
|
|
159
|
+
response = fetch_connection(azure_base_url).get(azure_models_path) do |req|
|
|
161
160
|
req.headers["api-key"] = @api_key
|
|
162
161
|
end
|
|
163
162
|
raise DiscoveryError, azure_error_message(response) unless response.success?
|
|
164
163
|
JSON.parse(response.body).fetch("data", []).map { |e| { id: e["id"], display_name: e["id"] } }
|
|
165
164
|
end
|
|
166
165
|
|
|
166
|
+
def azure_v1_mode?
|
|
167
|
+
@api_version.blank?
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def azure_models_path
|
|
171
|
+
azure_v1_mode? ? "/openai/v1/models" : "/openai/deployments?api-version=#{@api_version}"
|
|
172
|
+
end
|
|
173
|
+
|
|
167
174
|
def azure_base_url
|
|
168
175
|
@api_endpoint.to_s.strip.delete_suffix("/")
|
|
169
176
|
end
|
|
170
177
|
|
|
171
178
|
def azure_error_message(response)
|
|
172
179
|
detail = extract_provider_error_message(response.body)
|
|
173
|
-
|
|
180
|
+
hint = azure_v1_mode? ? "Check the endpoint base URL." : "Check the endpoint base URL and api-version."
|
|
181
|
+
path = azure_v1_mode? ? "/openai/v1/models" : "/openai/deployments"
|
|
182
|
+
with_detail("Azure did not return a model list at #{path} (#{response.status}). #{hint}", detail)
|
|
174
183
|
end
|
|
175
184
|
|
|
176
185
|
def reconcile(discovered)
|
|
@@ -428,11 +437,13 @@ module CompletionKit
|
|
|
428
437
|
f.request :retry, max: 1, interval: 0.5
|
|
429
438
|
f.adapter Faraday.default_adapter
|
|
430
439
|
end
|
|
440
|
+
body = { messages: [{ role: "user", content: input }], max_tokens: max_tokens }
|
|
441
|
+
body[:model] = model_id if azure_v1_mode?
|
|
431
442
|
conn.post do |req|
|
|
432
|
-
req.url "/openai/deployments/#{model_id}/chat/completions?api-version=#{@api_version}"
|
|
443
|
+
req.url(azure_v1_mode? ? "/openai/v1/chat/completions" : "/openai/deployments/#{model_id}/chat/completions?api-version=#{@api_version}")
|
|
433
444
|
req.headers["Content-Type"] = "application/json"
|
|
434
445
|
req.headers["api-key"] = @api_key
|
|
435
|
-
req.body =
|
|
446
|
+
req.body = body.to_json
|
|
436
447
|
end
|
|
437
448
|
end
|
|
438
449
|
end
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
<% if dataset.persisted? %>
|
|
2
|
+
<% dataset_delete_id = "ck_delete_dataset_#{dataset.id}" %>
|
|
3
|
+
<% runs_n = dataset.runs.count %>
|
|
4
|
+
<% responses_n = CompletionKit::Response.where(run_id: dataset.runs.select(:id)).count %>
|
|
5
|
+
<% dataset_delete_confirm = runs_n.zero? ?
|
|
6
|
+
"Delete \"#{dataset.name}\"? It has no runs." :
|
|
7
|
+
"Delete \"#{dataset.name}\"? Cascades through #{pluralize(runs_n, 'run')} and #{pluralize(responses_n, 'response')} (and their reviews) that used this dataset." %>
|
|
8
|
+
<% end %>
|
|
1
9
|
<%= form_with(model: dataset, local: true) do |form| %>
|
|
2
10
|
<% if dataset.errors.any? %>
|
|
3
11
|
<div class="ck-flash ck-flash--alert" role="alert">
|
|
@@ -31,6 +39,9 @@
|
|
|
31
39
|
<%= render "completion_kit/tags/picker", record: dataset, param_namespace: :dataset %>
|
|
32
40
|
|
|
33
41
|
<div class="ck-actions">
|
|
42
|
+
<% if dataset.persisted? %>
|
|
43
|
+
<%= ck_delete_trigger(form_id: dataset_delete_id, label: "Delete dataset", confirm: dataset_delete_confirm) %>
|
|
44
|
+
<% end %>
|
|
34
45
|
<%= link_to "Cancel", datasets_path, class: ck_button_classes(:light, variant: :outline), tabindex: "0" %>
|
|
35
46
|
<%= form.submit(dataset.persisted? ? "Save dataset" : "Create dataset", class: ck_button_classes(:dark)) %>
|
|
36
47
|
</div>
|
|
@@ -66,12 +77,5 @@ ckDatasetHeaderPreview();
|
|
|
66
77
|
<% end %>
|
|
67
78
|
|
|
68
79
|
<% if dataset.persisted? %>
|
|
69
|
-
|
|
70
|
-
<% responses_n = CompletionKit::Response.where(run_id: dataset.runs.select(:id)).count %>
|
|
71
|
-
<% confirm = if runs_n.zero?
|
|
72
|
-
"Delete \"#{dataset.name}\"? It has no runs."
|
|
73
|
-
else
|
|
74
|
-
"Delete \"#{dataset.name}\"? Cascades through #{pluralize(runs_n, 'run')} and #{pluralize(responses_n, 'response')} (and their reviews) that used this dataset."
|
|
75
|
-
end %>
|
|
76
|
-
<%= render "completion_kit/shared/delete_action", path: dataset_path(dataset), label: "Delete dataset", confirm: confirm %>
|
|
80
|
+
<%= render "completion_kit/shared/delete_form", form_id: dataset_delete_id, path: dataset_path(dataset) %>
|
|
77
81
|
<% end %>
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
<% if metric_group.persisted? %>
|
|
2
|
+
<% metric_group_delete_id = "ck_delete_metric_group_#{metric_group.id}" %>
|
|
3
|
+
<% members_n = metric_group.metrics.count %>
|
|
4
|
+
<% metric_group_delete_confirm = members_n.zero? ?
|
|
5
|
+
"Delete \"#{metric_group.name}\"? It has no members." :
|
|
6
|
+
"Delete \"#{metric_group.name}\"? Removes this grouping. #{pluralize(members_n, 'member metric')} #{members_n == 1 ? 'is' : 'are'} kept." %>
|
|
7
|
+
<% end %>
|
|
1
8
|
<%= form_with(model: metric_group, url: metric_group.persisted? ? metric_group_path(metric_group) : metric_groups_path, local: true) do |form| %>
|
|
2
9
|
<% name_error = metric_group.errors[:name].first %>
|
|
3
10
|
|
|
@@ -80,6 +87,9 @@
|
|
|
80
87
|
</script>
|
|
81
88
|
|
|
82
89
|
<div class="ck-actions">
|
|
90
|
+
<% if metric_group.persisted? %>
|
|
91
|
+
<%= ck_delete_trigger(form_id: metric_group_delete_id, label: "Delete metric group", confirm: metric_group_delete_confirm) %>
|
|
92
|
+
<% end %>
|
|
83
93
|
<%= link_to "Cancel", metrics_path, class: ck_button_classes(:light, variant: :outline), tabindex: "0" %>
|
|
84
94
|
<%= form.submit(metric_group.persisted? ? "Save metric group" : "Create metric group", class: ck_button_classes(:dark)) %>
|
|
85
95
|
</div>
|
|
@@ -87,9 +97,5 @@
|
|
|
87
97
|
<% end %>
|
|
88
98
|
|
|
89
99
|
<% if metric_group.persisted? %>
|
|
90
|
-
|
|
91
|
-
<% confirm = members_n.zero? ?
|
|
92
|
-
"Delete \"#{metric_group.name}\"? It has no members." :
|
|
93
|
-
"Delete \"#{metric_group.name}\"? Removes this grouping. #{pluralize(members_n, 'member metric')} #{members_n == 1 ? 'is' : 'are'} kept." %>
|
|
94
|
-
<%= render "completion_kit/shared/delete_action", path: metric_group_path(metric_group), label: "Delete metric group", confirm: confirm %>
|
|
100
|
+
<%= render "completion_kit/shared/delete_form", form_id: metric_group_delete_id, path: metric_group_path(metric_group) %>
|
|
95
101
|
<% end %>
|
|
@@ -3,6 +3,58 @@
|
|
|
3
3
|
<% suggestion_bands = suggestion ? Array(suggestion.rubric_bands).each_with_object({}) { |b, h| h[b["stars"].to_i] = b["description"].to_s } : {} %>
|
|
4
4
|
<% suggested_instruction = suggestion&.instruction.to_s %>
|
|
5
5
|
<% instruction_changed = suggestion && suggested_instruction.present? && suggested_instruction != metric.instruction.to_s %>
|
|
6
|
+
<% if metric.persisted? %>
|
|
7
|
+
<% metric_delete_id = "ck_delete_metric_#{metric.id}" %>
|
|
8
|
+
<% groups_n = metric.metric_groups.count %>
|
|
9
|
+
<% reviews_n = metric.reviews.count %>
|
|
10
|
+
<% parts = [] %>
|
|
11
|
+
<% parts << "in #{pluralize(groups_n, 'metric group')} (removed from each)" if groups_n > 0 %>
|
|
12
|
+
<% parts << "scored in #{pluralize(reviews_n, 'review')} (scores kept, link cleared)" if reviews_n > 0 %>
|
|
13
|
+
<% metric_delete_confirm = parts.empty? ? "Delete \"#{metric.name}\"? It's not in use." : "Delete \"#{metric.name}\"? It's #{parts.to_sentence}." %>
|
|
14
|
+
<% end %>
|
|
15
|
+
|
|
16
|
+
<% if edit_draft %>
|
|
17
|
+
<% pub = local_assigns[:published_metric_version] %>
|
|
18
|
+
<% draft_instr_changed = pub && pub.instruction.to_s != edit_draft.instruction.to_s %>
|
|
19
|
+
<% draft_rubric_changed = pub && pub.rubric_bands != edit_draft.rubric_bands %>
|
|
20
|
+
<div class="ck-suggestion-banner" role="status">
|
|
21
|
+
<div class="ck-suggestion-banner__body">
|
|
22
|
+
<p class="ck-kicker">Draft pending</p>
|
|
23
|
+
<p class="ck-meta-copy">The form below shows your unpublished draft. Publish to replace the live<%= " instruction" if draft_instr_changed %><%= " and" if draft_instr_changed && draft_rubric_changed %><%= " rubric" if draft_rubric_changed %> for future runs, or keep editing.</p>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="ck-suggestion-banner__actions">
|
|
26
|
+
<%= button_to "Discard draft", dismiss_suggestion_metric_path(metric, draft_id: edit_draft.id, back_to: "edit"),
|
|
27
|
+
method: :delete, form_class: "inline-block",
|
|
28
|
+
class: ck_button_classes(:light, variant: :outline),
|
|
29
|
+
data: { turbo_confirm: "Drop this draft?", ck_confirm_label: "Discard", ck_confirm_tone: "danger" } %>
|
|
30
|
+
<%= button_to "Publish this version", publish_draft_metric_path(metric, draft_id: edit_draft.id),
|
|
31
|
+
method: :post, form_class: "inline-block",
|
|
32
|
+
class: ck_button_classes(:dark) %>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<% if suggestion %>
|
|
38
|
+
<div class="ck-suggestion-banner" role="status">
|
|
39
|
+
<div class="ck-suggestion-banner__body">
|
|
40
|
+
<p class="ck-kicker ck-kicker--icon"><%= heroicon_tag "sparkles", variant: :outline, class: "ck-magic-icon", "aria-hidden": "true" %>Proposed changes</p>
|
|
41
|
+
<p class="ck-meta-copy">Based on human reviews, here are some proposed changes to the metric.</p>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="ck-suggestion-banner__actions">
|
|
44
|
+
<%= button_to suggest_variants_metric_path(metric, back_to: "edit"),
|
|
45
|
+
method: :post, form_class: "inline-block", class: "ck-icon-btn",
|
|
46
|
+
title: "Try again", "aria-label": "Try again",
|
|
47
|
+
data: { turbo_confirm: "Replace these changes with fresh ones from the model?" } do %><%= heroicon_tag "arrow-path", variant: :outline, size: 16, "aria-hidden": "true" %><% end %>
|
|
48
|
+
<%= button_to dismiss_suggestion_metric_path(metric, draft_id: suggestion.id, back_to: "edit"),
|
|
49
|
+
method: :delete, form_class: "inline-block", class: "ck-icon-btn",
|
|
50
|
+
title: "Discard these changes", "aria-label": "Discard",
|
|
51
|
+
data: { turbo_confirm: "Drop these changes?", ck_confirm_label: "Discard", ck_confirm_tone: "danger" } do %><%= heroicon_tag "trash", variant: :outline, size: 16, "aria-hidden": "true" %><% end %>
|
|
52
|
+
<%= button_to "Apply all", publish_draft_metric_path(metric, draft_id: suggestion.id),
|
|
53
|
+
method: :post, form_class: "inline-block",
|
|
54
|
+
class: ck_button_classes(:dark) %>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<% end %>
|
|
6
58
|
|
|
7
59
|
<%= form_with(model: metric, local: true) do |form| %>
|
|
8
60
|
<% if metric.errors.any? %>
|
|
@@ -16,49 +68,6 @@
|
|
|
16
68
|
</div>
|
|
17
69
|
<% end %>
|
|
18
70
|
|
|
19
|
-
<% if edit_draft %>
|
|
20
|
-
<% pub = local_assigns[:published_metric_version] %>
|
|
21
|
-
<% draft_instr_changed = pub && pub.instruction.to_s != edit_draft.instruction.to_s %>
|
|
22
|
-
<% draft_rubric_changed = pub && pub.rubric_bands != edit_draft.rubric_bands %>
|
|
23
|
-
<div class="ck-suggestion-banner" role="status">
|
|
24
|
-
<div class="ck-suggestion-banner__body">
|
|
25
|
-
<p class="ck-kicker">Draft pending</p>
|
|
26
|
-
<p class="ck-meta-copy">The form below shows your unpublished draft. Publish to replace the live<%= " instruction" if draft_instr_changed %><%= " and" if draft_instr_changed && draft_rubric_changed %><%= " rubric" if draft_rubric_changed %> for future runs, or keep editing.</p>
|
|
27
|
-
</div>
|
|
28
|
-
<div class="ck-suggestion-banner__actions">
|
|
29
|
-
<%= button_to "Discard draft", dismiss_suggestion_metric_path(metric, draft_id: edit_draft.id, back_to: "edit"),
|
|
30
|
-
method: :delete, form_class: "inline-block",
|
|
31
|
-
class: ck_button_classes(:light, variant: :outline),
|
|
32
|
-
data: { turbo_confirm: "Drop this draft?" } %>
|
|
33
|
-
<%= button_to "Publish this version", publish_draft_metric_path(metric, draft_id: edit_draft.id),
|
|
34
|
-
method: :post, form_class: "inline-block",
|
|
35
|
-
class: ck_button_classes(:dark) %>
|
|
36
|
-
</div>
|
|
37
|
-
</div>
|
|
38
|
-
<% end %>
|
|
39
|
-
|
|
40
|
-
<% if suggestion %>
|
|
41
|
-
<div class="ck-suggestion-banner" role="status">
|
|
42
|
-
<div class="ck-suggestion-banner__body">
|
|
43
|
-
<p class="ck-kicker ck-kicker--icon"><%= heroicon_tag "sparkles", variant: :outline, class: "ck-magic-icon", "aria-hidden": "true" %>Proposed changes</p>
|
|
44
|
-
<p class="ck-meta-copy">Based on human reviews, here are some proposed changes to the metric.</p>
|
|
45
|
-
</div>
|
|
46
|
-
<div class="ck-suggestion-banner__actions">
|
|
47
|
-
<%= button_to suggest_variants_metric_path(metric, back_to: "edit"),
|
|
48
|
-
method: :post, form_class: "inline-block", class: "ck-icon-btn",
|
|
49
|
-
title: "Try again", "aria-label": "Try again",
|
|
50
|
-
data: { turbo_confirm: "Replace these changes with fresh ones from the model?" } do %><%= heroicon_tag "arrow-path", variant: :outline, size: 16, "aria-hidden": "true" %><% end %>
|
|
51
|
-
<%= button_to dismiss_suggestion_metric_path(metric, draft_id: suggestion.id, back_to: "edit"),
|
|
52
|
-
method: :delete, form_class: "inline-block", class: "ck-icon-btn",
|
|
53
|
-
title: "Discard these changes", "aria-label": "Discard",
|
|
54
|
-
data: { turbo_confirm: "Drop these changes?" } do %><%= heroicon_tag "trash", variant: :outline, size: 16, "aria-hidden": "true" %><% end %>
|
|
55
|
-
<%= button_to "Apply all", publish_draft_metric_path(metric, draft_id: suggestion.id),
|
|
56
|
-
method: :post, form_class: "inline-block",
|
|
57
|
-
class: ck_button_classes(:dark) %>
|
|
58
|
-
</div>
|
|
59
|
-
</div>
|
|
60
|
-
<% end %>
|
|
61
|
-
|
|
62
71
|
<div class="ck-card ck-form-card">
|
|
63
72
|
<div class="ck-field">
|
|
64
73
|
<%= form.label :name, "Metric name", class: "ck-label" %>
|
|
@@ -254,6 +263,9 @@
|
|
|
254
263
|
<%= render "completion_kit/tags/picker", record: metric, param_namespace: :metric %>
|
|
255
264
|
|
|
256
265
|
<div class="ck-actions">
|
|
266
|
+
<% if metric.persisted? %>
|
|
267
|
+
<%= ck_delete_trigger(form_id: metric_delete_id, label: "Delete metric", confirm: metric_delete_confirm) %>
|
|
268
|
+
<% end %>
|
|
257
269
|
<%= link_to "Cancel", metrics_path, class: ck_button_classes(:light, variant: :outline), tabindex: "0" %>
|
|
258
270
|
<%= form.submit(metric.persisted? ? "Save metric" : "Create metric", class: ck_button_classes(:dark)) %>
|
|
259
271
|
</div>
|
|
@@ -261,11 +273,5 @@
|
|
|
261
273
|
<% end %>
|
|
262
274
|
|
|
263
275
|
<% if metric.persisted? %>
|
|
264
|
-
|
|
265
|
-
<% reviews_n = metric.reviews.count %>
|
|
266
|
-
<% parts = [] %>
|
|
267
|
-
<% parts << "in #{pluralize(groups_n, 'metric group')} (removed from each)" if groups_n > 0 %>
|
|
268
|
-
<% parts << "scored in #{pluralize(reviews_n, 'review')} (scores kept, link cleared)" if reviews_n > 0 %>
|
|
269
|
-
<% confirm = parts.empty? ? "Delete \"#{metric.name}\"? It's not in use." : "Delete \"#{metric.name}\"? It's #{parts.to_sentence}." %>
|
|
270
|
-
<%= render "completion_kit/shared/delete_action", path: metric_path(metric), label: "Delete metric", confirm: confirm %>
|
|
276
|
+
<%= render "completion_kit/shared/delete_form", form_id: metric_delete_id, path: metric_path(metric) %>
|
|
271
277
|
<% end %>
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
<% if prompt.persisted? %>
|
|
2
|
+
<% prompt_delete_id = "ck_delete_prompt_#{prompt.id}" %>
|
|
3
|
+
<% runs_n = prompt.runs.count %>
|
|
4
|
+
<% responses_n = prompt.responses.count %>
|
|
5
|
+
<% prompt_delete_confirm = runs_n.zero? ?
|
|
6
|
+
"Delete \"#{prompt.display_name}\"? This version has no runs." :
|
|
7
|
+
"Delete \"#{prompt.display_name}\"? Cascades through #{pluralize(runs_n, 'run')} and #{pluralize(responses_n, 'response')} (and their reviews). Other versions of this prompt are untouched." %>
|
|
8
|
+
<% end %>
|
|
1
9
|
<%= form_with(model: prompt, local: true) do |form| %>
|
|
2
10
|
<% if prompt.errors.any? %>
|
|
3
11
|
<div class="ck-flash ck-flash--alert" role="alert">
|
|
@@ -58,6 +66,9 @@
|
|
|
58
66
|
<%= render "completion_kit/tags/picker", record: prompt, param_namespace: :prompt %>
|
|
59
67
|
|
|
60
68
|
<div class="ck-actions">
|
|
69
|
+
<% if prompt.persisted? %>
|
|
70
|
+
<%= ck_delete_trigger(form_id: prompt_delete_id, label: "Delete prompt", confirm: prompt_delete_confirm) %>
|
|
71
|
+
<% end %>
|
|
61
72
|
<%= link_to "Cancel", prompts_path, class: ck_button_classes(:light, variant: :outline), tabindex: "0" %>
|
|
62
73
|
<%= form.submit(prompt.persisted? ? "Save prompt" : "Create prompt", class: ck_button_classes(:dark), disabled: available.empty?) %>
|
|
63
74
|
</div>
|
|
@@ -65,12 +76,5 @@
|
|
|
65
76
|
<% end %>
|
|
66
77
|
|
|
67
78
|
<% if prompt.persisted? %>
|
|
68
|
-
|
|
69
|
-
<% responses_n = prompt.responses.count %>
|
|
70
|
-
<% confirm = if runs_n.zero?
|
|
71
|
-
"Delete \"#{prompt.display_name}\"? This version has no runs."
|
|
72
|
-
else
|
|
73
|
-
"Delete \"#{prompt.display_name}\"? Cascades through #{pluralize(runs_n, 'run')} and #{pluralize(responses_n, 'response')} (and their reviews). Other versions of this prompt are untouched."
|
|
74
|
-
end %>
|
|
75
|
-
<%= render "completion_kit/shared/delete_action", path: prompt_path(prompt), label: "Delete prompt", confirm: confirm %>
|
|
79
|
+
<%= render "completion_kit/shared/delete_form", form_id: prompt_delete_id, path: prompt_path(prompt) %>
|
|
76
80
|
<% end %>
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
<% if provider_credential.persisted? %>
|
|
2
|
+
<% pc_delete_id = "ck_delete_provider_#{provider_credential.id}" %>
|
|
3
|
+
<% pc_delete_blocked = provider_credential.in_use? %>
|
|
4
|
+
<% pc_delete_confirm = "Delete the #{provider_credential.display_provider} provider and its discovered models? This can't be undone." %>
|
|
5
|
+
<% end %>
|
|
1
6
|
<%= form_with(model: provider_credential, local: true) do |form| %>
|
|
2
7
|
<% if provider_credential.errors.any? %>
|
|
3
8
|
<div class="ck-flash ck-flash--alert" role="alert">
|
|
@@ -13,7 +18,7 @@
|
|
|
13
18
|
<div class="ck-card ck-form-card">
|
|
14
19
|
<div class="ck-field">
|
|
15
20
|
<%= form.label :provider, class: "ck-label" %>
|
|
16
|
-
<%= form.select :provider, CompletionKit::ProviderCredential::PROVIDERS.map { |p| [CompletionKit::ProviderCredential::PROVIDER_LABELS[p] || p.titleize, p] }, {}, { class: "ck-input" } %>
|
|
21
|
+
<%= form.select :provider, CompletionKit::ProviderCredential::PROVIDERS.map { |p| [CompletionKit::ProviderCredential::PROVIDER_LABELS[p] || p.titleize, p] }, {}, { class: "ck-input", data: { ck_provider_select: true } } %>
|
|
17
22
|
</div>
|
|
18
23
|
|
|
19
24
|
<div class="ck-field">
|
|
@@ -28,26 +33,29 @@
|
|
|
28
33
|
<%= ck_field_error(form, :api_endpoint) %>
|
|
29
34
|
</div>
|
|
30
35
|
|
|
31
|
-
<div class="ck-field"
|
|
36
|
+
<div class="ck-field" data-ck-provider-field="azure_foundry"<%= provider_credential.azure_foundry? ? "" : " hidden" %>>
|
|
32
37
|
<%= form.label :api_version, "API version", class: "ck-label" %>
|
|
33
|
-
<%= form.text_field :api_version, class: "ck-input", placeholder: "
|
|
38
|
+
<%= form.text_field :api_version, class: "ck-input", placeholder: "e.g. 2024-10-21", **ck_field_aria(form, :api_version) %>
|
|
34
39
|
<%= ck_field_error(form, :api_version) %>
|
|
40
|
+
<p class="ck-field-hint">Optional. Leave blank to use Azure's v1 API, or set a dated version for the legacy API (which also lists your deployments during discovery).</p>
|
|
35
41
|
</div>
|
|
36
42
|
|
|
37
43
|
<div class="ck-actions">
|
|
44
|
+
<% if provider_credential.persisted? %>
|
|
45
|
+
<%= ck_delete_trigger(form_id: pc_delete_id, label: "Delete provider", confirm: pc_delete_confirm, disabled: pc_delete_blocked, title: (pc_delete_blocked ? provider_credential.in_use_message : "Delete provider")) %>
|
|
46
|
+
<% end %>
|
|
38
47
|
<%= link_to "Cancel", provider_credentials_path, class: ck_button_classes(:light, variant: :outline), tabindex: "0" %>
|
|
39
48
|
<%= form.submit(provider_credential.persisted? ? "Save provider" : "Create provider", class: ck_button_classes(:dark)) %>
|
|
40
49
|
</div>
|
|
50
|
+
<% if provider_credential.persisted? && pc_delete_blocked %>
|
|
51
|
+
<p class="ck-field-hint"><%= provider_credential.in_use_message %></p>
|
|
52
|
+
<% end %>
|
|
41
53
|
|
|
42
54
|
</div>
|
|
43
55
|
<% end %>
|
|
44
56
|
|
|
45
|
-
<% if provider_credential.persisted? %>
|
|
46
|
-
<%= render "completion_kit/shared/
|
|
47
|
-
path: provider_credential_path(provider_credential),
|
|
48
|
-
label: "Delete provider",
|
|
49
|
-
confirm: "Delete the #{provider_credential.display_provider} provider and its discovered models? This can't be undone.",
|
|
50
|
-
blocked_reason: (provider_credential.in_use_message if provider_credential.in_use?) %>
|
|
57
|
+
<% if provider_credential.persisted? && !pc_delete_blocked %>
|
|
58
|
+
<%= render "completion_kit/shared/delete_form", form_id: pc_delete_id, path: provider_credential_path(provider_credential) %>
|
|
51
59
|
<% end %>
|
|
52
60
|
|
|
53
61
|
<% if provider_credential.persisted? %>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div class="ck-actions" id="run_actions">
|
|
2
2
|
<% running = run.status == "running" %>
|
|
3
|
-
<%= button_to run_path(run), method: :delete, form_class: "inline-block", class: "ck-icon-btn", title: "Delete run", "aria-label": "Delete run", disabled: running, data: { turbo_confirm: "Delete this run and all its responses?" } do %><%= heroicon_tag "trash", variant: :outline, size: 16, "aria-hidden": "true" %><% end %>
|
|
3
|
+
<%= button_to run_path(run), method: :delete, form_class: "inline-block", class: "ck-icon-btn", title: "Delete run", "aria-label": "Delete run", disabled: running, data: { turbo_confirm: "Delete this run and all its responses?", ck_confirm_label: "Delete", ck_confirm_tone: "danger" } do %><%= heroicon_tag "trash", variant: :outline, size: 16, "aria-hidden": "true" %><% end %>
|
|
4
4
|
<% if running %>
|
|
5
5
|
<%= link_to "Edit", edit_run_path(run), class: ck_button_classes(:light, variant: :outline) + " disabled", "aria-disabled": "true", tabindex: "-1" %>
|
|
6
6
|
<% else %>
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
<% if tag.persisted? %>
|
|
2
|
+
<% tag_delete_id = "ck_delete_tag_#{tag.id}" %>
|
|
3
|
+
<% applied_n = tag.taggings.count %>
|
|
4
|
+
<% tag_delete_confirm = applied_n.zero? ?
|
|
5
|
+
"Delete \"#{tag.name}\"? It's not currently applied to anything." :
|
|
6
|
+
"Delete \"#{tag.name}\"? It's currently applied to #{pluralize(applied_n, 'item')}. They'll lose this tag." %>
|
|
7
|
+
<% end %>
|
|
1
8
|
<%= form_with(model: tag, local: true) do |form| %>
|
|
2
9
|
<div class="ck-card ck-form-card">
|
|
3
10
|
<% name_error = tag.errors[:name].first %>
|
|
@@ -17,6 +24,9 @@
|
|
|
17
24
|
</div>
|
|
18
25
|
|
|
19
26
|
<div class="ck-actions">
|
|
27
|
+
<% if tag.persisted? %>
|
|
28
|
+
<%= ck_delete_trigger(form_id: tag_delete_id, label: "Delete tag", confirm: tag_delete_confirm) %>
|
|
29
|
+
<% end %>
|
|
20
30
|
<%= link_to "Cancel", tags_path, class: ck_button_classes(:light, variant: :outline), tabindex: "0" %>
|
|
21
31
|
<%= form.submit(tag.persisted? ? "Save tag" : "Create tag", class: ck_button_classes(:dark)) %>
|
|
22
32
|
</div>
|
|
@@ -24,11 +34,5 @@
|
|
|
24
34
|
<% end %>
|
|
25
35
|
|
|
26
36
|
<% if tag.persisted? %>
|
|
27
|
-
|
|
28
|
-
<% confirm = if applied_n.zero?
|
|
29
|
-
"Delete \"#{tag.name}\"? It's not currently applied to anything."
|
|
30
|
-
else
|
|
31
|
-
"Delete \"#{tag.name}\"? It's currently applied to #{pluralize(applied_n, 'item')}. They'll lose this tag."
|
|
32
|
-
end %>
|
|
33
|
-
<%= render "completion_kit/shared/delete_action", path: tag_path(tag), label: "Delete tag", confirm: confirm %>
|
|
37
|
+
<%= render "completion_kit/shared/delete_form", form_id: tag_delete_id, path: tag_path(tag) %>
|
|
34
38
|
<% end %>
|
|
@@ -60,5 +60,22 @@
|
|
|
60
60
|
<%= yield %>
|
|
61
61
|
</div>
|
|
62
62
|
</main>
|
|
63
|
+
|
|
64
|
+
<dialog id="ck-confirm-modal" class="ck-modal ck-modal--sm" role="alertdialog" aria-labelledby="ck-confirm-title" aria-describedby="ck-confirm-message">
|
|
65
|
+
<article class="ck-modal__panel" tabindex="-1">
|
|
66
|
+
<header class="ck-modal__header">
|
|
67
|
+
<div class="ck-modal__heading">
|
|
68
|
+
<h2 class="ck-modal__title" id="ck-confirm-title">Please confirm</h2>
|
|
69
|
+
</div>
|
|
70
|
+
</header>
|
|
71
|
+
<div class="ck-modal__body">
|
|
72
|
+
<p class="ck-confirm__message" id="ck-confirm-message"></p>
|
|
73
|
+
</div>
|
|
74
|
+
<div class="ck-modal__footer">
|
|
75
|
+
<button type="button" class="<%= ck_button_classes(:light, variant: :outline) %>" data-ck-confirm-cancel>Cancel</button>
|
|
76
|
+
<button type="button" class="<%= ck_button_classes(:dark) %>" data-ck-confirm-accept>Confirm</button>
|
|
77
|
+
</div>
|
|
78
|
+
</article>
|
|
79
|
+
</dialog>
|
|
63
80
|
</body>
|
|
64
81
|
</html>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: completion-kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.26.
|
|
4
|
+
version: 0.26.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Damien Bastin
|
|
@@ -421,7 +421,7 @@ files:
|
|
|
421
421
|
- app/views/completion_kit/runs/new.html.erb
|
|
422
422
|
- app/views/completion_kit/runs/show.html.erb
|
|
423
423
|
- app/views/completion_kit/shared/_branded_select.html.erb
|
|
424
|
-
- app/views/completion_kit/shared/
|
|
424
|
+
- app/views/completion_kit/shared/_delete_form.html.erb
|
|
425
425
|
- app/views/completion_kit/shared/_settings_nav.html.erb
|
|
426
426
|
- app/views/completion_kit/suggestions/_scoreboard.html.erb
|
|
427
427
|
- app/views/completion_kit/suggestions/_state.html.erb
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
<%# locals: (path:, label:, confirm:, blocked_reason: nil) %>
|
|
2
|
-
<div class="ck-delete-action">
|
|
3
|
-
<% if blocked_reason.present? %>
|
|
4
|
-
<button type="button" class="<%= ck_button_classes(:red, variant: :outline) %>" disabled aria-disabled="true">
|
|
5
|
-
<%= heroicon_tag "trash", variant: :outline, size: 15, "aria-hidden": "true" %>
|
|
6
|
-
<%= label %>
|
|
7
|
-
</button>
|
|
8
|
-
<p class="ck-field-hint"><%= blocked_reason %></p>
|
|
9
|
-
<% else %>
|
|
10
|
-
<%= button_to path, method: :delete,
|
|
11
|
-
form_class: "inline-block",
|
|
12
|
-
class: ck_button_classes(:red, variant: :outline),
|
|
13
|
-
data: { turbo_confirm: confirm } do %>
|
|
14
|
-
<%= heroicon_tag "trash", variant: :outline, size: 15, "aria-hidden": "true" %>
|
|
15
|
-
<%= label %>
|
|
16
|
-
<% end %>
|
|
17
|
-
<% end %>
|
|
18
|
-
</div>
|