@finos/legend-application-studio 28.21.4 → 28.21.5

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 (54) hide show
  1. package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.d.ts +1 -1
  2. package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.d.ts.map +1 -1
  3. package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.js +3 -3
  4. package/lib/components/editor/editor-group/data-editor/EmbeddedDataEditor.js.map +1 -1
  5. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts +3 -0
  6. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.d.ts.map +1 -1
  7. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js +12 -35
  8. package/lib/components/editor/editor-group/data-editor/RelationElementsDataEditor.js.map +1 -1
  9. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
  10. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +19 -6
  11. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
  12. package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.d.ts.map +1 -1
  13. package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.js +59 -22
  14. package/lib/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.js.map +1 -1
  15. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.d.ts.map +1 -1
  16. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js +113 -75
  17. package/lib/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.js.map +1 -1
  18. package/lib/components/editor/editor-group/testable/TestableSharedComponents.d.ts.map +1 -1
  19. package/lib/components/editor/editor-group/testable/TestableSharedComponents.js +1 -1
  20. package/lib/components/editor/editor-group/testable/TestableSharedComponents.js.map +1 -1
  21. package/lib/components/editor/side-bar/DevMetadataPanel.d.ts.map +1 -1
  22. package/lib/components/editor/side-bar/DevMetadataPanel.js +37 -6
  23. package/lib/components/editor/side-bar/DevMetadataPanel.js.map +1 -1
  24. package/lib/index.css +2 -2
  25. package/lib/index.css.map +1 -1
  26. package/lib/package.json +1 -1
  27. package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.d.ts +1 -1
  28. package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.d.ts.map +1 -1
  29. package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.js +20 -48
  30. package/lib/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.js.map +1 -1
  31. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts +9 -14
  32. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts.map +1 -1
  33. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js +125 -78
  34. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js.map +1 -1
  35. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts +18 -4
  36. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.d.ts.map +1 -1
  37. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js +214 -53
  38. package/lib/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.js.map +1 -1
  39. package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.d.ts +9 -0
  40. package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.d.ts.map +1 -1
  41. package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.js +55 -0
  42. package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.js.map +1 -1
  43. package/package.json +16 -16
  44. package/src/components/editor/editor-group/data-editor/EmbeddedDataEditor.tsx +3 -0
  45. package/src/components/editor/editor-group/data-editor/RelationElementsDataEditor.tsx +200 -186
  46. package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +25 -7
  47. package/src/components/editor/editor-group/dataProduct/testable/DataProductTestableEditor.tsx +149 -86
  48. package/src/components/editor/editor-group/function-activator/testable/FunctionTestableEditor.tsx +425 -308
  49. package/src/components/editor/editor-group/testable/TestableSharedComponents.tsx +2 -11
  50. package/src/components/editor/side-bar/DevMetadataPanel.tsx +194 -10
  51. package/src/stores/editor/editor-state/element-editor-state/data/EmbeddedDataState.ts +28 -50
  52. package/src/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.ts +164 -100
  53. package/src/stores/editor/editor-state/element-editor-state/function-activator/testable/FunctionTestableState.ts +303 -72
  54. package/src/stores/editor/sidebar-state/dev-metadata/DevMetadataState.ts +76 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-application-studio",
3
- "version": "28.21.4",
3
+ "version": "28.21.5",
4
4
  "description": "Legend Studio application core",
5
5
  "keywords": [
6
6
  "legend",
@@ -47,21 +47,21 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "@dagrejs/dagre": "1.1.4",
50
- "@finos/legend-application": "16.0.105",
51
- "@finos/legend-art": "7.1.147",
52
- "@finos/legend-code-editor": "2.0.170",
53
- "@finos/legend-data-cube": "0.3.87",
54
- "@finos/legend-extension-dsl-data-product": "0.0.79",
55
- "@finos/legend-extension-dsl-diagram": "8.1.234",
56
- "@finos/legend-graph": "32.6.2",
57
- "@finos/legend-lego": "2.0.190",
58
- "@finos/legend-query-builder": "4.18.8",
59
- "@finos/legend-server-depot": "6.1.11",
60
- "@finos/legend-server-lakehouse": "0.3.51",
61
- "@finos/legend-server-sdlc": "5.4.2",
62
- "@finos/legend-server-showcase": "0.2.65",
63
- "@finos/legend-shared": "11.0.24",
64
- "@finos/legend-storage": "3.0.145",
50
+ "@finos/legend-application": "16.0.106",
51
+ "@finos/legend-art": "7.1.148",
52
+ "@finos/legend-code-editor": "2.0.171",
53
+ "@finos/legend-data-cube": "0.3.88",
54
+ "@finos/legend-extension-dsl-data-product": "0.0.80",
55
+ "@finos/legend-extension-dsl-diagram": "8.1.235",
56
+ "@finos/legend-graph": "32.6.3",
57
+ "@finos/legend-lego": "2.0.191",
58
+ "@finos/legend-query-builder": "4.18.9",
59
+ "@finos/legend-server-depot": "6.1.12",
60
+ "@finos/legend-server-lakehouse": "0.3.52",
61
+ "@finos/legend-server-sdlc": "5.4.3",
62
+ "@finos/legend-server-showcase": "0.2.66",
63
+ "@finos/legend-shared": "11.0.25",
64
+ "@finos/legend-storage": "3.0.146",
65
65
  "@testing-library/dom": "10.4.0",
66
66
  "@testing-library/react": "16.2.0",
67
67
  "@types/react": "19.0.10",
@@ -237,6 +237,7 @@ export const DataElementReferenceDataEditor = observer(
237
237
  {renderEmbeddedDataEditor(
238
238
  dataElementReferenceState.embeddedDataValueState,
239
239
  isReadOnly,
240
+ true,
240
241
  )}
241
242
  </div>
242
243
  </div>
@@ -377,6 +378,7 @@ export const EmbeddedDataEditor = observer(
377
378
  export function renderEmbeddedDataEditor(
378
379
  embeddedDataState: EmbeddedDataState,
379
380
  isReadOnly: boolean,
381
+ isSharedData?: boolean,
380
382
  ): React.ReactNode {
381
383
  if (embeddedDataState instanceof ExternalFormatDataState) {
382
384
  return (
@@ -397,6 +399,7 @@ export function renderEmbeddedDataEditor(
397
399
  <RelationElementsDataEditor
398
400
  dataState={embeddedDataState}
399
401
  isReadOnly={isReadOnly}
402
+ isSharedData={isSharedData}
400
403
  />
401
404
  );
402
405
  } else if (embeddedDataState instanceof DataElementReferenceState) {
@@ -223,15 +223,13 @@ export const RelationElementEditor = observer(
223
223
  (props: {
224
224
  relationElementState: RelationElementState;
225
225
  isReadOnly: boolean;
226
+ hideColumnDefinitions?: boolean;
226
227
  }) => {
227
- const { relationElementState, isReadOnly } = props;
228
+ const { relationElementState, isReadOnly, hideColumnDefinitions } = props;
228
229
  const editorStore = useEditorStore();
229
230
  const embeddedData = relationElementState.relationElement;
230
231
  const canEditColumns =
231
232
  !isReadOnly && relationElementState.supportsColumnEditing;
232
- const [exportFormat, setExportFormat] = useState<'json' | 'csv' | 'sql'>(
233
- 'json',
234
- );
235
233
  const fileInputRef = useRef<HTMLInputElement>(null);
236
234
 
237
235
  const addColumn = (): void => {
@@ -297,39 +295,13 @@ export const RelationElementEditor = observer(
297
295
  }
298
296
  };
299
297
 
300
- const exportData = (): void => {
301
- let content = '';
302
- let filename = '';
303
- let mimeType = '';
304
-
305
- switch (exportFormat) {
306
- case 'json':
307
- content = relationElementState.exportJSON();
308
- filename = 'test_data.json';
309
- mimeType = 'application/json';
310
- break;
311
- case 'csv':
312
- content = relationElementState.exportCSV();
313
- filename = 'test_data.csv';
314
- mimeType = 'text/csv';
315
- break;
316
- case 'sql':
317
- content = relationElementState.exportSQL();
318
- filename = 'test_data.sql';
319
- mimeType = 'text/sql';
320
- break;
321
- default:
322
- content = relationElementState.exportJSON();
323
- filename = 'test_data.json';
324
- mimeType = 'application/json';
325
- break;
326
- }
327
-
328
- const blob = new Blob([content], { type: mimeType });
298
+ const exportCSV = (): void => {
299
+ const content = relationElementState.exportCSV();
300
+ const blob = new Blob([content], { type: 'text/csv' });
329
301
  const url = URL.createObjectURL(blob);
330
302
  const a = document.createElement('a');
331
303
  a.href = url;
332
- a.download = filename;
304
+ a.download = 'test_data.csv';
333
305
  document.body.appendChild(a);
334
306
  a.click();
335
307
  document.body.removeChild(a);
@@ -359,53 +331,101 @@ export const RelationElementEditor = observer(
359
331
 
360
332
  return (
361
333
  <div className="relation-test-data-editor__content">
362
- <div className="relation-test-data-editor__columns">
334
+ <div className="relation-test-data-editor__data">
363
335
  <div className="relation-test-data-editor__section-header">
364
- <div className="relation-test-data-editor__section-title">
365
- Column Definitions
336
+ <div className="relation-test-data-editor__section-header__left">
337
+ <div className="relation-test-data-editor__section-title">
338
+ Test Data ({embeddedData.rows.length} rows)
339
+ </div>
366
340
  </div>
367
- <button
368
- className="btn--icon btn--dark btn--sm"
369
- onClick={addColumn}
370
- disabled={!canEditColumns}
371
- title="Add Column"
372
- >
373
- <PlusIcon />
374
- </button>
375
- </div>
376
- <div className="relation-test-data-editor__columns-grid">
377
- {embeddedData.columns.map((column, index) => (
378
- <div
379
- key={`column-${guaranteeNonNullable(index)}`}
380
- className="relation-test-data-editor__column-row"
381
- >
382
- <input
383
- className="relation-test-data-editor__column-input"
384
- type="text"
385
- value={column}
386
- onChange={(e) => updateColumn(index, e.target.value)}
387
- placeholder="Column Name"
388
- disabled={!canEditColumns}
389
- />
390
- <button
391
- className="btn--icon btn--caution btn--dark btn--sm"
392
- onClick={() => removeColumn(index)}
393
- disabled={!canEditColumns}
394
- title="Remove Column"
395
- >
396
- <TimesIcon />
397
- </button>
341
+ <div className="relation-test-data-editor__toolbar">
342
+ <div className="relation-test-data-editor__toolbar__left">
343
+ <div className="relation-test-data-editor__action-control">
344
+ <span className="relation-test-data-editor__action-control__label">
345
+ Add Column
346
+ </span>
347
+ <button
348
+ className="btn--icon btn--dark btn--sm"
349
+ onClick={addColumn}
350
+ disabled={!canEditColumns}
351
+ title="Add Column"
352
+ >
353
+ <PlusIcon />
354
+ </button>
355
+ </div>
356
+ <div className="relation-test-data-editor__action-control">
357
+ <span className="relation-test-data-editor__action-control__label">
358
+ Add Row
359
+ </span>
360
+ <button
361
+ className="btn--icon btn--dark btn--sm"
362
+ onClick={addRow}
363
+ disabled={isReadOnly || embeddedData.columns.length === 0}
364
+ title="Add Row"
365
+ >
366
+ <PlusIcon />
367
+ </button>
368
+ </div>
369
+ </div>
370
+ <div className="relation-test-data-editor__toolbar__right">
371
+ <div className="relation-test-data-editor__import-controls">
372
+ <span className="relation-test-data-editor__import-controls__label">
373
+ Upload CSV
374
+ </span>
375
+ <input
376
+ ref={fileInputRef}
377
+ type="file"
378
+ accept=".csv"
379
+ onChange={handleFileUpload}
380
+ style={{ display: 'none' }}
381
+ disabled={isReadOnly}
382
+ />
383
+ <button
384
+ className="btn--icon btn--dark btn--sm"
385
+ onClick={() => fileInputRef.current?.click()}
386
+ disabled={isReadOnly}
387
+ title="Upload CSV"
388
+ >
389
+ <UploadIcon />
390
+ </button>
391
+ </div>
398
392
  </div>
399
- ))}
400
- </div>
401
- </div>
402
-
403
- <div className="relation-test-data-editor__data">
404
- <div className="relation-test-data-editor__section-header">
405
- <div className="relation-test-data-editor__section-title">
406
- Test Data ({embeddedData.rows.length} rows)
407
393
  </div>
408
394
  </div>
395
+ {!hideColumnDefinitions ? (
396
+ <div className="relation-test-data-editor__columns">
397
+ <div className="relation-test-data-editor__section-header">
398
+ <div className="relation-test-data-editor__section-title">
399
+ Column Definitions
400
+ </div>
401
+ </div>
402
+ <div className="relation-test-data-editor__columns-grid">
403
+ {embeddedData.columns.map((column, index) => (
404
+ <div
405
+ key={`column-${guaranteeNonNullable(index)}`}
406
+ className="relation-test-data-editor__column-row"
407
+ >
408
+ <input
409
+ className="relation-test-data-editor__column-input"
410
+ type="text"
411
+ value={column}
412
+ onChange={(e) => updateColumn(index, e.target.value)}
413
+ placeholder="Column Name"
414
+ disabled={!canEditColumns}
415
+ />
416
+ <button
417
+ className="btn--icon btn--caution btn--dark btn--sm"
418
+ onClick={() => removeColumn(index)}
419
+ disabled={!canEditColumns}
420
+ title="Remove Column"
421
+ >
422
+ <TimesIcon />
423
+ </button>
424
+ </div>
425
+ ))}
426
+ </div>
427
+ </div>
428
+ ) : null}
409
429
  {embeddedData.rows.length === 0 ? (
410
430
  <div className="relation-test-data-editor__empty-data">
411
431
  <div className="relation-test-data-editor__empty-text">
@@ -415,71 +435,82 @@ export const RelationElementEditor = observer(
415
435
  </div>
416
436
  ) : (
417
437
  <div className="relation-test-data-editor__data-grid">
418
- <div className="relation-test-data-editor__data-header">
419
- {embeddedData.columns.map((column) => (
420
- <div
421
- key={column}
422
- className="relation-test-data-editor__data-header-cell"
423
- >
424
- {column}
425
- {/* <span className="relation-test-data-editor__data-type">
426
- ({column.type})
427
- </span> */}
428
- </div>
429
- ))}
430
- <div className="relation-test-data-editor__data-header-cell relation-test-data-editor__data-actions">
431
- Actions
432
- </div>
433
- </div>
434
- {embeddedData.rows.map((row, rowIndex) => (
435
- <div
436
- key={`row-${guaranteeNonNullable(rowIndex)}`}
437
- className="relation-test-data-editor__data-row"
438
- >
439
- {embeddedData.columns.map((column, columnIndex) => (
440
- <div
441
- key={column}
442
- className="relation-test-data-editor__data-cell"
438
+ <table className="relation-test-data-editor__table">
439
+ <thead>
440
+ <tr>
441
+ {embeddedData.columns.map((column, columnIndex) => (
442
+ <th
443
+ key={column}
444
+ className="relation-test-data-editor__th"
445
+ >
446
+ <div className="relation-test-data-editor__th__inner">
447
+ <span className="relation-test-data-editor__th__label">
448
+ {column}
449
+ </span>
450
+ <button
451
+ className="relation-test-data-editor__th__delete"
452
+ onClick={() => removeColumn(columnIndex)}
453
+ disabled={!canEditColumns}
454
+ title={`Remove column ${column}`}
455
+ >
456
+ <TimesIcon />
457
+ </button>
458
+ </div>
459
+ </th>
460
+ ))}
461
+ <th className="relation-test-data-editor__th relation-test-data-editor__th--actions" />
462
+ </tr>
463
+ </thead>
464
+ <tbody>
465
+ {embeddedData.rows.map((_row, rowIndex) => (
466
+ <tr
467
+ key={`row-${guaranteeNonNullable(rowIndex)}`}
468
+ className="relation-test-data-editor__tr"
443
469
  >
444
- <input
445
- type="text"
446
- value={row.values[columnIndex] ?? ''}
447
- onChange={(e) =>
448
- updateCellValue(rowIndex, columnIndex, e.target.value)
449
- }
450
- disabled={isReadOnly}
451
- className="relation-test-data-editor__data-input"
452
- />
453
- </div>
470
+ {embeddedData.columns.map((column, columnIndex) => (
471
+ <td
472
+ key={column}
473
+ className="relation-test-data-editor__td"
474
+ >
475
+ <input
476
+ type="text"
477
+ value={relationElementState.getDisplayValue(
478
+ rowIndex,
479
+ columnIndex,
480
+ )}
481
+ onChange={(e) =>
482
+ updateCellValue(
483
+ rowIndex,
484
+ columnIndex,
485
+ e.target.value,
486
+ )
487
+ }
488
+ disabled={isReadOnly}
489
+ className="relation-test-data-editor__data-input"
490
+ />
491
+ </td>
492
+ ))}
493
+ <td className="relation-test-data-editor__td relation-test-data-editor__td--actions">
494
+ <button
495
+ className="btn--icon btn--caution btn--dark btn--sm relation-test-data-editor__icon-button--compact"
496
+ onClick={() => removeRow(rowIndex)}
497
+ disabled={isReadOnly}
498
+ title="Remove Row"
499
+ >
500
+ <TimesIcon />
501
+ </button>
502
+ </td>
503
+ </tr>
454
504
  ))}
455
- <div className="relation-test-data-editor__data-cell relation-test-data-editor__data-actions">
456
- <button
457
- className="btn--icon btn--caution btn--dark btn--sm"
458
- onClick={() => removeRow(rowIndex)}
459
- disabled={isReadOnly}
460
- title="Remove Row"
461
- >
462
- <TimesIcon />
463
- </button>
464
- </div>
465
- </div>
466
- ))}
505
+ </tbody>
506
+ </table>
467
507
  </div>
468
508
  )}
469
509
 
470
- <div className="relation-test-data-editor__export-controls">
471
- <div className="relation-test-data-editor__export-controls__btn-group">
510
+ <div className="relation-test-data-editor__footer-actions">
511
+ <div className="relation-test-data-editor__footer-actions__left">
472
512
  <button
473
513
  className="btn--icon btn--dark btn--sm"
474
- onClick={addRow}
475
- disabled={isReadOnly || embeddedData.columns.length === 0}
476
- title="Add Row"
477
- >
478
- <PlusIcon />
479
- </button>
480
-
481
- <button
482
- className="btn--icon btn--caution btn--dark btn--sm"
483
514
  onClick={handleClearData}
484
515
  disabled={isReadOnly || embeddedData.rows.length === 0}
485
516
  title="Clear All Data"
@@ -487,48 +518,20 @@ export const RelationElementEditor = observer(
487
518
  <TrashIcon />
488
519
  </button>
489
520
  </div>
490
- <div className="relation-test-data-editor__export-format">
491
- <label htmlFor="exportFormat">Export as:</label>
492
- <select
493
- id="exportFormat"
494
- value={exportFormat}
495
- onChange={(e) =>
496
- setExportFormat(e.target.value as 'json' | 'csv' | 'sql')
497
- }
498
- disabled={isReadOnly}
499
- className="relation-test-data-editor__export-select"
500
- >
501
- <option value="json">JSON</option>
502
- <option value="csv">CSV</option>
503
- <option value="sql">SQL INSERT</option>
504
- </select>
505
- <button
506
- className="btn--icon btn--dark btn--sm"
507
- onClick={exportData}
508
- disabled={isReadOnly}
509
- title={`Export as ${exportFormat.toUpperCase()}`}
510
- >
511
- <FileImportIcon />
512
- </button>
513
- </div>
514
-
515
- <div className="relation-test-data-editor__import-controls">
516
- <input
517
- ref={fileInputRef}
518
- type="file"
519
- accept=".csv"
520
- onChange={handleFileUpload}
521
- style={{ display: 'none' }}
522
- disabled={isReadOnly}
523
- />
524
- <button
525
- className="btn--icon btn--dark btn--sm"
526
- onClick={() => fileInputRef.current?.click()}
527
- disabled={isReadOnly}
528
- title="Upload a file of CSV"
529
- >
530
- <UploadIcon />
531
- </button>
521
+ <div className="relation-test-data-editor__footer-actions__right">
522
+ <div className="relation-test-data-editor__action-control">
523
+ <span className="relation-test-data-editor__action-control__label">
524
+ Export CSV
525
+ </span>
526
+ <button
527
+ className="btn--icon btn--dark btn--sm"
528
+ onClick={exportCSV}
529
+ disabled={isReadOnly}
530
+ title="Export as CSV"
531
+ >
532
+ <FileImportIcon />
533
+ </button>
534
+ </div>
532
535
  </div>
533
536
  </div>
534
537
  </div>
@@ -538,8 +541,14 @@ export const RelationElementEditor = observer(
538
541
  );
539
542
 
540
543
  export const RelationElementsDataEditor = observer(
541
- (props: { dataState: RelationElementsDataState; isReadOnly: boolean }) => {
542
- const { dataState, isReadOnly } = props;
544
+ (props: {
545
+ dataState: RelationElementsDataState;
546
+ isReadOnly: boolean;
547
+ isSharedData?: boolean | undefined;
548
+ hideColumnDefinitions?: boolean;
549
+ }) => {
550
+ const { dataState, isReadOnly, isSharedData, hideColumnDefinitions } =
551
+ props;
543
552
 
544
553
  useApplicationNavigationContext(
545
554
  LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY.EMBEDDED_DATA_RELATIONAL_EDITOR,
@@ -606,7 +615,7 @@ export const RelationElementsDataEditor = observer(
606
615
  ) : (
607
616
  <span>{relationElementState.relationElement.paths[0]}</span>
608
617
  )}
609
- {!isReadOnly && (
618
+ {!isReadOnly && !isSharedData && (
610
619
  <button
611
620
  className="service-editor__tab__close-btn"
612
621
  onClick={(e): void => {
@@ -621,13 +630,15 @@ export const RelationElementsDataEditor = observer(
621
630
  </div>
622
631
  ))}
623
632
  </div>
624
- <button
625
- onClick={addRelationElement}
626
- disabled={isReadOnly}
627
- title="Add Relation Element"
628
- >
629
- <PlusIcon />
630
- </button>
633
+ {!isSharedData && (
634
+ <button
635
+ onClick={addRelationElement}
636
+ disabled={isReadOnly}
637
+ title="Add Relation Element"
638
+ >
639
+ <PlusIcon />
640
+ </button>
641
+ )}
631
642
  </div>
632
643
  {dataState.relationElementStates.length === 0 ||
633
644
  dataState.activeRelationElement === undefined ? (
@@ -642,6 +653,9 @@ export const RelationElementsDataEditor = observer(
642
653
  <RelationElementEditor
643
654
  relationElementState={dataState.activeRelationElement}
644
655
  isReadOnly={isReadOnly}
656
+ {...(hideColumnDefinitions !== undefined
657
+ ? { hideColumnDefinitions }
658
+ : {})}
645
659
  />
646
660
  )}
647
661
  </PanelContent>
@@ -2231,6 +2231,9 @@ const AccessPointGroupTab = observer(
2231
2231
  const DataProductSidebar = observer(
2232
2232
  (props: { dataProductEditorState: DataProductEditorState }) => {
2233
2233
  const { dataProductEditorState } = props;
2234
+ const showTestingTab =
2235
+ dataProductEditorState.editorStore.applicationStore.config.options
2236
+ .NonProductionFeatureFlag;
2234
2237
  const sidebarTabs = [
2235
2238
  {
2236
2239
  label: DATA_PRODUCT_TAB.HOME,
@@ -2246,11 +2249,15 @@ const DataProductSidebar = observer(
2246
2249
  title: 'Operational Metadata',
2247
2250
  icon: <GearSuggestIcon />,
2248
2251
  },
2249
- {
2250
- label: DATA_PRODUCT_TAB.TESTING,
2251
- title: 'Testing',
2252
- icon: <FlaskIcon />,
2253
- },
2252
+ ...(showTestingTab
2253
+ ? [
2254
+ {
2255
+ label: DATA_PRODUCT_TAB.TESTING,
2256
+ title: 'Testing',
2257
+ icon: <FlaskIcon />,
2258
+ },
2259
+ ]
2260
+ : []),
2254
2261
  {
2255
2262
  label: DATA_PRODUCT_TAB.SUPPORT,
2256
2263
  icon: <QuestionCircleIcon />,
@@ -3359,6 +3366,8 @@ export const DataProductEditor = observer(() => {
3359
3366
  const [showPreview, setShowPreview] = useState(false);
3360
3367
  const [dataProductViewerState, setDataProductViewerState] =
3361
3368
  useState<DataProductViewerState>();
3369
+ const showTestingTab =
3370
+ editorStore.applicationStore.config.options.NonProductionFeatureFlag;
3362
3371
 
3363
3372
  const selectedActivity = dataProductEditorState.selectedTab;
3364
3373
  const renderActivivtyBarTab = (): React.ReactNode => {
@@ -3392,12 +3401,12 @@ export const DataProductEditor = observer(() => {
3392
3401
  />
3393
3402
  );
3394
3403
  case DATA_PRODUCT_TAB.TESTING:
3395
- return (
3404
+ return showTestingTab ? (
3396
3405
  <DataProductTestableEditor
3397
3406
  dataProductEditorState={dataProductEditorState}
3398
3407
  isReadOnly={isReadOnly}
3399
3408
  />
3400
- );
3409
+ ) : null;
3401
3410
  default:
3402
3411
  return null;
3403
3412
  }
@@ -3413,6 +3422,15 @@ export const DataProductEditor = observer(() => {
3413
3422
  );
3414
3423
  }, [dataProductEditorState]);
3415
3424
 
3425
+ useEffect(() => {
3426
+ if (
3427
+ !showTestingTab &&
3428
+ dataProductEditorState.selectedTab === DATA_PRODUCT_TAB.TESTING
3429
+ ) {
3430
+ dataProductEditorState.setSelectedTab(DATA_PRODUCT_TAB.HOME);
3431
+ }
3432
+ }, [dataProductEditorState, showTestingTab]);
3433
+
3416
3434
  useEffect(
3417
3435
  () =>
3418
3436
  autorun(