@finos/legend-application-studio 28.19.53 → 28.19.55

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 (22) hide show
  1. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
  2. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +95 -24
  3. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
  4. package/lib/index.css +2 -2
  5. package/lib/index.css.map +1 -1
  6. package/lib/package.json +1 -1
  7. package/lib/stores/editor/NewElementState.d.ts.map +1 -1
  8. package/lib/stores/editor/NewElementState.js +3 -2
  9. package/lib/stores/editor/NewElementState.js.map +1 -1
  10. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +4 -0
  11. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
  12. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +10 -1
  13. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
  14. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +7 -1
  15. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
  16. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js +18 -0
  17. package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js.map +1 -1
  18. package/package.json +10 -10
  19. package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +265 -26
  20. package/src/stores/editor/NewElementState.ts +3 -0
  21. package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +15 -0
  22. package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +38 -0
@@ -20,6 +20,7 @@ import {
20
20
  type AccessPointGroupState,
21
21
  type AccessPointState,
22
22
  DATA_PRODUCT_TAB,
23
+ DATA_PRODUCT_TYPE,
23
24
  DataProductEditorState,
24
25
  generateUrlToDeployOnOpen,
25
26
  LakehouseAccessPointState,
@@ -116,6 +117,10 @@ import {
116
117
  V1_PureGraphManager,
117
118
  V1_RemoteEngine,
118
119
  validate_PureExecutionMapping,
120
+ InternalDataProductType,
121
+ ExternalDataProductType,
122
+ DataProductLink,
123
+ observer_DataProductLink,
119
124
  } from '@finos/legend-graph';
120
125
  import {
121
126
  accessPoint_setClassification,
@@ -135,10 +140,16 @@ import {
135
140
  runtimeInfo_setDescription,
136
141
  supportInfo_setSupportUrl,
137
142
  supportInfo_setWebsite,
143
+ dataProduct_setType,
138
144
  expertise_setDescription,
139
145
  expertise_addId,
140
146
  expertise_deleteId,
141
147
  dataProduct_deleteExpertise,
148
+ externalType_setLinkURL,
149
+ externalType_setLinkLabel,
150
+ accessPointGroup_setTitle,
151
+ accessPoint_setDescription,
152
+ accessPoint_setTitle,
142
153
  } from '../../../../stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
143
154
  import { LEGEND_STUDIO_TEST_ID } from '../../../../__lib__/LegendStudioTesting.js';
144
155
  import { LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT_KEY } from '../../../../__lib__/LegendStudioApplicationNavigationContext.js';
@@ -235,7 +246,7 @@ const AccessPointTitle = observer(
235
246
  };
236
247
  const updateAccessPointName: React.ChangeEventHandler<HTMLTextAreaElement> =
237
248
  action((event) => {
238
- if (event.target.value.match(/^[0-9a-zA-Z_]+$/)) {
249
+ if (event.target.value.match(/^[0-9a-zA-Z_]*$/)) {
239
250
  accessPoint.id = event.target.value;
240
251
  }
241
252
  });
@@ -259,7 +270,7 @@ const AccessPointTitle = observer(
259
270
  <div
260
271
  className="access-point-editor__name__label"
261
272
  onClick={handleNameEdit}
262
- title="Click to edit access point title"
273
+ title="Click to edit access point name"
263
274
  style={{ flex: '1 1 auto' }}
264
275
  >
265
276
  {accessPoint.id}
@@ -451,25 +462,38 @@ export const LakehouseDataProductAccessPointEditor = observer(
451
462
  .filter(filterByType(LakehouseAccessPointState))
452
463
  .find((pm) => pm.lambdaState.parserError);
453
464
  const [editingDescription, setEditingDescription] = useState(false);
454
- const [isHovering, setIsHovering] = useState(false);
465
+ const [isHoveringDesc, setIsHoveringDesc] = useState(false);
466
+ const [editingTitle, setEditingTitle] = useState(false);
467
+ const [isHoveringTitle, setIsHoveringTitle] = useState(false);
455
468
  const ref = useRef<HTMLDivElement>(null);
456
469
  const [debugOutput, setDebugOutput] = useState('');
457
470
 
458
471
  const handleDescriptionEdit = () => setEditingDescription(true);
459
472
  const handleDescriptionBlur = () => {
460
473
  setEditingDescription(false);
461
- setIsHovering(false);
474
+ setIsHoveringDesc(false);
462
475
  };
463
- const handleMouseOver: React.MouseEventHandler<HTMLDivElement> = () => {
464
- setIsHovering(true);
476
+ const handleMouseOverDesc: React.MouseEventHandler<HTMLDivElement> = () => {
477
+ setIsHoveringDesc(true);
465
478
  };
466
- const handleMouseOut: React.MouseEventHandler<HTMLDivElement> = () => {
467
- setIsHovering(false);
479
+ const handleMouseOutDesc: React.MouseEventHandler<HTMLDivElement> = () => {
480
+ setIsHoveringDesc(false);
468
481
  };
469
- const updateAccessPointDescription: React.ChangeEventHandler<HTMLTextAreaElement> =
470
- action((event) => {
471
- accessPoint.description = event.target.value;
472
- });
482
+
483
+ const handleTitleEdit = () => setEditingTitle(true);
484
+ const handleTitleBlur = () => {
485
+ setEditingTitle(false);
486
+ setIsHoveringTitle(false);
487
+ };
488
+ const handleMouseOverTitle: React.MouseEventHandler<
489
+ HTMLDivElement
490
+ > = () => {
491
+ setIsHoveringTitle(true);
492
+ };
493
+ const handleMouseOutTitle: React.MouseEventHandler<HTMLDivElement> = () => {
494
+ setIsHoveringTitle(false);
495
+ };
496
+
473
497
  const updateAccessPointTargetEnvironment = action(
474
498
  (targetEnvironment: LakehouseTargetEnv) => {
475
499
  accessPoint.targetEnvironment = targetEnvironment;
@@ -758,12 +782,56 @@ export const LakehouseDataProductAccessPointEditor = observer(
758
782
  </ControlledDropdownMenu>
759
783
  </div>
760
784
  </div>
785
+ {editingTitle ? (
786
+ <textarea
787
+ className="access-point-editor__name"
788
+ spellCheck={false}
789
+ value={accessPoint.title}
790
+ onChange={(event) =>
791
+ accessPoint_setTitle(accessPoint, event.target.value)
792
+ }
793
+ placeholder={'Access Point Title'}
794
+ onBlur={handleTitleBlur}
795
+ style={{
796
+ borderColor: 'transparent',
797
+ margin: '0.5rem',
798
+ }}
799
+ />
800
+ ) : (
801
+ <div
802
+ onClick={handleTitleEdit}
803
+ title="Click to edit access point title"
804
+ className="access-point-editor__description-container"
805
+ >
806
+ {accessPoint.title ? (
807
+ <HoverTextArea
808
+ text={accessPoint.title}
809
+ handleMouseOver={handleMouseOverTitle}
810
+ handleMouseOut={handleMouseOutTitle}
811
+ className="access-point-editor__title"
812
+ />
813
+ ) : (
814
+ <div
815
+ className="access-point-editor__group-container__description--warning"
816
+ onMouseOver={handleMouseOverTitle}
817
+ onMouseOut={handleMouseOutTitle}
818
+ style={{ fontSize: '15px' }}
819
+ >
820
+ <ErrorWarnIcon />
821
+ Provide a title for this Access Point
822
+ </div>
823
+ )}
824
+ {isHoveringTitle && hoverIcon()}
825
+ </div>
826
+ )}
761
827
  {editingDescription ? (
762
828
  <textarea
763
829
  className="panel__content__form__section__input"
764
830
  spellCheck={false}
765
831
  value={accessPoint.description ?? ''}
766
- onChange={updateAccessPointDescription}
832
+ onChange={(event) =>
833
+ accessPoint_setDescription(accessPoint, event.target.value)
834
+ }
767
835
  placeholder="Access Point description"
768
836
  onBlur={handleDescriptionBlur}
769
837
  style={{
@@ -783,20 +851,20 @@ export const LakehouseDataProductAccessPointEditor = observer(
783
851
  {accessPoint.description ? (
784
852
  <HoverTextArea
785
853
  text={accessPoint.description}
786
- handleMouseOver={handleMouseOver}
787
- handleMouseOut={handleMouseOut}
854
+ handleMouseOver={handleMouseOverDesc}
855
+ handleMouseOut={handleMouseOutDesc}
788
856
  />
789
857
  ) : (
790
858
  <div
791
859
  className="access-point-editor__group-container__description--warning"
792
- onMouseOver={handleMouseOver}
793
- onMouseOut={handleMouseOut}
860
+ onMouseOver={handleMouseOverDesc}
861
+ onMouseOut={handleMouseOutDesc}
794
862
  >
795
- <WarningIcon />
863
+ <ErrorWarnIcon />
796
864
  {AP_EMPTY_DESC_WARNING}
797
865
  </div>
798
866
  )}
799
- {isHovering && hoverIcon()}
867
+ {isHoveringDesc && hoverIcon()}
800
868
  </div>
801
869
  )}
802
870
  <div className="access-point-editor__content">
@@ -1242,6 +1310,8 @@ const AccessPointGroupEditor = observer(
1242
1310
  groupState.value.id === newNamePlaceholder,
1243
1311
  );
1244
1312
  const [isHoveringName, setIsHoveringName] = useState(false);
1313
+ const [editingTitle, setEditingTitle] = useState(false);
1314
+ const [isHoveringTitle, setIsHoveringTitle] = useState(false);
1245
1315
  const handleDescriptionEdit = () => setEditingDescription(true);
1246
1316
  const handleDescriptionBlur = () => {
1247
1317
  setEditingDescription(false);
@@ -1280,6 +1350,23 @@ const AccessPointGroupEditor = observer(
1280
1350
  }
1281
1351
  };
1282
1352
 
1353
+ const handleTitleEdit = () => setEditingTitle(true);
1354
+ const handleTitleBlur = () => {
1355
+ setEditingTitle(false);
1356
+ setIsHoveringTitle(false);
1357
+ };
1358
+ const handleMouseOverTitle: React.MouseEventHandler<
1359
+ HTMLDivElement
1360
+ > = () => {
1361
+ setIsHoveringTitle(true);
1362
+ };
1363
+ const handleMouseOutTitle: React.MouseEventHandler<HTMLDivElement> = () => {
1364
+ setIsHoveringTitle(false);
1365
+ };
1366
+ const updateGroupTitle = (val: string | undefined): void => {
1367
+ accessPointGroup_setTitle(groupState.value, val);
1368
+ };
1369
+
1283
1370
  const handleRemoveAccessPointGroup = (): void => {
1284
1371
  editorStore.applicationStore.alertService.setActionAlertInfo({
1285
1372
  message: `Are you sure you want to delete Access Point Group ${groupState.value.id} and all of its Access Points?`,
@@ -1314,7 +1401,7 @@ const AccessPointGroupEditor = observer(
1314
1401
  className="access-point-editor__group-container"
1315
1402
  data-testid={LEGEND_STUDIO_TEST_ID.ACCESS_POINT_GROUP_EDITOR}
1316
1403
  >
1317
- <div className="access-point-editor__group-container__title-editor">
1404
+ <div className="access-point-editor__group-container__name-editor">
1318
1405
  {editingName ? (
1319
1406
  <textarea
1320
1407
  className="panel__content__form__section__input"
@@ -1338,13 +1425,13 @@ const AccessPointGroupEditor = observer(
1338
1425
  <div
1339
1426
  onClick={handleNameEdit}
1340
1427
  title="Click to edit group name"
1341
- className="access-point-editor__group-container__title"
1428
+ className="access-point-editor__group-container__name"
1342
1429
  >
1343
1430
  <HoverTextArea
1344
1431
  text={groupState.value.id}
1345
1432
  handleMouseOver={handleMouseOverName}
1346
1433
  handleMouseOut={handleMouseOutName}
1347
- className="access-point-editor__group-container__title"
1434
+ className="access-point-editor__group-container__name"
1348
1435
  />
1349
1436
 
1350
1437
  {isHoveringName && hoverIcon()}
@@ -1363,6 +1450,50 @@ const AccessPointGroupEditor = observer(
1363
1450
  </button>
1364
1451
  )}
1365
1452
  </div>
1453
+ <div className="access-point-editor__group-container__name-editor">
1454
+ {editingTitle ? (
1455
+ <textarea
1456
+ className="panel__content__form__section__input"
1457
+ spellCheck={false}
1458
+ value={groupState.value.title}
1459
+ onChange={(event) => updateGroupTitle(event.target.value)}
1460
+ placeholder="Access Point Group Title"
1461
+ onBlur={handleTitleBlur}
1462
+ style={{
1463
+ overflow: 'hidden',
1464
+ resize: 'none',
1465
+ padding: '0.25rem',
1466
+ margin: '0.5rem 0.5rem 0.5rem 0rem',
1467
+ }}
1468
+ />
1469
+ ) : (
1470
+ <div
1471
+ onClick={handleTitleEdit}
1472
+ title="Click to edit group title"
1473
+ className="access-point-editor__group-container__description"
1474
+ >
1475
+ {groupState.value.title ? (
1476
+ <HoverTextArea
1477
+ text={groupState.value.title}
1478
+ handleMouseOver={handleMouseOverTitle}
1479
+ handleMouseOut={handleMouseOutTitle}
1480
+ className="access-point-editor__group-container__title"
1481
+ />
1482
+ ) : (
1483
+ <div
1484
+ className="access-point-editor__group-container__description--warning"
1485
+ onMouseOver={handleMouseOverTitle}
1486
+ onMouseOut={handleMouseOutTitle}
1487
+ style={{ fontSize: '15px' }}
1488
+ >
1489
+ <ErrorWarnIcon />
1490
+ Provide a title for this Access Point Group
1491
+ </div>
1492
+ )}
1493
+ {isHoveringTitle && hoverIcon()}
1494
+ </div>
1495
+ )}
1496
+ </div>
1366
1497
  <div className="access-point-editor__group-container__description-editor">
1367
1498
  {editingDescription ? (
1368
1499
  <textarea
@@ -1397,7 +1528,7 @@ const AccessPointGroupEditor = observer(
1397
1528
  onMouseOver={handleMouseOverDescription}
1398
1529
  onMouseOut={handleMouseOutDescription}
1399
1530
  >
1400
- <WarningIcon />
1531
+ <ErrorWarnIcon />
1401
1532
  Users request access at the access point group level. Click
1402
1533
  here to add a meaningful description to guide users.
1403
1534
  </div>
@@ -1867,8 +1998,12 @@ const DataProductIconEditor = observer(
1867
1998
  );
1868
1999
 
1869
2000
  const HomeTab = observer(
1870
- (props: { product: DataProduct; isReadOnly: boolean }) => {
1871
- const { product, isReadOnly } = props;
2001
+ (props: {
2002
+ dataProductEditorState: DataProductEditorState;
2003
+ isReadOnly: boolean;
2004
+ }) => {
2005
+ const { dataProductEditorState, isReadOnly } = props;
2006
+ const product = dataProductEditorState.product;
1872
2007
 
1873
2008
  const updateDataProductTitle = (val: string | undefined): void => {
1874
2009
  dataProduct_setTitle(product, val ?? '');
@@ -1879,6 +2014,42 @@ const HomeTab = observer(
1879
2014
  dataProduct_setDescription(product, event.target.value);
1880
2015
  };
1881
2016
 
2017
+ const DATA_PRODUCT_TYPE_OPTIONS = [
2018
+ { label: DATA_PRODUCT_TYPE.INTERNAL, value: DATA_PRODUCT_TYPE.INTERNAL },
2019
+ { label: DATA_PRODUCT_TYPE.EXTERNAL, value: DATA_PRODUCT_TYPE.EXTERNAL },
2020
+ ];
2021
+ const handleDataProductTypeChange = action(
2022
+ (val: { label: string; value: string } | null): void => {
2023
+ if (val?.value === DATA_PRODUCT_TYPE.INTERNAL) {
2024
+ dataProduct_setType(product, new InternalDataProductType());
2025
+ } else if (val?.value === DATA_PRODUCT_TYPE.EXTERNAL) {
2026
+ const externalType = new ExternalDataProductType();
2027
+ const externalLink = observer_DataProductLink(
2028
+ new DataProductLink(''),
2029
+ );
2030
+ externalType.link = externalLink;
2031
+ dataProduct_setType(product, externalType);
2032
+ }
2033
+ },
2034
+ );
2035
+ const handleExternalURLChange: ChangeEventHandler<HTMLTextAreaElement> = (
2036
+ event,
2037
+ ) => {
2038
+ if (
2039
+ product.type instanceof ExternalDataProductType &&
2040
+ event.target.value
2041
+ ) {
2042
+ externalType_setLinkURL(product.type, event.target.value);
2043
+ }
2044
+ };
2045
+ const handleExternalLabelChange: ChangeEventHandler<HTMLTextAreaElement> = (
2046
+ event,
2047
+ ) => {
2048
+ if (product.type instanceof ExternalDataProductType) {
2049
+ externalType_setLinkLabel(product.type, event.target.value);
2050
+ }
2051
+ };
2052
+
1882
2053
  return (
1883
2054
  <div className="panel__content">
1884
2055
  <div className="data-product-editor__home-tab">
@@ -1888,6 +2059,8 @@ const HomeTab = observer(
1888
2059
  prompt="Provide a descriptive name for the Data Product to appear in Marketplace."
1889
2060
  update={updateDataProductTitle}
1890
2061
  placeholder="Enter title"
2062
+ hasError={product.title === '' || product.title === undefined}
2063
+ errorClassName="data-product-editor__textbox-error"
1891
2064
  />
1892
2065
  <div className="panel__content__form__section">
1893
2066
  <div
@@ -1931,6 +2104,67 @@ const HomeTab = observer(
1931
2104
  }}
1932
2105
  />
1933
2106
  </div>
2107
+ <div className="panel__content__form__section">
2108
+ <div
2109
+ className="panel__content__form__section__header__label"
2110
+ style={{ justifyContent: 'space-between', width: '45rem' }}
2111
+ >
2112
+ Data Product Type
2113
+ </div>
2114
+ <div className="panel__content__form__section__header__prompt">
2115
+ Select if this Data Product is Internal or External
2116
+ </div>
2117
+ <div className="panel__content__form__section__list__new-item__input">
2118
+ <CustomSelectorInput
2119
+ options={DATA_PRODUCT_TYPE_OPTIONS}
2120
+ onChange={handleDataProductTypeChange}
2121
+ value={
2122
+ product.type instanceof InternalDataProductType
2123
+ ? DATA_PRODUCT_TYPE_OPTIONS.find(
2124
+ (option) => option.value === DATA_PRODUCT_TYPE.INTERNAL,
2125
+ )
2126
+ : product.type instanceof ExternalDataProductType
2127
+ ? DATA_PRODUCT_TYPE_OPTIONS.find(
2128
+ (option) =>
2129
+ option.value === DATA_PRODUCT_TYPE.EXTERNAL,
2130
+ )
2131
+ : null
2132
+ }
2133
+ darkMode={true}
2134
+ />
2135
+ </div>
2136
+ {product.type instanceof ExternalDataProductType && (
2137
+ <div className="data-product-editor__external-link">
2138
+ <div className="panel__content__form__section__header__prompt">
2139
+ External Link
2140
+ </div>
2141
+ <textarea
2142
+ className="input input-group__input panel__content__form__section__input input--dark input--small"
2143
+ spellCheck={false}
2144
+ disabled={isReadOnly}
2145
+ placeholder="External URL"
2146
+ value={product.type.link.url}
2147
+ onChange={handleExternalURLChange}
2148
+ style={{
2149
+ resize: 'none',
2150
+ padding: '0.25rem 0.5rem',
2151
+ }}
2152
+ />
2153
+ <textarea
2154
+ className="input input-group__input panel__content__form__section__input input--dark input--small"
2155
+ spellCheck={false}
2156
+ disabled={isReadOnly}
2157
+ placeholder="External Link Label"
2158
+ value={product.type.link.label ?? ''}
2159
+ onChange={handleExternalLabelChange}
2160
+ style={{
2161
+ resize: 'none',
2162
+ padding: '0.25rem 0.5rem',
2163
+ }}
2164
+ />
2165
+ </div>
2166
+ )}
2167
+ </div>
1934
2168
  <DataProductIconEditor product={product} isReadOnly={isReadOnly} />
1935
2169
  </div>
1936
2170
  </div>
@@ -2411,7 +2645,12 @@ export const DataProductEditor = observer(() => {
2411
2645
  const renderActivivtyBarTab = (): React.ReactNode => {
2412
2646
  switch (selectedActivity) {
2413
2647
  case DATA_PRODUCT_TAB.HOME:
2414
- return <HomeTab product={product} isReadOnly={isReadOnly} />;
2648
+ return (
2649
+ <HomeTab
2650
+ dataProductEditorState={dataProductEditorState}
2651
+ isReadOnly={isReadOnly}
2652
+ />
2653
+ );
2415
2654
  case DATA_PRODUCT_TAB.SUPPORT:
2416
2655
  return (
2417
2656
  <SupportTab
@@ -90,6 +90,7 @@ import {
90
90
  ModelAccessPointGroup,
91
91
  stub_Mapping,
92
92
  DataProductRuntimeInfo,
93
+ InternalDataProductType,
93
94
  } from '@finos/legend-graph';
94
95
  import type { DSL_Mapping_LegendStudioApplicationPlugin_Extension } from '../extensions/DSL_Mapping_LegendStudioApplicationPlugin_Extension.js';
95
96
  import {
@@ -117,6 +118,7 @@ import { createEmbeddedData } from './editor-state/element-editor-state/data/Emb
117
118
  import {
118
119
  dataProduct_addAccessPointGroup,
119
120
  dataProduct_setTitle,
121
+ dataProduct_setType,
120
122
  } from '../graph-modifier/DSL_DataProduct_GraphModifierHelper.js';
121
123
 
122
124
  export const CUSTOM_LABEL = '(custom)';
@@ -547,6 +549,7 @@ export class NewLakehouseDataProductDriver extends NewElementDriver<DataProduct>
547
549
  override createElement(name: string): DataProduct {
548
550
  const dataProduct = new DataProduct(name);
549
551
  dataProduct_setTitle(dataProduct, this.title);
552
+ dataProduct_setType(dataProduct, new InternalDataProductType());
550
553
 
551
554
  if (this.type === DataProductType.LAKEHOUSE) {
552
555
  const defaultGroup = new AccessPointGroup();
@@ -108,6 +108,11 @@ export enum DATA_PRODUCT_TAB {
108
108
  APG = 'APG',
109
109
  }
110
110
 
111
+ export enum DATA_PRODUCT_TYPE {
112
+ INTERNAL = 'Internal',
113
+ EXTERNAL = 'External',
114
+ }
115
+
111
116
  export class AccessPointState {
112
117
  readonly uuid = uuid();
113
118
  state: AccessPointGroupState;
@@ -356,8 +361,18 @@ export class AccessPointGroupState {
356
361
  return (
357
362
  this.accessPointStates.length === 0 ||
358
363
  this.value.id === '' ||
364
+ !this.value.description ||
365
+ !this.value.title ||
359
366
  Boolean(
360
367
  this.accessPointStates.find((apState) => apState.accessPoint.id === ''),
368
+ ) ||
369
+ Boolean(
370
+ this.accessPointStates.find((apState) => !apState.accessPoint.title),
371
+ ) ||
372
+ Boolean(
373
+ this.accessPointStates.find(
374
+ (apState) => !apState.accessPoint.description,
375
+ ),
361
376
  )
362
377
  );
363
378
  }
@@ -34,6 +34,8 @@ import {
34
34
  type DataProductDiagram,
35
35
  type DataProductElementScope,
36
36
  observe_APG,
37
+ type DataProductType,
38
+ type ExternalDataProductType,
37
39
  observe_Expertise,
38
40
  type Expertise,
39
41
  } from '@finos/legend-graph';
@@ -64,6 +66,18 @@ export const accessPoint_setReproducible = action(
64
66
  },
65
67
  );
66
68
 
69
+ export const accessPoint_setDescription = action(
70
+ (accessPoint: AccessPoint, description: string | undefined) => {
71
+ accessPoint.description = description;
72
+ },
73
+ );
74
+
75
+ export const accessPoint_setTitle = action(
76
+ (accessPoint: AccessPoint, title: string | undefined) => {
77
+ accessPoint.title = title;
78
+ },
79
+ );
80
+
67
81
  export const accessPointGroup_setDescription = action(
68
82
  (group: AccessPointGroup, description: string) => {
69
83
  group.description = description;
@@ -76,6 +90,12 @@ export const accessPointGroup_setName = action(
76
90
  },
77
91
  );
78
92
 
93
+ export const accessPointGroup_setTitle = action(
94
+ (group: AccessPointGroup, title: string | undefined) => {
95
+ group.title = title;
96
+ },
97
+ );
98
+
79
99
  export const modelAccessPointGroup_setDefaultRuntime = action(
80
100
  (group: ModelAccessPointGroup, runtime: DataProductRuntimeInfo) => {
81
101
  group.defaultRuntime = runtime;
@@ -241,6 +261,24 @@ export const dataProduct_setDescription = action(
241
261
  },
242
262
  );
243
263
 
264
+ export const dataProduct_setType = action(
265
+ (product: DataProduct, type: DataProductType) => {
266
+ product.type = type;
267
+ },
268
+ );
269
+
270
+ export const externalType_setLinkURL = action(
271
+ (external: ExternalDataProductType, url: string) => {
272
+ external.link.url = url;
273
+ },
274
+ );
275
+
276
+ export const externalType_setLinkLabel = action(
277
+ (external: ExternalDataProductType, label: string | undefined) => {
278
+ external.link.label = label;
279
+ },
280
+ );
281
+
244
282
  export const dataProduct_setIcon = action(
245
283
  (product: DataProduct, icon: DataProductIcon | undefined) => {
246
284
  product.icon = icon;