Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f17819c
added DataGrid and TreeList demos for AIColumn
dmlvr Nov 4, 2025
29a615d
fix lint
dmlvr Nov 4, 2025
3919def
updated menuMeta.json
dmlvr Nov 4, 2025
7d1fd98
Merge branch '25_2' into dg_25_2_ai_column_jquery_demo
dmlvr Nov 4, 2025
0b3066a
Update apps/demos/Demos/TreeList/AIColumn/JQuery/index.js
dmlvr Nov 5, 2025
ded0d2e
fix lint
dmlvr Nov 5, 2025
31af444
merge updates
dmlvr Nov 5, 2025
04fbc0b
Merge branch '25_2' into dg_25_2_ai_column_jquery_demo
dmlvr Nov 5, 2025
b983caa
merge 25_2
dmlvr Nov 5, 2025
c2eb9b5
update demo by review comments
dmlvr Nov 5, 2025
46ae17b
Load order
Nov 5, 2025
0c278ee
Change theme
Nov 5, 2025
bce1369
Linter
Nov 6, 2025
f50958f
Fix path
Nov 6, 2025
fdd489b
Fix TreeList path
Nov 6, 2025
f5a8440
Fix cell style
Nov 6, 2025
5f7d139
Merge branch '25_2' of github.com:DevExpress/DevExtreme into dg_25_2_…
Nov 6, 2025
ddc0217
Linter
Nov 6, 2025
7bb7dc7
Category style
Nov 6, 2025
b6cf6bc
Popover appearance
Nov 6, 2025
88f6d21
Remove unused properties
Nov 6, 2025
5a1dc0b
TreeList DataSource
Nov 6, 2025
97e3d5f
Linter
Nov 6, 2025
0bfb51d
Merge branch '25_2' of github.com:DevExpress/DevExtreme into dg_25_2_…
Nov 7, 2025
30b0c64
TreeList images
Nov 10, 2025
e78e975
Merge branch '25_2' of github.com:DevExpress/DevExtreme into dg_25_2_…
Nov 10, 2025
f9f8ad9
Replace popover to popup
Nov 10, 2025
f392200
Remove flag from prompt
Nov 10, 2025
aad4f02
Merge branch '25_2' of github.com:DevExpress/DevExtreme into dg_25_2_…
Nov 10, 2025
05eaca7
Fix name
Nov 10, 2025
621e22d
Fix styles
Nov 10, 2025
1593bcc
Image accessibility
Nov 10, 2025
1a9c8aa
ShowCloseButton
Nov 10, 2025
6a043b2
Selector refactoring
Nov 10, 2025
dfd87b4
AI Column bg
Nov 10, 2025
c4ff9ef
typo
Nov 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,897 changes: 1,897 additions & 0 deletions apps/demos/Demos/DataGrid/AIColumn/jQuery/data.js

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions apps/demos/Demos/DataGrid/AIColumn/jQuery/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<link rel="stylesheet" type="text/css" href="../../../../node_modules/devextreme/dist/css/dx.light.css" />
<script src="../../../../node_modules/jquery/dist/jquery.min.js"></script>
<script src="../../../../node_modules/devextreme-dist/js/dx.all.js"></script>
<script type="module">
import { AzureOpenAI } from "https://esm.sh/openai@4.73.1";

window.AzureOpenAI = AzureOpenAI;
</script>
<script src="data.js"></script>
<script src="../../../../node_modules/devextreme-dist/js/dx.ai-integration.js"></script>
<script src="index.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body class="dx-viewport">
<div class="demo-container">
Comment thread
dmlvr marked this conversation as resolved.
<div id="data-grid-demo">
<div id="gridContainer"></div>
<div id="popup"></div>
</div>
</div>
</body>
</html>
202 changes: 202 additions & 0 deletions apps/demos/Demos/DataGrid/AIColumn/jQuery/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
$(() => {
const aiService = new AzureOpenAI({
dangerouslyAllowBrowser: true,
deployment,
endpoint,
apiVersion,
apiKey,
});
Comment thread
Raushen marked this conversation as resolved.

async function getAIResponse(messages, signal) {
const params = {
messages,
model: deployment,
max_tokens: 1000,
temperature: 0.7,
};
const response = await aiService.chat.completions.create(params, { signal });
const result = response.choices[0].message?.content;

return result;
}

const aiIntegration = new DevExpress.aiIntegration({
sendRequest({ prompt }) {
const controller = new AbortController();
const signal = controller.signal;

const aiPrompt = [
{ role: 'system', content: prompt.system },
{ role: 'user', content: prompt.user },
];

const promise = getAIResponse(aiPrompt, signal);

const result = {
promise,
abort: () => {
controller.abort();
},
};

return result;
},
});

const popupContentTemplate = function (vehicle) {
const {
Source,
LicenseName,
Author,
Edits,
} = vehicle;
const sourceLink = `https://${Source}`;
return $('<div>').append(
$('<p>')
.append($('<b>').text('Image licensed under: '))
.append($('<span>').text(LicenseName)),
$('<p>')
.append($('<b>').text('Author: '))
.append($('<span>').text(Author)),
$('<p>')
.append($('<b>').text('Source link: '))
.append(
$('<a>', {
href: sourceLink,
target: '_blank',
})
.text(sourceLink),
),
$('<p>')
.append($('<b>').text('Edits: '))
.append($('<span>').text(Edits)),
);
};

const popup = $('#popup').dxPopup({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we explicitly set the showCloseButton option? By default, it has different values ​​in different themes.

width: 360,
height: 260,
visible: false,
dragEnabled: false,
hideOnOutsideClick: true,
showCloseButton: true,
title: 'Image Info',
position: {
at: 'center',
my: 'center',
collision: 'fit',
},
}).dxPopup('instance');

const createTrademarkTemplate = (vehicle) => {
const {
ID,
Name,
TrademarkName,
} = vehicle;
Comment thread
Raushen marked this conversation as resolved.
const trademarkWrapper = $('<div>').addClass('trademark__wrapper');
const imgWrapper = $('<div>').addClass('trademark__img-wrapper');
const img = $('<img>').addClass('trademark__img');
img.attr({
src: `../../../../images/vehicles/image_${ID}.png`,
alt: `${TrademarkName} ${Name}`,
tabindex: 0,
role: 'button',
'aria-haspopup': 'dialog',
'aria-label': `${TrademarkName} ${Name} - press Enter for image info`,
});

const showPopup = () => {
popup.option('contentTemplate', () => popupContentTemplate(vehicle));
popup.show();
};

img.on('click', showPopup);

img.on('keydown', (e) => {
if (e.key === 'Enter') {
showPopup();
}
});

imgWrapper.append(img);
trademarkWrapper.append(imgWrapper);

const textWrapper = $('<div>').addClass('trademark__text-wrapper');
const trademarkText = $('<div>').addClass('trademark__text trademark__text--title').text(TrademarkName);
const nameText = $('<div>').addClass('trademark__text trademark__text--subtitle').text(Name);
Comment thread
dmlvr marked this conversation as resolved.

textWrapper.append(trademarkText, nameText);
trademarkWrapper.append(textWrapper);

return trademarkWrapper;
};

const createCategoryTemplate = ({ CategoryName }) => $('<div>').addClass('category__wrapper').text(CategoryName);
Comment thread
dmlvr marked this conversation as resolved.
Comment thread
Raushen marked this conversation as resolved.

$('#gridContainer').dxDataGrid({
dataSource: vehicles,
Comment thread
dmlvr marked this conversation as resolved.
Comment thread
dmlvr marked this conversation as resolved.
Comment thread
Raushen marked this conversation as resolved.
keyExpr: 'ID',
paging: {
pageSize: 10,
},
aiIntegration,
grouping: {
contextMenuEnabled: false,
},
groupPanel: {
visible: false,
},
columns: [
{
caption: 'Trademark',
width: 220,
cellTemplate: (container, options) => {
const vehicle = options.data;
const imageWrapper = createTrademarkTemplate(vehicle);
container.append(imageWrapper);
},
},
{
dataField: 'Price',
format: 'currency',
width: 100,
},
{
caption: 'Category',
Comment thread
dmlvr marked this conversation as resolved.
cellTemplate: (container, options) => {
const category = options.data;
const categoryWrapper = createCategoryTemplate(category);
container.append(categoryWrapper);
},
minWidth: 180,
},
{
dataField: 'Modification',
width: 180,
},
{
dataField: 'Horsepower',
width: 140,
},
{
dataField: 'BodyStyleName',
caption: 'Body Style',
width: 180,
},
{
name: 'AI column',
Comment thread
dmlvr marked this conversation as resolved.
caption: 'AI Column',
type: 'ai',
ai: {
prompt: 'Identify the country where this vehicle model is originally manufactured or developed, based on its brand, model, and specifications.',
mode: 'auto',
},
width: 200,
fixed: true,
fixedPosition: 'right',
cssClass: 'ai__cell',
},
],
});
});
52 changes: 52 additions & 0 deletions apps/demos/Demos/DataGrid/AIColumn/jQuery/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#gridContainer .ai__cell {
background-color: var(--dx-datagrid-row-alternation-bg);
}

.trademark__wrapper {
display: flex;
align-items: center;
gap: 8px;
}

.trademark__img-wrapper {
width: 40px;
height: 40px;
border: var(--dx-border-width) solid var(--dx-color-border);
border-radius: var(--dx-border-radius);
cursor: pointer;
}

.trademark__img-wrapper img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
border-radius: var(--dx-border-radius);
}

.trademark__text-wrapper {
width: calc(100% - 48px);
}

.trademark__text {
margin: 0;
padding: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.trademark__text--title {
font-weight: 600;
}

.trademark__text--subtitle {
font-weight: 400;
}

.category__wrapper {
display: inline-block;
padding: 2px 8px;
border-radius: 24px;
background-color: var(--dx-color-separator);
}
Comment on lines +1 to +52

Copilot AI Nov 10, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire styles.css file for DataGrid is identical to the TreeList styles.css file (52 lines). This is code duplication that should be extracted to a shared stylesheet to improve maintainability. Consider creating a common styles file that both demos can reference.

Suggested change
#gridContainer .ai__cell {
background-color: var(--dx-color-main-bg);
}
.trademark__wrapper {
display: flex;
align-items: center;
gap: 8px;
}
.trademark__img-wrapper {
width: 40px;
height: 40px;
border: var(--dx-border-width) solid var(--dx-color-border);
border-radius: var(--dx-border-radius);
cursor: pointer;
}
.trademark__img-wrapper img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
border-radius: var(--dx-border-radius);
}
.trademark__text-wrapper {
width: calc(100% - 48px);
}
.trademark__text {
margin: 0;
padding: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.trademark__text--title {
font-weight: 600;
}
.trademark__text--subtitle {
font-weight: 400;
}
.category__wrapper {
display: inline-block;
padding: 2px 8px;
border-radius: 24px;
background-color: var(--dx-color-separator);
}
@import "../../common/ai-column-shared.css";

Copilot uses AI. Check for mistakes.
Loading
Loading