@finos/legend-application-studio 28.21.7 → 28.21.9

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 (27) hide show
  1. package/lib/application/LegendStudioApplicationConfig.d.ts +4 -0
  2. package/lib/application/LegendStudioApplicationConfig.d.ts.map +1 -1
  3. package/lib/application/LegendStudioApplicationConfig.js +5 -0
  4. package/lib/application/LegendStudioApplicationConfig.js.map +1 -1
  5. package/lib/components/editor/editor-group/accessor/AccessorQueryBuilderHelper.js +1 -1
  6. package/lib/components/editor/editor-group/accessor/AccessorQueryBuilderHelper.js.map +1 -1
  7. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
  8. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +7 -20
  9. package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
  10. package/lib/components/editor/editor-group/service-editor/ServiceEditor.d.ts.map +1 -1
  11. package/lib/components/editor/editor-group/service-editor/ServiceEditor.js +39 -6
  12. package/lib/components/editor/editor-group/service-editor/ServiceEditor.js.map +1 -1
  13. package/lib/index.css +2 -2
  14. package/lib/index.css.map +1 -1
  15. package/lib/package.json +1 -1
  16. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.d.ts.map +1 -1
  17. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js +3 -5
  18. package/lib/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.js.map +1 -1
  19. package/lib/stores/extensions/DSL_Service_LegendStudioApplicationPlugin_Extension.d.ts +6 -1
  20. package/lib/stores/extensions/DSL_Service_LegendStudioApplicationPlugin_Extension.d.ts.map +1 -1
  21. package/package.json +11 -11
  22. package/src/application/LegendStudioApplicationConfig.ts +9 -0
  23. package/src/components/editor/editor-group/accessor/AccessorQueryBuilderHelper.tsx +1 -1
  24. package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +8 -26
  25. package/src/components/editor/editor-group/service-editor/ServiceEditor.tsx +93 -7
  26. package/src/stores/editor/editor-state/element-editor-state/dataProduct/testable/DataProductTestableState.ts +10 -13
  27. package/src/stores/extensions/DSL_Service_LegendStudioApplicationPlugin_Extension.ts +10 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finos/legend-application-studio",
3
- "version": "28.21.7",
3
+ "version": "28.21.9",
4
4
  "description": "Legend Studio application core",
5
5
  "keywords": [
6
6
  "legend",
@@ -47,17 +47,17 @@
47
47
  },
48
48
  "dependencies": {
49
49
  "@dagrejs/dagre": "1.1.4",
50
- "@finos/legend-application": "16.0.107",
51
- "@finos/legend-art": "7.1.148",
52
- "@finos/legend-code-editor": "2.0.172",
53
- "@finos/legend-data-cube": "0.3.89",
54
- "@finos/legend-extension-dsl-data-product": "0.0.82",
55
- "@finos/legend-extension-dsl-diagram": "8.1.236",
56
- "@finos/legend-graph": "32.6.4",
57
- "@finos/legend-lego": "2.0.192",
58
- "@finos/legend-query-builder": "4.18.11",
50
+ "@finos/legend-application": "16.0.108",
51
+ "@finos/legend-art": "7.1.149",
52
+ "@finos/legend-code-editor": "2.0.174",
53
+ "@finos/legend-data-cube": "0.3.91",
54
+ "@finos/legend-extension-dsl-data-product": "0.0.84",
55
+ "@finos/legend-extension-dsl-diagram": "8.1.238",
56
+ "@finos/legend-graph": "32.6.6",
57
+ "@finos/legend-lego": "2.0.194",
58
+ "@finos/legend-query-builder": "4.18.13",
59
59
  "@finos/legend-server-depot": "6.1.12",
60
- "@finos/legend-server-lakehouse": "0.3.53",
60
+ "@finos/legend-server-lakehouse": "0.3.55",
61
61
  "@finos/legend-server-sdlc": "5.4.3",
62
62
  "@finos/legend-server-showcase": "0.2.66",
63
63
  "@finos/legend-shared": "11.0.25",
@@ -191,6 +191,7 @@ export interface LegendStudioApplicationConfigurationData
191
191
  query?: { url: string };
192
192
  showcase?: { url: string };
193
193
  pct?: { reportUrl: string };
194
+ legendAI?: { url: string };
194
195
  }
195
196
 
196
197
  export class LegendStudioApplicationConfig extends LegendApplicationConfig {
@@ -205,6 +206,7 @@ export class LegendStudioApplicationConfig extends LegendApplicationConfig {
205
206
  readonly queryApplicationUrl?: string | undefined;
206
207
  readonly showcaseServerUrl?: string | undefined;
207
208
  readonly pctReportUrl?: string | undefined;
209
+ readonly legendAIUrl?: string | undefined;
208
210
 
209
211
  constructor(
210
212
  input: LegendApplicationConfigurationInput<LegendStudioApplicationConfigurationData>,
@@ -275,6 +277,13 @@ export class LegendStudioApplicationConfig extends LegendApplicationConfig {
275
277
  );
276
278
  }
277
279
 
280
+ // legend AI
281
+ if (input.configData.legendAI?.url) {
282
+ this.legendAIUrl = LegendApplicationConfig.resolveAbsoluteUrl(
283
+ input.configData.legendAI.url,
284
+ );
285
+ }
286
+
278
287
  // options
279
288
  this.options = LegendStudioApplicationCoreOptions.create(
280
289
  input.configData.extensions?.core ?? {},
@@ -45,7 +45,7 @@ export const queryAccessorSource = async (
45
45
  editorStore.applicationStore.config.options.queryBuilderConfig,
46
46
  editorStore.editorMode.getSourceInfo(),
47
47
  );
48
- queryBuilderState.changeAccessorOwner(element);
48
+ await queryBuilderState.changeAccessorOwner(element);
49
49
  const compatibleRuntimes = getCompatibleRuntimesFromAccessorOwner(
50
50
  element,
51
51
  editorStore.graphManagerState,
@@ -847,7 +847,7 @@ export const LakehouseDataProductAccessPointEditor = observer(
847
847
  applicationStore.config.options.queryBuilderConfig,
848
848
  editorStore.editorMode.getSourceInfo(),
849
849
  );
850
- queryBuilderState.changeAccessorOwner(ingestDefinition);
850
+ await queryBuilderState.changeAccessorOwner(ingestDefinition);
851
851
  const compatibleRuntimes = getCompatibleRuntimesFromAccessorOwner(
852
852
  ingestDefinition,
853
853
  editorStore.graphManagerState,
@@ -2232,9 +2232,6 @@ const AccessPointGroupTab = observer(
2232
2232
  const DataProductSidebar = observer(
2233
2233
  (props: { dataProductEditorState: DataProductEditorState }) => {
2234
2234
  const { dataProductEditorState } = props;
2235
- const showTestingTab =
2236
- dataProductEditorState.editorStore.applicationStore.config.options
2237
- .NonProductionFeatureFlag;
2238
2235
  const sidebarTabs = [
2239
2236
  {
2240
2237
  label: DATA_PRODUCT_TAB.HOME,
@@ -2250,15 +2247,11 @@ const DataProductSidebar = observer(
2250
2247
  title: 'Operational Metadata',
2251
2248
  icon: <GearSuggestIcon />,
2252
2249
  },
2253
- ...(showTestingTab
2254
- ? [
2255
- {
2256
- label: DATA_PRODUCT_TAB.TESTING,
2257
- title: 'Testing',
2258
- icon: <FlaskIcon />,
2259
- },
2260
- ]
2261
- : []),
2250
+ {
2251
+ label: DATA_PRODUCT_TAB.TESTING,
2252
+ title: 'Testing',
2253
+ icon: <FlaskIcon />,
2254
+ },
2262
2255
  {
2263
2256
  label: DATA_PRODUCT_TAB.SUPPORT,
2264
2257
  icon: <QuestionCircleIcon />,
@@ -3367,8 +3360,6 @@ export const DataProductEditor = observer(() => {
3367
3360
  const [showPreview, setShowPreview] = useState(false);
3368
3361
  const [dataProductViewerState, setDataProductViewerState] =
3369
3362
  useState<DataProductViewerState>();
3370
- const showTestingTab =
3371
- editorStore.applicationStore.config.options.NonProductionFeatureFlag;
3372
3363
 
3373
3364
  const selectedActivity = dataProductEditorState.selectedTab;
3374
3365
  const renderActivivtyBarTab = (): React.ReactNode => {
@@ -3402,12 +3393,12 @@ export const DataProductEditor = observer(() => {
3402
3393
  />
3403
3394
  );
3404
3395
  case DATA_PRODUCT_TAB.TESTING:
3405
- return showTestingTab ? (
3396
+ return (
3406
3397
  <DataProductTestableEditor
3407
3398
  dataProductEditorState={dataProductEditorState}
3408
3399
  isReadOnly={isReadOnly}
3409
3400
  />
3410
- ) : null;
3401
+ );
3411
3402
  default:
3412
3403
  return null;
3413
3404
  }
@@ -3423,15 +3414,6 @@ export const DataProductEditor = observer(() => {
3423
3414
  );
3424
3415
  }, [dataProductEditorState]);
3425
3416
 
3426
- useEffect(() => {
3427
- if (
3428
- !showTestingTab &&
3429
- dataProductEditorState.selectedTab === DATA_PRODUCT_TAB.TESTING
3430
- ) {
3431
- dataProductEditorState.setSelectedTab(DATA_PRODUCT_TAB.HOME);
3432
- }
3433
- }, [dataProductEditorState, showTestingTab]);
3434
-
3435
3417
  useEffect(
3436
3418
  () =>
3437
3419
  autorun(
@@ -35,6 +35,7 @@ import {
35
35
  CustomSelectorInput,
36
36
  PanelFormValidatedTextField,
37
37
  PanelContentLists,
38
+ SparkleIcon,
38
39
  } from '@finos/legend-art';
39
40
  import { debounce, prettyCONSTName } from '@finos/legend-shared';
40
41
  import { ServiceExecutionEditor } from './ServiceExecutionEditor.js';
@@ -72,6 +73,7 @@ import { flowResult } from 'mobx';
72
73
  import { LEGEND_STUDIO_DOCUMENTATION_KEY } from '../../../../__lib__/LegendStudioDocumentation.js';
73
74
  import { DocumentationLink } from '@finos/legend-lego/application';
74
75
  import { ServicePostValidationsEditor } from './ServicePostValidationEditor.js';
76
+ import type { DSL_Service_LegendStudioApplicationPlugin_Extension } from '../../../../stores/extensions/DSL_Service_LegendStudioApplicationPlugin_Extension.js';
75
77
 
76
78
  type UserOption = { label: string; value: string };
77
79
 
@@ -242,6 +244,43 @@ const ServiceGeneralEditor = observer(() => {
242
244
  }
243
245
  };
244
246
 
247
+ // AI documentation suggestion
248
+ const legendAIUrl = editorStore.applicationStore.config.legendAIUrl;
249
+ const aiDocSuggester = legendAIUrl
250
+ ? editorStore.pluginManager
251
+ .getApplicationPlugins()
252
+ .map((p) =>
253
+ (
254
+ p as DSL_Service_LegendStudioApplicationPlugin_Extension
255
+ ).getExtraServiceDocumentationAISuggester?.(),
256
+ )
257
+ .find(Boolean)
258
+ : undefined;
259
+ const [isSuggestingWithAI, setIsSuggestingWithAI] = useState(false);
260
+ const [aiDocSuggestion, setAIDocSuggestion] = useState<string | undefined>(
261
+ undefined,
262
+ );
263
+ const suggestDocumentationWithAI = async (): Promise<void> => {
264
+ if (!aiDocSuggester || !legendAIUrl) {
265
+ return;
266
+ }
267
+ setIsSuggestingWithAI(true);
268
+ setAIDocSuggestion(undefined);
269
+ try {
270
+ const suggestion = await aiDocSuggester(service, legendAIUrl);
271
+ setAIDocSuggestion(suggestion);
272
+ } finally {
273
+ setIsSuggestingWithAI(false);
274
+ }
275
+ };
276
+ const applyAIDocSuggestion = (): void => {
277
+ if (!aiDocSuggestion) {
278
+ return;
279
+ }
280
+ service_setDocumentation(service, aiDocSuggestion);
281
+ setAIDocSuggestion(undefined);
282
+ };
283
+
245
284
  const changeTitle: React.ChangeEventHandler<HTMLInputElement> = (event) => {
246
285
  if (!isReadOnly) {
247
286
  service_setTitle(service, event.target.value);
@@ -392,29 +431,76 @@ const ServiceGeneralEditor = observer(() => {
392
431
  <div className="panel__content__form__section">
393
432
  <div className="panel__content__form__section__header__label">
394
433
  Documentation
434
+ {aiDocSuggestion && (
435
+ <span className="service-editor__ai-suggestion-badge">
436
+ <SparkleIcon />
437
+ AI Suggestion
438
+ </span>
439
+ )}
440
+ {aiDocSuggester && !aiDocSuggestion && (
441
+ <button
442
+ className="service-editor__ai-suggest-btn"
443
+ onClick={(): void => {
444
+ suggestDocumentationWithAI().catch(
445
+ editorStore.applicationStore.alertUnhandledError,
446
+ );
447
+ }}
448
+ disabled={isSuggestingWithAI || isReadOnly}
449
+ title="Use AI to suggest documentation for this service"
450
+ >
451
+ <SparkleIcon />
452
+ <span>
453
+ {isSuggestingWithAI ? 'Suggesting...' : 'Suggest with AI'}
454
+ </span>
455
+ </button>
456
+ )}
395
457
  </div>
396
458
  <div
397
459
  className={clsx('panel__content__form__section__header__prompt', {
398
- 'service-editor__general__warning-prompt': !service.documentation,
460
+ 'service-editor__general__warning-prompt':
461
+ !service.documentation && !aiDocSuggestion,
399
462
  })}
400
463
  >
401
- {!service.documentation && (
464
+ {!service.documentation && !aiDocSuggestion && (
402
465
  <ErrorWarnIcon style={{ fontSize: '1.2rem' }} />
403
466
  )}
404
467
  {`Provide a brief description of the service's functionalities and usage`}
405
468
  </div>
406
469
  <textarea
407
- className="panel__content__form__section__textarea service-editor__documentation__input"
470
+ className={clsx(
471
+ 'panel__content__form__section__textarea service-editor__documentation__input',
472
+ { 'textarea--ai-suggested': Boolean(aiDocSuggestion) },
473
+ )}
408
474
  spellCheck={false}
409
475
  disabled={isReadOnly}
410
- value={service.documentation}
476
+ readOnly={Boolean(aiDocSuggestion)}
477
+ value={aiDocSuggestion ?? service.documentation}
411
478
  onChange={changeDocumentation}
412
479
  style={{
413
- borderColor: !service.documentation
414
- ? 'var(--color-red-300)'
415
- : undefined,
480
+ borderColor:
481
+ !service.documentation && !aiDocSuggestion
482
+ ? 'var(--color-red-300)'
483
+ : undefined,
416
484
  }}
417
485
  />
486
+ {aiDocSuggestion && (
487
+ <div className="service-editor__ai-suggestion__actions">
488
+ <button
489
+ className="btn btn--dark service-editor__ai-suggestion__apply-btn"
490
+ onClick={applyAIDocSuggestion}
491
+ title="Apply AI suggestion to documentation"
492
+ >
493
+ Apply Suggestion
494
+ </button>
495
+ <button
496
+ className="btn service-editor__ai-suggestion__dismiss-btn"
497
+ onClick={(): void => setAIDocSuggestion(undefined)}
498
+ title="Dismiss AI suggestion"
499
+ >
500
+ Dismiss
501
+ </button>
502
+ </div>
503
+ )}
418
504
  </div>
419
505
  </PanelForm>
420
506
  <PanelForm>
@@ -322,11 +322,12 @@ export class DataProductElementTestDataState {
322
322
  let columns: string[] = [];
323
323
  try {
324
324
  if (element instanceof IngestDefinition) {
325
- const accessor = graphManager.createAccessorFromPackageableElement(
326
- element,
327
- graph,
328
- { schemaName: undefined, tableName: item.id },
329
- );
325
+ const accessor =
326
+ await graphManager.createAccessorFromPackageableElement(
327
+ element,
328
+ graph,
329
+ { schemaName: undefined, tableName: item.id },
330
+ );
330
331
  if (accessor) {
331
332
  columns = accessor.relationType.columns.map((c) => c.name);
332
333
  }
@@ -575,10 +576,8 @@ export class DataProductTestSuiteState extends TestableTestSuiteEditorState {
575
576
  rawLambdaForTest,
576
577
  this.editorStore.graphManagerState.graph,
577
578
  )) as Accessor[];
578
- resolvedAccessors = all.filter(
579
- (accessor) =>
580
- isIngestOrDataProductAccessor(accessor) &&
581
- accessor.parentElement.path !== this.testableState.dataProduct.path,
579
+ resolvedAccessors = all.filter((accessor) =>
580
+ isIngestOrDataProductAccessor(accessor),
582
581
  );
583
582
  }
584
583
 
@@ -833,10 +832,8 @@ export class DataProductTestableState {
833
832
  rawLambdaForSuite,
834
833
  this.editorStore.graphManagerState.graph,
835
834
  )) as Accessor[];
836
- const externalAccessors = all.filter(
837
- (accessor) =>
838
- isIngestOrDataProductAccessor(accessor) &&
839
- accessor.parentElement.path !== dp.path,
835
+ const externalAccessors = all.filter((accessor) =>
836
+ isIngestOrDataProductAccessor(accessor),
840
837
  );
841
838
  const byElement = new Map<string, Accessor[]>();
842
839
  for (const acc of externalAccessors) {
@@ -23,6 +23,7 @@ import type {
23
23
  ObserverContext,
24
24
  PostDeploymentProperties,
25
25
  HostedService,
26
+ Service,
26
27
  } from '@finos/legend-graph';
27
28
 
28
29
  export type ServiceTestRuntimeConnectionBuilder = (
@@ -48,6 +49,11 @@ export type PostDeploymentActionTypeGetter = (
48
49
  metamodel: PostDeploymentProperties,
49
50
  ) => string | undefined;
50
51
 
52
+ export type ServiceDocumentationAISuggester = (
53
+ service: Service,
54
+ legendAIUrl: string,
55
+ ) => Promise<string>;
56
+
51
57
  export interface DSL_Service_LegendStudioApplicationPlugin_Extension
52
58
  extends DSL_LegendStudioApplicationPlugin_Extension {
53
59
  /**
@@ -70,4 +76,8 @@ export interface DSL_Service_LegendStudioApplicationPlugin_Extension
70
76
  * Get the list of the Classifiers for Post Deployment Actions.
71
77
  */
72
78
  getExtraPostDeploymentActionClassifierGetters?(): PostDeploymentActionTypeGetter[];
79
+ /**
80
+ * Get a suggester function that generates AI-suggested documentation for a service.
81
+ */
82
+ getExtraServiceDocumentationAISuggester?(): ServiceDocumentationAISuggester;
73
83
  }