plutonium 0.49.1 → 0.50.0
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/.claude/skills/plutonium-definition/SKILL.md +87 -2
- data/.claude/skills/plutonium-installation/SKILL.md +6 -0
- data/.claude/skills/plutonium-views/SKILL.md +59 -0
- data/CHANGELOG.md +12 -0
- data/app/assets/plutonium.css +2 -2
- data/app/assets/plutonium.js +369 -25
- data/app/assets/plutonium.js.map +4 -4
- data/app/assets/plutonium.min.js +45 -45
- data/app/assets/plutonium.min.js.map +4 -4
- data/app/views/plutonium/_resource_header.html.erb +4 -4
- data/app/views/plutonium/_resource_sidebar.html.erb +9 -9
- data/app/views/resource/_resource_grid.html.erb +1 -0
- data/config/brakeman.ignore +25 -2
- data/docs/reference/definition/actions.md +14 -1
- data/docs/reference/definition/index.md +58 -0
- data/docs/reference/views/index.md +43 -0
- data/docs/superpowers/plans/2026-05-07-ui-layout-overhaul.md +841 -0
- data/docs/superpowers/plans/2026-05-07-ui-layout-overhaul.md.tasks.json +103 -0
- data/docs/superpowers/specs/2026-05-07-ui-layout-overhaul-design.md +270 -0
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/core/install/templates/config/initializers/plutonium.rb +1 -0
- data/lib/generators/pu/core/update/update_generator.rb +20 -0
- data/lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb +54 -5
- data/lib/plutonium/action/base.rb +44 -1
- data/lib/plutonium/action/interactive.rb +1 -1
- data/lib/plutonium/configuration.rb +4 -0
- data/lib/plutonium/definition/actions.rb +3 -0
- data/lib/plutonium/definition/base.rb +8 -0
- data/lib/plutonium/definition/metadata.rb +40 -0
- data/lib/plutonium/definition/views.rb +94 -0
- data/lib/plutonium/helpers/turbo_helper.rb +1 -1
- data/lib/plutonium/interaction/response/redirect.rb +1 -1
- data/lib/plutonium/query/base.rb +8 -0
- data/lib/plutonium/query/filters/association.rb +30 -8
- data/lib/plutonium/query/filters/boolean.rb +5 -0
- data/lib/plutonium/resource/controllers/presentable.rb +11 -2
- data/lib/plutonium/resource/definition.rb +42 -0
- data/lib/plutonium/resource/query_object.rb +64 -6
- data/lib/plutonium/testing/resource_definition.rb +2 -2
- data/lib/plutonium/ui/action_button.rb +4 -2
- data/lib/plutonium/ui/component/kit.rb +12 -0
- data/lib/plutonium/ui/display/base.rb +3 -1
- data/lib/plutonium/ui/display/resource.rb +109 -25
- data/lib/plutonium/ui/display/theme.rb +2 -1
- data/lib/plutonium/ui/dyna_frame/content.rb +8 -14
- data/lib/plutonium/ui/empty_card.rb +1 -1
- data/lib/plutonium/ui/form/base.rb +29 -1
- data/lib/plutonium/ui/form/components/hidden_wrapper.rb +25 -0
- data/lib/plutonium/ui/form/components/resource_select.rb +79 -1
- data/lib/plutonium/ui/form/components/secure_association.rb +7 -2
- data/lib/plutonium/ui/form/components/sticky_footer.rb +17 -0
- data/lib/plutonium/ui/form/resource.rb +48 -9
- data/lib/plutonium/ui/form/theme.rb +1 -1
- data/lib/plutonium/ui/frame_navigator_panel.rb +7 -4
- data/lib/plutonium/ui/grid/card.rb +235 -0
- data/lib/plutonium/ui/grid/resource.rb +149 -0
- data/lib/plutonium/ui/layout/base.rb +37 -1
- data/lib/plutonium/ui/layout/header.rb +1 -2
- data/lib/plutonium/ui/layout/icon_rail.rb +212 -0
- data/lib/plutonium/ui/layout/resource_layout.rb +10 -3
- data/lib/plutonium/ui/layout/sidebar.rb +12 -24
- data/lib/plutonium/ui/layout/topbar.rb +100 -0
- data/lib/plutonium/ui/modal/base.rb +109 -0
- data/lib/plutonium/ui/modal/centered.rb +21 -0
- data/lib/plutonium/ui/modal/slideover.rb +26 -0
- data/lib/plutonium/ui/page/base.rb +25 -6
- data/lib/plutonium/ui/page/edit.rb +13 -1
- data/lib/plutonium/ui/page/index.rb +40 -1
- data/lib/plutonium/ui/page/interactive_action.rb +8 -39
- data/lib/plutonium/ui/page/new.rb +13 -1
- data/lib/plutonium/ui/page/show.rb +8 -1
- data/lib/plutonium/ui/page_header.rb +8 -13
- data/lib/plutonium/ui/panel.rb +10 -19
- data/lib/plutonium/ui/sidebar_menu.rb +2 -25
- data/lib/plutonium/ui/tab_list.rb +29 -7
- data/lib/plutonium/ui/table/base.rb +106 -0
- data/lib/plutonium/ui/table/components/bulk_actions_toolbar.rb +12 -4
- data/lib/plutonium/ui/table/components/filter_form.rb +171 -0
- data/lib/plutonium/ui/table/components/filter_pills.rb +89 -0
- data/lib/plutonium/ui/table/components/row_actions_dropdown.rb +13 -12
- data/lib/plutonium/ui/table/components/scopes_pills.rb +67 -0
- data/lib/plutonium/ui/table/components/selection_column.rb +2 -11
- data/lib/plutonium/ui/table/components/toolbar.rb +104 -0
- data/lib/plutonium/ui/table/components/view_switcher.rb +81 -0
- data/lib/plutonium/ui/table/resource.rb +158 -89
- data/lib/plutonium/ui/table/theme.rb +14 -5
- data/lib/plutonium/version.rb +1 -1
- data/lib/plutonium.rb +6 -0
- data/package.json +1 -1
- data/src/css/components.css +304 -131
- data/src/css/tokens.css +101 -85
- data/src/js/controllers/autosubmit_controller.js +24 -0
- data/src/js/controllers/bulk_actions_controller.js +15 -16
- data/src/js/controllers/capture_url_controller.js +14 -0
- data/src/js/controllers/filter_panel_controller.js +77 -19
- data/src/js/controllers/frame_navigator_controller.js +34 -6
- data/src/js/controllers/icon_rail_controller.js +22 -0
- data/src/js/controllers/icon_rail_flyout_controller.js +128 -0
- data/src/js/controllers/register_controllers.js +16 -0
- data/src/js/controllers/resource_tab_list_controller.js +56 -3
- data/src/js/controllers/row_click_controller.js +21 -0
- data/src/js/controllers/table_column_menu_controller.js +43 -0
- data/src/js/controllers/table_header_controller.js +16 -0
- data/src/js/controllers/view_switcher_controller.js +29 -0
- metadata +31 -3
data/app/assets/plutonium.js
CHANGED
|
@@ -13326,6 +13326,12 @@
|
|
|
13326
13326
|
this.frameTarget.removeEventListener("turbo:fetch-request-error", this.frameFailed);
|
|
13327
13327
|
}
|
|
13328
13328
|
frameLoading(event) {
|
|
13329
|
+
if (event) {
|
|
13330
|
+
const trigger = event.target.closest("a, form");
|
|
13331
|
+
const requested = trigger?.dataset?.turboFrame;
|
|
13332
|
+
if (requested && requested !== this.frameTarget.id)
|
|
13333
|
+
return;
|
|
13334
|
+
}
|
|
13329
13335
|
this.#loadingStarted();
|
|
13330
13336
|
}
|
|
13331
13337
|
frameFailed(event) {
|
|
@@ -13347,17 +13353,26 @@
|
|
|
13347
13353
|
}
|
|
13348
13354
|
homeButtonClicked(event) {
|
|
13349
13355
|
this.frameLoading(null);
|
|
13356
|
+
this.srcHistory = [this.originalFrameSrc];
|
|
13357
|
+
this.#updateNavigationButtonsDisplay();
|
|
13358
|
+
this._homeRequested = true;
|
|
13350
13359
|
this.frameTarget.src = this.originalFrameSrc;
|
|
13360
|
+
this.frameTarget.reload();
|
|
13351
13361
|
}
|
|
13352
13362
|
get currentSrc() {
|
|
13353
13363
|
return this.srcHistory[this.srcHistory.length - 1];
|
|
13354
13364
|
}
|
|
13355
13365
|
#notifySrcChanged(src) {
|
|
13356
|
-
if (
|
|
13357
|
-
|
|
13366
|
+
if (this._homeRequested) {
|
|
13367
|
+
this._homeRequested = false;
|
|
13358
13368
|
this.srcHistory = [src];
|
|
13359
|
-
|
|
13369
|
+
this.originalFrameSrc = src;
|
|
13370
|
+
} else if (src == this.currentSrc) {
|
|
13371
|
+
} else if (src == this.originalFrameSrc) {
|
|
13372
|
+
this.srcHistory = [src];
|
|
13373
|
+
} else {
|
|
13360
13374
|
this.srcHistory.push(src);
|
|
13375
|
+
}
|
|
13361
13376
|
this.#updateNavigationButtonsDisplay();
|
|
13362
13377
|
if (this.hasMaximizeLinkTarget)
|
|
13363
13378
|
this.maximizeLinkTarget.href = src;
|
|
@@ -16974,12 +16989,28 @@ ${text2}</tr>
|
|
|
16974
16989
|
connect() {
|
|
16975
16990
|
this.activeClasses = this.hasActiveClassesValue ? this.activeClassesValue.split(" ") : [];
|
|
16976
16991
|
this.inActiveClasses = this.hasInActiveClassesValue ? this.inActiveClassesValue.split(" ") : [];
|
|
16977
|
-
this.#
|
|
16992
|
+
const fromHash = this.#buttonIdFromHash();
|
|
16993
|
+
const initialId = fromHash || this.defaultTabValue || this.btnTargets[0]?.id;
|
|
16994
|
+
this.#selectInternal(initialId, { skipFocus: true, skipHashUpdate: true });
|
|
16995
|
+
this._syncFromHash = this._syncFromHash.bind(this);
|
|
16996
|
+
window.addEventListener("hashchange", this._syncFromHash);
|
|
16997
|
+
document.addEventListener("turbo:load", this._syncFromHash);
|
|
16998
|
+
}
|
|
16999
|
+
disconnect() {
|
|
17000
|
+
if (this._syncFromHash) {
|
|
17001
|
+
window.removeEventListener("hashchange", this._syncFromHash);
|
|
17002
|
+
document.removeEventListener("turbo:load", this._syncFromHash);
|
|
17003
|
+
}
|
|
17004
|
+
}
|
|
17005
|
+
_syncFromHash() {
|
|
17006
|
+
const id2 = this.#buttonIdFromHash();
|
|
17007
|
+
if (id2)
|
|
17008
|
+
this.#selectInternal(id2, { skipFocus: true, skipHashUpdate: true });
|
|
16978
17009
|
}
|
|
16979
17010
|
select(event) {
|
|
16980
17011
|
this.#selectInternal(event.currentTarget.id);
|
|
16981
17012
|
}
|
|
16982
|
-
#selectInternal(id2) {
|
|
17013
|
+
#selectInternal(id2, options2 = {}) {
|
|
16983
17014
|
const selectedBtn = this.btnTargets.find((element) => element.id === id2);
|
|
16984
17015
|
if (!selectedBtn) {
|
|
16985
17016
|
console.error(`Tab Button with id "${id2}" not found`);
|
|
@@ -17006,10 +17037,29 @@ ${text2}</tr>
|
|
|
17006
17037
|
selectedBtn.classList.add(...this.activeClasses);
|
|
17007
17038
|
selectedTab.hidden = false;
|
|
17008
17039
|
selectedTab.setAttribute("aria-hidden", "false");
|
|
17009
|
-
if (
|
|
17040
|
+
if (!options2.skipHashUpdate)
|
|
17041
|
+
this.#updateHash(id2);
|
|
17042
|
+
if (!options2.skipFocus && selectedBtn !== document.activeElement) {
|
|
17010
17043
|
selectedBtn.focus();
|
|
17011
17044
|
}
|
|
17012
17045
|
}
|
|
17046
|
+
// Button ids follow `${identifier}-tab`. The URL hash carries just
|
|
17047
|
+
// the identifier (e.g., #details, #orders).
|
|
17048
|
+
#buttonIdFromHash() {
|
|
17049
|
+
const hash3 = window.location.hash.replace(/^#/, "");
|
|
17050
|
+
if (!hash3)
|
|
17051
|
+
return null;
|
|
17052
|
+
const candidateId = `${hash3}-tab`;
|
|
17053
|
+
const exists = this.btnTargets.some((btn) => btn.id === candidateId);
|
|
17054
|
+
return exists ? candidateId : null;
|
|
17055
|
+
}
|
|
17056
|
+
#updateHash(buttonId) {
|
|
17057
|
+
const identifier = buttonId.replace(/-tab$/, "");
|
|
17058
|
+
const newHash = `#${identifier}`;
|
|
17059
|
+
if (window.location.hash !== newHash) {
|
|
17060
|
+
history.replaceState(null, "", newHash);
|
|
17061
|
+
}
|
|
17062
|
+
}
|
|
17013
17063
|
};
|
|
17014
17064
|
|
|
17015
17065
|
// node_modules/@uppy/utils/lib/Translator.js
|
|
@@ -27854,18 +27904,7 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
27854
27904
|
|
|
27855
27905
|
// src/js/controllers/bulk_actions_controller.js
|
|
27856
27906
|
var bulk_actions_controller_default = class extends Controller {
|
|
27857
|
-
static targets = ["checkbox", "checkboxAll", "toolbar", "selectedCount", "actionButton", "
|
|
27858
|
-
static values = {
|
|
27859
|
-
hasActions: { type: Boolean, default: false }
|
|
27860
|
-
};
|
|
27861
|
-
connect() {
|
|
27862
|
-
if (this.hasActionsValue) {
|
|
27863
|
-
this.enableSelection();
|
|
27864
|
-
}
|
|
27865
|
-
}
|
|
27866
|
-
enableSelection() {
|
|
27867
|
-
this.selectionCellTargets.forEach((el) => el.classList.remove("hidden"));
|
|
27868
|
-
}
|
|
27907
|
+
static targets = ["checkbox", "checkboxAll", "toolbar", "selectedCount", "actionButton", "filterPills"];
|
|
27869
27908
|
toggle() {
|
|
27870
27909
|
this.updateUI();
|
|
27871
27910
|
}
|
|
@@ -27884,6 +27923,9 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
27884
27923
|
if (this.hasToolbarTarget) {
|
|
27885
27924
|
this.toolbarTarget.classList.toggle("hidden", checked.length === 0);
|
|
27886
27925
|
}
|
|
27926
|
+
if (this.hasFilterPillsTarget) {
|
|
27927
|
+
this.filterPillsTarget.classList.toggle("hidden", checked.length > 0);
|
|
27928
|
+
}
|
|
27887
27929
|
if (this.hasSelectedCountTarget) {
|
|
27888
27930
|
this.selectedCountTarget.textContent = checked.length;
|
|
27889
27931
|
}
|
|
@@ -27919,6 +27961,14 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
27919
27961
|
const allowedActions = checkbox.dataset.allowedActions;
|
|
27920
27962
|
return allowedActions ? allowedActions.split(",").filter((a4) => a4) : [];
|
|
27921
27963
|
}
|
|
27964
|
+
clearSelection() {
|
|
27965
|
+
this.checkboxTargets.forEach((cb) => cb.checked = false);
|
|
27966
|
+
if (this.hasCheckboxAllTarget) {
|
|
27967
|
+
this.checkboxAllTarget.checked = false;
|
|
27968
|
+
this.checkboxAllTarget.indeterminate = false;
|
|
27969
|
+
}
|
|
27970
|
+
this.updateUI();
|
|
27971
|
+
}
|
|
27922
27972
|
get checked() {
|
|
27923
27973
|
return this.checkboxTargets.filter((cb) => cb.checked);
|
|
27924
27974
|
}
|
|
@@ -27929,6 +27979,56 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
27929
27979
|
|
|
27930
27980
|
// src/js/controllers/filter_panel_controller.js
|
|
27931
27981
|
var filter_panel_controller_default = class extends Controller {
|
|
27982
|
+
static targets = ["panel", "backdrop"];
|
|
27983
|
+
connect() {
|
|
27984
|
+
this._onKeydown = this._onKeydown.bind(this);
|
|
27985
|
+
}
|
|
27986
|
+
disconnect() {
|
|
27987
|
+
if (this.isOpen) {
|
|
27988
|
+
document.removeEventListener("keydown", this._onKeydown);
|
|
27989
|
+
this._unlockBodyScroll();
|
|
27990
|
+
}
|
|
27991
|
+
}
|
|
27992
|
+
toggle() {
|
|
27993
|
+
this.isOpen ? this.close() : this.open();
|
|
27994
|
+
}
|
|
27995
|
+
open() {
|
|
27996
|
+
if (this.hasPanelTarget) {
|
|
27997
|
+
this.panelTarget.setAttribute("data-open", "");
|
|
27998
|
+
this.panelTarget.setAttribute("aria-hidden", "false");
|
|
27999
|
+
}
|
|
28000
|
+
if (this.hasBackdropTarget)
|
|
28001
|
+
this.backdropTarget.setAttribute("data-open", "");
|
|
28002
|
+
this._lockBodyScroll();
|
|
28003
|
+
document.addEventListener("keydown", this._onKeydown);
|
|
28004
|
+
}
|
|
28005
|
+
close() {
|
|
28006
|
+
if (this.hasPanelTarget) {
|
|
28007
|
+
this.panelTarget.removeAttribute("data-open");
|
|
28008
|
+
this.panelTarget.setAttribute("aria-hidden", "true");
|
|
28009
|
+
}
|
|
28010
|
+
if (this.hasBackdropTarget)
|
|
28011
|
+
this.backdropTarget.removeAttribute("data-open");
|
|
28012
|
+
this._unlockBodyScroll();
|
|
28013
|
+
document.removeEventListener("keydown", this._onKeydown);
|
|
28014
|
+
}
|
|
28015
|
+
// Mirrors remote-modal's approach: stash the body's current overflow
|
|
28016
|
+
// and restore it on close. Avoids stomping a value another component
|
|
28017
|
+
// (e.g. an open dialog) may have set.
|
|
28018
|
+
_lockBodyScroll() {
|
|
28019
|
+
if (this._previousBodyOverflow != null)
|
|
28020
|
+
return;
|
|
28021
|
+
this._previousBodyOverflow = document.body.style.overflow;
|
|
28022
|
+
document.body.style.overflow = "hidden";
|
|
28023
|
+
}
|
|
28024
|
+
_unlockBodyScroll() {
|
|
28025
|
+
if (this._previousBodyOverflow == null)
|
|
28026
|
+
return;
|
|
28027
|
+
document.body.style.overflow = this._previousBodyOverflow;
|
|
28028
|
+
this._previousBodyOverflow = null;
|
|
28029
|
+
}
|
|
28030
|
+
// Reset every input under this controller's scope, then submit so the
|
|
28031
|
+
// table reflects the cleared filters immediately.
|
|
27932
28032
|
clear() {
|
|
27933
28033
|
this.element.querySelectorAll("input, select, textarea").forEach((input) => {
|
|
27934
28034
|
if (input.type === "checkbox" || input.type === "radio") {
|
|
@@ -27936,23 +28036,27 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
27936
28036
|
} else if (input.tagName === "SELECT") {
|
|
27937
28037
|
input.selectedIndex = 0;
|
|
27938
28038
|
} else if (input.type === "hidden") {
|
|
27939
|
-
if (input.dataset.controller === "flatpickr")
|
|
28039
|
+
if (input.dataset.controller === "flatpickr")
|
|
27940
28040
|
input.value = "";
|
|
27941
|
-
}
|
|
27942
28041
|
} else {
|
|
27943
28042
|
input.value = "";
|
|
27944
28043
|
}
|
|
27945
28044
|
});
|
|
27946
28045
|
this.element.querySelectorAll('[data-controller="flatpickr"]').forEach((input) => {
|
|
27947
28046
|
const controller = this.application.getControllerForElementAndIdentifier(input, "flatpickr");
|
|
27948
|
-
if (controller?.picker)
|
|
28047
|
+
if (controller?.picker)
|
|
27949
28048
|
controller.picker.clear();
|
|
27950
|
-
}
|
|
27951
28049
|
});
|
|
27952
|
-
const form = this.element.
|
|
27953
|
-
if (form)
|
|
28050
|
+
const form = this.element.querySelector("form");
|
|
28051
|
+
if (form)
|
|
27954
28052
|
form.requestSubmit();
|
|
27955
|
-
|
|
28053
|
+
}
|
|
28054
|
+
get isOpen() {
|
|
28055
|
+
return this.hasPanelTarget && this.panelTarget.hasAttribute("data-open");
|
|
28056
|
+
}
|
|
28057
|
+
_onKeydown(event) {
|
|
28058
|
+
if (event.key === "Escape")
|
|
28059
|
+
this.close();
|
|
27956
28060
|
}
|
|
27957
28061
|
};
|
|
27958
28062
|
|
|
@@ -28033,6 +28137,238 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
28033
28137
|
}
|
|
28034
28138
|
};
|
|
28035
28139
|
|
|
28140
|
+
// src/js/controllers/icon_rail_controller.js
|
|
28141
|
+
var icon_rail_controller_default = class extends Controller {
|
|
28142
|
+
static values = {
|
|
28143
|
+
storageKey: { type: String, default: "pu_rail_pinned" }
|
|
28144
|
+
};
|
|
28145
|
+
connect() {
|
|
28146
|
+
const pinned = localStorage.getItem(this.storageKeyValue) === "true";
|
|
28147
|
+
if (pinned) {
|
|
28148
|
+
document.body.classList.add("pu-rail-pinned");
|
|
28149
|
+
}
|
|
28150
|
+
}
|
|
28151
|
+
togglePin() {
|
|
28152
|
+
const pinned = document.body.classList.toggle("pu-rail-pinned");
|
|
28153
|
+
localStorage.setItem(this.storageKeyValue, pinned);
|
|
28154
|
+
}
|
|
28155
|
+
};
|
|
28156
|
+
|
|
28157
|
+
// src/js/controllers/icon_rail_flyout_controller.js
|
|
28158
|
+
var icon_rail_flyout_controller_default = class extends Controller {
|
|
28159
|
+
static targets = ["trigger", "panel"];
|
|
28160
|
+
static values = {
|
|
28161
|
+
closeDelay: { type: Number, default: 150 }
|
|
28162
|
+
};
|
|
28163
|
+
connect() {
|
|
28164
|
+
this._closeTimer = null;
|
|
28165
|
+
this._open = false;
|
|
28166
|
+
this._panel = null;
|
|
28167
|
+
this._panelHome = null;
|
|
28168
|
+
this._onPanelEnter = () => {
|
|
28169
|
+
if (this._closeTimer) {
|
|
28170
|
+
clearTimeout(this._closeTimer);
|
|
28171
|
+
this._closeTimer = null;
|
|
28172
|
+
}
|
|
28173
|
+
};
|
|
28174
|
+
this._onPanelLeave = () => this.scheduleClose();
|
|
28175
|
+
}
|
|
28176
|
+
disconnect() {
|
|
28177
|
+
this._returnPanel();
|
|
28178
|
+
}
|
|
28179
|
+
open() {
|
|
28180
|
+
if (this._closeTimer) {
|
|
28181
|
+
clearTimeout(this._closeTimer);
|
|
28182
|
+
this._closeTimer = null;
|
|
28183
|
+
}
|
|
28184
|
+
if (this._open)
|
|
28185
|
+
return;
|
|
28186
|
+
if (!this._panel && !this.hasPanelTarget)
|
|
28187
|
+
return;
|
|
28188
|
+
this._open = true;
|
|
28189
|
+
this.element.dataset.flyoutOpen = "true";
|
|
28190
|
+
this._portalPanel();
|
|
28191
|
+
this._position();
|
|
28192
|
+
}
|
|
28193
|
+
scheduleClose() {
|
|
28194
|
+
if (this._closeTimer)
|
|
28195
|
+
clearTimeout(this._closeTimer);
|
|
28196
|
+
this._closeTimer = setTimeout(() => this.close(), this.closeDelayValue);
|
|
28197
|
+
}
|
|
28198
|
+
close() {
|
|
28199
|
+
if (!this._open)
|
|
28200
|
+
return;
|
|
28201
|
+
this._open = false;
|
|
28202
|
+
delete this.element.dataset.flyoutOpen;
|
|
28203
|
+
this._returnPanel();
|
|
28204
|
+
}
|
|
28205
|
+
toggle(event) {
|
|
28206
|
+
event.preventDefault();
|
|
28207
|
+
this._open ? this.close() : this.open();
|
|
28208
|
+
}
|
|
28209
|
+
closeOnEsc(event) {
|
|
28210
|
+
if (event.key === "Escape")
|
|
28211
|
+
this.close();
|
|
28212
|
+
}
|
|
28213
|
+
_portalPanel() {
|
|
28214
|
+
if (this._panel)
|
|
28215
|
+
return;
|
|
28216
|
+
const panel = this.panelTarget;
|
|
28217
|
+
if (!panel)
|
|
28218
|
+
return;
|
|
28219
|
+
this._panel = panel;
|
|
28220
|
+
this._panelHome = panel.parentElement;
|
|
28221
|
+
panel.addEventListener("mouseenter", this._onPanelEnter);
|
|
28222
|
+
panel.addEventListener("mouseleave", this._onPanelLeave);
|
|
28223
|
+
document.body.appendChild(panel);
|
|
28224
|
+
panel.style.display = "block";
|
|
28225
|
+
}
|
|
28226
|
+
_returnPanel() {
|
|
28227
|
+
if (!this._panel)
|
|
28228
|
+
return;
|
|
28229
|
+
const panel = this._panel;
|
|
28230
|
+
panel.removeEventListener("mouseenter", this._onPanelEnter);
|
|
28231
|
+
panel.removeEventListener("mouseleave", this._onPanelLeave);
|
|
28232
|
+
panel.style.position = "";
|
|
28233
|
+
panel.style.left = "";
|
|
28234
|
+
panel.style.top = "";
|
|
28235
|
+
panel.style.display = "";
|
|
28236
|
+
if (this._panelHome && document.contains(this._panelHome)) {
|
|
28237
|
+
this._panelHome.appendChild(panel);
|
|
28238
|
+
} else {
|
|
28239
|
+
panel.remove();
|
|
28240
|
+
}
|
|
28241
|
+
this._panel = null;
|
|
28242
|
+
this._panelHome = null;
|
|
28243
|
+
}
|
|
28244
|
+
_position() {
|
|
28245
|
+
if (!this._panel || !this.hasTriggerTarget)
|
|
28246
|
+
return;
|
|
28247
|
+
const panel = this._panel;
|
|
28248
|
+
const triggerRect = this.triggerTarget.getBoundingClientRect();
|
|
28249
|
+
panel.style.position = "fixed";
|
|
28250
|
+
panel.style.left = `${triggerRect.right + 4}px`;
|
|
28251
|
+
panel.style.top = `${triggerRect.top}px`;
|
|
28252
|
+
requestAnimationFrame(() => {
|
|
28253
|
+
const panelRect = panel.getBoundingClientRect();
|
|
28254
|
+
const viewportH = window.innerHeight;
|
|
28255
|
+
if (panelRect.bottom > viewportH - 8) {
|
|
28256
|
+
const overflow = panelRect.bottom - (viewportH - 8);
|
|
28257
|
+
panel.style.top = `${parseFloat(panel.style.top) - overflow}px`;
|
|
28258
|
+
}
|
|
28259
|
+
});
|
|
28260
|
+
}
|
|
28261
|
+
};
|
|
28262
|
+
|
|
28263
|
+
// src/js/controllers/table_header_controller.js
|
|
28264
|
+
var table_header_controller_default = class extends Controller {
|
|
28265
|
+
headerClick(event) {
|
|
28266
|
+
if (!event.shiftKey)
|
|
28267
|
+
return;
|
|
28268
|
+
const link2 = event.currentTarget;
|
|
28269
|
+
const multiHref = link2.dataset.tableHeaderMultiHref;
|
|
28270
|
+
if (!multiHref)
|
|
28271
|
+
return;
|
|
28272
|
+
event.preventDefault();
|
|
28273
|
+
Turbo.visit(multiHref);
|
|
28274
|
+
}
|
|
28275
|
+
};
|
|
28276
|
+
|
|
28277
|
+
// src/js/controllers/table_column_menu_controller.js
|
|
28278
|
+
var table_column_menu_controller_default = class extends Controller {
|
|
28279
|
+
static targets = ["panel"];
|
|
28280
|
+
connect() {
|
|
28281
|
+
this._onDocClick = this._onDocClick.bind(this);
|
|
28282
|
+
}
|
|
28283
|
+
toggle(event) {
|
|
28284
|
+
event.preventDefault();
|
|
28285
|
+
event.stopPropagation();
|
|
28286
|
+
if (this.hasPanelTarget) {
|
|
28287
|
+
const isNowVisible = !this.panelTarget.classList.toggle("hidden");
|
|
28288
|
+
if (isNowVisible) {
|
|
28289
|
+
document.addEventListener("click", this._onDocClick);
|
|
28290
|
+
this._onKey = (e4) => {
|
|
28291
|
+
if (e4.key === "Escape")
|
|
28292
|
+
this._close();
|
|
28293
|
+
};
|
|
28294
|
+
document.addEventListener("keydown", this._onKey);
|
|
28295
|
+
} else {
|
|
28296
|
+
this._unbind();
|
|
28297
|
+
}
|
|
28298
|
+
}
|
|
28299
|
+
}
|
|
28300
|
+
_close() {
|
|
28301
|
+
if (this.hasPanelTarget)
|
|
28302
|
+
this.panelTarget.classList.add("hidden");
|
|
28303
|
+
this._unbind();
|
|
28304
|
+
}
|
|
28305
|
+
_unbind() {
|
|
28306
|
+
document.removeEventListener("click", this._onDocClick);
|
|
28307
|
+
if (this._onKey) {
|
|
28308
|
+
document.removeEventListener("keydown", this._onKey);
|
|
28309
|
+
this._onKey = null;
|
|
28310
|
+
}
|
|
28311
|
+
}
|
|
28312
|
+
_onDocClick(event) {
|
|
28313
|
+
if (!this.element.contains(event.target))
|
|
28314
|
+
this._close();
|
|
28315
|
+
}
|
|
28316
|
+
};
|
|
28317
|
+
|
|
28318
|
+
// src/js/controllers/capture_url_controller.js
|
|
28319
|
+
var capture_url_controller_default = class extends Controller {
|
|
28320
|
+
connect() {
|
|
28321
|
+
if ("value" in this.element) {
|
|
28322
|
+
this.element.value = window.location.href;
|
|
28323
|
+
}
|
|
28324
|
+
}
|
|
28325
|
+
};
|
|
28326
|
+
|
|
28327
|
+
// src/js/controllers/row_click_controller.js
|
|
28328
|
+
var row_click_controller_default = class extends Controller {
|
|
28329
|
+
click(event) {
|
|
28330
|
+
if (event.target.closest("a, button, input, label, select, textarea, [data-row-click-ignore]")) {
|
|
28331
|
+
return;
|
|
28332
|
+
}
|
|
28333
|
+
this.element.querySelector('[data-row-click-target="show"]')?.click();
|
|
28334
|
+
}
|
|
28335
|
+
};
|
|
28336
|
+
|
|
28337
|
+
// src/js/controllers/view_switcher_controller.js
|
|
28338
|
+
var view_switcher_controller_default = class extends Controller {
|
|
28339
|
+
static values = { cookieName: String, cookiePath: { type: String, default: "/" } };
|
|
28340
|
+
select(event) {
|
|
28341
|
+
const view = event.params.view;
|
|
28342
|
+
if (!view || !this.cookieNameValue)
|
|
28343
|
+
return;
|
|
28344
|
+
const maxAge = 60 * 60 * 24 * 365;
|
|
28345
|
+
const path = this.cookiePathValue || "/";
|
|
28346
|
+
document.cookie = `${this.cookieNameValue}=${encodeURIComponent(view)}; Path=${path}; Max-Age=${maxAge}; SameSite=Lax`;
|
|
28347
|
+
const url = new URL(window.location.href);
|
|
28348
|
+
url.searchParams.delete("view");
|
|
28349
|
+
window.location.href = url.toString();
|
|
28350
|
+
}
|
|
28351
|
+
};
|
|
28352
|
+
|
|
28353
|
+
// src/js/controllers/autosubmit_controller.js
|
|
28354
|
+
var autosubmit_controller_default = class extends Controller {
|
|
28355
|
+
static values = { delay: { type: Number, default: 300 } };
|
|
28356
|
+
connect() {
|
|
28357
|
+
this._timer = null;
|
|
28358
|
+
}
|
|
28359
|
+
disconnect() {
|
|
28360
|
+
if (this._timer)
|
|
28361
|
+
clearTimeout(this._timer);
|
|
28362
|
+
}
|
|
28363
|
+
submit() {
|
|
28364
|
+
if (this._timer)
|
|
28365
|
+
clearTimeout(this._timer);
|
|
28366
|
+
this._timer = setTimeout(() => {
|
|
28367
|
+
this.element.closest("form")?.requestSubmit();
|
|
28368
|
+
}, this.delayValue);
|
|
28369
|
+
}
|
|
28370
|
+
};
|
|
28371
|
+
|
|
28036
28372
|
// src/js/controllers/register_controllers.js
|
|
28037
28373
|
function register_controllers_default(application2) {
|
|
28038
28374
|
application2.register("password-visibility", password_visibility_controller_default);
|
|
@@ -28060,6 +28396,14 @@ this.ifd0Offset: ${this.ifd0Offset}, file.byteLength: ${e4.byteLength}`), e4.tif
|
|
|
28060
28396
|
application2.register("filter-panel", filter_panel_controller_default);
|
|
28061
28397
|
application2.register("textarea-autogrow", textarea_autogrow_controller_default);
|
|
28062
28398
|
application2.register("clipboard", clipboard_controller_default);
|
|
28399
|
+
application2.register("icon-rail", icon_rail_controller_default);
|
|
28400
|
+
application2.register("icon-rail-flyout", icon_rail_flyout_controller_default);
|
|
28401
|
+
application2.register("table-header", table_header_controller_default);
|
|
28402
|
+
application2.register("table-column-menu", table_column_menu_controller_default);
|
|
28403
|
+
application2.register("capture-url", capture_url_controller_default);
|
|
28404
|
+
application2.register("row-click", row_click_controller_default);
|
|
28405
|
+
application2.register("view-switcher", view_switcher_controller_default);
|
|
28406
|
+
application2.register("autosubmit", autosubmit_controller_default);
|
|
28063
28407
|
}
|
|
28064
28408
|
|
|
28065
28409
|
// src/js/turbo/turbo_actions.js
|