easy-admin-rails 0.1.14 → 0.2.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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/easy_admin.base.js +254 -18
  3. data/app/assets/builds/easy_admin.base.js.map +4 -4
  4. data/app/assets/builds/easy_admin.css +112 -18
  5. data/app/components/easy_admin/base_component.rb +1 -0
  6. data/app/components/easy_admin/form_tabs_component.rb +5 -2
  7. data/app/components/easy_admin/navbar_component.rb +5 -1
  8. data/app/components/easy_admin/permissions/user_role_assignment_component.rb +254 -0
  9. data/app/components/easy_admin/permissions/user_role_permissions_component.rb +186 -0
  10. data/app/components/easy_admin/resources/index_component.rb +1 -4
  11. data/app/components/easy_admin/sidebar_component.rb +67 -2
  12. data/app/components/easy_admin/versions/diff_modal_component.rb +5 -1
  13. data/app/controllers/easy_admin/application_controller.rb +131 -1
  14. data/app/controllers/easy_admin/batch_actions_controller.rb +27 -0
  15. data/app/controllers/easy_admin/concerns/belongs_to_editing.rb +201 -0
  16. data/app/controllers/easy_admin/concerns/inline_field_editing.rb +297 -0
  17. data/app/controllers/easy_admin/concerns/resource_authorization.rb +55 -0
  18. data/app/controllers/easy_admin/concerns/resource_filtering.rb +178 -0
  19. data/app/controllers/easy_admin/concerns/resource_loading.rb +149 -0
  20. data/app/controllers/easy_admin/concerns/resource_pagination.rb +135 -0
  21. data/app/controllers/easy_admin/dashboard_controller.rb +2 -1
  22. data/app/controllers/easy_admin/dashboards_controller.rb +6 -40
  23. data/app/controllers/easy_admin/resources_controller.rb +13 -762
  24. data/app/controllers/easy_admin/row_actions_controller.rb +25 -0
  25. data/app/helpers/easy_admin/fields_helper.rb +61 -9
  26. data/app/javascript/easy_admin/controllers/event_emitter_controller.js +2 -4
  27. data/app/javascript/easy_admin/controllers/infinite_scroll_controller.js +0 -10
  28. data/app/javascript/easy_admin/controllers/jsoneditor_controller.js +1 -4
  29. data/app/javascript/easy_admin/controllers/permission_toggle_controller.js +227 -0
  30. data/app/javascript/easy_admin/controllers/role_preview_controller.js +93 -0
  31. data/app/javascript/easy_admin/controllers/select_field_controller.js +1 -2
  32. data/app/javascript/easy_admin/controllers/settings_button_controller.js +1 -2
  33. data/app/javascript/easy_admin/controllers/settings_sidebar_controller.js +1 -4
  34. data/app/javascript/easy_admin/controllers/turbo_stream_redirect.js +0 -2
  35. data/app/javascript/easy_admin/controllers.js +5 -1
  36. data/app/models/easy_admin/admin_user.rb +6 -0
  37. data/app/policies/admin_user_policy.rb +36 -0
  38. data/app/policies/application_policy.rb +83 -0
  39. data/app/views/easy_admin/application/authorization_failure.turbo_stream.erb +8 -0
  40. data/app/views/easy_admin/dashboards/card.html.erb +5 -0
  41. data/app/views/easy_admin/dashboards/card.turbo_stream.erb +7 -0
  42. data/app/views/easy_admin/dashboards/card_error.html.erb +3 -0
  43. data/app/views/easy_admin/dashboards/card_error.turbo_stream.erb +5 -0
  44. data/app/views/easy_admin/dashboards/show.turbo_stream.erb +7 -0
  45. data/app/views/easy_admin/resources/belongs_to_edit_attached.html.erb +6 -0
  46. data/app/views/easy_admin/resources/belongs_to_edit_attached.turbo_stream.erb +8 -0
  47. data/app/views/easy_admin/resources/belongs_to_reattach.html.erb +5 -0
  48. data/app/views/easy_admin/resources/edit.html.erb +1 -1
  49. data/app/views/easy_admin/resources/edit_field.html.erb +5 -0
  50. data/app/views/easy_admin/resources/edit_field.turbo_stream.erb +7 -0
  51. data/app/views/easy_admin/resources/index.html.erb +1 -1
  52. data/app/views/easy_admin/resources/index_frame.html.erb +8 -142
  53. data/app/views/easy_admin/resources/update_belongs_to_attached.turbo_stream.erb +25 -0
  54. data/app/views/layouts/easy_admin/application.html.erb +15 -2
  55. data/config/initializers/easy_admin_permissions.rb +73 -0
  56. data/db/seeds/easy_admin_permissions.rb +121 -0
  57. data/lib/easy-admin-rails.rb +2 -0
  58. data/lib/easy_admin/permissions/component.rb +168 -0
  59. data/lib/easy_admin/permissions/configuration.rb +37 -0
  60. data/lib/easy_admin/permissions/controller.rb +164 -0
  61. data/lib/easy_admin/permissions/dsl.rb +180 -0
  62. data/lib/easy_admin/permissions/models.rb +44 -0
  63. data/lib/easy_admin/permissions/permission_denied_component.rb +121 -0
  64. data/lib/easy_admin/permissions/resource_permissions.rb +231 -0
  65. data/lib/easy_admin/permissions/role_definition.rb +45 -0
  66. data/lib/easy_admin/permissions/role_denied_component.rb +159 -0
  67. data/lib/easy_admin/permissions/role_dsl.rb +73 -0
  68. data/lib/easy_admin/permissions/user_extensions.rb +129 -0
  69. data/lib/easy_admin/permissions.rb +113 -0
  70. data/lib/easy_admin/resource/base.rb +119 -0
  71. data/lib/easy_admin/resource/configuration.rb +148 -0
  72. data/lib/easy_admin/resource/dsl.rb +117 -0
  73. data/lib/easy_admin/resource/field_registry.rb +189 -0
  74. data/lib/easy_admin/resource/form_builder.rb +123 -0
  75. data/lib/easy_admin/resource/layout_builder.rb +249 -0
  76. data/lib/easy_admin/resource/scope_manager.rb +252 -0
  77. data/lib/easy_admin/resource/show_builder.rb +359 -0
  78. data/lib/easy_admin/resource.rb +8 -835
  79. data/lib/easy_admin/resource_modules.rb +11 -0
  80. data/lib/easy_admin/version.rb +1 -1
  81. data/lib/generators/easy_admin/permissions/install_generator.rb +90 -0
  82. data/lib/generators/easy_admin/permissions/templates/initializers/permissions.rb +37 -0
  83. data/lib/generators/easy_admin/permissions/templates/migrations/create_permission_tables.rb +27 -0
  84. data/lib/generators/easy_admin/permissions/templates/migrations/update_users_for_permissions.rb +6 -0
  85. data/lib/generators/easy_admin/permissions/templates/models/permission.rb +9 -0
  86. data/lib/generators/easy_admin/permissions/templates/models/role.rb +9 -0
  87. data/lib/generators/easy_admin/permissions/templates/models/role_permission.rb +9 -0
  88. data/lib/generators/easy_admin/permissions/templates/models/user_role.rb +9 -0
  89. data/lib/generators/easy_admin/permissions/templates/policies/application_policy.rb +47 -0
  90. data/lib/generators/easy_admin/permissions/templates/policies/user_policy.rb +36 -0
  91. data/lib/generators/easy_admin/permissions/templates/seeds/permissions.rb +89 -0
  92. metadata +62 -5
  93. data/db/migrate/20250101000001_create_easy_admin_admin_users.rb +0 -45
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cff58e24500b585a0346cd5da70625a6197c4445fff7c17200d35f9f71c32f95
4
- data.tar.gz: 48e3480d8a897c2fb5381304de2876b89a1cfa3f9426c2415aa35f7c64aca6e1
3
+ metadata.gz: e27a938d7c68cc803a52c941ab073b82d077d2019a09d1dab636e92016f2ae78
4
+ data.tar.gz: 94c16e1bd8b00dbcbddee3adad22dc0122eb50d118e6aa815f7d28dd437d0404
5
5
  SHA512:
6
- metadata.gz: 0cb57146ae144a8b4292a1ac4de928476e3df92997c230471edea4af021d67d4074900202402e45836e4f4e85540a72caf053c0b1230f113e09898131f60a0f5
7
- data.tar.gz: 96a1ca2a86f51334744e5b6e980f6c814d8b860e38a5b074505cb3c10eee11cf203320d9324b7619f6d5e8ca04400d7fbfab0097df463c75e966d541fba0dda4
6
+ metadata.gz: 3d55741831c57254342bb1ef6546ffb1913070219896775251059f4dffdfa50b72af935d8d2fd47f103698d986a6b7eb56c67f9e318a706ecdf5bb430f955ba8
7
+ data.tar.gz: 663d5266e79bcb4a6ba283924f5edefd0b7c7dea0a56a9112789e6010513da638ad15a747d82c0328832412f4f12acbc7f4f9d6ab7b20724abf967f161e3a407
@@ -23928,7 +23928,6 @@ ${m = t3 ? m : H(m, ",")}
23928
23928
  }
23929
23929
  filter(event) {
23930
23930
  const searchTerm = event.target.value;
23931
- console.log("Filter called with term:", searchTerm, "Suggest mode:", this.suggestValue);
23932
23931
  if (this.suggestValue) {
23933
23932
  this.debouncedSuggestSearch(searchTerm);
23934
23933
  } else {
@@ -39953,7 +39952,6 @@ ${m = t3 ? m : H(m, ",")}
39953
39952
  if (this.isLoading || !this.hasMoreValue) {
39954
39953
  return;
39955
39954
  }
39956
- console.log("Loading next page:", this.urlValue);
39957
39955
  this.isLoading = true;
39958
39956
  this.showLoading();
39959
39957
  try {
@@ -39962,10 +39960,6 @@ ${m = t3 ? m : H(m, ",")}
39962
39960
  });
39963
39961
  if (response.ok) {
39964
39962
  this.dispatch("loaded", { detail: { url: this.urlValue } });
39965
- console.log("Loaded successfully, new state will be:", {
39966
- currentUrl: this.urlValue,
39967
- hasMore: this.hasMoreValue
39968
- });
39969
39963
  } else {
39970
39964
  this.dispatch("error", { detail: { response } });
39971
39965
  }
@@ -39998,11 +39992,6 @@ ${m = t3 ? m : H(m, ",")}
39998
39992
  }
39999
39993
  // Debug method to log current state
40000
39994
  logState() {
40001
- console.log("InfiniteScroll State:", {
40002
- urlValue: this.urlValue,
40003
- hasMoreValue: this.hasMoreValue,
40004
- isLoading: this.isLoading
40005
- });
40006
39995
  }
40007
39996
  showEndMessage() {
40008
39997
  if (this.hasEndTarget) {
@@ -40121,14 +40110,11 @@ ${m = t3 ? m : H(m, ",")}
40121
40110
  var settings_sidebar_controller_default = class extends Controller {
40122
40111
  static targets = ["container"];
40123
40112
  connect() {
40124
- console.log("Settings sidebar controller connected");
40125
- console.log("Container target:", this.containerTarget);
40126
40113
  this.isOpen = false;
40127
40114
  document.addEventListener("settings:open", this.open.bind(this));
40128
40115
  document.addEventListener("settings:close", this.close.bind(this));
40129
40116
  }
40130
40117
  open() {
40131
- console.log("Settings sidebar open() called");
40132
40118
  this.isOpen = true;
40133
40119
  this.containerTarget.classList.remove("translate-x-full");
40134
40120
  this.containerTarget.classList.add("translate-x-0");
@@ -40257,7 +40243,6 @@ ${m = t3 ? m : H(m, ",")}
40257
40243
  emit() {
40258
40244
  const eventName = this.eventValue;
40259
40245
  const eventDetail = this.hasDetailValue ? this.detailValue : {};
40260
- console.log(`Event emitter dispatching: ${eventName}`, eventDetail);
40261
40246
  const customEvent = new CustomEvent(eventName, {
40262
40247
  detail: eventDetail,
40263
40248
  bubbles: true
@@ -40933,14 +40918,11 @@ ${m = t3 ? m : H(m, ",")}
40933
40918
  const jsonData = this.editor.get();
40934
40919
  const jsonString = JSON.stringify(jsonData);
40935
40920
  this.hiddenFieldTarget.value = jsonString;
40936
- console.log("JSON Editor: Updated hidden field with:", jsonString);
40937
40921
  } catch (error2) {
40938
- console.warn("JSON Editor: Invalid JSON, not updating hidden field:", error2);
40939
40922
  try {
40940
40923
  if (this.editor.mode === "code") {
40941
40924
  const text = this.editor.getText();
40942
40925
  this.hiddenFieldTarget.value = text;
40943
- console.log("JSON Editor: Updated hidden field with raw text:", text);
40944
40926
  }
40945
40927
  } catch (textError) {
40946
40928
  console.warn("JSON Editor: Could not get text content:", textError);
@@ -41054,6 +41036,258 @@ ${m = t3 ? m : H(m, ",")}
41054
41036
  }
41055
41037
  };
41056
41038
 
41039
+ // app/javascript/easy_admin/controllers/role_preview_controller.js
41040
+ var role_preview_controller_default = class extends Controller {
41041
+ static targets = ["preview"];
41042
+ static values = {
41043
+ roles: Array
41044
+ };
41045
+ updatePreview(event) {
41046
+ const selectedRoleId = parseInt(event.target.value);
41047
+ const selectedRole = this.rolesValue.find((role) => role.id === selectedRoleId);
41048
+ if (selectedRole && this.hasPreviewTarget) {
41049
+ this.renderRolePreview(selectedRole);
41050
+ } else if (this.hasPreviewTarget) {
41051
+ this.clearPreview();
41052
+ }
41053
+ }
41054
+ renderRolePreview(role) {
41055
+ const previewHTML = this.buildPreviewHTML(role);
41056
+ this.previewTarget.innerHTML = previewHTML;
41057
+ this.previewTarget.style.display = "block";
41058
+ }
41059
+ clearPreview() {
41060
+ this.previewTarget.innerHTML = "";
41061
+ this.previewTarget.style.display = "none";
41062
+ }
41063
+ buildPreviewHTML(role) {
41064
+ const permissionsCount = Object.values(role.permissions || {}).flat().length;
41065
+ let html = `
41066
+ <div class="mb-4">
41067
+ <h3 class="text-lg font-medium text-gray-900 mb-2">Role Permissions Preview</h3>
41068
+ <p class="text-sm text-gray-600">
41069
+ Permissions that will be granted with the <strong>${role.name}</strong> role:
41070
+ </p>
41071
+ </div>
41072
+ `;
41073
+ if (permissionsCount === 0) {
41074
+ html += `
41075
+ <div class="text-center py-6">
41076
+ <svg class="w-8 h-8 text-gray-400 mx-auto mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
41077
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
41078
+ </svg>
41079
+ <h4 class="text-md font-medium text-gray-900 mb-1">No Permissions</h4>
41080
+ <p class="text-gray-600">This role has no permissions assigned.</p>
41081
+ </div>
41082
+ `;
41083
+ } else {
41084
+ html += '<div class="space-y-4">';
41085
+ Object.entries(role.permissions || {}).forEach(([resourceType, permissions]) => {
41086
+ html += `
41087
+ <div class="bg-white border border-gray-200 rounded-lg p-4">
41088
+ <div class="flex items-center mb-3">
41089
+ <h4 class="text-md font-medium text-gray-900 capitalize">${resourceType.replace(/_/g, " ")}</h4>
41090
+ <span class="ml-2 inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
41091
+ ${permissions.length} permissions
41092
+ </span>
41093
+ </div>
41094
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-2">
41095
+ `;
41096
+ permissions.forEach((permission) => {
41097
+ html += `
41098
+ <div class="flex items-center p-2 bg-green-50 border border-green-200 rounded">
41099
+ <svg class="w-4 h-4 text-green-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
41100
+ <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
41101
+ </svg>
41102
+ <div class="flex-1 min-w-0">
41103
+ <span class="text-sm font-medium text-gray-900 capitalize">${permission.action.replace(/_/g, " ")}</span>
41104
+ ${permission.description ? `<p class="text-xs text-gray-600 mt-1">${permission.description}</p>` : ""}
41105
+ </div>
41106
+ </div>
41107
+ `;
41108
+ });
41109
+ html += `
41110
+ </div>
41111
+ </div>
41112
+ `;
41113
+ });
41114
+ html += "</div>";
41115
+ }
41116
+ return html;
41117
+ }
41118
+ };
41119
+
41120
+ // app/javascript/easy_admin/controllers/permission_toggle_controller.js
41121
+ var permission_toggle_controller_default = class extends Controller {
41122
+ static targets = ["permissionCard", "hiddenInput"];
41123
+ static values = {
41124
+ userId: Number
41125
+ };
41126
+ connect() {
41127
+ console.log("\u{1F3AF} PermissionToggleController connected");
41128
+ console.log("\u{1F3AF} User ID:", this.userIdValue);
41129
+ const cards = this.permissionCardTargets;
41130
+ console.log("\u{1F3AF} Found", cards.length, "permission cards");
41131
+ cards.forEach((card, index2) => {
41132
+ console.log(`\u{1F3AF} Card ${index2}:`, {
41133
+ permission: card.dataset.permissionName,
41134
+ granted: card.dataset.granted,
41135
+ resourceType: card.dataset.resourceType
41136
+ });
41137
+ });
41138
+ const hiddenInputs = this.element.querySelectorAll('input[type="hidden"][data-permission-toggle-target="hiddenInput"]');
41139
+ console.log("\u{1F3AF} Found", hiddenInputs.length, "hidden inputs");
41140
+ hiddenInputs.forEach((input, index2) => {
41141
+ console.log(`\u{1F3AF} Hidden input ${index2}:`, {
41142
+ name: input.name,
41143
+ value: input.value
41144
+ });
41145
+ });
41146
+ }
41147
+ togglePermission(event) {
41148
+ event.preventDefault();
41149
+ const card = event.currentTarget;
41150
+ const permissionName = card.dataset.permissionName;
41151
+ const currentlyGranted = card.dataset.granted === "true";
41152
+ const newGrantedState = !currentlyGranted;
41153
+ console.log("\u{1F3AF} Toggling permission:", {
41154
+ permission: permissionName,
41155
+ wasGranted: currentlyGranted,
41156
+ nowGranted: newGrantedState
41157
+ });
41158
+ this.updateCardUI(card, newGrantedState);
41159
+ this.updateHiddenInput(card, newGrantedState);
41160
+ this.showNotification(
41161
+ `Permission ${newGrantedState ? "granted" : "revoked"}`,
41162
+ newGrantedState ? "success" : "warning"
41163
+ );
41164
+ }
41165
+ toggleAllForResource(event) {
41166
+ event.preventDefault();
41167
+ const resourceType = event.currentTarget.dataset.resourceType;
41168
+ const resourceCards = this.permissionCardTargets.filter(
41169
+ (card) => card.dataset.resourceType === resourceType
41170
+ );
41171
+ const hasAnyDenied = resourceCards.some((card) => card.dataset.granted === "false");
41172
+ const newState = hasAnyDenied;
41173
+ resourceCards.forEach((card) => {
41174
+ if (card.dataset.granted === "true" !== newState) {
41175
+ const permissionId = card.dataset.permissionId;
41176
+ const permissionName = card.dataset.permissionName;
41177
+ this.updateCardUI(card, newState);
41178
+ this.updateHiddenInput(card, newState);
41179
+ }
41180
+ });
41181
+ this.showNotification(
41182
+ `${newState ? "Granted" : "Revoked"} all ${resourceType.replace(/_/g, " ")} permissions (UI only)`,
41183
+ newState ? "success" : "warning"
41184
+ );
41185
+ }
41186
+ updateCardUI(card, isGranted) {
41187
+ card.dataset.granted = isGranted.toString();
41188
+ card.className = `permission-card cursor-pointer transition-all duration-200 ${this.getCardClasses(isGranted)}`;
41189
+ const iconContainer = card.querySelector(".flex-shrink-0");
41190
+ if (iconContainer) {
41191
+ iconContainer.innerHTML = this.getPermissionIconSVG(isGranted);
41192
+ }
41193
+ const actionSpan = card.querySelector(".text-sm.font-medium");
41194
+ if (actionSpan) {
41195
+ actionSpan.className = `text-sm font-medium ${isGranted ? "text-green-900" : "text-gray-900"} capitalize`;
41196
+ }
41197
+ const badge = card.querySelector(".px-2.py-1.rounded.text-xs.font-medium");
41198
+ if (badge) {
41199
+ badge.className = `ml-2 inline-flex items-center px-2 py-1 rounded text-xs font-medium ${this.getPermissionBadgeClasses(isGranted)}`;
41200
+ }
41201
+ const description = card.querySelector(".leading-relaxed");
41202
+ if (description) {
41203
+ description.className = `text-xs ${isGranted ? "text-green-700" : "text-gray-600"} leading-relaxed`;
41204
+ }
41205
+ const technicalName = card.querySelector(".font-mono");
41206
+ if (technicalName) {
41207
+ technicalName.className = `text-xs ${isGranted ? "text-green-600" : "text-gray-500"} font-mono mt-1`;
41208
+ }
41209
+ const statusIndicator = card.querySelector(".rounded-full");
41210
+ if (statusIndicator) {
41211
+ statusIndicator.textContent = isGranted ? "Granted" : "Denied";
41212
+ statusIndicator.className = `inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${this.getStatusClasses(isGranted)}`;
41213
+ }
41214
+ }
41215
+ // TODO: Implement backend integration
41216
+ // async sendToggleRequest(permissionId, permissionName, isGranted) {
41217
+ // const response = await fetch('/admin/permissions/toggle', {
41218
+ // method: 'POST',
41219
+ // headers: {
41220
+ // 'Content-Type': 'application/json',
41221
+ // 'X-CSRF-Token': this.getCSRFToken(),
41222
+ // 'Accept': 'application/json'
41223
+ // },
41224
+ // body: JSON.stringify({
41225
+ // user_id: this.userIdValue,
41226
+ // permission_id: permissionId,
41227
+ // permission_name: permissionName,
41228
+ // granted: isGranted
41229
+ // })
41230
+ // })
41231
+ // if (!response.ok) {
41232
+ // throw new Error(`HTTP error! status: ${response.status}`)
41233
+ // }
41234
+ // return await response.json()
41235
+ // }
41236
+ updateHiddenInput(card, isGranted) {
41237
+ const hiddenInput = card.querySelector('input[type="hidden"][data-permission-toggle-target="hiddenInput"]');
41238
+ if (hiddenInput) {
41239
+ const oldValue = hiddenInput.value;
41240
+ hiddenInput.value = isGranted.toString();
41241
+ console.log("\u{1F3AF} Updated hidden input:", {
41242
+ name: hiddenInput.name,
41243
+ oldValue,
41244
+ newValue: hiddenInput.value
41245
+ });
41246
+ } else {
41247
+ console.warn(`\u{1F3AF} No hidden input found for permission card: ${card.dataset.permissionName}`);
41248
+ }
41249
+ }
41250
+ getCSRFToken() {
41251
+ const metaTag = document.querySelector('meta[name="csrf-token"]');
41252
+ return metaTag ? metaTag.getAttribute("content") : "";
41253
+ }
41254
+ showNotification(message, type = "info") {
41255
+ const event = new CustomEvent("notification:show", {
41256
+ detail: { message, type }
41257
+ });
41258
+ window.dispatchEvent(event);
41259
+ }
41260
+ // Helper methods for CSS classes (matching the Ruby component)
41261
+ getCardClasses(isGranted) {
41262
+ if (isGranted) {
41263
+ return "bg-green-50 border border-green-200 hover:border-green-300 hover:bg-green-100";
41264
+ } else {
41265
+ return "bg-red-50 border border-red-200 hover:border-red-300 hover:bg-red-100";
41266
+ }
41267
+ }
41268
+ getPermissionBadgeClasses(isGranted) {
41269
+ if (isGranted) {
41270
+ return "bg-green-100 text-green-800";
41271
+ } else {
41272
+ return "bg-red-100 text-red-800";
41273
+ }
41274
+ }
41275
+ getStatusClasses(isGranted) {
41276
+ if (isGranted) {
41277
+ return "bg-green-100 text-green-800";
41278
+ } else {
41279
+ return "bg-red-100 text-red-800";
41280
+ }
41281
+ }
41282
+ getPermissionIconSVG(isGranted) {
41283
+ if (isGranted) {
41284
+ return '<svg class="w-5 h-5 text-green-500 mt-0.5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>';
41285
+ } else {
41286
+ return '<svg class="w-5 h-5 text-red-500 mt-0.5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>';
41287
+ }
41288
+ }
41289
+ };
41290
+
41057
41291
  // app/javascript/easy_admin/controllers.js
41058
41292
  application.register("sidebar", sidebar_controller_default);
41059
41293
  application.register("sidebar-nav", sidebar_nav_controller_default);
@@ -41081,6 +41315,8 @@ ${m = t3 ? m : H(m, ",")}
41081
41315
  application.register("row-action", row_action_controller_default);
41082
41316
  application.register("jsoneditor", jsoneditor_controller_default);
41083
41317
  application.register("version-revert", version_revert_controller_default);
41318
+ application.register("role-preview", role_preview_controller_default);
41319
+ application.register("permission-toggle", permission_toggle_controller_default);
41084
41320
 
41085
41321
  // node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
41086
41322
  var turbo_es2017_esm_exports = {};