@praxisui/crud 10.0.0-rc.21 → 10.0.0-rc.23

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-10-15T04:35:19.773Z",
3
+ "generatedAt": "2026-10-15T13:02:39.040Z",
4
4
  "packageName": "@praxisui/crud",
5
- "packageVersion": "10.0.0-rc.21",
5
+ "packageVersion": "10.0.0-rc.23",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 2,
@@ -3811,7 +3811,10 @@ function validateCrudKpiBand(metadata, diagnostics) {
3811
3811
  diagnostics.push(errorDiagnostic('crud.metadata.kpiBand.cards.value.required', `KPI card #${index + 1} requires a displayed value`, `metadata.kpiBand.cards.${index}.value`));
3812
3812
  }
3813
3813
  if (card?.filter !== undefined &&
3814
- (!card.filter || typeof card.filter !== 'object' || Array.isArray(card.filter))) {
3814
+ (!card.filter ||
3815
+ typeof card.filter !== 'object' ||
3816
+ Array.isArray(card.filter) ||
3817
+ Object.keys(card.filter).some((key) => !trimString(key)))) {
3815
3818
  diagnostics.push(errorDiagnostic('crud.metadata.kpiBand.cards.filter.invalid', `KPI card #${index + 1} filter must be a valid criteria object`, `metadata.kpiBand.cards.${index}.filter`));
3816
3819
  }
3817
3820
  });
@@ -3832,8 +3835,11 @@ function validateCrudFilterBar(metadata, diagnostics) {
3832
3835
  const filterVal = qf?.filter;
3833
3836
  const isInvalidFilter = filterVal === undefined ||
3834
3837
  filterVal === null ||
3838
+ (typeof filterVal === 'string' && !filterVal.trim()) ||
3835
3839
  (typeof filterVal !== 'string' &&
3836
- (typeof filterVal !== 'object' || Array.isArray(filterVal)));
3840
+ (typeof filterVal !== 'object' ||
3841
+ Array.isArray(filterVal) ||
3842
+ Object.keys(filterVal).some((key) => !trimString(key))));
3837
3843
  if (isInvalidFilter) {
3838
3844
  diagnostics.push(errorDiagnostic('crud.metadata.filterBar.quickFilters.filter.invalid', `Quick filter #${index + 1} requires a valid filter condition`, `metadata.filterBar.quickFilters.${index}.filter`));
3839
3845
  }
@@ -5164,6 +5170,7 @@ class CrudMetadataEditorComponent {
5164
5170
  // Observe the supplied snapshot with its external resource, before local edits.
5165
5171
  this.providedSnapshotOwner();
5166
5172
  this.synchronizeSchemaScope();
5173
+ this.initialValueDrafts.set({});
5167
5174
  this.kpiFilterJsonDrafts.set({});
5168
5175
  this.quickFilterExpressionDrafts.set({});
5169
5176
  this.syncState();
@@ -5292,9 +5299,9 @@ class CrudMetadataEditorComponent {
5292
5299
  else {
5293
5300
  parts.push(this.tx('crud.authoring.action.paramsNone', 'No param mappings yet'));
5294
5301
  }
5295
- const draft = this.actionInitialValueDraft(actionName).trim();
5302
+ const hasInvalidDraft = this.initialValueDrafts()[actionName] !== undefined;
5296
5303
  const hasInitialValue = !!this.actionValue(actionName).form?.initialValue;
5297
- if (draft && !hasInitialValue) {
5304
+ if (hasInvalidDraft) {
5298
5305
  parts.push(this.tx('crud.authoring.action.initialValueInvalid', 'Initial value JSON is not valid yet'));
5299
5306
  }
5300
5307
  else if (hasInitialValue) {
@@ -5313,9 +5320,9 @@ class CrudMetadataEditorComponent {
5313
5320
  return this.tx('crud.authoring.action.paramsNoteReady', 'Mappings ready');
5314
5321
  }
5315
5322
  actionInitialValueNote(actionName) {
5316
- const draft = this.actionInitialValueDraft(actionName).trim();
5323
+ const hasInvalidDraft = this.initialValueDrafts()[actionName] !== undefined;
5317
5324
  const hasInitialValue = !!this.actionValue(actionName).form?.initialValue;
5318
- if (draft && !hasInitialValue) {
5325
+ if (hasInvalidDraft) {
5319
5326
  return this.tx('crud.authoring.action.initialValueInvalid', 'Initial value JSON is not valid yet');
5320
5327
  }
5321
5328
  if (hasInitialValue) {
@@ -5492,6 +5499,9 @@ class CrudMetadataEditorComponent {
5492
5499
  if (diagnosticPaths.some((issue) => issue.level === 'error')) {
5493
5500
  return 'invalid';
5494
5501
  }
5502
+ if (this.initialValueDrafts()[actionName] !== undefined) {
5503
+ return 'invalid';
5504
+ }
5495
5505
  const action = this.actionValue(actionName);
5496
5506
  const effectiveMode = (action.openMode || this.defaultsOpenMode());
5497
5507
  const hasBinding = effectiveMode === 'route'
@@ -5797,6 +5807,13 @@ class CrudMetadataEditorComponent {
5797
5807
  if (section === 'kpis' && Object.keys(this.kpiFilterJsonDrafts()).length > 0) {
5798
5808
  return 'invalid';
5799
5809
  }
5810
+ if (section === 'filters' && this.hasInvalidQuickFilterDraft()) {
5811
+ return 'invalid';
5812
+ }
5813
+ if (section === 'actions' &&
5814
+ this.actionKeys.some((actionName) => this.actionStatus(actionName) === 'invalid')) {
5815
+ return 'invalid';
5816
+ }
5800
5817
  if (diagnostics.some((issue) => issue.level === 'warning')) {
5801
5818
  return 'pending';
5802
5819
  }
@@ -6393,7 +6410,7 @@ class CrudMetadataEditorComponent {
6393
6410
  [index]: raw,
6394
6411
  }));
6395
6412
  const trimmed = String(raw || '').trim();
6396
- if (trimmed.startsWith('{')) {
6413
+ if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
6397
6414
  try {
6398
6415
  const parsed = JSON.parse(trimmed);
6399
6416
  if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
@@ -6405,8 +6422,10 @@ class CrudMetadataEditorComponent {
6405
6422
  }
6406
6423
  }
6407
6424
  catch {
6408
- // Fall through to string expression
6425
+ // Keep malformed JSON draft in signal so sectionStatus('filters') surfaces 'invalid'
6409
6426
  }
6427
+ this.syncState();
6428
+ return;
6410
6429
  }
6411
6430
  this.patchQuickFilter(index, (qf) => ({
6412
6431
  ...qf,
@@ -6558,12 +6577,9 @@ class CrudMetadataEditorComponent {
6558
6577
  });
6559
6578
  }
6560
6579
  setActionInitialValue(actionName, raw) {
6561
- this.initialValueDrafts.update((drafts) => ({
6562
- ...drafts,
6563
- [actionName]: raw,
6564
- }));
6565
6580
  const trimmed = raw.trim();
6566
6581
  if (!trimmed) {
6582
+ this.clearActionInitialValueDraft(actionName);
6567
6583
  this.patchAction(actionName, (action) => ({
6568
6584
  ...action,
6569
6585
  form: {
@@ -6575,20 +6591,26 @@ class CrudMetadataEditorComponent {
6575
6591
  }
6576
6592
  try {
6577
6593
  const parsed = JSON.parse(trimmed);
6578
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
6594
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
6595
+ this.clearActionInitialValueDraft(actionName);
6596
+ this.patchAction(actionName, (action) => ({
6597
+ ...action,
6598
+ form: {
6599
+ ...(action.form || {}),
6600
+ initialValue: parsed,
6601
+ },
6602
+ }));
6579
6603
  return;
6580
6604
  }
6581
- this.patchAction(actionName, (action) => ({
6582
- ...action,
6583
- form: {
6584
- ...(action.form || {}),
6585
- initialValue: parsed,
6586
- },
6587
- }));
6588
6605
  }
6589
6606
  catch {
6590
- return;
6607
+ // Keep invalid draft in signal so actionStatus and sectionStatus('actions') surface 'invalid'
6591
6608
  }
6609
+ this.initialValueDrafts.update((drafts) => ({
6610
+ ...drafts,
6611
+ [actionName]: raw,
6612
+ }));
6613
+ this.syncState();
6592
6614
  }
6593
6615
  setActionBackField(actionName, field, value) {
6594
6616
  this.patchAction(actionName, (action) => ({
@@ -6666,6 +6688,31 @@ class CrudMetadataEditorComponent {
6666
6688
  return next;
6667
6689
  });
6668
6690
  }
6691
+ clearActionInitialValueDraft(actionName) {
6692
+ if (this.initialValueDrafts()[actionName] === undefined) {
6693
+ return;
6694
+ }
6695
+ this.initialValueDrafts.update((drafts) => {
6696
+ const next = { ...drafts };
6697
+ delete next[actionName];
6698
+ return next;
6699
+ });
6700
+ }
6701
+ hasInvalidQuickFilterDraft() {
6702
+ return Object.values(this.quickFilterExpressionDrafts()).some((raw) => {
6703
+ const trimmed = String(raw ?? '').trim();
6704
+ if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
6705
+ return false;
6706
+ }
6707
+ try {
6708
+ const parsed = JSON.parse(trimmed);
6709
+ return !parsed || typeof parsed !== 'object' || Array.isArray(parsed);
6710
+ }
6711
+ catch {
6712
+ return true;
6713
+ }
6714
+ });
6715
+ }
6669
6716
  updateFilterBar(updater) {
6670
6717
  this.updateMetadata((metadata) => {
6671
6718
  const base = this.effectiveFilterBar() || {};
@@ -6808,10 +6855,12 @@ class CrudMetadataEditorComponent {
6808
6855
  syncState() {
6809
6856
  const currentSignature = JSON.stringify(serializeCrudAuthoringDocument(this.currentDocument()));
6810
6857
  const initialSignature = JSON.stringify(serializeCrudAuthoringDocument(this.initialDocument()));
6811
- const hasInvalidKpiJson = Object.keys(this.kpiFilterJsonDrafts()).length > 0;
6812
- this.isDirty$.next(currentSignature !== initialSignature || hasInvalidKpiJson);
6858
+ const hasInvalidDraft = Object.keys(this.kpiFilterJsonDrafts()).length > 0 ||
6859
+ this.hasInvalidQuickFilterDraft() ||
6860
+ Object.keys(this.initialValueDrafts()).length > 0;
6861
+ this.isDirty$.next(currentSignature !== initialSignature || hasInvalidDraft);
6813
6862
  const hasErrorDiagnostics = this.diagnostics().some((issue) => issue.level === 'error');
6814
- this.isValid$.next(!hasErrorDiagnostics && !hasInvalidKpiJson);
6863
+ this.isValid$.next(!hasErrorDiagnostics && !hasInvalidDraft);
6815
6864
  }
6816
6865
  tx(key, fallback) {
6817
6866
  return translateCrudAuthoringText(this.i18n, key, fallback);
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@praxisui/crud",
3
- "version": "10.0.0-rc.21",
3
+ "version": "10.0.0-rc.23",
4
4
  "description": "CRUD building blocks for Praxis UI: integrates dynamic forms and tables with unified configuration and services.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
- "@praxisui/dynamic-form": "^10.0.0-rc.21",
9
- "@praxisui/table": "^10.0.0-rc.21",
10
- "@praxisui/core": "^10.0.0-rc.21",
11
- "@praxisui/dynamic-fields": "^10.0.0-rc.21",
12
- "@praxisui/settings-panel": "^10.0.0-rc.21",
8
+ "@praxisui/dynamic-form": "^10.0.0-rc.23",
9
+ "@praxisui/table": "^10.0.0-rc.23",
10
+ "@praxisui/core": "^10.0.0-rc.23",
11
+ "@praxisui/dynamic-fields": "^10.0.0-rc.23",
12
+ "@praxisui/settings-panel": "^10.0.0-rc.23",
13
13
  "@angular/cdk": "^21.0.0",
14
14
  "@angular/forms": "^21.0.0",
15
15
  "@angular/material": "^21.0.0",
16
16
  "@angular/router": "^21.0.0",
17
- "@praxisui/ai": "^10.0.0-rc.21",
17
+ "@praxisui/ai": "^10.0.0-rc.23",
18
18
  "rxjs": "~7.8.0"
19
19
  },
20
20
  "dependencies": {
@@ -996,6 +996,8 @@ declare class CrudMetadataEditorComponent implements SettingsValueProvider {
996
996
  private updateKpiBand;
997
997
  private patchKpiCard;
998
998
  private clearKpiFilterJsonDraft;
999
+ private clearActionInitialValueDraft;
1000
+ private hasInvalidQuickFilterDraft;
999
1001
  private updateFilterBar;
1000
1002
  private patchQuickFilter;
1001
1003
  private resourceSchemaIdentity;