ngx-dynamic-entity 1.5.0 → 1.6.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.
@@ -4140,12 +4140,19 @@ class DynamicFormComponent {
4140
4140
  */
4141
4141
  isFieldReadonly(field) {
4142
4142
  return (this.readonly ||
4143
+ // `permissions.edit` gated the Save button and nothing else, so a role without edit
4144
+ // rights received a fully editable form: it could type into every field, and only
4145
+ // discovered the record was not theirs to change when no Save button appeared. The
4146
+ // permission means the record may not be edited, so the fields say so.
4147
+ !this.permissions.canEdit ||
4143
4148
  !!field.readonly ||
4144
4149
  this.readOnlyFields.includes(field.id) ||
4145
4150
  this.isFieldLocked(field));
4146
4151
  }
4147
4152
  toggleFieldLock(field) {
4148
- if (!field.criticalField || this.readonly)
4153
+ // Unlocking is an edit. Without the permission check a viewer could open the lock on a
4154
+ // critical field, which is the one control that exists to make editing deliberate.
4155
+ if (!field.criticalField || this.readonly || !this.permissions.canEdit)
4149
4156
  return;
4150
4157
  const next = new Set(this.unlockedFields());
4151
4158
  if (next.has(field.id))
@@ -4854,6 +4861,7 @@ class DynamicRecordFormComponent {
4854
4861
  sectionSave = new EventEmitter();
4855
4862
  dynamicFormComp;
4856
4863
  rulesEvaluation = inject(RulesEvaluationService);
4864
+ rbacService = inject(RbacService);
4857
4865
  host = inject(ElementRef);
4858
4866
  injector = inject(Injector);
4859
4867
  currentData = signal({}, ...(ngDevMode ? [{ debugName: "currentData" }] : /* istanbul ignore next */ []));
@@ -4883,9 +4891,21 @@ class DynamicRecordFormComponent {
4883
4891
  dismissInfoBanner(fieldId) {
4884
4892
  this.dismissed.set(new Set(this.dismissed()).add(fieldId));
4885
4893
  }
4894
+ /**
4895
+ * Whether the current roles may edit this record.
4896
+ *
4897
+ * `userRoles` was declared as an input here and then read by nothing at all — this
4898
+ * component computed no permissions of any kind, so the record view was fully editable
4899
+ * for every role while the plain form at least hid its Save button. Cached on the same
4900
+ * terms as the sibling component: it depends only on `config` and `userRoles`.
4901
+ */
4902
+ permissionsCache = null;
4903
+ get permissions() {
4904
+ return (this.permissionsCache ??= this.rbacService.getPermissions(this.config, this.userRoles));
4905
+ }
4886
4906
  /** True when nothing in the record may be edited. */
4887
4907
  get recordReadOnly() {
4888
- return this.readonly || this.isReadOnly;
4908
+ return this.readonly || this.isReadOnly || !this.permissions.canEdit;
4889
4909
  }
4890
4910
  // ─── Inline array-row editing ───────────────────────────────────────────────
4891
4911
  /**
@@ -5097,6 +5117,11 @@ class DynamicRecordFormComponent {
5097
5117
  * after the first keystroke.
5098
5118
  */
5099
5119
  ngOnChanges(changes) {
5120
+ // Permissions depend on these two and nothing else; a stale cache would keep a record
5121
+ // editable after a role switch.
5122
+ if (changes['config'] || changes['userRoles']) {
5123
+ this.permissionsCache = null;
5124
+ }
5100
5125
  if (changes['initialData'] || changes['config']) {
5101
5126
  this.originalBaseline.set({ ...(this.initialData ?? {}) });
5102
5127
  this.currentData.set({ ...(this.initialData ?? {}) });