@finos/legend-lego 2.0.196 → 2.0.198
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.
- package/lib/code-editor/CodeEditor.d.ts.map +1 -1
- package/lib/code-editor/CodeEditor.js +14 -1
- package/lib/code-editor/CodeEditor.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/legend-ai/LegendAIDocEnrichment.d.ts +60 -0
- package/lib/legend-ai/LegendAIDocEnrichment.d.ts.map +1 -0
- package/lib/legend-ai/LegendAIDocEnrichment.js +429 -0
- package/lib/legend-ai/LegendAIDocEnrichment.js.map +1 -0
- package/lib/legend-ai/LegendAITypes.d.ts +127 -1
- package/lib/legend-ai/LegendAITypes.d.ts.map +1 -1
- package/lib/legend-ai/LegendAITypes.js +111 -2
- package/lib/legend-ai/LegendAITypes.js.map +1 -1
- package/lib/legend-ai/LegendAI_LegendApplicationPlugin_Extension.d.ts +14 -1
- package/lib/legend-ai/LegendAI_LegendApplicationPlugin_Extension.d.ts.map +1 -1
- package/lib/legend-ai/LegendAI_LegendApplicationPlugin_Extension.js.map +1 -1
- package/lib/legend-ai/__test-utils__/LegendAITestUtils.d.ts +2 -1
- package/lib/legend-ai/__test-utils__/LegendAITestUtils.d.ts.map +1 -1
- package/lib/legend-ai/__test-utils__/LegendAITestUtils.js +37 -2
- package/lib/legend-ai/__test-utils__/LegendAITestUtils.js.map +1 -1
- package/lib/legend-ai/components/LegendAIAnalysisPanel.d.ts.map +1 -1
- package/lib/legend-ai/components/LegendAIAnalysisPanel.js +11 -12
- package/lib/legend-ai/components/LegendAIAnalysisPanel.js.map +1 -1
- package/lib/legend-ai/components/LegendAIAnalysisUtils.d.ts +7 -0
- package/lib/legend-ai/components/LegendAIAnalysisUtils.d.ts.map +1 -1
- package/lib/legend-ai/components/LegendAIAnalysisUtils.js +106 -41
- package/lib/legend-ai/components/LegendAIAnalysisUtils.js.map +1 -1
- package/lib/legend-ai/components/LegendAIChat.d.ts +1 -5
- package/lib/legend-ai/components/LegendAIChat.d.ts.map +1 -1
- package/lib/legend-ai/components/LegendAIChat.js +168 -109
- package/lib/legend-ai/components/LegendAIChat.js.map +1 -1
- package/lib/legend-ai/components/LegendAIChatHelpers.d.ts +21 -0
- package/lib/legend-ai/components/LegendAIChatHelpers.d.ts.map +1 -0
- package/lib/legend-ai/components/LegendAIChatHelpers.js +85 -0
- package/lib/legend-ai/components/LegendAIChatHelpers.js.map +1 -0
- package/lib/legend-ai/components/LegendAIChatInput.d.ts +21 -0
- package/lib/legend-ai/components/LegendAIChatInput.d.ts.map +1 -0
- package/lib/legend-ai/components/LegendAIChatInput.js +78 -0
- package/lib/legend-ai/components/LegendAIChatInput.js.map +1 -0
- package/lib/legend-ai/components/LegendAIScopeSelector.d.ts +25 -0
- package/lib/legend-ai/components/LegendAIScopeSelector.d.ts.map +1 -0
- package/lib/legend-ai/components/LegendAIScopeSelector.js +85 -0
- package/lib/legend-ai/components/LegendAIScopeSelector.js.map +1 -0
- package/lib/legend-ai/index.d.ts +8 -3
- package/lib/legend-ai/index.d.ts.map +1 -1
- package/lib/legend-ai/index.js +8 -3
- package/lib/legend-ai/index.js.map +1 -1
- package/lib/legend-ai/stores/LegendAIChatProcessors.d.ts +105 -0
- package/lib/legend-ai/stores/LegendAIChatProcessors.d.ts.map +1 -0
- package/lib/legend-ai/stores/LegendAIChatProcessors.js +1482 -0
- package/lib/legend-ai/stores/LegendAIChatProcessors.js.map +1 -0
- package/lib/legend-ai/stores/LegendAIChatState.d.ts +2 -35
- package/lib/legend-ai/stores/LegendAIChatState.d.ts.map +1 -1
- package/lib/legend-ai/stores/LegendAIChatState.js +114 -949
- package/lib/legend-ai/stores/LegendAIChatState.js.map +1 -1
- package/package.json +5 -5
- package/src/code-editor/CodeEditor.tsx +19 -0
- package/src/legend-ai/LegendAIDocEnrichment.ts +572 -0
- package/src/legend-ai/LegendAITypes.ts +213 -5
- package/src/legend-ai/LegendAI_LegendApplicationPlugin_Extension.ts +25 -0
- package/src/legend-ai/__test-utils__/LegendAITestUtils.ts +55 -1
- package/src/legend-ai/components/LegendAIAnalysisPanel.tsx +14 -34
- package/src/legend-ai/components/LegendAIAnalysisUtils.ts +157 -47
- package/src/legend-ai/components/LegendAIChat.tsx +389 -206
- package/src/legend-ai/components/LegendAIChatHelpers.ts +117 -0
- package/src/legend-ai/components/LegendAIChatInput.tsx +209 -0
- package/src/legend-ai/components/LegendAIScopeSelector.tsx +199 -0
- package/src/legend-ai/index.ts +31 -4
- package/src/legend-ai/stores/LegendAIChatProcessors.ts +2563 -0
- package/src/legend-ai/stores/LegendAIChatState.ts +161 -1697
- package/tsconfig.json +5 -0
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
LegendAIChartType,
|
|
21
21
|
} from '../LegendAI_LegendApplicationPlugin_Extension.js';
|
|
22
22
|
import type { LegendAIGridData } from '../LegendAITypes.js';
|
|
23
|
-
import {
|
|
23
|
+
import { isNumber, isString } from '@finos/legend-shared';
|
|
24
24
|
|
|
25
25
|
const CHART_PALETTE_COUNT = 10;
|
|
26
26
|
const MAX_CHART_ITEMS = 10;
|
|
@@ -36,10 +36,17 @@ interface ColumnProfile {
|
|
|
36
36
|
isNumeric: boolean;
|
|
37
37
|
isString: boolean;
|
|
38
38
|
uniqueCount: number;
|
|
39
|
-
|
|
39
|
+
nonNullCount: number;
|
|
40
40
|
numericValues: number[];
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export interface LegendAIGridAnalysis {
|
|
44
|
+
metrics: LegendAIKeyMetric[];
|
|
45
|
+
chartType: LegendAIChartType;
|
|
46
|
+
chartData: LegendAIChartDataPoint[];
|
|
47
|
+
numericColumnName: string | undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
43
50
|
function profileColumns(gridData: LegendAIGridData): ColumnProfile[] {
|
|
44
51
|
const rows =
|
|
45
52
|
gridData.rowData.length > MAX_PROFILE_SAMPLE
|
|
@@ -48,20 +55,45 @@ function profileColumns(gridData: LegendAIGridData): ColumnProfile[] {
|
|
|
48
55
|
|
|
49
56
|
return gridData.columnDefs.map((col) => {
|
|
50
57
|
const field = col.field ?? col.colId ?? '';
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
58
|
+
let nonNullCount = 0;
|
|
59
|
+
let stringCount = 0;
|
|
60
|
+
const numericValues: number[] = [];
|
|
61
|
+
const unique = new Set<string>();
|
|
62
|
+
|
|
63
|
+
for (const r of rows) {
|
|
64
|
+
const v = r[field];
|
|
65
|
+
if (v !== null && v !== undefined) {
|
|
66
|
+
nonNullCount++;
|
|
67
|
+
unique.add(String(v));
|
|
68
|
+
if (isNumber(v)) {
|
|
69
|
+
numericValues.push(v);
|
|
70
|
+
}
|
|
71
|
+
if (isString(v)) {
|
|
72
|
+
stringCount++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
54
77
|
return {
|
|
55
78
|
name: field,
|
|
56
|
-
isNumeric: numericValues.length ===
|
|
57
|
-
isString:
|
|
79
|
+
isNumeric: numericValues.length === nonNullCount && nonNullCount > 0,
|
|
80
|
+
isString: nonNullCount > 0 && stringCount === nonNullCount,
|
|
58
81
|
uniqueCount: unique.size,
|
|
59
|
-
|
|
82
|
+
nonNullCount,
|
|
60
83
|
numericValues,
|
|
61
84
|
};
|
|
62
85
|
});
|
|
63
86
|
}
|
|
64
87
|
|
|
88
|
+
function findBestCategoricalColumn(
|
|
89
|
+
profiles: ColumnProfile[],
|
|
90
|
+
rowCount: number,
|
|
91
|
+
): ColumnProfile | undefined {
|
|
92
|
+
return profiles
|
|
93
|
+
.filter((c) => c.isString && c.uniqueCount > 1 && c.uniqueCount < rowCount)
|
|
94
|
+
.sort((a, b) => a.uniqueCount - b.uniqueCount)[0];
|
|
95
|
+
}
|
|
96
|
+
|
|
65
97
|
function formatNumber(n: number): string {
|
|
66
98
|
if (Number.isInteger(n) && Math.abs(n) < 1_000_000) {
|
|
67
99
|
return n.toLocaleString();
|
|
@@ -111,12 +143,11 @@ function computeNumericMetrics(
|
|
|
111
143
|
}
|
|
112
144
|
}
|
|
113
145
|
|
|
114
|
-
|
|
115
|
-
|
|
146
|
+
function computeKeyMetricsFromProfiles(
|
|
147
|
+
profiles: ColumnProfile[],
|
|
148
|
+
rowCount: number,
|
|
116
149
|
): LegendAIKeyMetric[] {
|
|
117
|
-
const profiles = profileColumns(gridData);
|
|
118
150
|
const metrics: LegendAIKeyMetric[] = [];
|
|
119
|
-
const rowCount = gridData.rowData.length;
|
|
120
151
|
|
|
121
152
|
metrics.push({
|
|
122
153
|
label: 'Total Rows',
|
|
@@ -143,66 +174,122 @@ export function computeKeyMetrics(
|
|
|
143
174
|
return metrics.slice(0, MAX_KEY_METRICS);
|
|
144
175
|
}
|
|
145
176
|
|
|
146
|
-
export function
|
|
147
|
-
|
|
177
|
+
export function computeKeyMetrics(
|
|
178
|
+
gridData: LegendAIGridData,
|
|
179
|
+
): LegendAIKeyMetric[] {
|
|
180
|
+
return computeKeyMetricsFromProfiles(
|
|
181
|
+
profileColumns(gridData),
|
|
182
|
+
gridData.rowData.length,
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function inferChartTypeFromProfiles(
|
|
187
|
+
profiles: ColumnProfile[],
|
|
188
|
+
rowCount: number,
|
|
189
|
+
): LegendAIChartType {
|
|
148
190
|
const numericCols = profiles.filter((c) => c.isNumeric);
|
|
149
191
|
const stringCols = profiles.filter((c) => c.isString && c.uniqueCount > 1);
|
|
150
192
|
|
|
151
193
|
if (
|
|
152
194
|
stringCols.length >= 1 &&
|
|
153
195
|
numericCols.length >= 1 &&
|
|
154
|
-
|
|
196
|
+
rowCount <= MAX_BAR_CHART_ROWS
|
|
155
197
|
) {
|
|
156
|
-
if (
|
|
198
|
+
if (rowCount <= MAX_PIE_CHART_ROWS) {
|
|
157
199
|
return LegendAIChartType.PIE;
|
|
158
200
|
}
|
|
159
201
|
return LegendAIChartType.BAR;
|
|
160
202
|
}
|
|
161
203
|
|
|
162
|
-
if (numericCols.length >= 1 &&
|
|
204
|
+
if (numericCols.length >= 1 && rowCount > 1) {
|
|
163
205
|
return LegendAIChartType.BAR;
|
|
164
206
|
}
|
|
165
207
|
|
|
208
|
+
if (rowCount > 1) {
|
|
209
|
+
const categoricalCol = findBestCategoricalColumn(profiles, rowCount);
|
|
210
|
+
if (categoricalCol) {
|
|
211
|
+
return categoricalCol.uniqueCount <= MAX_PIE_CHART_ROWS
|
|
212
|
+
? LegendAIChartType.PIE
|
|
213
|
+
: LegendAIChartType.BAR;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
166
217
|
return LegendAIChartType.NONE;
|
|
167
218
|
}
|
|
168
219
|
|
|
169
|
-
export function
|
|
220
|
+
export function inferChartType(gridData: LegendAIGridData): LegendAIChartType {
|
|
221
|
+
return inferChartTypeFromProfiles(
|
|
222
|
+
profileColumns(gridData),
|
|
223
|
+
gridData.rowData.length,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function computeChartDataFromProfiles(
|
|
228
|
+
profiles: ColumnProfile[],
|
|
170
229
|
gridData: LegendAIGridData,
|
|
171
230
|
): LegendAIChartDataPoint[] {
|
|
172
|
-
const profiles = profileColumns(gridData);
|
|
173
231
|
const numericCol = profiles.find((c) => c.isNumeric);
|
|
174
232
|
const labelCol = profiles.find((c) => c.isString && c.uniqueCount > 1);
|
|
175
233
|
|
|
176
|
-
if (
|
|
234
|
+
if (numericCol) {
|
|
235
|
+
const field = numericCol.name;
|
|
236
|
+
const labelField = labelCol?.name;
|
|
237
|
+
const rows =
|
|
238
|
+
gridData.rowData.length > MAX_PROFILE_SAMPLE
|
|
239
|
+
? gridData.rowData.slice(0, MAX_PROFILE_SAMPLE)
|
|
240
|
+
: gridData.rowData;
|
|
241
|
+
|
|
242
|
+
const entries = rows
|
|
243
|
+
.map((row) => {
|
|
244
|
+
const rawValue = row[field];
|
|
245
|
+
return {
|
|
246
|
+
label: labelField
|
|
247
|
+
? String(row[labelField] ?? '')
|
|
248
|
+
: String(row[gridData.columnDefs[0]?.field ?? ''] ?? ''),
|
|
249
|
+
value: typeof rawValue === 'number' ? rawValue : 0,
|
|
250
|
+
};
|
|
251
|
+
})
|
|
252
|
+
.filter((e) => e.label.length > 0)
|
|
253
|
+
.sort((a, b) => b.value - a.value)
|
|
254
|
+
.slice(0, MAX_CHART_ITEMS);
|
|
255
|
+
|
|
256
|
+
return entries.map((e, i) => ({
|
|
257
|
+
label: e.label,
|
|
258
|
+
value: e.value,
|
|
259
|
+
colorIndex: i % CHART_PALETTE_COUNT,
|
|
260
|
+
}));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const categoricalCol = findBestCategoricalColumn(
|
|
264
|
+
profiles,
|
|
265
|
+
gridData.rowData.length,
|
|
266
|
+
);
|
|
267
|
+
if (!categoricalCol) {
|
|
177
268
|
return [];
|
|
178
269
|
}
|
|
179
270
|
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
271
|
+
const freqMap = new Map<string, number>();
|
|
272
|
+
for (const row of gridData.rowData) {
|
|
273
|
+
const val = String(row[categoricalCol.name] ?? '');
|
|
274
|
+
if (val.length > 0) {
|
|
275
|
+
freqMap.set(val, (freqMap.get(val) ?? 0) + 1);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
186
278
|
|
|
187
|
-
|
|
188
|
-
.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return entries.map((e, i) => ({
|
|
202
|
-
label: e.label,
|
|
203
|
-
value: e.value,
|
|
204
|
-
colorIndex: i % CHART_PALETTE_COUNT,
|
|
205
|
-
}));
|
|
279
|
+
return [...freqMap.entries()]
|
|
280
|
+
.sort((a, b) => b[1] - a[1])
|
|
281
|
+
.slice(0, MAX_CHART_ITEMS)
|
|
282
|
+
.map(([label, value], i) => ({
|
|
283
|
+
label,
|
|
284
|
+
value,
|
|
285
|
+
colorIndex: i % CHART_PALETTE_COUNT,
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function computeChartData(
|
|
290
|
+
gridData: LegendAIGridData,
|
|
291
|
+
): LegendAIChartDataPoint[] {
|
|
292
|
+
return computeChartDataFromProfiles(profileColumns(gridData), gridData);
|
|
206
293
|
}
|
|
207
294
|
|
|
208
295
|
export function computeTopItems(
|
|
@@ -211,10 +298,10 @@ export function computeTopItems(
|
|
|
211
298
|
return computeChartData(gridData).slice(0, TOP_N_ITEMS);
|
|
212
299
|
}
|
|
213
300
|
|
|
214
|
-
|
|
301
|
+
function findNumericColumnNameFromProfiles(
|
|
302
|
+
profiles: ColumnProfile[],
|
|
215
303
|
gridData: LegendAIGridData,
|
|
216
304
|
): string | undefined {
|
|
217
|
-
const profiles = profileColumns(gridData);
|
|
218
305
|
const numericCol = profiles.find((c) => c.isNumeric);
|
|
219
306
|
if (!numericCol) {
|
|
220
307
|
return undefined;
|
|
@@ -224,3 +311,26 @@ export function findNumericColumnName(
|
|
|
224
311
|
);
|
|
225
312
|
return colDef?.headerName ?? colDef?.field;
|
|
226
313
|
}
|
|
314
|
+
|
|
315
|
+
export function findNumericColumnName(
|
|
316
|
+
gridData: LegendAIGridData,
|
|
317
|
+
): string | undefined {
|
|
318
|
+
return findNumericColumnNameFromProfiles(profileColumns(gridData), gridData);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function analyzeGridData(
|
|
322
|
+
gridData: LegendAIGridData,
|
|
323
|
+
): LegendAIGridAnalysis {
|
|
324
|
+
const profiles = profileColumns(gridData);
|
|
325
|
+
const rowCount = gridData.rowData.length;
|
|
326
|
+
const chartType = inferChartTypeFromProfiles(profiles, rowCount);
|
|
327
|
+
return {
|
|
328
|
+
metrics: computeKeyMetricsFromProfiles(profiles, rowCount),
|
|
329
|
+
chartType,
|
|
330
|
+
chartData:
|
|
331
|
+
chartType === LegendAIChartType.NONE
|
|
332
|
+
? []
|
|
333
|
+
: computeChartDataFromProfiles(profiles, gridData),
|
|
334
|
+
numericColumnName: findNumericColumnNameFromProfiles(profiles, gridData),
|
|
335
|
+
};
|
|
336
|
+
}
|