").dxForm({
77 | formData: formData,
78 | validationGroup: validationGroupName,
79 | showColonAfterLabel: true,
80 | items: [{
81 | itemType: "group",
82 | colCount: 2,
83 | items: [
84 | {
85 | dataField: "FirstName",
86 | validationRules: validationRules.firstName,
87 | label: {
88 | template: labelTemplate("user"),
89 | },
90 | },
91 | {
92 | dataField: "Position",
93 | editorType: "dxSelectBox",
94 | editorOptions: {
95 | items: positions,
96 | searchEnabled: true,
97 | },
98 | label: {
99 | template: labelTemplate("info"),
100 | },
101 | },
102 | {
103 | dataField: "LastName",
104 | validationRules: validationRules.lastName,
105 | label: {
106 | template: labelTemplate("user"),
107 | },
108 | },
109 | {
110 | dataField: "Address",
111 | label: {
112 | template: labelTemplate("home"),
113 | },
114 | },
115 | {
116 | dataField: "BirthDate",
117 | editorType: "dxDateBox",
118 | validationRules: validationRules.birthDate,
119 | label: {
120 | template: labelTemplate("event"),
121 | },
122 | },
123 | {
124 | dataField: "HireDate",
125 | editorType: "dxDateBox",
126 | label: {
127 | template: labelTemplate("event"),
128 | },
129 | },
130 | {
131 | colSpan: 2,
132 | dataField: "Notes",
133 | editorType: "dxTextArea",
134 | editorOptions: {
135 | height: 90,
136 | maxLength: 200,
137 | },
138 | label: {
139 | template: (data, element) => {
140 | const lineBreak = "
";
141 | const infoIcon =
142 | `
`;
143 | const labelText = `Additional${lineBreak}${data.text}`;
144 |
145 | element.append(
146 | `
${infoIcon}${labelText}
`
147 | );
148 |
149 | $("
").dxTooltip({
150 | target: "#helpedInfo",
151 | showEvent: "mouseenter",
152 | hideEvent: "mouseleave",
153 | contentTemplate(args) {
154 | args.html(
155 | `
This field must not exceed 200 characters
`
156 | );
157 | },
158 | }).appendTo(element);
159 | },
160 | },
161 | },
162 | {
163 | dataField: "Phone",
164 | validationRules: validationRules.phone,
165 | editorOptions: {
166 | mask: "+1 (X00) 000-0000",
167 | maskRules: { X: /[02-9]/ },
168 | maskInvalidMessage:
169 | "The phone must have a correct USA phone format",
170 | },
171 | label: {
172 | template: labelTemplate("tel"),
173 | },
174 | },
175 | {
176 | dataField: "Email",
177 | validationRules: validationRules.email,
178 | label: {
179 | template: labelTemplate("email"),
180 | },
181 | },
182 | ],
183 | }],
184 | });
185 | };
186 |
187 | const popup = $("#popup").dxPopup({
188 | hideOnOutsideClick: true,
189 | height: "auto",
190 | }).dxPopup("instance");
191 |
192 | const confirmItem = {
193 | widget: "dxButton",
194 | location: "after",
195 | toolbar: "bottom",
196 | options: {
197 | text: "Confirm",
198 | type: "success",
199 | },
200 | };
201 |
202 | const cancelItem = {
203 | widget: "dxButton",
204 | location: "after",
205 | toolbar: "bottom",
206 | options: {
207 | text: "Cancel",
208 | onClick: () => {
209 | popup.hide();
210 | },
211 | },
212 | };
213 |
214 | const showPopup = (isNewRecord, data) => {
215 | const contentTemplate = createPopupTemplate(data);
216 | popup.option({
217 | title: isNewRecord ? "Add" : "Edit",
218 | contentTemplate,
219 | toolbarItems: [
220 | {
221 | ...confirmItem,
222 | onClick: () => {
223 | let result = DevExpress.validationEngine.validateGroup(validationGroupName);
224 | if (!result.isValid)
225 | return;
226 | const gridSource = grid.getDataSource(),
227 | gridStore = gridSource.store();
228 | if (isNewRecord)
229 | gridStore.insert(data);
230 | else
231 | gridStore.update(data["ID"], data);
232 | grid.refresh(true);
233 | popup.hide();
234 | },
235 | },
236 | cancelItem,
237 | ],
238 | visible: true,
239 | });
240 | };
241 | });
242 |
--------------------------------------------------------------------------------
/test-example.ps1:
--------------------------------------------------------------------------------
1 | # For local testing, you can pass buildVersion.
2 | # Example usage:
3 | # ./test-example.ps1 -buildVersion 23.1.13
4 | param (
5 | [string]$buildVersion = $Env:CodeCentralBuildVersion
6 | )
7 |
8 | # Masstest-specific parameter. Specifies the minor version (example: '21.1.5')
9 | $global:BUILD_VERSION = $buildVersion
10 |
11 | $global:ERROR_CODE = 0
12 | $global:FAILED_PROJECTS = @()
13 |
14 | function Test-NpmVersionExists {
15 | param ([string]$Pkg, [string]$Ver)
16 | npm view "$Pkg@$Ver" > $null 2>&1
17 | return ($LASTEXITCODE -eq 0)
18 | }
19 |
20 | function Get-ValidNpmVersion {
21 | param (
22 | [string]$PackageName,
23 | [string]$Version
24 | )
25 |
26 | Write-Host "Checking $PackageName@$Version..."
27 | if (Test-NpmVersionExists -Pkg $PackageName -Ver $Version) {
28 | Write-Host "$PackageName@$Version exists."
29 | return $Version
30 | }
31 |
32 | try {
33 | $v = [version]$Version
34 | $fallback = "$($v.Major).$($v.Minor)-stable"
35 | } catch {
36 | Write-Host "Invalid version format: $Version"
37 | return $null
38 | }
39 |
40 | Write-Host "$PackageName@$Version not found. Trying fallback: $PackageName@$fallback..."
41 | if (Test-NpmVersionExists -Pkg $PackageName -Ver $fallback) {
42 | Write-Host "$PackageName@$fallback exists (fallback)."
43 | return $fallback
44 | }
45 |
46 | Write-Host "Neither $PackageName@$Version nor @$fallback exist."
47 | return $null
48 | }
49 |
50 | function Install-Packages {
51 | param (
52 | [string]$folderName,
53 | [string[]]$packages,
54 | [string]$buildVersion
55 | )
56 |
57 | Write-Output "`nInstalling packages in folder: $folderName"
58 |
59 | foreach ($package in $packages) {
60 | $packageVersion = Get-ValidNpmVersion -PackageName $package -Version $buildVersion
61 | $packageWithVersion = "$package@$packageVersion"
62 | Write-Output "Installing $packageWithVersion..."
63 |
64 | npm install --save --save-exact --no-fund --loglevel=error --force $packageWithVersion
65 | if (-not $?) {
66 | Write-Error "`nERROR: Failed to install $packageWithVersion in $folderName"
67 | throw "Installation failed for $packageWithVersion in $folderName"
68 | }
69 | }
70 |
71 | Write-Output "`nAll packages installed successfully in $folderName"
72 | }
73 |
74 | function Build-Project {
75 | param (
76 | [string]$folderName
77 | )
78 | Write-Output "`nBuilding the project in folder: $folderName"
79 |
80 | npm run build
81 | if (-not $?) {
82 | Write-Error "`nERROR: Failed to build the project in $folderName"
83 | throw "Build failed in $folderName"
84 | }
85 | }
86 |
87 | function Process-JavaScriptProjects {
88 | param (
89 | [string]$buildVersion
90 | )
91 | Write-Output "`n--== Starting JavaScript Projects Processing ==--"
92 |
93 | [hashtable[]]$folders = @(
94 | @{ Name = "Angular"; Packages = @("devextreme", "devextreme-angular") },
95 | @{ Name = "React"; Packages = @("devextreme", "devextreme-react") },
96 | @{ Name = "Vue"; Packages = @("devextreme", "devextreme-vue") }
97 | )
98 |
99 | $jQueryEntry = @{
100 | Name = "jQuery";
101 | Packages = if ([version]$buildVersion -ge [version]23.1) {
102 | @("devextreme", "devextreme-dist")
103 | } else {
104 | @("devextreme")
105 | }
106 | }
107 |
108 | $folders = @($jQueryEntry) + $folders
109 |
110 | foreach ($folder in $folders) {
111 | $folderName = $folder.Name
112 | $packages = $folder.Packages
113 |
114 | if (-not (Test-Path $folderName)) {
115 | Write-Output "`nDirectory $folderName does not exist. Skipping..."
116 | continue
117 | }
118 |
119 | Write-Output "`nProcessing folder: $folderName"
120 | Push-Location $folderName
121 |
122 | try {
123 | Write-Output "`nRemoving node_modules & package-lock.json: $pwd"
124 | Remove-Item -Recurse -Force node_modules -ErrorAction SilentlyContinue
125 | Remove-Item -Force package-lock.json -ErrorAction SilentlyContinue
126 | Install-Packages -folderName $folderName -packages $packages -buildVersion $buildVersion
127 | Write-Output "`nInstalling remaining packages in $folderName"
128 | npm install --save --save-exact --no-fund --loglevel=error
129 | if (-not $?) {
130 | throw "ERROR: Failed to install remaining packages in $folderName"
131 | }
132 | Build-Project -folderName $folderName
133 | } catch {
134 | Write-Error "`nAn error occurred: $_"
135 | $global:LASTEXITCODE = 1
136 | $global:ERROR_CODE = 1
137 | $global:FAILED_PROJECTS += $folderName
138 | } finally {
139 | Pop-Location
140 | }
141 | }
142 |
143 | Write-Output "`n--== JavaScript Projects Processing Completed ==--"
144 | }
145 |
146 | function Resolve-NuGetVersionWithFallback {
147 | param (
148 | [string]$PackageName,
149 | [string]$RequestedVersion
150 | )
151 |
152 | function Test-PackageAvailable {
153 | param ([string]$name, [string]$ver)
154 | dotnet add package $name --version $ver > $null 2>&1
155 | return ($LASTEXITCODE -eq 0)
156 | }
157 |
158 | if (Test-PackageAvailable -name $PackageName -ver $RequestedVersion) {
159 | Write-Host "$PackageName@$RequestedVersion is available."
160 | return $RequestedVersion
161 | }
162 |
163 | Write-Host "$PackageName@$RequestedVersion not found. Checking for -beta and -alpha versions..."
164 |
165 | $suffixes = @("beta", "alpha")
166 | foreach ($suffix in $suffixes) {
167 | $fallbackVersion = "$RequestedVersion-$suffix"
168 | if (Test-PackageAvailable -name $PackageName -ver $fallbackVersion) {
169 | Write-Host "Found $PackageName@$fallbackVersion"
170 | return $fallbackVersion
171 | }
172 | }
173 |
174 | Write-Warning "No matching versions found for $PackageName@$RequestedVersion"
175 | return $null
176 | }
177 |
178 | function Process-AspNetCoreProject {
179 | param (
180 | [Parameter(Mandatory = $true)]
181 | [string]$buildVersion
182 | )
183 |
184 | $folderPath = Get-ChildItem -Directory |
185 | Where-Object { $_.Name -match '(?i)^ASP\.NET\s*Core$' } |
186 | Select-Object -First 1 -ExpandProperty FullName
187 |
188 | if (-not $folderPath) {
189 | Write-Error "Directory matching 'ASP.NET Core' not found."
190 | return
191 | }
192 |
193 | Write-Host "Found project directory: $folderPath"
194 | Push-Location $folderPath
195 |
196 | try {
197 | $resolvedNugetVersion = Resolve-NuGetVersionWithFallback -PackageName "DevExtreme.AspNet.Core" -RequestedVersion $buildVersion
198 | if (-not $resolvedNugetVersion) {
199 | throw "No valid version found for DevExtreme.AspNet.Core"
200 | }
201 |
202 | Write-Host "Installing DevExtreme.AspNet.Core@$resolvedNugetVersion..."
203 | dotnet add package DevExtreme.AspNet.Core --version $resolvedNugetVersion
204 |
205 | $packageJsonPath = Get-ChildItem -Path $folderPath -Filter "package.json" -Recurse -File -ErrorAction SilentlyContinue |
206 | Select-Object -First 1 -ExpandProperty FullName
207 |
208 | if ($packageJsonPath) {
209 | Write-Host "Found package.json: $packageJsonPath"
210 |
211 | try {
212 | $packageJson = Get-Content -Path $packageJsonPath -Raw | ConvertFrom-Json
213 | $updated = $false
214 |
215 | if ($packageJson.dependencies.devextreme) {
216 | $validDevextremeVersion = Get-ValidNpmVersion -PackageName "devextreme" -Version $buildVersion
217 | if ($validDevextremeVersion) {
218 | $packageJson.dependencies.devextreme = $validDevextremeVersion
219 | $updated = $true
220 | }
221 | }
222 |
223 | if ($packageJson.dependencies.'devextreme-dist') {
224 | $validDevextremeDistVersion = Get-ValidNpmVersion -PackageName "devextreme-dist" -Version $buildVersion
225 | if ($validDevextremeDistVersion) {
226 | $packageJson.dependencies.'devextreme-dist' = $validDevextremeDistVersion
227 | $updated = $true
228 | }
229 | }
230 |
231 | if ($updated) {
232 | $packageJson | ConvertTo-Json -Depth 10 | Set-Content -Path $packageJsonPath -Encoding UTF8
233 | Write-Host "Updated package.json with valid versions."
234 | } else {
235 | Write-Host "No matching dependencies found in package.json to update."
236 | }
237 |
238 | Write-Host "Installing NPM dependencies..."
239 | npm install --save --save-exact --no-fund --loglevel=error
240 | if (-not $?) {
241 | throw "Failed to install npm dependencies"
242 | }
243 | } catch {
244 | Write-Error "Failed to update package.json: $_"
245 | }
246 | } else {
247 | Write-Warning "No package.json file found in '$folderPath'."
248 | }
249 |
250 | Write-Host "Running dotnet build..."
251 | dotnet build
252 | if ($LASTEXITCODE -eq 0) {
253 | Write-Host "Build succeeded."
254 | } else {
255 | throw
256 | }
257 | } catch {
258 | Write-Error "An error occurred: $_"
259 | $global:LASTEXITCODE = 1
260 | $global:ERROR_CODE = 1
261 | $global:FAILED_PROJECTS += "ASP.NET Core"
262 | } finally {
263 | Pop-Location
264 | }
265 | }
266 |
267 | function Write-BuildInfo {
268 | $BUILD_VERSION = if ($global:BUILD_VERSION -ne $null -and $global:BUILD_VERSION -ne "") {
269 | $global:BUILD_VERSION
270 | } else {
271 | "(empty)"
272 | }
273 |
274 | Write-Output "Build Version: $BUILD_VERSION"
275 | }
276 |
277 | Write-BuildInfo
278 | Process-JavaScriptProjects -buildVersion $global:BUILD_VERSION
279 | Process-AspNetCoreProject -buildVersion $global:BUILD_VERSION
280 |
281 | Write-Output "`nFinished testing version: $global:BUILD_VERSION. Error code: $global:ERROR_CODE"
282 | if ($global:ERROR_CODE -ne 0 -and $global:FAILED_PROJECTS.Count -gt 0) {
283 | Write-Output "`FAILED PROJECTS: $(($global:FAILED_PROJECTS -join ", "))"
284 | }
285 |
286 | exit $global:ERROR_CODE
287 |
--------------------------------------------------------------------------------