@adaptabletools/adaptable 20.0.0-canary.3 → 20.0.0-canary.4
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/package.json +1 -1
- package/src/AdaptableOptions/CellSummaryOptions.d.ts +1 -1
- package/src/AdaptableOptions/ContainerOptions.d.ts +0 -7
- package/src/AdaptableOptions/DefaultAdaptableOptions.js +0 -1
- package/src/AdaptableOptions/EditOptions.d.ts +1 -1
- package/src/AdaptableOptions/ExportOptions.d.ts +4 -18
- package/src/AdaptableOptions/PredicateOptions.d.ts +4 -4
- package/src/Api/Implementation/AdaptableApiImpl.js +1 -0
- package/src/Api/Implementation/ExportApiImpl.js +3 -2
- package/src/Api/Implementation/ScheduleApiImpl.js +1 -1
- package/src/Api/Implementation/StyledColumnApiImpl.js +1 -1
- package/src/Api/Internal/EventInternalApi.js +6 -1
- package/src/Api/Internal/ExportInternalApi.js +1 -1
- package/src/PredefinedConfig/Common/AdaptableColumnContext.d.ts +1 -1
- package/src/PredefinedConfig/ExportState.d.ts +3 -3
- package/src/PredefinedConfig/LayoutState.d.ts +14 -14
- package/src/PredefinedConfig/StyledColumnState.d.ts +1 -1
- package/src/Strategy/StyledColumnModule.js +6 -6
- package/src/Utilities/ObjectFactory.js +1 -0
- package/src/View/Schedule/Wizard/ScheduleSettingsWizard/ScheduleSettingsReport.d.ts +2 -0
- package/src/View/Schedule/Wizard/ScheduleSettingsWizard/ScheduleSettingsReport.js +18 -2
- package/src/View/Schedule/Wizard/ScheduleSettingsWizard/ScheduleSettingsSummary.js +4 -0
- package/src/View/Schedule/Wizard/ScheduleSettingsWizard/ScheduleSettingsWizard.js +2 -1
- package/src/View/StyledColumn/Wizard/StyledColumnSparklineSettingsSection.d.ts +3 -4
- package/src/View/StyledColumn/Wizard/StyledColumnSparklineSettingsSection.js +348 -191
- package/src/View/StyledColumn/Wizard/StyledColumnWizard.js +2 -2
- package/src/View/StyledColumn/Wizard/StyledColumnWizardColumnSection.js +1 -1
- package/src/View/StyledColumn/Wizard/StyledColumnWizardTypeSection.js +4 -4
- package/src/agGrid/AdaptableAgGrid.d.ts +1 -6
- package/src/agGrid/AdaptableAgGrid.js +24 -42
- package/src/agGrid/AgGridAdapter.js +4 -1
- package/src/agGrid/AgGridColumnAdapter.js +5 -3
- package/src/components/ColorPicker/ColorPicker.js +2 -2
- package/src/env.js +2 -2
- package/src/metamodel/adaptable.metamodel.d.ts +0 -15
- package/src/metamodel/adaptable.metamodel.js +1 -1
- package/src/migration/VersionUpgrade20.d.ts +1 -0
- package/src/migration/VersionUpgrade20.js +25 -0
- package/src/types.d.ts +1 -1
- package/tsconfig.esm.tsbuildinfo +1 -1
|
@@ -14,7 +14,7 @@ export const renderStyledColumnTypeSummary = (data) => {
|
|
|
14
14
|
else if (data.PercentBarStyle) {
|
|
15
15
|
type = 'Percent Bar';
|
|
16
16
|
}
|
|
17
|
-
else if (data.
|
|
17
|
+
else if (data.SparklineStyle) {
|
|
18
18
|
type = 'Spark Line';
|
|
19
19
|
}
|
|
20
20
|
else if (data.BadgeStyle) {
|
|
@@ -33,7 +33,7 @@ export const StyledColumnWizardTypeSection = (props) => {
|
|
|
33
33
|
};
|
|
34
34
|
delete newStyledColumn.GradientStyle;
|
|
35
35
|
delete newStyledColumn.PercentBarStyle;
|
|
36
|
-
delete newStyledColumn.
|
|
36
|
+
delete newStyledColumn.SparklineStyle;
|
|
37
37
|
delete newStyledColumn.BadgeStyle;
|
|
38
38
|
switch (type) {
|
|
39
39
|
case 'gradient':
|
|
@@ -43,7 +43,7 @@ export const StyledColumnWizardTypeSection = (props) => {
|
|
|
43
43
|
newStyledColumn.PercentBarStyle = {};
|
|
44
44
|
break;
|
|
45
45
|
case 'sparkline':
|
|
46
|
-
newStyledColumn.
|
|
46
|
+
newStyledColumn.SparklineStyle = {
|
|
47
47
|
options: {
|
|
48
48
|
type: 'line',
|
|
49
49
|
},
|
|
@@ -64,6 +64,6 @@ export const StyledColumnWizardTypeSection = (props) => {
|
|
|
64
64
|
React.createElement(Tabs.Content, null,
|
|
65
65
|
React.createElement(TypeRadio, { text: "Gradient", description: "Colour each cell in the column using a Gradient value (Numeric Columns)", checked: Boolean(data.GradientStyle), onClick: () => handleTypeChange('gradient') }),
|
|
66
66
|
React.createElement(TypeRadio, { text: "Percent Bar", description: "Display a coloured Bar where the width is based on the cell (Numeric Columns)", checked: Boolean(data.PercentBarStyle), onClick: () => handleTypeChange('percent') }),
|
|
67
|
-
adaptable.api.styledColumnApi.canDisplaySparklines() && (React.createElement(TypeRadio, { text: "Sparkline", description: "Render the column as a Sparkline (Numeric Array Columns)", checked: Boolean(data.
|
|
67
|
+
adaptable.api.styledColumnApi.canDisplaySparklines() && (React.createElement(TypeRadio, { text: "Sparkline", description: "Render the column as a Sparkline (Numeric Array Columns)", checked: Boolean(data.SparklineStyle), onClick: () => handleTypeChange('sparkline') })),
|
|
68
68
|
React.createElement(TypeRadio, { text: "Badge", description: "Display the column's values as Badges (All Columns)", checked: Boolean(data.BadgeStyle), onClick: () => handleTypeChange('badge') })))));
|
|
69
69
|
};
|
|
@@ -61,11 +61,6 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
61
61
|
hasAutogeneratedPrimaryKey: boolean;
|
|
62
62
|
hasAdaptableToolPanel: boolean;
|
|
63
63
|
private initWithLazyData;
|
|
64
|
-
/**
|
|
65
|
-
* once layouts are properly handled with the new aggrid methods & events
|
|
66
|
-
* we can remove this hack
|
|
67
|
-
*/
|
|
68
|
-
private previousAgGridLayoutState;
|
|
69
64
|
_rawAdaptableOptions: AdaptableOptions;
|
|
70
65
|
adaptableOptions: AdaptableOptions;
|
|
71
66
|
_isDetailGrid: boolean;
|
|
@@ -147,6 +142,7 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
147
142
|
*/
|
|
148
143
|
static _initInternal(config: AdaptableInitInternalConfig): Promise<AdaptableApi>;
|
|
149
144
|
private _initAdaptableAgGrid;
|
|
145
|
+
midwayDestroy(): void;
|
|
150
146
|
normalizeAdaptableState(state: AdaptableState, agGridOptions: NormalizeAdaptableStateOptions): AdaptableState;
|
|
151
147
|
private normaliseLayoutState;
|
|
152
148
|
private normaliseToolPanelState;
|
|
@@ -337,6 +333,5 @@ export declare class AdaptableAgGrid implements IAdaptable {
|
|
|
337
333
|
refreshLayout(): void;
|
|
338
334
|
private isRowGroupDifferentInLayout;
|
|
339
335
|
private onLayoutChange;
|
|
340
|
-
private getColumnSorts;
|
|
341
336
|
}
|
|
342
337
|
export {};
|
|
@@ -131,11 +131,6 @@ const adaptableInstances = {};
|
|
|
131
131
|
const publishTimestamp = Number(ADAPTABLE_PUBLISH_TIMESTAMP);
|
|
132
132
|
export class AdaptableAgGrid {
|
|
133
133
|
constructor(config) {
|
|
134
|
-
/**
|
|
135
|
-
* once layouts are properly handled with the new aggrid methods & events
|
|
136
|
-
* we can remove this hack
|
|
137
|
-
*/
|
|
138
|
-
this.previousAgGridLayoutState = '';
|
|
139
134
|
this.filteredOutPrimaryKeys = new Set();
|
|
140
135
|
this.columnMinMaxValuesCache = {};
|
|
141
136
|
this.renderReactRoot = (node, container) => defaultRenderReactRoot(node, container);
|
|
@@ -295,11 +290,6 @@ export class AdaptableAgGrid {
|
|
|
295
290
|
this.api = new AdaptableApiImpl(this);
|
|
296
291
|
this.forPlugins((plugin) => plugin.afterInitApi(this, this.api));
|
|
297
292
|
this.lifecycleState = 'initAdaptableState';
|
|
298
|
-
// just in case Adaptable was destroyed while loading the store (which is an async operation)
|
|
299
|
-
if (this.isDestroyed) {
|
|
300
|
-
return Promise.reject('Adaptable was destroyed while loading the store.');
|
|
301
|
-
// FIXME AFL MIG: is this enough?! talk with the team
|
|
302
|
-
}
|
|
303
293
|
this.initServices();
|
|
304
294
|
this.forPlugins((plugin) => plugin.afterInitServices(this));
|
|
305
295
|
this.adaptableModules = this.initModules();
|
|
@@ -330,6 +320,7 @@ export class AdaptableAgGrid {
|
|
|
330
320
|
perfLoadStore.end();
|
|
331
321
|
// just in case Adaptable was destroyed while loading the store (which is an async operation)
|
|
332
322
|
if (this.isDestroyed) {
|
|
323
|
+
this.midwayDestroy();
|
|
333
324
|
return Promise.reject('Adaptable was destroyed while loading the store.');
|
|
334
325
|
// FIXME AFL MIG: is this enough?! talk with the team
|
|
335
326
|
}
|
|
@@ -365,6 +356,7 @@ export class AdaptableAgGrid {
|
|
|
365
356
|
this.agGridColumnAdapter.setupColumnFloatingFilterTemporarily(gridOptions);
|
|
366
357
|
const agGridApi = await this.initializeAgGrid(gridOptions, config.modules, config.renderAgGridFrameworkComponent);
|
|
367
358
|
if (agGridApi === false) {
|
|
359
|
+
this.midwayDestroy();
|
|
368
360
|
this.logger.consoleError(`Adaptable failed to initialize AG Grid!`);
|
|
369
361
|
return Promise.reject('Adaptable failed to initialize AG Grid!');
|
|
370
362
|
}
|
|
@@ -472,6 +464,12 @@ export class AdaptableAgGrid {
|
|
|
472
464
|
perfInitAdaptableAgGrid.end();
|
|
473
465
|
return Promise.resolve(this.api);
|
|
474
466
|
}
|
|
467
|
+
midwayDestroy() {
|
|
468
|
+
this.destroy({
|
|
469
|
+
destroyAgGrid: false,
|
|
470
|
+
unmount: false,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
475
473
|
normalizeAdaptableState(state, agGridOptions) {
|
|
476
474
|
state = this.normaliseLayoutState(state, agGridOptions);
|
|
477
475
|
state = this.normaliseToolPanelState(state);
|
|
@@ -1042,7 +1040,14 @@ You need to define at least one Layout!`);
|
|
|
1042
1040
|
*/
|
|
1043
1041
|
async initializeAgGrid(gridOptions, modules, renderAgGridFrameworkComponent) {
|
|
1044
1042
|
if (renderAgGridFrameworkComponent) {
|
|
1045
|
-
|
|
1043
|
+
let result = false;
|
|
1044
|
+
try {
|
|
1045
|
+
result = await renderAgGridFrameworkComponent(gridOptions);
|
|
1046
|
+
}
|
|
1047
|
+
catch (err) {
|
|
1048
|
+
console.log('Failed to get AG Grid API');
|
|
1049
|
+
result = false;
|
|
1050
|
+
}
|
|
1046
1051
|
if (result === false) {
|
|
1047
1052
|
return false;
|
|
1048
1053
|
}
|
|
@@ -1050,6 +1055,10 @@ You need to define at least one Layout!`);
|
|
|
1050
1055
|
// framework wrapper may have altered the context value via props
|
|
1051
1056
|
// in that case, we have to re-populate it with the Adaptable context values
|
|
1052
1057
|
const agGridContext = agGridApi.getGridOption('context');
|
|
1058
|
+
if (!agGridContext) {
|
|
1059
|
+
console.log('Failed to get AG Grid context');
|
|
1060
|
+
return false;
|
|
1061
|
+
}
|
|
1053
1062
|
if (!agGridContext.__adaptable) {
|
|
1054
1063
|
agGridContext.__adaptable = this;
|
|
1055
1064
|
agGridContext.adaptableApi = this.api;
|
|
@@ -1335,7 +1344,7 @@ You need to define at least one Layout!`);
|
|
|
1335
1344
|
return currentLayout.AutoSizeColumns;
|
|
1336
1345
|
}
|
|
1337
1346
|
autoSizeLayoutIfNeeded() {
|
|
1338
|
-
if (this.shouldAutoSizeLayout()) {
|
|
1347
|
+
if (this.isAvailable && this.shouldAutoSizeLayout()) {
|
|
1339
1348
|
requestAnimationFrame(() => {
|
|
1340
1349
|
if (this.isAvailable) {
|
|
1341
1350
|
this.autoSizeAllColumns();
|
|
@@ -2792,8 +2801,9 @@ You need to define at least one Layout!`);
|
|
|
2792
2801
|
}
|
|
2793
2802
|
}
|
|
2794
2803
|
this.__prevLayoutForOnChange = undefined;
|
|
2795
|
-
this.layoutManager
|
|
2796
|
-
this.
|
|
2804
|
+
this.layoutManager?.destroy();
|
|
2805
|
+
this.layoutManager = null;
|
|
2806
|
+
this.filteredOutPrimaryKeys?.clear();
|
|
2797
2807
|
if (this.agGridAdapter?.getAgGridApi() && !this.agGridAdapter.getAgGridApi().isDestroyed()) {
|
|
2798
2808
|
this.agGridAdapter
|
|
2799
2809
|
.getAgGridApi()
|
|
@@ -2872,7 +2882,6 @@ You need to define at least one Layout!`);
|
|
|
2872
2882
|
if (config?.destroyAgGrid === true) {
|
|
2873
2883
|
this.agGridAdapter.getAgGridApi()?.destroy();
|
|
2874
2884
|
}
|
|
2875
|
-
this.previousAgGridLayoutState = '';
|
|
2876
2885
|
const gridContainerElement = this.getAgGridContainerElement();
|
|
2877
2886
|
if (gridContainerElement) {
|
|
2878
2887
|
gridContainerElement.removeEventListener('keydown', this.agGridListenerKeydown, true);
|
|
@@ -2883,8 +2892,6 @@ You need to define at least one Layout!`);
|
|
|
2883
2892
|
this.agGridListenerMouseLeave = null;
|
|
2884
2893
|
}
|
|
2885
2894
|
this.api._internalDestroySelf();
|
|
2886
|
-
this.layoutManager?.destroy();
|
|
2887
|
-
this.layoutManager = null;
|
|
2888
2895
|
this.agGridOptionsService?.destroy();
|
|
2889
2896
|
this.agGridOptionsService = null;
|
|
2890
2897
|
this.agGridAdapter?.destroy();
|
|
@@ -3340,29 +3347,4 @@ You need to define at least one Layout!`);
|
|
|
3340
3347
|
this.__prevLayoutForOnChange = layout;
|
|
3341
3348
|
this.api.layoutApi.createOrUpdateLayout(layout);
|
|
3342
3349
|
}
|
|
3343
|
-
getColumnSorts() {
|
|
3344
|
-
const columnSorts = [];
|
|
3345
|
-
const { columnApi } = this.api;
|
|
3346
|
-
const columnState = this.agGridAdapter.getAgGridApi().getColumnState();
|
|
3347
|
-
columnState.forEach((colState) => {
|
|
3348
|
-
const { colId } = colState;
|
|
3349
|
-
if (columnApi.isAutoRowGroupColumn(colId)) {
|
|
3350
|
-
return;
|
|
3351
|
-
}
|
|
3352
|
-
if (colState.sort && colState.sortIndex != null) {
|
|
3353
|
-
columnSorts.push({
|
|
3354
|
-
ColumnId: colId,
|
|
3355
|
-
SortOrder: colState.sort === 'asc' ? 'Asc' : 'Desc',
|
|
3356
|
-
SortIndex: colState.sortIndex,
|
|
3357
|
-
});
|
|
3358
|
-
}
|
|
3359
|
-
});
|
|
3360
|
-
columnSorts.sort((a, b) => a.SortIndex - b.SortIndex);
|
|
3361
|
-
return columnSorts.map((c) => {
|
|
3362
|
-
return {
|
|
3363
|
-
ColumnId: c.ColumnId,
|
|
3364
|
-
SortOrder: c.SortOrder,
|
|
3365
|
-
};
|
|
3366
|
-
});
|
|
3367
|
-
}
|
|
3368
3350
|
}
|
|
@@ -5,7 +5,7 @@ import { createUuid } from '../PredefinedConfig/Uuid';
|
|
|
5
5
|
import ArrayExtensions from '../Utilities/Extensions/ArrayExtensions';
|
|
6
6
|
import * as ModuleConstants from '../Utilities/Constants/ModuleConstants';
|
|
7
7
|
import { ALL_AG_GRID_MODULES } from './agGridModules';
|
|
8
|
-
import { agGridDataTypeDefinitions, ALL_ADAPTABLE_DATA_TYPES
|
|
8
|
+
import { agGridDataTypeDefinitions, ALL_ADAPTABLE_DATA_TYPES } from './agGridDataTypeDefinitions';
|
|
9
9
|
// AG GRID obfuscates its internals, this is (currently) the best way to get hold of its internal services
|
|
10
10
|
const DANGER_AG_GRID_BEANS_MAP = {};
|
|
11
11
|
const getColumnApiModule = () => ColumnApiModule;
|
|
@@ -31,6 +31,9 @@ export class AgGridAdapter {
|
|
|
31
31
|
}
|
|
32
32
|
destroy() {
|
|
33
33
|
delete DANGER_AG_GRID_BEANS_MAP[this._agGridId];
|
|
34
|
+
this.initialGridOptions = null;
|
|
35
|
+
this.DANGER_gridApi_from_args = null;
|
|
36
|
+
this.DANGER_USE_GETTER_gridApi = null;
|
|
34
37
|
this.DANGER_updateGridOptionsMonkeyPatcher = null;
|
|
35
38
|
this._adaptableInstance = null;
|
|
36
39
|
}
|
|
@@ -12,6 +12,7 @@ import Helper from '../Utilities/Helpers/Helper';
|
|
|
12
12
|
import { AdaptableNumberEditor, AdaptableReactNumberEditor } from './editors/AdaptableNumberEditor';
|
|
13
13
|
import { AdaptableDateEditor, AdaptableReactDateEditor } from './editors/AdaptableDateEditor';
|
|
14
14
|
import { AgGridExportAdapter } from './AgGridExportAdapter';
|
|
15
|
+
import { AdaptableHelper, } from '../Utilities/Helpers/AdaptableHelper';
|
|
15
16
|
export function getEditorForColumnDataType(columnDataType, variant) {
|
|
16
17
|
if (columnDataType === 'number') {
|
|
17
18
|
return variant === 'react' ? AdaptableReactNumberEditor : AdaptableNumberEditor;
|
|
@@ -278,7 +279,7 @@ export class AgGridColumnAdapter {
|
|
|
278
279
|
if (styledColumn.BadgeStyle) {
|
|
279
280
|
return getBadgeRendererForColumn(styledColumn.BadgeStyle, abColumn, this.adaptableApi);
|
|
280
281
|
}
|
|
281
|
-
if (styledColumn.
|
|
282
|
+
if (styledColumn.SparklineStyle) {
|
|
282
283
|
return 'agSparklineCellRenderer';
|
|
283
284
|
}
|
|
284
285
|
}
|
|
@@ -286,8 +287,9 @@ export class AgGridColumnAdapter {
|
|
|
286
287
|
this.setColDefProperty(col, 'cellRendererParams', (userDefined) => {
|
|
287
288
|
const styledColumn = this.adaptableApi.styledColumnApi.getStyledColumnForColumnId(abColumn.columnId);
|
|
288
289
|
if (styledColumn && !styledColumn.IsSuspended) {
|
|
289
|
-
if (styledColumn.
|
|
290
|
-
const
|
|
290
|
+
if (styledColumn.SparklineStyle) {
|
|
291
|
+
const sanitizedSparklineOptions = AdaptableHelper.removeAdaptableObjectPrimitives(styledColumn.SparklineStyle.options);
|
|
292
|
+
const sparklineOptions = merge({}, userDefined?.sparklineOptions, sanitizedSparklineOptions);
|
|
291
293
|
return {
|
|
292
294
|
...userDefined,
|
|
293
295
|
sparklineOptions,
|
|
@@ -31,11 +31,11 @@ export const ColorPicker = React.forwardRef((props, ref) => {
|
|
|
31
31
|
}, value: preparedValue, ref: ref, type: "color", style: {
|
|
32
32
|
width: 70,
|
|
33
33
|
padding: 0 /* we need this to be 0, since otherwise on Windows browsers, the chosen color cannot be seen */,
|
|
34
|
-
}, list: "ABcolorChoices" }),
|
|
34
|
+
}, list: "ABcolorChoices", title: props.title }),
|
|
35
35
|
ABcolorChoices,
|
|
36
36
|
includeAlpha && (React.createElement(Flex, { alignItems: "center" },
|
|
37
37
|
React.createElement(Box, { mr: 1 }, "Opacity"),
|
|
38
|
-
React.createElement(Input, { className: "ab-ColorPicker-range", style: { background: rangeBackround }, value: alpha, onChange: (event) => {
|
|
38
|
+
React.createElement(Input, { disabled: props.disabled, className: "ab-ColorPicker-range", style: { background: rangeBackround }, value: alpha, onChange: (event) => {
|
|
39
39
|
const color = tinycolor(value).setAlpha(event.target.value).toRgbString();
|
|
40
40
|
props.onChange(color);
|
|
41
41
|
}, min: 0, max: 1, step: 0.01, type: "range" })))));
|
package/src/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
NEXT_PUBLIC_INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
|
|
3
|
-
PUBLISH_TIMESTAMP:
|
|
4
|
-
VERSION: "20.0.0-canary.
|
|
3
|
+
PUBLISH_TIMESTAMP: 1740989608096 || Date.now(),
|
|
4
|
+
VERSION: "20.0.0-canary.4" || '--current-version--',
|
|
5
5
|
};
|
|
@@ -2721,16 +2721,6 @@ export declare const ADAPTABLE_METAMODEL: {
|
|
|
2721
2721
|
kind: string;
|
|
2722
2722
|
desc: string;
|
|
2723
2723
|
};
|
|
2724
|
-
DataFormatTypeContext: {
|
|
2725
|
-
name: string;
|
|
2726
|
-
kind: string;
|
|
2727
|
-
desc: string;
|
|
2728
|
-
props: {
|
|
2729
|
-
name: string;
|
|
2730
|
-
kind: string;
|
|
2731
|
-
desc: string;
|
|
2732
|
-
}[];
|
|
2733
|
-
};
|
|
2734
2724
|
DataImportFileHandler: {
|
|
2735
2725
|
name: string;
|
|
2736
2726
|
kind: string;
|
|
@@ -2967,11 +2957,6 @@ export declare const ADAPTABLE_METAMODEL: {
|
|
|
2967
2957
|
ref: string;
|
|
2968
2958
|
})[];
|
|
2969
2959
|
};
|
|
2970
|
-
ExportableColumnContext: {
|
|
2971
|
-
name: string;
|
|
2972
|
-
kind: string;
|
|
2973
|
-
desc: string;
|
|
2974
|
-
};
|
|
2975
2960
|
ExportFormContext: {
|
|
2976
2961
|
name: string;
|
|
2977
2962
|
kind: string;
|