flowquery 1.0.8 → 1.0.10
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/dist/flowquery.min.js +1 -1
- package/dist/parsing/functions/function_factory.d.ts +2 -0
- package/dist/parsing/functions/function_factory.d.ts.map +1 -1
- package/dist/parsing/functions/function_factory.js +2 -0
- package/dist/parsing/functions/function_factory.js.map +1 -1
- package/dist/parsing/functions/keys.d.ts +7 -0
- package/dist/parsing/functions/keys.d.ts.map +1 -0
- package/dist/parsing/functions/keys.js +42 -0
- package/dist/parsing/functions/keys.js.map +1 -0
- package/dist/parsing/functions/type.d.ts +7 -0
- package/dist/parsing/functions/type.d.ts.map +1 -0
- package/dist/parsing/functions/type.js +49 -0
- package/dist/parsing/functions/type.js.map +1 -0
- package/docs/flowquery.min.js +1 -1
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/misc/apps/RAG/package.json +3 -1
- package/misc/apps/RAG/src/components/AdaptiveCardRenderer.css +172 -0
- package/misc/apps/RAG/src/components/AdaptiveCardRenderer.tsx +312 -0
- package/misc/apps/RAG/src/components/ChatContainer.tsx +159 -112
- package/misc/apps/RAG/src/components/ChatInput.tsx +58 -44
- package/misc/apps/RAG/src/components/ChatMessage.tsx +186 -101
- package/misc/apps/RAG/src/components/FlowQueryAgent.ts +50 -6
- package/misc/apps/RAG/src/components/FlowQueryRunner.css +9 -0
- package/misc/apps/RAG/src/components/FlowQueryRunner.tsx +44 -5
- package/misc/apps/RAG/src/components/index.ts +4 -0
- package/misc/apps/RAG/src/plugins/index.ts +6 -4
- package/misc/apps/RAG/src/plugins/loaders/CatFacts.ts +1 -2
- package/misc/apps/RAG/src/plugins/loaders/FetchJson.ts +1 -2
- package/misc/apps/RAG/src/plugins/loaders/Form.ts +578 -0
- package/misc/apps/RAG/src/plugins/loaders/Llm.ts +1 -2
- package/misc/apps/RAG/src/plugins/loaders/MockData.ts +2 -4
- package/misc/apps/RAG/src/plugins/loaders/Table.ts +271 -0
- package/misc/apps/RAG/src/prompts/FlowQuerySystemPrompt.ts +12 -0
- package/package.json +1 -1
- package/src/parsing/functions/function_factory.ts +2 -0
- package/src/parsing/functions/keys.ts +31 -0
- package/src/parsing/functions/type.ts +39 -0
- package/tests/compute/runner.test.ts +8 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
.adaptive-card-container {
|
|
2
|
+
margin: 8px 0;
|
|
3
|
+
border-radius: 8px;
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.adaptive-card-container .ac-adaptiveCard {
|
|
8
|
+
padding: 12px;
|
|
9
|
+
background: var(--colorNeutralBackground1, #ffffff);
|
|
10
|
+
border: 1px solid var(--colorNeutralStroke1, #e0e0e0);
|
|
11
|
+
border-radius: 8px;
|
|
12
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Table styling */
|
|
16
|
+
.adaptive-card-container .ac-table {
|
|
17
|
+
width: 100%;
|
|
18
|
+
border-collapse: collapse;
|
|
19
|
+
margin: 8px 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.adaptive-card-container .ac-tableRow {
|
|
23
|
+
border-bottom: 1px solid var(--colorNeutralStroke2, #e0e0e0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.adaptive-card-container .ac-tableRow:first-child {
|
|
27
|
+
background: var(--colorNeutralBackground3, #f5f5f5);
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.adaptive-card-container .ac-tableCell {
|
|
32
|
+
padding: 8px 12px;
|
|
33
|
+
text-align: left;
|
|
34
|
+
vertical-align: top;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Text styling */
|
|
38
|
+
.adaptive-card-container .ac-textBlock {
|
|
39
|
+
margin: 0;
|
|
40
|
+
line-height: 1.5;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.adaptive-card-container .ac-textBlock.ac-text-large {
|
|
44
|
+
font-size: 18px;
|
|
45
|
+
line-height: 1.3;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.adaptive-card-container .ac-textBlock.ac-text-medium {
|
|
49
|
+
font-size: 14px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.adaptive-card-container .ac-textBlock.ac-text-small {
|
|
53
|
+
font-size: 12px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* FactSet styling */
|
|
57
|
+
.adaptive-card-container .ac-factSet {
|
|
58
|
+
display: grid;
|
|
59
|
+
grid-template-columns: auto 1fr;
|
|
60
|
+
gap: 4px 16px;
|
|
61
|
+
margin: 8px 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.adaptive-card-container .ac-fact-title {
|
|
65
|
+
font-weight: 600;
|
|
66
|
+
color: var(--colorNeutralForeground1, #242424);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.adaptive-card-container .ac-fact-value {
|
|
70
|
+
color: var(--colorNeutralForeground2, #616161);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Button/Action styling */
|
|
74
|
+
.adaptive-card-container .ac-pushButton {
|
|
75
|
+
font-family: inherit;
|
|
76
|
+
font-size: 14px;
|
|
77
|
+
padding: 6px 12px;
|
|
78
|
+
border-radius: 4px;
|
|
79
|
+
border: 1px solid var(--colorBrandBackground, #0078d4);
|
|
80
|
+
background: var(--colorBrandBackground, #0078d4);
|
|
81
|
+
color: white;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
transition: background-color 0.1s ease;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.adaptive-card-container .ac-pushButton:hover {
|
|
87
|
+
background: var(--colorBrandBackgroundHover, #106ebe);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.adaptive-card-container .ac-pushButton:active {
|
|
91
|
+
background: var(--colorBrandBackgroundPressed, #005a9e);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* Input styling */
|
|
95
|
+
.adaptive-card-container .ac-input {
|
|
96
|
+
font-family: inherit;
|
|
97
|
+
font-size: 14px;
|
|
98
|
+
padding: 6px 10px;
|
|
99
|
+
border: 1px solid var(--colorNeutralStroke1, #d1d1d1);
|
|
100
|
+
border-radius: 4px;
|
|
101
|
+
background: var(--colorNeutralBackground1, #ffffff);
|
|
102
|
+
color: var(--colorNeutralForeground1, #242424);
|
|
103
|
+
width: 100%;
|
|
104
|
+
box-sizing: border-box;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.adaptive-card-container .ac-input:focus {
|
|
108
|
+
outline: none;
|
|
109
|
+
border-color: var(--colorBrandStroke1, #0078d4);
|
|
110
|
+
box-shadow: 0 0 0 1px var(--colorBrandStroke1, #0078d4);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Error styling */
|
|
114
|
+
.adaptive-card-error {
|
|
115
|
+
padding: 12px;
|
|
116
|
+
background: var(--colorStatusDangerBackground1, #fde7e9);
|
|
117
|
+
color: var(--colorStatusDangerForeground1, #a80000);
|
|
118
|
+
border: 1px solid var(--colorStatusDangerBorder1, #f1bbbc);
|
|
119
|
+
border-radius: 4px;
|
|
120
|
+
font-size: 13px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Image styling */
|
|
124
|
+
.adaptive-card-container .ac-image {
|
|
125
|
+
max-width: 100%;
|
|
126
|
+
height: auto;
|
|
127
|
+
border-radius: 4px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* Container styling */
|
|
131
|
+
.adaptive-card-container .ac-container {
|
|
132
|
+
padding: 8px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Separator */
|
|
136
|
+
.adaptive-card-container .ac-separator {
|
|
137
|
+
height: 1px;
|
|
138
|
+
background: var(--colorNeutralStroke2, #e0e0e0);
|
|
139
|
+
margin: 8px 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Column set */
|
|
143
|
+
.adaptive-card-container .ac-columnSet {
|
|
144
|
+
display: flex;
|
|
145
|
+
gap: 8px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.adaptive-card-container .ac-column {
|
|
149
|
+
flex: 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Dark mode support */
|
|
153
|
+
@media (prefers-color-scheme: dark) {
|
|
154
|
+
.adaptive-card-container .ac-adaptiveCard {
|
|
155
|
+
background: var(--colorNeutralBackground1, #292929);
|
|
156
|
+
border-color: var(--colorNeutralStroke1, #404040);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.adaptive-card-container .ac-tableRow:first-child {
|
|
160
|
+
background: var(--colorNeutralBackground3, #1f1f1f);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.adaptive-card-container .ac-tableRow {
|
|
164
|
+
border-color: var(--colorNeutralStroke2, #404040);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.adaptive-card-error {
|
|
168
|
+
background: var(--colorStatusDangerBackground1, #3b1f1f);
|
|
169
|
+
color: var(--colorStatusDangerForeground1, #ff8c8c);
|
|
170
|
+
border-color: var(--colorStatusDangerBorder1, #6b3030);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import * as AdaptiveCards from 'adaptivecards';
|
|
3
|
+
import * as ACData from 'adaptivecards-templating';
|
|
4
|
+
import './AdaptiveCardRenderer.css';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Data passed when an Action.Submit is triggered
|
|
8
|
+
*/
|
|
9
|
+
export interface SubmitActionData {
|
|
10
|
+
/**
|
|
11
|
+
* The data property from the Action.Submit (if any)
|
|
12
|
+
*/
|
|
13
|
+
actionData: unknown;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* All input values collected from the card
|
|
17
|
+
*/
|
|
18
|
+
inputValues: Record<string, string>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The original action object
|
|
22
|
+
*/
|
|
23
|
+
action: AdaptiveCards.SubmitAction;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface AdaptiveCardRendererProps {
|
|
27
|
+
/**
|
|
28
|
+
* The Adaptive Card payload (JSON object conforming to Adaptive Cards schema).
|
|
29
|
+
* Can be a template with ${expression} bindings if `data` prop is provided.
|
|
30
|
+
*/
|
|
31
|
+
card: Record<string, unknown>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Optional data context for template binding.
|
|
35
|
+
* When provided, the card is treated as a template and expressions like
|
|
36
|
+
* ${property} or ${$root.property} will be evaluated against this data.
|
|
37
|
+
*/
|
|
38
|
+
data?: Record<string, unknown>;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Optional host config for styling the card
|
|
42
|
+
*/
|
|
43
|
+
hostConfig?: Record<string, unknown>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Callback when an Action.Submit is executed.
|
|
47
|
+
* Receives the action data and all input values from the card.
|
|
48
|
+
*/
|
|
49
|
+
onSubmit?: (submitData: SubmitActionData) => void;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Callback when any action is executed (e.g., Action.Submit, Action.OpenUrl).
|
|
53
|
+
* For Action.Submit, prefer using onSubmit which provides collected input values.
|
|
54
|
+
*/
|
|
55
|
+
onExecuteAction?: (action: AdaptiveCards.Action) => void;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Optional CSS class name for the container
|
|
59
|
+
*/
|
|
60
|
+
className?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Default host config styled to match Fluent UI aesthetics
|
|
65
|
+
*/
|
|
66
|
+
const defaultHostConfig: AdaptiveCards.HostConfig = new AdaptiveCards.HostConfig({
|
|
67
|
+
fontFamily: "'Segoe UI', 'Segoe UI Web (West European)', -apple-system, BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif",
|
|
68
|
+
containerStyles: {
|
|
69
|
+
default: {
|
|
70
|
+
backgroundColor: "#ffffff",
|
|
71
|
+
foregroundColors: {
|
|
72
|
+
default: {
|
|
73
|
+
default: "#242424",
|
|
74
|
+
subtle: "#616161"
|
|
75
|
+
},
|
|
76
|
+
accent: {
|
|
77
|
+
default: "#0078D4",
|
|
78
|
+
subtle: "#0063B1"
|
|
79
|
+
},
|
|
80
|
+
good: {
|
|
81
|
+
default: "#107C10",
|
|
82
|
+
subtle: "#0B5C0B"
|
|
83
|
+
},
|
|
84
|
+
warning: {
|
|
85
|
+
default: "#D83B01",
|
|
86
|
+
subtle: "#C43501"
|
|
87
|
+
},
|
|
88
|
+
attention: {
|
|
89
|
+
default: "#A80000",
|
|
90
|
+
subtle: "#8B0000"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
emphasis: {
|
|
95
|
+
backgroundColor: "#F5F5F5",
|
|
96
|
+
foregroundColors: {
|
|
97
|
+
default: {
|
|
98
|
+
default: "#242424",
|
|
99
|
+
subtle: "#616161"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
accent: {
|
|
104
|
+
backgroundColor: "#E6F2FB",
|
|
105
|
+
foregroundColors: {
|
|
106
|
+
default: {
|
|
107
|
+
default: "#242424",
|
|
108
|
+
subtle: "#616161"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
spacing: {
|
|
114
|
+
small: 4,
|
|
115
|
+
default: 8,
|
|
116
|
+
medium: 12,
|
|
117
|
+
large: 16,
|
|
118
|
+
extraLarge: 24,
|
|
119
|
+
padding: 12
|
|
120
|
+
},
|
|
121
|
+
separator: {
|
|
122
|
+
lineThickness: 1,
|
|
123
|
+
lineColor: "#E0E0E0"
|
|
124
|
+
},
|
|
125
|
+
actions: {
|
|
126
|
+
maxActions: 5,
|
|
127
|
+
spacing: AdaptiveCards.Spacing.Default,
|
|
128
|
+
buttonSpacing: 8,
|
|
129
|
+
showCard: {
|
|
130
|
+
actionMode: AdaptiveCards.ShowCardActionMode.Inline,
|
|
131
|
+
inlineTopMargin: 8
|
|
132
|
+
},
|
|
133
|
+
actionsOrientation: AdaptiveCards.Orientation.Horizontal,
|
|
134
|
+
actionAlignment: AdaptiveCards.ActionAlignment.Left
|
|
135
|
+
},
|
|
136
|
+
adaptiveCard: {
|
|
137
|
+
allowCustomStyle: true
|
|
138
|
+
},
|
|
139
|
+
textBlock: {
|
|
140
|
+
headingLevel: 2
|
|
141
|
+
},
|
|
142
|
+
factSet: {
|
|
143
|
+
title: {
|
|
144
|
+
color: AdaptiveCards.TextColor.Default,
|
|
145
|
+
size: AdaptiveCards.TextSize.Default,
|
|
146
|
+
isSubtle: false,
|
|
147
|
+
weight: AdaptiveCards.TextWeight.Bolder,
|
|
148
|
+
wrap: true
|
|
149
|
+
},
|
|
150
|
+
value: {
|
|
151
|
+
color: AdaptiveCards.TextColor.Default,
|
|
152
|
+
size: AdaptiveCards.TextSize.Default,
|
|
153
|
+
isSubtle: false,
|
|
154
|
+
weight: AdaptiveCards.TextWeight.Default,
|
|
155
|
+
wrap: true
|
|
156
|
+
},
|
|
157
|
+
spacing: 8
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Renders an Adaptive Card using the adaptivecards library.
|
|
163
|
+
* Adaptive Cards are platform-agnostic UI snippets authored in JSON.
|
|
164
|
+
*/
|
|
165
|
+
export class AdaptiveCardRenderer extends React.Component<AdaptiveCardRendererProps> {
|
|
166
|
+
private containerRef = React.createRef<HTMLDivElement>();
|
|
167
|
+
private adaptiveCard: AdaptiveCards.AdaptiveCard | null = null;
|
|
168
|
+
|
|
169
|
+
componentDidMount(): void {
|
|
170
|
+
this.createAdaptiveCard();
|
|
171
|
+
this.renderCard();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
componentDidUpdate(prevProps: AdaptiveCardRendererProps): void {
|
|
175
|
+
// Recreate adaptive card instance if host config changes
|
|
176
|
+
if (prevProps.hostConfig !== this.props.hostConfig) {
|
|
177
|
+
this.createAdaptiveCard();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Re-render if card, data, hostConfig, or action handler changes
|
|
181
|
+
if (
|
|
182
|
+
prevProps.card !== this.props.card ||
|
|
183
|
+
prevProps.data !== this.props.data ||
|
|
184
|
+
prevProps.hostConfig !== this.props.hostConfig ||
|
|
185
|
+
prevProps.onExecuteAction !== this.props.onExecuteAction ||
|
|
186
|
+
prevProps.onSubmit !== this.props.onSubmit
|
|
187
|
+
) {
|
|
188
|
+
this.renderCard();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Collects all input values from the rendered card
|
|
194
|
+
*/
|
|
195
|
+
private collectInputValues(): Record<string, string> {
|
|
196
|
+
const inputs: Record<string, string> = {};
|
|
197
|
+
|
|
198
|
+
if (!this.adaptiveCard) {
|
|
199
|
+
return inputs;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Get all input elements from the card
|
|
203
|
+
const allInputs = this.adaptiveCard.getAllInputs();
|
|
204
|
+
|
|
205
|
+
for (const input of allInputs) {
|
|
206
|
+
if (input.id) {
|
|
207
|
+
inputs[input.id] = input.value ?? '';
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return inputs;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private createAdaptiveCard(): void {
|
|
215
|
+
const { hostConfig } = this.props;
|
|
216
|
+
|
|
217
|
+
this.adaptiveCard = new AdaptiveCards.AdaptiveCard();
|
|
218
|
+
|
|
219
|
+
// Apply host config
|
|
220
|
+
if (hostConfig) {
|
|
221
|
+
this.adaptiveCard.hostConfig = new AdaptiveCards.HostConfig(hostConfig);
|
|
222
|
+
} else {
|
|
223
|
+
this.adaptiveCard.hostConfig = defaultHostConfig;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private renderCard(): void {
|
|
228
|
+
const { card, data, onExecuteAction, onSubmit } = this.props;
|
|
229
|
+
|
|
230
|
+
if (!this.containerRef.current || !card || !this.adaptiveCard) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Clear previous content
|
|
235
|
+
this.containerRef.current.innerHTML = '';
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
// Apply data binding if data is provided
|
|
239
|
+
let cardPayload = card;
|
|
240
|
+
if (data) {
|
|
241
|
+
const template = new ACData.Template(card);
|
|
242
|
+
cardPayload = template.expand({
|
|
243
|
+
$root: data
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Set up action handler
|
|
248
|
+
this.adaptiveCard.onExecuteAction = (action: AdaptiveCards.Action) => {
|
|
249
|
+
// Handle Action.Submit specially to collect input values
|
|
250
|
+
if (action instanceof AdaptiveCards.SubmitAction) {
|
|
251
|
+
const inputValues = this.collectInputValues();
|
|
252
|
+
|
|
253
|
+
if (onSubmit) {
|
|
254
|
+
onSubmit({
|
|
255
|
+
actionData: action.data,
|
|
256
|
+
inputValues,
|
|
257
|
+
action
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Call general action handler if provided
|
|
263
|
+
if (onExecuteAction) {
|
|
264
|
+
onExecuteAction(action);
|
|
265
|
+
} else if (action instanceof AdaptiveCards.OpenUrlAction && action.url) {
|
|
266
|
+
// Default: open URLs in new tab
|
|
267
|
+
window.open(action.url, '_blank', 'noopener,noreferrer');
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// Parse and render the card
|
|
272
|
+
this.adaptiveCard.parse(cardPayload);
|
|
273
|
+
const renderedCard = this.adaptiveCard.render();
|
|
274
|
+
|
|
275
|
+
if (renderedCard) {
|
|
276
|
+
this.containerRef.current.appendChild(renderedCard);
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.error('Failed to render Adaptive Card:', error);
|
|
280
|
+
|
|
281
|
+
// Show error message in the container
|
|
282
|
+
const errorDiv = document.createElement('div');
|
|
283
|
+
errorDiv.className = 'adaptive-card-error';
|
|
284
|
+
errorDiv.textContent = `Failed to render card: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
|
285
|
+
this.containerRef.current.appendChild(errorDiv);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
render(): React.ReactNode {
|
|
290
|
+
const { className } = this.props;
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<div
|
|
294
|
+
ref={this.containerRef}
|
|
295
|
+
className={`adaptive-card-container ${className || ''}`}
|
|
296
|
+
/>
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Helper function to check if an object looks like an Adaptive Card
|
|
303
|
+
*/
|
|
304
|
+
export function isAdaptiveCard(obj: unknown): obj is Record<string, unknown> {
|
|
305
|
+
return (
|
|
306
|
+
typeof obj === 'object' &&
|
|
307
|
+
obj !== null &&
|
|
308
|
+
(obj as Record<string, unknown>).type === 'AdaptiveCard'
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export default AdaptiveCardRenderer;
|