Skip to content

Commit 952428a

Browse files
dmlvrCopilotRaushen
authored
✨AI Column: Write jQuery Demo (#31582)
Signed-off-by: Dmitry Lavrinovich <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Raushen <[email protected]>
1 parent 9ed69f7 commit 952428a

File tree

16 files changed

+4426
-0
lines changed

16 files changed

+4426
-0
lines changed

apps/demos/Demos/DataGrid/AIColumn/jQuery/data.js

Lines changed: 1897 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE html>
2+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
3+
<head>
4+
<title>DevExtreme Demo</title>
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
8+
<link rel="stylesheet" type="text/css" href="../../../../node_modules/devextreme/dist/css/dx.light.css" />
9+
<script src="../../../../node_modules/jquery/dist/jquery.min.js"></script>
10+
<script src="../../../../node_modules/devextreme-dist/js/dx.all.js"></script>
11+
<script type="module">
12+
import { AzureOpenAI } from "https://esm.sh/[email protected]";
13+
14+
window.AzureOpenAI = AzureOpenAI;
15+
</script>
16+
<script src="data.js"></script>
17+
<script src="../../../../node_modules/devextreme-dist/js/dx.ai-integration.js"></script>
18+
<script src="index.js"></script>
19+
<link rel="stylesheet" type="text/css" href="styles.css" />
20+
</head>
21+
<body class="dx-viewport">
22+
<div class="demo-container">
23+
<div id="data-grid-demo">
24+
<div id="gridContainer"></div>
25+
<div id="popup"></div>
26+
</div>
27+
</div>
28+
</body>
29+
</html>
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
$(() => {
2+
const aiService = new AzureOpenAI({
3+
dangerouslyAllowBrowser: true,
4+
deployment,
5+
endpoint,
6+
apiVersion,
7+
apiKey,
8+
});
9+
10+
async function getAIResponse(messages, signal) {
11+
const params = {
12+
messages,
13+
model: deployment,
14+
max_tokens: 1000,
15+
temperature: 0.7,
16+
};
17+
const response = await aiService.chat.completions.create(params, { signal });
18+
const result = response.choices[0].message?.content;
19+
20+
return result;
21+
}
22+
23+
const aiIntegration = new DevExpress.aiIntegration({
24+
sendRequest({ prompt }) {
25+
const controller = new AbortController();
26+
const signal = controller.signal;
27+
28+
const aiPrompt = [
29+
{ role: 'system', content: prompt.system },
30+
{ role: 'user', content: prompt.user },
31+
];
32+
33+
const promise = getAIResponse(aiPrompt, signal);
34+
35+
const result = {
36+
promise,
37+
abort: () => {
38+
controller.abort();
39+
},
40+
};
41+
42+
return result;
43+
},
44+
});
45+
46+
const popupContentTemplate = function (vehicle) {
47+
const {
48+
Source,
49+
LicenseName,
50+
Author,
51+
Edits,
52+
} = vehicle;
53+
const sourceLink = `https://${Source}`;
54+
return $('<div>').append(
55+
$('<p>')
56+
.append($('<b>').text('Image licensed under: '))
57+
.append($('<span>').text(LicenseName)),
58+
$('<p>')
59+
.append($('<b>').text('Author: '))
60+
.append($('<span>').text(Author)),
61+
$('<p>')
62+
.append($('<b>').text('Source link: '))
63+
.append(
64+
$('<a>', {
65+
href: sourceLink,
66+
target: '_blank',
67+
})
68+
.text(sourceLink),
69+
),
70+
$('<p>')
71+
.append($('<b>').text('Edits: '))
72+
.append($('<span>').text(Edits)),
73+
);
74+
};
75+
76+
const popup = $('#popup').dxPopup({
77+
width: 360,
78+
height: 260,
79+
visible: false,
80+
dragEnabled: false,
81+
hideOnOutsideClick: true,
82+
showCloseButton: true,
83+
title: 'Image Info',
84+
position: {
85+
at: 'center',
86+
my: 'center',
87+
collision: 'fit',
88+
},
89+
}).dxPopup('instance');
90+
91+
const createTrademarkTemplate = (vehicle) => {
92+
const {
93+
ID,
94+
Name,
95+
TrademarkName,
96+
} = vehicle;
97+
const trademarkWrapper = $('<div>').addClass('trademark__wrapper');
98+
const imgWrapper = $('<div>').addClass('trademark__img-wrapper');
99+
const img = $('<img>').addClass('trademark__img');
100+
img.attr({
101+
src: `../../../../images/vehicles/image_${ID}.png`,
102+
alt: `${TrademarkName} ${Name}`,
103+
tabindex: 0,
104+
role: 'button',
105+
'aria-haspopup': 'dialog',
106+
'aria-label': `${TrademarkName} ${Name} - press Enter for image info`,
107+
});
108+
109+
const showPopup = () => {
110+
popup.option('contentTemplate', () => popupContentTemplate(vehicle));
111+
popup.show();
112+
};
113+
114+
img.on('click', showPopup);
115+
116+
img.on('keydown', (e) => {
117+
if (e.key === 'Enter') {
118+
showPopup();
119+
}
120+
});
121+
122+
imgWrapper.append(img);
123+
trademarkWrapper.append(imgWrapper);
124+
125+
const textWrapper = $('<div>').addClass('trademark__text-wrapper');
126+
const trademarkText = $('<div>').addClass('trademark__text trademark__text--title').text(TrademarkName);
127+
const nameText = $('<div>').addClass('trademark__text trademark__text--subtitle').text(Name);
128+
129+
textWrapper.append(trademarkText, nameText);
130+
trademarkWrapper.append(textWrapper);
131+
132+
return trademarkWrapper;
133+
};
134+
135+
const createCategoryTemplate = ({ CategoryName }) => $('<div>').addClass('category__wrapper').text(CategoryName);
136+
137+
$('#gridContainer').dxDataGrid({
138+
dataSource: vehicles,
139+
keyExpr: 'ID',
140+
paging: {
141+
pageSize: 10,
142+
},
143+
aiIntegration,
144+
grouping: {
145+
contextMenuEnabled: false,
146+
},
147+
groupPanel: {
148+
visible: false,
149+
},
150+
columns: [
151+
{
152+
caption: 'Trademark',
153+
width: 220,
154+
cellTemplate: (container, options) => {
155+
const vehicle = options.data;
156+
const imageWrapper = createTrademarkTemplate(vehicle);
157+
container.append(imageWrapper);
158+
},
159+
},
160+
{
161+
dataField: 'Price',
162+
format: 'currency',
163+
width: 100,
164+
},
165+
{
166+
caption: 'Category',
167+
cellTemplate: (container, options) => {
168+
const category = options.data;
169+
const categoryWrapper = createCategoryTemplate(category);
170+
container.append(categoryWrapper);
171+
},
172+
minWidth: 180,
173+
},
174+
{
175+
dataField: 'Modification',
176+
width: 180,
177+
},
178+
{
179+
dataField: 'Horsepower',
180+
width: 140,
181+
},
182+
{
183+
dataField: 'BodyStyleName',
184+
caption: 'Body Style',
185+
width: 180,
186+
},
187+
{
188+
name: 'AI column',
189+
caption: 'AI Column',
190+
type: 'ai',
191+
ai: {
192+
prompt: 'Identify the country where this vehicle model is originally manufactured or developed, based on its brand, model, and specifications.',
193+
mode: 'auto',
194+
},
195+
width: 200,
196+
fixed: true,
197+
fixedPosition: 'right',
198+
cssClass: 'ai__cell',
199+
},
200+
],
201+
});
202+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#gridContainer .ai__cell {
2+
background-color: var(--dx-datagrid-row-alternation-bg);
3+
}
4+
5+
.trademark__wrapper {
6+
display: flex;
7+
align-items: center;
8+
gap: 8px;
9+
}
10+
11+
.trademark__img-wrapper {
12+
width: 40px;
13+
height: 40px;
14+
border: var(--dx-border-width) solid var(--dx-color-border);
15+
border-radius: var(--dx-border-radius);
16+
cursor: pointer;
17+
}
18+
19+
.trademark__img-wrapper img {
20+
width: 100%;
21+
height: 100%;
22+
object-fit: cover;
23+
object-position: center;
24+
border-radius: var(--dx-border-radius);
25+
}
26+
27+
.trademark__text-wrapper {
28+
width: calc(100% - 48px);
29+
}
30+
31+
.trademark__text {
32+
margin: 0;
33+
padding: 0;
34+
white-space: nowrap;
35+
overflow: hidden;
36+
text-overflow: ellipsis;
37+
}
38+
39+
.trademark__text--title {
40+
font-weight: 600;
41+
}
42+
43+
.trademark__text--subtitle {
44+
font-weight: 400;
45+
}
46+
47+
.category__wrapper {
48+
display: inline-block;
49+
padding: 2px 8px;
50+
border-radius: 24px;
51+
background-color: var(--dx-color-separator);
52+
}

0 commit comments

Comments
 (0)