@robertraaijmakers/pptb-securityplugin 0.1.4 → 0.1.6-beta.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.
package/dist/app.js CHANGED
@@ -14758,13 +14758,39 @@ ${logTarget.textContent}`;
14758
14758
  "delete",
14759
14759
  "append",
14760
14760
  "appendto",
14761
- "assign"
14761
+ "assign",
14762
+ "share"
14762
14763
  ];
14764
+ var privilegeLabels = {
14765
+ create: "Create",
14766
+ read: "Read",
14767
+ write: "Write",
14768
+ delete: "Delete",
14769
+ append: "Append",
14770
+ appendto: "Append To",
14771
+ assign: "Assign",
14772
+ share: "Share"
14773
+ };
14763
14774
  var levelOptions = [
14764
14775
  { level: "user", icon: "\u{1F464}", label: "User", className: "level-user" },
14765
- { level: "businessUnit", icon: "\u{1F3E2}", label: "Business Unit", className: "level-businessUnit" },
14766
- { level: "parentChild", icon: "\u{1F9E9}", label: "Parent: Child BU", className: "level-parentChild" },
14767
- { level: "organization", icon: "\u{1F310}", label: "Organization", className: "level-organization" },
14776
+ {
14777
+ level: "businessUnit",
14778
+ icon: "\u{1F3E2}",
14779
+ label: "Business Unit",
14780
+ className: "level-businessUnit"
14781
+ },
14782
+ {
14783
+ level: "parentChild",
14784
+ icon: "\u{1F9E9}",
14785
+ label: "Parent: Child BU",
14786
+ className: "level-parentChild"
14787
+ },
14788
+ {
14789
+ level: "organization",
14790
+ icon: "\u{1F310}",
14791
+ label: "Organization",
14792
+ className: "level-organization"
14793
+ },
14768
14794
  { level: "none", icon: "\u26D4", label: "None", className: "level-none" }
14769
14795
  ];
14770
14796
  var levelColorMap = {
@@ -14789,6 +14815,10 @@ ${logTarget.textContent}`;
14789
14815
  loadingDashboardRoleTeamCounts: "Loading teams per role",
14790
14816
  loadingDashboardFilters: "Preparing dashboard filters",
14791
14817
  tableTitlePrivileges: "Privileges",
14818
+ bulkUpdateSelect: "Set visible...",
14819
+ bulkUpdateApply: "Set",
14820
+ bulkUpdateNoRights: "No visible rights in this column",
14821
+ bulkUpdateNoSelection: "Select a level first",
14792
14822
  roleFilterAll: "All roles",
14793
14823
  statusAssigned: "Assigned",
14794
14824
  statusNotAssigned: "Not assigned",
@@ -14889,6 +14919,15 @@ ${logTarget.textContent}`;
14889
14919
  function formatCachedPrivileges(privilegeCount, rolePrivilegeCount, roleCount) {
14890
14920
  return `Cached ${privilegeCount} privileges and ${rolePrivilegeCount} role privilege rows for ${roleCount} roles.`;
14891
14921
  }
14922
+ function formatBulkUpdatedVisible(privilegeLabel, levelLabel, updatedCount, skippedCount) {
14923
+ if (skippedCount > 0) {
14924
+ return `Bulk set ${privilegeLabel} to ${levelLabel} for ${updatedCount} visible rows (${skippedCount} skipped).`;
14925
+ }
14926
+ return `Bulk set ${privilegeLabel} to ${levelLabel} for ${updatedCount} visible rows.`;
14927
+ }
14928
+ function formatBulkUpdateNoRows(privilegeLabel) {
14929
+ return `No visible rows with editable ${privilegeLabel} rights.`;
14930
+ }
14892
14931
  function formatRoleAssignmentLogUsers(action, roleName, userNames) {
14893
14932
  const verb = action === "add" ? "Added" : "Removed";
14894
14933
  const prep = action === "add" ? "to" : "from";
@@ -14990,7 +15029,8 @@ ${logTarget.textContent}`;
14990
15029
  delete: "",
14991
15030
  append: "",
14992
15031
  appendto: "",
14993
- assign: ""
15032
+ assign: "",
15033
+ share: ""
14994
15034
  },
14995
15035
  eventsHooked: false,
14996
15036
  readyToastShown: false,
@@ -15002,56 +15042,130 @@ ${logTarget.textContent}`;
15002
15042
  }
15003
15043
  };
15004
15044
  var elements2 = {
15005
- connectionBadge: document.getElementById("connection-badge"),
15045
+ connectionBadge: document.getElementById(
15046
+ "connection-badge"
15047
+ ),
15006
15048
  filterMode: document.getElementById("filter-mode"),
15007
15049
  roleSelect: document.getElementById("role-select"),
15008
15050
  entitySelect: document.getElementById("entity-select"),
15009
- roleSelectControl: document.getElementById("role-select-control"),
15010
- entitySelectControl: document.getElementById("entity-select-control"),
15051
+ roleSelectControl: document.getElementById(
15052
+ "role-select-control"
15053
+ ),
15054
+ entitySelectControl: document.getElementById(
15055
+ "entity-select-control"
15056
+ ),
15011
15057
  rightsFilter: document.getElementById("rights-filter"),
15012
- roleFilterControl: document.getElementById("role-filter-control"),
15013
- roleFilterButton: document.getElementById("role-filter-button"),
15058
+ roleFilterControl: document.getElementById(
15059
+ "role-filter-control"
15060
+ ),
15061
+ roleFilterButton: document.getElementById(
15062
+ "role-filter-button"
15063
+ ),
15014
15064
  roleFilterMenu: document.getElementById("role-filter-menu"),
15015
15065
  roleFilterList: document.getElementById("role-filter-list"),
15016
- roleFilterAll: document.getElementById("role-filter-all"),
15017
- roleFilterNone: document.getElementById("role-filter-none"),
15018
- rolesCustomOnlyGlobal: document.getElementById("roles-custom-only-global"),
15019
- tabButtons: Array.from(document.querySelectorAll(".tab-button")),
15066
+ roleFilterAll: document.getElementById(
15067
+ "role-filter-all"
15068
+ ),
15069
+ roleFilterNone: document.getElementById(
15070
+ "role-filter-none"
15071
+ ),
15072
+ rolesCustomOnlyGlobal: document.getElementById(
15073
+ "roles-custom-only-global"
15074
+ ),
15075
+ tabButtons: Array.from(
15076
+ document.querySelectorAll(".tab-button")
15077
+ ),
15020
15078
  tabPrivileges: document.getElementById("tab-privileges"),
15021
15079
  tabAssignments: document.getElementById("tab-assignments"),
15022
15080
  tabDashboard: document.getElementById("tab-dashboard"),
15023
- assignmentMode: document.getElementById("assignment-mode"),
15024
- assignmentRoleSelect: document.getElementById("assignment-role-select"),
15025
- assignmentUserSelect: document.getElementById("assignment-user-select"),
15026
- assignmentTeamSelect: document.getElementById("assignment-team-select"),
15027
- assignmentRoleControl: document.getElementById("assignment-role-control"),
15028
- assignmentUserControl: document.getElementById("assignment-user-control"),
15029
- assignmentTeamControl: document.getElementById("assignment-team-control"),
15030
- assignmentTitle: document.getElementById("assignment-title"),
15081
+ assignmentMode: document.getElementById(
15082
+ "assignment-mode"
15083
+ ),
15084
+ assignmentRoleSelect: document.getElementById(
15085
+ "assignment-role-select"
15086
+ ),
15087
+ assignmentUserSelect: document.getElementById(
15088
+ "assignment-user-select"
15089
+ ),
15090
+ assignmentTeamSelect: document.getElementById(
15091
+ "assignment-team-select"
15092
+ ),
15093
+ assignmentRoleControl: document.getElementById(
15094
+ "assignment-role-control"
15095
+ ),
15096
+ assignmentUserControl: document.getElementById(
15097
+ "assignment-user-control"
15098
+ ),
15099
+ assignmentTeamControl: document.getElementById(
15100
+ "assignment-team-control"
15101
+ ),
15102
+ assignmentTitle: document.getElementById(
15103
+ "assignment-title"
15104
+ ),
15031
15105
  assignmentAdd: document.getElementById("assignment-add"),
15032
- assignmentRemove: document.getElementById("assignment-remove"),
15033
- assignmentCount: document.getElementById("assignment-count"),
15034
- assignmentSelectAll: document.getElementById("assignment-select-all"),
15035
- assignmentClear: document.getElementById("assignment-clear"),
15036
- assignmentStatus: document.getElementById("assignment-status"),
15037
- assignmentTableBody: document.getElementById("assignment-table-body"),
15106
+ assignmentRemove: document.getElementById(
15107
+ "assignment-remove"
15108
+ ),
15109
+ assignmentCount: document.getElementById(
15110
+ "assignment-count"
15111
+ ),
15112
+ assignmentSelectAll: document.getElementById(
15113
+ "assignment-select-all"
15114
+ ),
15115
+ assignmentClear: document.getElementById(
15116
+ "assignment-clear"
15117
+ ),
15118
+ assignmentStatus: document.getElementById(
15119
+ "assignment-status"
15120
+ ),
15121
+ assignmentTableBody: document.getElementById(
15122
+ "assignment-table-body"
15123
+ ),
15038
15124
  assignmentSortButtons: Array.from(
15039
15125
  document.querySelectorAll("[data-assign-sort]")
15040
15126
  ),
15041
- assignmentFilterAssigned: document.getElementById("assignment-filter-assigned"),
15042
- assignmentSearch: document.getElementById("assignment-search"),
15043
- controlsPrivileges: document.getElementById("controls-privileges"),
15044
- controlsAssignments: document.getElementById("controls-assignments"),
15045
- controlsDashboard: document.getElementById("controls-dashboard"),
15046
- dashboardUserStatus: document.getElementById("dashboard-user-status"),
15047
- dashboardUserType: document.getElementById("dashboard-user-type"),
15048
- dashboardBusinessUnitSelect: document.getElementById("dashboard-bu-select"),
15049
- dashboardRoleSelect: document.getElementById("dashboard-role-select"),
15050
- dashboardTeamSelect: document.getElementById("dashboard-team-select"),
15051
- dashboardExport: document.getElementById("dashboard-export"),
15052
- dashboardLoading: document.getElementById("dashboard-loading"),
15053
- dashboardLoadingBar: document.getElementById("dashboard-loading-bar"),
15054
- dashboardLoadingText: document.getElementById("dashboard-loading-text"),
15127
+ assignmentFilterAssigned: document.getElementById(
15128
+ "assignment-filter-assigned"
15129
+ ),
15130
+ assignmentSearch: document.getElementById(
15131
+ "assignment-search"
15132
+ ),
15133
+ controlsPrivileges: document.getElementById(
15134
+ "controls-privileges"
15135
+ ),
15136
+ controlsAssignments: document.getElementById(
15137
+ "controls-assignments"
15138
+ ),
15139
+ controlsDashboard: document.getElementById(
15140
+ "controls-dashboard"
15141
+ ),
15142
+ dashboardUserStatus: document.getElementById(
15143
+ "dashboard-user-status"
15144
+ ),
15145
+ dashboardUserType: document.getElementById(
15146
+ "dashboard-user-type"
15147
+ ),
15148
+ dashboardBusinessUnitSelect: document.getElementById(
15149
+ "dashboard-bu-select"
15150
+ ),
15151
+ dashboardRoleSelect: document.getElementById(
15152
+ "dashboard-role-select"
15153
+ ),
15154
+ dashboardTeamSelect: document.getElementById(
15155
+ "dashboard-team-select"
15156
+ ),
15157
+ dashboardExport: document.getElementById(
15158
+ "dashboard-export"
15159
+ ),
15160
+ dashboardLoading: document.getElementById(
15161
+ "dashboard-loading"
15162
+ ),
15163
+ dashboardLoadingBar: document.getElementById(
15164
+ "dashboard-loading-bar"
15165
+ ),
15166
+ dashboardLoadingText: document.getElementById(
15167
+ "dashboard-loading-text"
15168
+ ),
15055
15169
  dashboardChartCards: Array.from(
15056
15170
  document.querySelectorAll("[data-dashboard-chart]")
15057
15171
  ),
@@ -15059,38 +15173,84 @@ ${logTarget.textContent}`;
15059
15173
  document.querySelectorAll(".chart-expand")
15060
15174
  ),
15061
15175
  chartModal: document.getElementById("chart-modal"),
15062
- chartModalTitle: document.getElementById("chart-modal-title"),
15063
- chartModalCanvas: document.getElementById("chart-modal-canvas"),
15064
- chartModalClose: document.getElementById("chart-modal-close"),
15065
- chartModalBackdrop: document.querySelector("[data-modal-close='true']"),
15176
+ chartModalTitle: document.getElementById(
15177
+ "chart-modal-title"
15178
+ ),
15179
+ chartModalCanvas: document.getElementById(
15180
+ "chart-modal-canvas"
15181
+ ),
15182
+ chartModalClose: document.getElementById(
15183
+ "chart-modal-close"
15184
+ ),
15185
+ chartModalBackdrop: document.querySelector(
15186
+ "[data-modal-close='true']"
15187
+ ),
15066
15188
  chartModalBody: document.querySelector(".modal-body"),
15067
- metricHumanActive: document.getElementById("metric-human-active"),
15068
- metricHumanInactive: document.getElementById("metric-human-inactive"),
15069
- metricAppActive: document.getElementById("metric-app-active"),
15070
- metricAppInactive: document.getElementById("metric-app-inactive"),
15071
- metricCustomRoles: document.getElementById("metric-custom-roles"),
15072
- metricManagedRoles: document.getElementById("metric-managed-roles"),
15073
- metricRolesWithoutUsers: document.getElementById("metric-roles-without-users"),
15074
- metricTotalTeams: document.getElementById("metric-total-teams"),
15075
- chartUsersByRole: document.getElementById("chart-users-by-role"),
15076
- chartTeamsByRole: document.getElementById("chart-teams-by-role"),
15077
- chartUsersByBusinessUnit: document.getElementById("chart-users-by-bu"),
15078
- chartUsersByTeam: document.getElementById("chart-users-by-team"),
15189
+ metricHumanActive: document.getElementById(
15190
+ "metric-human-active"
15191
+ ),
15192
+ metricHumanInactive: document.getElementById(
15193
+ "metric-human-inactive"
15194
+ ),
15195
+ metricAppActive: document.getElementById(
15196
+ "metric-app-active"
15197
+ ),
15198
+ metricAppInactive: document.getElementById(
15199
+ "metric-app-inactive"
15200
+ ),
15201
+ metricCustomRoles: document.getElementById(
15202
+ "metric-custom-roles"
15203
+ ),
15204
+ metricManagedRoles: document.getElementById(
15205
+ "metric-managed-roles"
15206
+ ),
15207
+ metricRolesWithoutUsers: document.getElementById(
15208
+ "metric-roles-without-users"
15209
+ ),
15210
+ metricTotalTeams: document.getElementById(
15211
+ "metric-total-teams"
15212
+ ),
15213
+ chartUsersByRole: document.getElementById(
15214
+ "chart-users-by-role"
15215
+ ),
15216
+ chartTeamsByRole: document.getElementById(
15217
+ "chart-teams-by-role"
15218
+ ),
15219
+ chartUsersByBusinessUnit: document.getElementById(
15220
+ "chart-users-by-bu"
15221
+ ),
15222
+ chartUsersByTeam: document.getElementById(
15223
+ "chart-users-by-team"
15224
+ ),
15079
15225
  applyBtn: document.getElementById("apply-btn"),
15080
15226
  undoBtn: document.getElementById("undo-btn"),
15081
15227
  refreshBtn: document.getElementById("refresh-btn"),
15082
15228
  pendingCount: document.getElementById("pending-count"),
15083
15229
  tableTitle: document.getElementById("table-title"),
15084
- privilegesTable: document.querySelector("#privileges-table tbody"),
15085
- privilegesTableRoot: document.getElementById("privileges-table"),
15230
+ privilegesTable: document.querySelector(
15231
+ "#privileges-table tbody"
15232
+ ),
15233
+ privilegesTableRoot: document.getElementById(
15234
+ "privileges-table"
15235
+ ),
15086
15236
  tableLoading: document.getElementById("table-loading"),
15087
15237
  tableEmpty: document.getElementById("table-empty"),
15088
15238
  loadingBar: document.getElementById("loading-bar"),
15089
15239
  loadingText: document.getElementById("loading-text"),
15090
15240
  log: document.getElementById("log"),
15091
15241
  themeToggle: document.getElementById("theme-toggle"),
15092
- sortButtons: Array.from(document.querySelectorAll(".sort-button")),
15093
- filterSelects: Array.from(document.querySelectorAll(".filter-select"))
15242
+ sortButtons: Array.from(
15243
+ document.querySelectorAll(".sort-button")
15244
+ ),
15245
+ bulkSelects: Array.from(
15246
+ document.querySelectorAll("[data-bulk-select]")
15247
+ ),
15248
+ bulkApplyButtons: Array.from(
15249
+ document.querySelectorAll("[data-bulk-apply]")
15250
+ ),
15251
+ filterSelects: Array.from(
15252
+ document.querySelectorAll(".filter-select")
15253
+ )
15094
15254
  };
15095
15255
  initLogger(elements2.log);
15096
15256
  function setTableTitle(text) {
@@ -15400,10 +15560,16 @@ ${logTarget.textContent}`;
15400
15560
  elements2.tabDashboard.classList.toggle("hidden", tab !== "dashboard");
15401
15561
  }
15402
15562
  if (elements2.controlsPrivileges) {
15403
- elements2.controlsPrivileges.classList.toggle("hidden", tab !== "privileges");
15563
+ elements2.controlsPrivileges.classList.toggle(
15564
+ "hidden",
15565
+ tab !== "privileges"
15566
+ );
15404
15567
  }
15405
15568
  if (elements2.controlsAssignments) {
15406
- elements2.controlsAssignments.classList.toggle("hidden", tab !== "assignments");
15569
+ elements2.controlsAssignments.classList.toggle(
15570
+ "hidden",
15571
+ tab !== "assignments"
15572
+ );
15407
15573
  }
15408
15574
  if (elements2.controlsDashboard) {
15409
15575
  elements2.controlsDashboard.classList.toggle("hidden", tab !== "dashboard");
@@ -15475,7 +15641,9 @@ ${logTarget.textContent}`;
15475
15641
  });
15476
15642
  return [...filtered].sort((a, b) => {
15477
15643
  if (state.assignmentSort.column === "label") {
15478
- const cmp = a.label.localeCompare(b.label, void 0, { sensitivity: "base" });
15644
+ const cmp = a.label.localeCompare(b.label, void 0, {
15645
+ sensitivity: "base"
15646
+ });
15479
15647
  return state.assignmentSort.direction === "asc" ? cmp : -cmp;
15480
15648
  }
15481
15649
  const aRank = a.assigned ? 1 : 2;
@@ -15620,12 +15788,146 @@ ${logTarget.textContent}`;
15620
15788
  for (const button of elements2.sortButtons) {
15621
15789
  button.classList.remove("sort-asc", "sort-desc");
15622
15790
  if (button.dataset.sort === state.sort.column) {
15623
- button.classList.add(state.sort.direction === "asc" ? "sort-asc" : "sort-desc");
15791
+ button.classList.add(
15792
+ state.sort.direction === "asc" ? "sort-asc" : "sort-desc"
15793
+ );
15624
15794
  }
15625
15795
  }
15626
15796
  }
15627
15797
  function isPrivilegeAvailable(row, privilege) {
15628
- return Boolean(state.privilegeIdByKey.get(`${row.entityLogicalName}:${privilege}`));
15798
+ return Boolean(
15799
+ state.privilegeIdByKey.get(`${row.entityLogicalName}:${privilege}`)
15800
+ );
15801
+ }
15802
+ function getAllowedLevelsForPrivilege(row, privilege) {
15803
+ const privilegeId = state.privilegeIdByKey.get(
15804
+ `${row.entityLogicalName}:${privilege}`
15805
+ );
15806
+ if (!privilegeId) {
15807
+ return [];
15808
+ }
15809
+ const info = state.privilegeInfoById.get(privilegeId);
15810
+ const allowedLevels = ["none"];
15811
+ if (info?.canBeBasic) {
15812
+ allowedLevels.push("user");
15813
+ }
15814
+ if (info?.canBeLocal) {
15815
+ allowedLevels.push("businessUnit");
15816
+ }
15817
+ if (info?.canBeDeep) {
15818
+ allowedLevels.push("parentChild");
15819
+ }
15820
+ if (info?.canBeGlobal) {
15821
+ allowedLevels.push("organization");
15822
+ }
15823
+ return allowedLevels;
15824
+ }
15825
+ function getRoleIdForVisibleRow(row, isRoleMode) {
15826
+ if (isRoleMode) {
15827
+ return elements2.roleSelect.value || void 0;
15828
+ }
15829
+ return row.roleId;
15830
+ }
15831
+ function renderBulkControls(rows, isRoleMode) {
15832
+ const selectByPrivilege = /* @__PURE__ */ new Map();
15833
+ for (const select of elements2.bulkSelects) {
15834
+ const privilege = select.dataset.bulkSelect;
15835
+ if (!privilege) {
15836
+ continue;
15837
+ }
15838
+ selectByPrivilege.set(privilege, select);
15839
+ }
15840
+ const buttonByPrivilege = /* @__PURE__ */ new Map();
15841
+ for (const button of elements2.bulkApplyButtons) {
15842
+ const privilege = button.dataset.bulkApply;
15843
+ if (!privilege) {
15844
+ continue;
15845
+ }
15846
+ buttonByPrivilege.set(privilege, button);
15847
+ }
15848
+ for (const privilege of accessRights) {
15849
+ const select = selectByPrivilege.get(privilege);
15850
+ const button = buttonByPrivilege.get(privilege);
15851
+ if (!select || !button) {
15852
+ continue;
15853
+ }
15854
+ const allowedLevels = /* @__PURE__ */ new Set();
15855
+ let hasEditableVisibleRows = false;
15856
+ for (const row of rows) {
15857
+ const roleId = getRoleIdForVisibleRow(row, isRoleMode);
15858
+ if (!roleId) {
15859
+ continue;
15860
+ }
15861
+ const rowAllowedLevels = getAllowedLevelsForPrivilege(row, privilege);
15862
+ if (rowAllowedLevels.length === 0) {
15863
+ continue;
15864
+ }
15865
+ hasEditableVisibleRows = true;
15866
+ for (const level of rowAllowedLevels) {
15867
+ allowedLevels.add(level);
15868
+ }
15869
+ }
15870
+ select.innerHTML = "";
15871
+ const placeholder = document.createElement("option");
15872
+ placeholder.value = "";
15873
+ placeholder.textContent = UI_TEXT.bulkUpdateSelect;
15874
+ select.appendChild(placeholder);
15875
+ for (const optionMeta of levelOptions) {
15876
+ if (!allowedLevels.has(optionMeta.level)) {
15877
+ continue;
15878
+ }
15879
+ const option = document.createElement("option");
15880
+ option.value = optionMeta.level;
15881
+ option.textContent = `${optionMeta.icon} ${optionMeta.label}`;
15882
+ select.appendChild(option);
15883
+ }
15884
+ select.disabled = !hasEditableVisibleRows;
15885
+ button.disabled = !hasEditableVisibleRows;
15886
+ button.textContent = UI_TEXT.bulkUpdateApply;
15887
+ button.title = hasEditableVisibleRows ? UI_TEXT.bulkUpdateApply : UI_TEXT.bulkUpdateNoRights;
15888
+ }
15889
+ }
15890
+ function applyBulkUpdate(privilege, level) {
15891
+ const isRoleMode = state.tableMode === "role";
15892
+ const visibleRows = applySortAndFilters(state.privilegeRows);
15893
+ let updatedCount = 0;
15894
+ let skippedCount = 0;
15895
+ for (const row of visibleRows) {
15896
+ const roleId = getRoleIdForVisibleRow(row, isRoleMode);
15897
+ if (!roleId) {
15898
+ skippedCount++;
15899
+ continue;
15900
+ }
15901
+ const allowedLevels = getAllowedLevelsForPrivilege(row, privilege);
15902
+ if (allowedLevels.length === 0 || !allowedLevels.includes(level)) {
15903
+ skippedCount++;
15904
+ continue;
15905
+ }
15906
+ const changed = updatePendingChange(
15907
+ roleId,
15908
+ row.entityLogicalName,
15909
+ privilege,
15910
+ level
15911
+ );
15912
+ if (changed) {
15913
+ updatedCount++;
15914
+ }
15915
+ }
15916
+ const privilegeLabel = privilegeLabels[privilege] ?? privilege;
15917
+ const levelLabel = levelOptions.find((option) => option.level === level)?.label ?? level;
15918
+ if (updatedCount > 0) {
15919
+ logMessage(
15920
+ formatBulkUpdatedVisible(
15921
+ privilegeLabel,
15922
+ levelLabel,
15923
+ updatedCount,
15924
+ skippedCount
15925
+ )
15926
+ );
15927
+ } else {
15928
+ logMessage(formatBulkUpdateNoRows(privilegeLabel));
15929
+ }
15930
+ renderPrivilegeTable();
15629
15931
  }
15630
15932
  function hasAnyRights(row) {
15631
15933
  return accessRights.some((privilege) => {
@@ -15646,11 +15948,17 @@ ${logTarget.textContent}`;
15646
15948
  );
15647
15949
  }
15648
15950
  function updatePendingChange(roleId, entityLogicalName, privilege, level) {
15649
- const currentLevel = getCurrentPrivilegeLevel(roleId, entityLogicalName, privilege);
15951
+ const currentLevel = getCurrentPrivilegeLevel(
15952
+ roleId,
15953
+ entityLogicalName,
15954
+ privilege
15955
+ );
15650
15956
  const existing = findPendingChange(roleId, entityLogicalName, privilege);
15651
15957
  if (level === currentLevel) {
15652
15958
  if (existing) {
15653
- state.pendingChanges = state.pendingChanges.filter((change) => change !== existing);
15959
+ state.pendingChanges = state.pendingChanges.filter(
15960
+ (change) => change !== existing
15961
+ );
15654
15962
  }
15655
15963
  updatePendingUi();
15656
15964
  return false;
@@ -15722,18 +16030,30 @@ ${logTarget.textContent}`;
15722
16030
  });
15723
16031
  const sorted = [...filtered].sort((a, b) => {
15724
16032
  if (state.sort.column === "label") {
15725
- const cmp = a.entityLabel.localeCompare(b.entityLabel, void 0, { sensitivity: "base" });
16033
+ const cmp = a.entityLabel.localeCompare(b.entityLabel, void 0, {
16034
+ sensitivity: "base"
16035
+ });
15726
16036
  return state.sort.direction === "asc" ? cmp : -cmp;
15727
16037
  }
15728
16038
  const privilege = state.sort.column;
15729
16039
  const aAvailable = isPrivilegeAvailable(a, privilege);
15730
16040
  const bAvailable = isPrivilegeAvailable(b, privilege);
15731
- const aRank = getPrivilegeSortRank(a[privilege], aAvailable, state.sort.direction);
15732
- const bRank = getPrivilegeSortRank(b[privilege], bAvailable, state.sort.direction);
16041
+ const aRank = getPrivilegeSortRank(
16042
+ a[privilege],
16043
+ aAvailable,
16044
+ state.sort.direction
16045
+ );
16046
+ const bRank = getPrivilegeSortRank(
16047
+ b[privilege],
16048
+ bAvailable,
16049
+ state.sort.direction
16050
+ );
15733
16051
  if (aRank !== bRank) {
15734
16052
  return aRank - bRank;
15735
16053
  }
15736
- return a.entityLabel.localeCompare(b.entityLabel, void 0, { sensitivity: "base" });
16054
+ return a.entityLabel.localeCompare(b.entityLabel, void 0, {
16055
+ sensitivity: "base"
16056
+ });
15737
16057
  });
15738
16058
  return sorted;
15739
16059
  }
@@ -15741,6 +16061,7 @@ ${logTarget.textContent}`;
15741
16061
  elements2.privilegesTable.innerHTML = "";
15742
16062
  const isRoleMode = state.tableMode === "role";
15743
16063
  const rows = applySortAndFilters(state.privilegeRows);
16064
+ renderBulkControls(rows, isRoleMode);
15744
16065
  if (elements2.tableEmpty) {
15745
16066
  elements2.tableEmpty.classList.toggle("hidden", state.cacheLoaded);
15746
16067
  }
@@ -15764,26 +16085,15 @@ ${logTarget.textContent}`;
15764
16085
  tr.appendChild(ownershipCell);
15765
16086
  for (const privilege of accessRights) {
15766
16087
  const td = document.createElement("td");
15767
- const privilegeId = state.privilegeIdByKey.get(`${row.entityLogicalName}:${privilege}`);
16088
+ const privilegeId = state.privilegeIdByKey.get(
16089
+ `${row.entityLogicalName}:${privilege}`
16090
+ );
15768
16091
  if (!privilegeId) {
15769
16092
  td.textContent = UI_TEXT.tableCellEmpty;
15770
16093
  tr.appendChild(td);
15771
16094
  continue;
15772
16095
  }
15773
- const info = state.privilegeInfoById.get(privilegeId);
15774
- const allowedLevels = ["none"];
15775
- if (info?.canBeBasic) {
15776
- allowedLevels.push("user");
15777
- }
15778
- if (info?.canBeLocal) {
15779
- allowedLevels.push("businessUnit");
15780
- }
15781
- if (info?.canBeDeep) {
15782
- allowedLevels.push("parentChild");
15783
- }
15784
- if (info?.canBeGlobal) {
15785
- allowedLevels.push("organization");
15786
- }
16096
+ const allowedLevels = getAllowedLevelsForPrivilege(row, privilege);
15787
16097
  const select = document.createElement("select");
15788
16098
  select.className = "level-select";
15789
16099
  select.dataset.entityLogicalName = row.entityLogicalName;
@@ -15813,7 +16123,12 @@ ${logTarget.textContent}`;
15813
16123
  return;
15814
16124
  }
15815
16125
  const level = select.value;
15816
- const isPending = updatePendingChange(roleId, row.entityLogicalName, privilege, level);
16126
+ const isPending = updatePendingChange(
16127
+ roleId,
16128
+ row.entityLogicalName,
16129
+ privilege,
16130
+ level
16131
+ );
15817
16132
  setPendingClass(select, isPending);
15818
16133
  });
15819
16134
  select.disabled = !isRoleMode && !row.roleId;
@@ -15823,7 +16138,11 @@ ${logTarget.textContent}`;
15823
16138
  });
15824
16139
  if (select.dataset.roleId) {
15825
16140
  const pending = Boolean(
15826
- findPendingChange(select.dataset.roleId, row.entityLogicalName, privilege)
16141
+ findPendingChange(
16142
+ select.dataset.roleId,
16143
+ row.entityLogicalName,
16144
+ privilege
16145
+ )
15827
16146
  );
15828
16147
  setPendingClass(select, pending);
15829
16148
  }
@@ -16041,7 +16360,8 @@ ${logTarget.textContent}`;
16041
16360
  { prefix: "prvDelete", access: "delete" },
16042
16361
  { prefix: "prvAppendTo", access: "appendto" },
16043
16362
  { prefix: "prvAppend", access: "append" },
16044
- { prefix: "prvAssign", access: "assign" }
16363
+ { prefix: "prvAssign", access: "assign" },
16364
+ { prefix: "prvShare", access: "share" }
16045
16365
  ];
16046
16366
  for (const { prefix, access } of prefixes) {
16047
16367
  if (name.startsWith(prefix)) {
@@ -16066,7 +16386,8 @@ ${logTarget.textContent}`;
16066
16386
  delete: "none",
16067
16387
  append: "none",
16068
16388
  appendto: "none",
16069
- assign: "none"
16389
+ assign: "none",
16390
+ share: "none"
16070
16391
  });
16071
16392
  }
16072
16393
  return roleMap.get(entityLogicalName);
@@ -16125,7 +16446,11 @@ ${logTarget.textContent}`;
16125
16446
  elements2.assignmentRoleSelect,
16126
16447
  state.roles,
16127
16448
  (item) => item.id,
16128
- (item) => formatAssignmentSelectLabel(item.name, counts.get(item.id) ?? 0, unitLabel)
16449
+ (item) => formatAssignmentSelectLabel(
16450
+ item.name,
16451
+ counts.get(item.id) ?? 0,
16452
+ unitLabel
16453
+ )
16129
16454
  );
16130
16455
  }
16131
16456
  function renderAssignmentUserOptionsWithCounts(unitLabel, counts) {
@@ -16133,7 +16458,11 @@ ${logTarget.textContent}`;
16133
16458
  elements2.assignmentUserSelect,
16134
16459
  state.users,
16135
16460
  (item) => item.id,
16136
- (item) => formatAssignmentSelectLabel(item.name, counts.get(item.id) ?? 0, unitLabel)
16461
+ (item) => formatAssignmentSelectLabel(
16462
+ item.name,
16463
+ counts.get(item.id) ?? 0,
16464
+ unitLabel
16465
+ )
16137
16466
  );
16138
16467
  }
16139
16468
  function renderAssignmentTeamOptionsWithCounts(unitLabel, counts) {
@@ -16141,7 +16470,11 @@ ${logTarget.textContent}`;
16141
16470
  elements2.assignmentTeamSelect,
16142
16471
  state.teams,
16143
16472
  (item) => item.id,
16144
- (item) => formatAssignmentSelectLabel(item.name, counts.get(item.id) ?? 0, unitLabel)
16473
+ (item) => formatAssignmentSelectLabel(
16474
+ item.name,
16475
+ counts.get(item.id) ?? 0,
16476
+ unitLabel
16477
+ )
16145
16478
  );
16146
16479
  }
16147
16480
  async function getAssignedUsersForRoleCached(roleId) {
@@ -16182,7 +16515,11 @@ ${logTarget.textContent}`;
16182
16515
  state.roles.length ? Promise.resolve() : loadRoles2(),
16183
16516
  state.teamsLoaded ? Promise.resolve() : loadTeams2()
16184
16517
  ]);
16185
- setDashboardLoadingProgress(++currentStep, totalSteps, UI_TEXT.loadingDashboardPeople);
16518
+ setDashboardLoadingProgress(
16519
+ ++currentStep,
16520
+ totalSteps,
16521
+ UI_TEXT.loadingDashboardPeople
16522
+ );
16186
16523
  const [users, businessUnits, teamMemberships] = await Promise.all([
16187
16524
  loadUsersForDashboard(),
16188
16525
  loadBusinessUnits(),
@@ -16407,9 +16744,15 @@ ${logTarget.textContent}`;
16407
16744
  continue;
16408
16745
  }
16409
16746
  if (isApplicationUser(user)) {
16410
- appCounts.set(user.businessUnitId, (appCounts.get(user.businessUnitId) ?? 0) + 1);
16747
+ appCounts.set(
16748
+ user.businessUnitId,
16749
+ (appCounts.get(user.businessUnitId) ?? 0) + 1
16750
+ );
16411
16751
  } else {
16412
- humanCounts.set(user.businessUnitId, (humanCounts.get(user.businessUnitId) ?? 0) + 1);
16752
+ humanCounts.set(
16753
+ user.businessUnitId,
16754
+ (humanCounts.get(user.businessUnitId) ?? 0) + 1
16755
+ );
16413
16756
  }
16414
16757
  }
16415
16758
  const units = state.dashboardBusinessUnits.map((unit) => ({
@@ -16437,11 +16780,17 @@ ${logTarget.textContent}`;
16437
16780
  const appCounts = /* @__PURE__ */ new Map();
16438
16781
  for (const membership of state.dashboardTeamMemberships) {
16439
16782
  if (humanIds.has(membership.userId)) {
16440
- humanCounts.set(membership.teamId, (humanCounts.get(membership.teamId) ?? 0) + 1);
16783
+ humanCounts.set(
16784
+ membership.teamId,
16785
+ (humanCounts.get(membership.teamId) ?? 0) + 1
16786
+ );
16441
16787
  continue;
16442
16788
  }
16443
16789
  if (appIds.has(membership.userId)) {
16444
- appCounts.set(membership.teamId, (appCounts.get(membership.teamId) ?? 0) + 1);
16790
+ appCounts.set(
16791
+ membership.teamId,
16792
+ (appCounts.get(membership.teamId) ?? 0) + 1
16793
+ );
16445
16794
  }
16446
16795
  }
16447
16796
  const teamFilterId = elements2.dashboardTeamSelect?.value ?? "";
@@ -16564,7 +16913,9 @@ ${logTarget.textContent}`;
16564
16913
  if (!elements2.chartModalBody || !elements2.chartModalCanvas) {
16565
16914
  return;
16566
16915
  }
16567
- let empty = elements2.chartModalBody.querySelector(".chart-empty");
16916
+ let empty = elements2.chartModalBody.querySelector(
16917
+ ".chart-empty"
16918
+ );
16568
16919
  if (!empty) {
16569
16920
  empty = document.createElement("div");
16570
16921
  empty.className = "chart-empty";
@@ -16592,13 +16943,27 @@ ${logTarget.textContent}`;
16592
16943
  elements2.chartUsersByRole,
16593
16944
  usersByRoleData.labels,
16594
16945
  [
16595
- { label: "Human users", data: usersByRoleData.human, backgroundColor: "#d35400" },
16596
- { label: "Application users", data: usersByRoleData.app, backgroundColor: "#f39c4a" }
16946
+ {
16947
+ label: "Human users",
16948
+ data: usersByRoleData.human,
16949
+ backgroundColor: "#d35400"
16950
+ },
16951
+ {
16952
+ label: "Application users",
16953
+ data: usersByRoleData.app,
16954
+ backgroundColor: "#f39c4a"
16955
+ }
16597
16956
  ],
16598
16957
  true
16599
16958
  );
16600
- setChartEmptyState(elements2.chartUsersByRole, usersByRoleData.labels.length === 0);
16601
- const teamsByRoleCounts = buildTeamsByRoleCounts(businessUnitId, teamFilterId);
16959
+ setChartEmptyState(
16960
+ elements2.chartUsersByRole,
16961
+ usersByRoleData.labels.length === 0
16962
+ );
16963
+ const teamsByRoleCounts = buildTeamsByRoleCounts(
16964
+ businessUnitId,
16965
+ teamFilterId
16966
+ );
16602
16967
  const teamsByRoleData = buildRoleTotalChartData(
16603
16968
  teamsByRoleCounts,
16604
16969
  roleFilterId || null,
@@ -16610,34 +16975,63 @@ ${logTarget.textContent}`;
16610
16975
  elements2.chartTeamsByRole,
16611
16976
  teamsByRoleData.labels,
16612
16977
  [
16613
- { label: "Teams", data: teamsByRoleData.values, backgroundColor: "#1f7a8c" }
16978
+ {
16979
+ label: "Teams",
16980
+ data: teamsByRoleData.values,
16981
+ backgroundColor: "#1f7a8c"
16982
+ }
16614
16983
  ]
16615
16984
  );
16616
- setChartEmptyState(elements2.chartTeamsByRole, teamsByRoleData.labels.length === 0);
16985
+ setChartEmptyState(
16986
+ elements2.chartTeamsByRole,
16987
+ teamsByRoleData.labels.length === 0
16988
+ );
16617
16989
  const usersByBuData = buildUsersByBusinessUnitData(filteredUsers, maxRoles);
16618
16990
  state.dashboardCharts.usersByBusinessUnit = renderOrUpdateBarChart(
16619
16991
  state.dashboardCharts.usersByBusinessUnit,
16620
16992
  elements2.chartUsersByBusinessUnit,
16621
16993
  usersByBuData.labels,
16622
16994
  [
16623
- { label: "Human users", data: usersByBuData.human, backgroundColor: "#d35400" },
16624
- { label: "Application users", data: usersByBuData.app, backgroundColor: "#f39c4a" }
16995
+ {
16996
+ label: "Human users",
16997
+ data: usersByBuData.human,
16998
+ backgroundColor: "#d35400"
16999
+ },
17000
+ {
17001
+ label: "Application users",
17002
+ data: usersByBuData.app,
17003
+ backgroundColor: "#f39c4a"
17004
+ }
16625
17005
  ],
16626
17006
  true
16627
17007
  );
16628
- setChartEmptyState(elements2.chartUsersByBusinessUnit, usersByBuData.labels.length === 0);
17008
+ setChartEmptyState(
17009
+ elements2.chartUsersByBusinessUnit,
17010
+ usersByBuData.labels.length === 0
17011
+ );
16629
17012
  const usersByTeamData = buildUsersByTeamData(filteredUsers, maxRoles);
16630
17013
  state.dashboardCharts.usersByTeam = renderOrUpdateBarChart(
16631
17014
  state.dashboardCharts.usersByTeam,
16632
17015
  elements2.chartUsersByTeam,
16633
17016
  usersByTeamData.labels,
16634
17017
  [
16635
- { label: "Human users", data: usersByTeamData.human, backgroundColor: "#d35400" },
16636
- { label: "Application users", data: usersByTeamData.app, backgroundColor: "#f39c4a" }
17018
+ {
17019
+ label: "Human users",
17020
+ data: usersByTeamData.human,
17021
+ backgroundColor: "#d35400"
17022
+ },
17023
+ {
17024
+ label: "Application users",
17025
+ data: usersByTeamData.app,
17026
+ backgroundColor: "#f39c4a"
17027
+ }
16637
17028
  ],
16638
17029
  true
16639
17030
  );
16640
- setChartEmptyState(elements2.chartUsersByTeam, usersByTeamData.labels.length === 0);
17031
+ setChartEmptyState(
17032
+ elements2.chartUsersByTeam,
17033
+ usersByTeamData.labels.length === 0
17034
+ );
16641
17035
  }
16642
17036
  function getDashboardChartData(kind, maxRoles) {
16643
17037
  const roleFilterId = elements2.dashboardRoleSelect?.value ?? "";
@@ -16658,13 +17052,24 @@ ${logTarget.textContent}`;
16658
17052
  labels: data.labels,
16659
17053
  stacked: true,
16660
17054
  datasets: [
16661
- { label: "Human users", data: data.human, backgroundColor: "#d35400" },
16662
- { label: "Application users", data: data.app, backgroundColor: "#f39c4a" }
17055
+ {
17056
+ label: "Human users",
17057
+ data: data.human,
17058
+ backgroundColor: "#d35400"
17059
+ },
17060
+ {
17061
+ label: "Application users",
17062
+ data: data.app,
17063
+ backgroundColor: "#f39c4a"
17064
+ }
16663
17065
  ]
16664
17066
  };
16665
17067
  }
16666
17068
  case "teamsByRole": {
16667
- const teamsByRoleCounts = buildTeamsByRoleCounts(businessUnitId, teamFilterId);
17069
+ const teamsByRoleCounts = buildTeamsByRoleCounts(
17070
+ businessUnitId,
17071
+ teamFilterId
17072
+ );
16668
17073
  const data = buildRoleTotalChartData(
16669
17074
  teamsByRoleCounts,
16670
17075
  roleFilterId || null,
@@ -16675,7 +17080,9 @@ ${logTarget.textContent}`;
16675
17080
  title: "Teams per role",
16676
17081
  labels: data.labels,
16677
17082
  stacked: false,
16678
- datasets: [{ label: "Teams", data: data.values, backgroundColor: "#1f7a8c" }]
17083
+ datasets: [
17084
+ { label: "Teams", data: data.values, backgroundColor: "#1f7a8c" }
17085
+ ]
16679
17086
  };
16680
17087
  }
16681
17088
  case "usersByBusinessUnit": {
@@ -16685,8 +17092,16 @@ ${logTarget.textContent}`;
16685
17092
  labels: data.labels,
16686
17093
  stacked: true,
16687
17094
  datasets: [
16688
- { label: "Human users", data: data.human, backgroundColor: "#d35400" },
16689
- { label: "Application users", data: data.app, backgroundColor: "#f39c4a" }
17095
+ {
17096
+ label: "Human users",
17097
+ data: data.human,
17098
+ backgroundColor: "#d35400"
17099
+ },
17100
+ {
17101
+ label: "Application users",
17102
+ data: data.app,
17103
+ backgroundColor: "#f39c4a"
17104
+ }
16690
17105
  ]
16691
17106
  };
16692
17107
  }
@@ -16697,8 +17112,16 @@ ${logTarget.textContent}`;
16697
17112
  labels: data.labels,
16698
17113
  stacked: true,
16699
17114
  datasets: [
16700
- { label: "Human users", data: data.human, backgroundColor: "#d35400" },
16701
- { label: "Application users", data: data.app, backgroundColor: "#f39c4a" }
17115
+ {
17116
+ label: "Human users",
17117
+ data: data.human,
17118
+ backgroundColor: "#d35400"
17119
+ },
17120
+ {
17121
+ label: "Application users",
17122
+ data: data.app,
17123
+ backgroundColor: "#f39c4a"
17124
+ }
16702
17125
  ]
16703
17126
  };
16704
17127
  }
@@ -16764,11 +17187,15 @@ ${logTarget.textContent}`;
16764
17187
  return isActiveUser(user) ? "Active" : "Inactive";
16765
17188
  }
16766
17189
  function buildUserRoleExportRows() {
16767
- const roleNameById = new Map(state.allRoles.map((role) => [role.id, role.name]));
17190
+ const roleNameById = new Map(
17191
+ state.allRoles.map((role) => [role.id, role.name])
17192
+ );
16768
17193
  const businessUnitById = new Map(
16769
17194
  state.dashboardBusinessUnits.map((unit) => [unit.id, unit.name])
16770
17195
  );
16771
- const usersById = new Map(state.dashboardUsers.map((user) => [user.id, user]));
17196
+ const usersById = new Map(
17197
+ state.dashboardUsers.map((user) => [user.id, user])
17198
+ );
16772
17199
  const rows = [
16773
17200
  ["User", "Email", "Status", "Business Unit", "Security Role"]
16774
17201
  ];
@@ -16791,7 +17218,9 @@ ${logTarget.textContent}`;
16791
17218
  }
16792
17219
  function buildUserTeamExportRows() {
16793
17220
  const teamNameById = new Map(state.teams.map((team) => [team.id, team.name]));
16794
- const usersById = new Map(state.dashboardUsers.map((user) => [user.id, user]));
17221
+ const usersById = new Map(
17222
+ state.dashboardUsers.map((user) => [user.id, user])
17223
+ );
16795
17224
  const rows = [["User", "Email", "Status", "Team"]];
16796
17225
  for (const membership of state.dashboardTeamMemberships) {
16797
17226
  const user = usersById.get(membership.userId);
@@ -16828,8 +17257,14 @@ ${logTarget.textContent}`;
16828
17257
  toolboxAPI2.fileSystem,
16829
17258
  toolboxAPI2.utils,
16830
17259
  [
16831
- { filename: `security-roles-users-${timestamp}.csv`, content: userRolesCsv },
16832
- { filename: `security-roles-teams-${timestamp}.csv`, content: userTeamsCsv }
17260
+ {
17261
+ filename: `security-roles-users-${timestamp}.csv`,
17262
+ content: userRolesCsv
17263
+ },
17264
+ {
17265
+ filename: `security-roles-teams-${timestamp}.csv`,
17266
+ content: userTeamsCsv
17267
+ }
16833
17268
  ],
16834
17269
  `security-roles-users-${timestamp}.csv`
16835
17270
  );
@@ -16872,7 +17307,10 @@ ${logTarget.textContent}`;
16872
17307
  canBeGlobal: Boolean(privilege.canbeglobal)
16873
17308
  });
16874
17309
  privilegeMeta.set(privilege.privilegeid, parsed);
16875
- privilegeIdByKey.set(`${parsed.entityLogicalName}:${parsed.access}`, privilege.privilegeid);
17310
+ privilegeIdByKey.set(
17311
+ `${parsed.entityLogicalName}:${parsed.access}`,
17312
+ privilege.privilegeid
17313
+ );
16876
17314
  }
16877
17315
  const rolePrivilegesCache = /* @__PURE__ */ new Map();
16878
17316
  const rolesToCache = state.allRoles.length > 0 ? state.allRoles : state.roles;
@@ -16896,7 +17334,11 @@ ${logTarget.textContent}`;
16896
17334
  rolePrivilegeCount += roleEntries.length;
16897
17335
  loadedRoles += 1;
16898
17336
  if (state.loading.active) {
16899
- updateLoadingProgress(loadedRoles, rolesToCache.length, UI_TEXT.loadingRolePrivileges);
17337
+ updateLoadingProgress(
17338
+ loadedRoles,
17339
+ rolesToCache.length,
17340
+ UI_TEXT.loadingRolePrivileges
17341
+ );
16900
17342
  }
16901
17343
  for (const entry of roleEntries) {
16902
17344
  const privilegeId = entry.PrivilegeId ?? entry.privilegeid ?? entry._privilegeid_value;
@@ -16909,7 +17351,10 @@ ${logTarget.textContent}`;
16909
17351
  continue;
16910
17352
  }
16911
17353
  const roleMap = rolePrivilegesCache.get(role.id);
16912
- const record = ensureRolePrivilegeRecord(roleMap, meta.entityLogicalName);
17354
+ const record = ensureRolePrivilegeRecord(
17355
+ roleMap,
17356
+ meta.entityLogicalName
17357
+ );
16913
17358
  record[meta.access] = mapPrivilegeLevelFromDepth(depth);
16914
17359
  }
16915
17360
  }
@@ -16919,7 +17364,11 @@ ${logTarget.textContent}`;
16919
17364
  state.rolePrivileges = rolePrivilegesCache;
16920
17365
  state.cacheLoaded = true;
16921
17366
  logMessage(
16922
- formatCachedPrivileges(privileges.length, rolePrivilegeCount, rolesToCache.length)
17367
+ formatCachedPrivileges(
17368
+ privileges.length,
17369
+ rolePrivilegeCount,
17370
+ rolesToCache.length
17371
+ )
16923
17372
  );
16924
17373
  return true;
16925
17374
  }
@@ -16969,7 +17418,8 @@ ${logTarget.textContent}`;
16969
17418
  delete: "none",
16970
17419
  append: "none",
16971
17420
  appendto: "none",
16972
- assign: "none"
17421
+ assign: "none",
17422
+ share: "none"
16973
17423
  };
16974
17424
  return {
16975
17425
  entityLabel: entity.displayName,
@@ -16981,7 +17431,8 @@ ${logTarget.textContent}`;
16981
17431
  delete: record.delete,
16982
17432
  append: record.append,
16983
17433
  appendto: record.appendto,
16984
- assign: record.assign
17434
+ assign: record.assign,
17435
+ share: record.share
16985
17436
  };
16986
17437
  });
16987
17438
  renderPrivilegeTable();
@@ -16994,8 +17445,12 @@ ${logTarget.textContent}`;
16994
17445
  return;
16995
17446
  }
16996
17447
  state.tableMode = "entity";
16997
- const entityLabel = state.entities.find((entity) => entity.logicalName === entityLogicalName)?.displayName;
16998
- const visibleRoles = state.roles.filter((role) => state.selectedRoleIds.has(role.id));
17448
+ const entityLabel = state.entities.find(
17449
+ (entity) => entity.logicalName === entityLogicalName
17450
+ )?.displayName;
17451
+ const visibleRoles = state.roles.filter(
17452
+ (role) => state.selectedRoleIds.has(role.id)
17453
+ );
16999
17454
  state.privilegeRows = visibleRoles.map((role) => {
17000
17455
  const record = state.rolePrivileges.get(role.id)?.get(entityLogicalName) ?? {
17001
17456
  create: "none",
@@ -17004,7 +17459,8 @@ ${logTarget.textContent}`;
17004
17459
  delete: "none",
17005
17460
  append: "none",
17006
17461
  appendto: "none",
17007
- assign: "none"
17462
+ assign: "none",
17463
+ share: "none"
17008
17464
  };
17009
17465
  return {
17010
17466
  roleId: role.id,
@@ -17017,11 +17473,14 @@ ${logTarget.textContent}`;
17017
17473
  delete: record.delete,
17018
17474
  append: record.append,
17019
17475
  appendto: record.appendto,
17020
- assign: record.assign
17476
+ assign: record.assign,
17477
+ share: record.share
17021
17478
  };
17022
17479
  });
17023
17480
  renderPrivilegeTable();
17024
- setTableTitle(formatPrivilegesForTableTitle(entityLabel ?? entityLogicalName));
17481
+ setTableTitle(
17482
+ formatPrivilegesForTableTitle(entityLabel ?? entityLogicalName)
17483
+ );
17025
17484
  }
17026
17485
  async function loadAssignmentView() {
17027
17486
  if (!state.allRoles.length) {
@@ -17039,7 +17498,10 @@ ${logTarget.textContent}`;
17039
17498
  activeUserIds
17040
17499
  );
17041
17500
  }
17042
- renderAssignmentRoleOptionsWithCounts(UI_TEXT.unitUsers, state.assignmentRoleUserCounts);
17501
+ renderAssignmentRoleOptionsWithCounts(
17502
+ UI_TEXT.unitUsers,
17503
+ state.assignmentRoleUserCounts
17504
+ );
17043
17505
  const roleId = elements2.assignmentRoleSelect.value;
17044
17506
  if (!roleId) {
17045
17507
  setAssignmentStatus(UI_TEXT.assignmentSelectRoleUsers);
@@ -17071,7 +17533,10 @@ ${logTarget.textContent}`;
17071
17533
  if (state.assignmentUserRoleCounts.size !== state.users.length) {
17072
17534
  state.assignmentUserRoleCounts = await loadUserAssignmentCounts();
17073
17535
  }
17074
- renderAssignmentUserOptionsWithCounts(UI_TEXT.unitRoles, state.assignmentUserRoleCounts);
17536
+ renderAssignmentUserOptionsWithCounts(
17537
+ UI_TEXT.unitRoles,
17538
+ state.assignmentUserRoleCounts
17539
+ );
17075
17540
  const userId = elements2.assignmentUserSelect.value;
17076
17541
  if (!userId) {
17077
17542
  setAssignmentStatus(UI_TEXT.assignmentSelectUserRoles);
@@ -17106,7 +17571,10 @@ ${logTarget.textContent}`;
17106
17571
  state.allRoles
17107
17572
  );
17108
17573
  }
17109
- renderAssignmentRoleOptionsWithCounts(UI_TEXT.unitTeams, state.assignmentRoleTeamCounts);
17574
+ renderAssignmentRoleOptionsWithCounts(
17575
+ UI_TEXT.unitTeams,
17576
+ state.assignmentRoleTeamCounts
17577
+ );
17110
17578
  const roleId = elements2.assignmentRoleSelect.value;
17111
17579
  if (!roleId) {
17112
17580
  setAssignmentStatus(UI_TEXT.assignmentSelectRoleTeams);
@@ -17138,7 +17606,10 @@ ${logTarget.textContent}`;
17138
17606
  if (state.assignmentTeamRoleCounts.size !== state.teams.length) {
17139
17607
  state.assignmentTeamRoleCounts = await loadTeamAssignmentCounts();
17140
17608
  }
17141
- renderAssignmentTeamOptionsWithCounts(UI_TEXT.unitRoles, state.assignmentTeamRoleCounts);
17609
+ renderAssignmentTeamOptionsWithCounts(
17610
+ UI_TEXT.unitRoles,
17611
+ state.assignmentTeamRoleCounts
17612
+ );
17142
17613
  const teamId = elements2.assignmentTeamSelect.value;
17143
17614
  if (!teamId) {
17144
17615
  setAssignmentStatus(UI_TEXT.assignmentSelectTeamRoles);
@@ -17191,7 +17662,9 @@ ${logTarget.textContent}`;
17191
17662
  processedUsers.push(user.name);
17192
17663
  }
17193
17664
  if (processedUsers.length > 0) {
17194
- logMessage(formatRoleAssignmentLogUsers(action, roleName, processedUsers));
17665
+ logMessage(
17666
+ formatRoleAssignmentLogUsers(action, roleName, processedUsers)
17667
+ );
17195
17668
  }
17196
17669
  } else if (state.assignmentMode === "user") {
17197
17670
  const userId = elements2.assignmentUserSelect.value;
@@ -17218,7 +17691,9 @@ ${logTarget.textContent}`;
17218
17691
  processedRoles.push(roleName);
17219
17692
  }
17220
17693
  if (processedRoles.length > 0) {
17221
- logMessage(formatRoleAssignmentLogRolesForUser(action, user.name, processedRoles));
17694
+ logMessage(
17695
+ formatRoleAssignmentLogRolesForUser(action, user.name, processedRoles)
17696
+ );
17222
17697
  }
17223
17698
  } else if (state.assignmentMode === "role-team") {
17224
17699
  const roleRootId = elements2.assignmentRoleSelect.value;
@@ -17245,7 +17720,9 @@ ${logTarget.textContent}`;
17245
17720
  processedTeams.push(team.name);
17246
17721
  }
17247
17722
  if (processedTeams.length > 0) {
17248
- logMessage(formatRoleAssignmentLogTeams(action, roleName, processedTeams));
17723
+ logMessage(
17724
+ formatRoleAssignmentLogTeams(action, roleName, processedTeams)
17725
+ );
17249
17726
  }
17250
17727
  } else {
17251
17728
  const teamId = elements2.assignmentTeamSelect.value;
@@ -17272,7 +17749,9 @@ ${logTarget.textContent}`;
17272
17749
  processedRoles.push(roleName);
17273
17750
  }
17274
17751
  if (processedRoles.length > 0) {
17275
- logMessage(formatRoleAssignmentLogRolesForTeam(action, team.name, processedRoles));
17752
+ logMessage(
17753
+ formatRoleAssignmentLogRolesForTeam(action, team.name, processedRoles)
17754
+ );
17276
17755
  }
17277
17756
  }
17278
17757
  resetAssignmentCaches();
@@ -17296,17 +17775,25 @@ ${logTarget.textContent}`;
17296
17775
  const removesByRole = /* @__PURE__ */ new Map();
17297
17776
  const addsByRole = /* @__PURE__ */ new Map();
17298
17777
  for (const change of state.pendingChanges) {
17299
- const privilegeId = state.privilegeIdByKey.get(`${change.entityLogicalName}:${change.privilege}`);
17778
+ const privilegeId = state.privilegeIdByKey.get(
17779
+ `${change.entityLogicalName}:${change.privilege}`
17780
+ );
17300
17781
  if (!privilegeId) {
17301
- logMessage(formatMissingPrivilegeId(change.entityLogicalName, change.privilege));
17782
+ logMessage(
17783
+ formatMissingPrivilegeId(change.entityLogicalName, change.privilege)
17784
+ );
17302
17785
  continue;
17303
17786
  }
17304
17787
  const roleMap = state.rolePrivileges.get(change.roleId) ?? /* @__PURE__ */ new Map();
17305
17788
  const record = roleMap.get(change.entityLogicalName) ?? {
17789
+ create: "none",
17306
17790
  read: "none",
17307
17791
  write: "none",
17792
+ delete: "none",
17308
17793
  append: "none",
17309
- appendto: "none"
17794
+ appendto: "none",
17795
+ assign: "none",
17796
+ share: "none"
17310
17797
  };
17311
17798
  const currentLevel = record[change.privilege];
17312
17799
  if (currentLevel === change.level) {
@@ -17343,20 +17830,31 @@ ${logTarget.textContent}`;
17343
17830
  for (const privilegeId of privilegeIds) {
17344
17831
  await removePrivilegesFromRole(roleId, privilegeId);
17345
17832
  completedCalls += 1;
17346
- updateLoadingProgress(completedCalls, totalCalls, UI_TEXT.loadingApplyingChanges);
17833
+ updateLoadingProgress(
17834
+ completedCalls,
17835
+ totalCalls,
17836
+ UI_TEXT.loadingApplyingChanges
17837
+ );
17347
17838
  }
17348
17839
  }
17349
17840
  for (const [roleId, privileges] of addsByRole) {
17350
17841
  await addPrivilegesToRole(roleId, privileges);
17351
17842
  completedCalls += 1;
17352
- updateLoadingProgress(completedCalls, totalCalls, UI_TEXT.loadingApplyingChanges);
17843
+ updateLoadingProgress(
17844
+ completedCalls,
17845
+ totalCalls,
17846
+ UI_TEXT.loadingApplyingChanges
17847
+ );
17353
17848
  }
17354
17849
  for (const change of state.pendingChanges) {
17355
17850
  if (!state.rolePrivileges.has(change.roleId)) {
17356
17851
  state.rolePrivileges.set(change.roleId, /* @__PURE__ */ new Map());
17357
17852
  }
17358
17853
  const roleMap = state.rolePrivileges.get(change.roleId);
17359
- const record = ensureRolePrivilegeRecord(roleMap, change.entityLogicalName);
17854
+ const record = ensureRolePrivilegeRecord(
17855
+ roleMap,
17856
+ change.entityLogicalName
17857
+ );
17360
17858
  record[change.privilege] = change.level;
17361
17859
  }
17362
17860
  } catch (error) {
@@ -17631,10 +18129,18 @@ ${logTarget.textContent}`;
17631
18129
  loadAssignmentView();
17632
18130
  }
17633
18131
  });
17634
- elements2.assignmentAdd.addEventListener("click", () => applyAssignmentChange("add"));
17635
- elements2.assignmentRemove.addEventListener("click", () => applyAssignmentChange("remove"));
18132
+ elements2.assignmentAdd.addEventListener(
18133
+ "click",
18134
+ () => applyAssignmentChange("add")
18135
+ );
18136
+ elements2.assignmentRemove.addEventListener(
18137
+ "click",
18138
+ () => applyAssignmentChange("remove")
18139
+ );
17636
18140
  elements2.assignmentSelectAll.addEventListener("click", () => {
17637
- state.selectedAssignmentIds = new Set(state.assignmentItems.map((item) => item.id));
18141
+ state.selectedAssignmentIds = new Set(
18142
+ state.assignmentItems.map((item) => item.id)
18143
+ );
17638
18144
  renderAssignmentTable(state.assignmentItems);
17639
18145
  updateAssignmentSelectionUi();
17640
18146
  });
@@ -17681,6 +18187,22 @@ ${logTarget.textContent}`;
17681
18187
  renderPrivilegeTable();
17682
18188
  });
17683
18189
  }
18190
+ for (const button of elements2.bulkApplyButtons) {
18191
+ button.addEventListener("click", () => {
18192
+ const privilege = button.dataset.bulkApply;
18193
+ if (!privilege) {
18194
+ return;
18195
+ }
18196
+ const select = elements2.bulkSelects.find(
18197
+ (item) => item.dataset.bulkSelect === privilege
18198
+ );
18199
+ if (!select || !select.value) {
18200
+ logMessage(UI_TEXT.bulkUpdateNoSelection);
18201
+ return;
18202
+ }
18203
+ applyBulkUpdate(privilege, select.value);
18204
+ });
18205
+ }
17684
18206
  for (const select of elements2.filterSelects) {
17685
18207
  select.addEventListener("change", async () => {
17686
18208
  const privilege = select.dataset.filter;