@@ -73,7 +73,7 @@ ClassMethod DeleteProductionDefinitionShards(productionClass As %String, deleteM
73
73
}
74
74
75
75
/// Exports a Studio project including both the provided PTD and export notes for the PTD
76
- ClassMethod ExportProjectForPTD (productionClass , ptdName , exportPath ) As %Status
76
+ ClassMethod ExportProjectForPTD (productionClass As %String , ptdName As %String , exportPath As %String ) As %Status
77
77
{
78
78
set st = $$$OK
79
79
try {
@@ -136,9 +136,9 @@ ClassMethod ExportProjectForPTD(productionClass, ptdName, exportPath) As %Status
136
136
137
137
/// Creates and exports a PTD item for a given internal name, either a single config item
138
138
/// or the production settings.
139
- ClassMethod ExportPTD (internalName As %String , nameMethod ) As %Status
139
+ ClassMethod ExportPTD (internalName As %String , nameMethod As %String ) As %Status
140
140
{
141
- Set name = $Piece (internalName ," ." ,1 ,$Length ( internalName , " . " ) -1 )
141
+ Set name = $Piece (internalName ," ." ,1 ,* -1 )
142
142
Set $ListBuild (productionName , itemName ) = $ListFromString (name , " ||" )
143
143
Set $ListBuild (itemName , itemClassName ) = $ListFromString (itemName , " |" )
144
144
Set sc = $$$OK
@@ -228,7 +228,7 @@ ClassMethod ExportProductionSettings(productionClass As %String, nameMethod As %
228
228
Return sc
229
229
}
230
230
231
- ClassMethod GetModifiedItemsBeforeSave (internalName , Location , Output modifiedItems )
231
+ ClassMethod GetModifiedItemsBeforeSave (internalName As %String , Location As %String , Output modifiedItems )
232
232
{
233
233
kill modifiedItems
234
234
set productionName = $piece (internalName ," ." ,1 ,*-1 )
@@ -255,17 +255,27 @@ ClassMethod GetModifiedItemsBeforeSave(internalName, Location, Output modifiedIt
255
255
set modifiedInternalName = " "
256
256
if $isobject (modifiedItem ) {
257
257
set modifiedInternalName = ..CreateInternalName (productionName , modifiedItem .Name , modifiedItem .ClassName , 0 )
258
- } else {
258
+ } elseif productionConfig . %IsModified () {
259
259
// cannot check %IsModified on production config settings because they are not actually modified at this point.
260
260
// workaround: just assume any change not to a specific item is to the production settings
261
261
set modifiedInternalName = ..CreateInternalName (productionName ,,,1 )
262
+ } else {
263
+ // if nothing is modified, assume this is deleting a config item
264
+ // only allow if no items are checked out by other users
265
+ // TODO: determine specific item being deleted in OnBeforeSave to allow for accurate editability checks
266
+ if $isobject (productionConfig ) {
267
+ set modifiedItems (..CreateInternalName (productionName ,,,1 )) = " M"
268
+ for i =1 :1 :productionConfig .Items .Count () {
269
+ set item = productionConfig .Items .GetAt (i )
270
+ set modifiedItems (..CreateInternalName (productionName , item .Name , item .ClassName , 0 )) = " M"
271
+ }
272
+ }
262
273
}
263
274
}
264
275
if ($get (modifiedInternalName ) '= " " ) {
265
276
set modifiedItems (modifiedInternalName ) = " M"
266
277
}
267
278
} else {
268
- // FUTURE: get the actually modified items by comparing the XDATA in Location with the XDATA in the compiled class
269
279
// If making changes from Studio, list every item in the production.
270
280
if $isobject (productionConfig ) {
271
281
set modifiedItems (..CreateInternalName (productionName ,,,1 )) = " M"
@@ -289,63 +299,80 @@ ClassMethod GetModifiedItemsBeforeSave(internalName, Location, Output modifiedIt
289
299
}
290
300
}
291
301
292
- ClassMethod GetModifiedItemsAfterSave (internalName , Output modifiedItems )
302
+ ClassMethod GetModifiedItemsAfterSave (internalName As %String , Output modifiedItems )
293
303
{
294
304
kill modifiedItems
295
305
set productionName = $piece (internalName ," ." ,1 ,*-1 )
296
- if ..IsEnsPortal () {
297
- // If adding/deleting from SMP, get the modified items by comparing items in temp global with items now
298
- set rs = ..ExecDirectNoPriv (
299
- " select Name, ClassName from Ens_Config.Item where Production = ?"
300
- , productionName )
301
- throw :rs .%SQLCODE <0 ##class (%Exception.SQL ).CreateFromSQLCODE (rs .%SQLCODE ,rs .%Message )
302
- while rs .%Next () {
303
- if '$get (^IRIS .Temp (" sscProd" ,$job ," items" , $listbuild (rs .Name , rs .ClassName ))) {
304
- set itemInternalName = ..CreateInternalName (productionName , rs .Name , rs .ClassName , 0 )
305
- set modifiedItems (itemInternalName ) = " A"
306
- }
307
- kill ^IRIS .Temp (" sscProd" ,$job ," items" , $listbuild (rs .Name , rs .ClassName ))
308
- }
309
- set key = $order (^IRIS .Temp (" sscProd" ,$job ," items" ," " ))
310
- while (key '= " " ) {
311
- set itemInternalName = ..CreateInternalName (productionName , $listget (key ,1 ), $listget (key ,2 ), 0 )
312
- set modifiedItems (itemInternalName ) = " D"
313
- set key = $order (^IRIS .Temp (" sscProd" ,$job ," items" ,key ))
314
- }
306
+ if ..IsEnsPortal (.source ) {
307
+ // If adding/deleting from SMP, get the modified items by comparing items in temp global with items now
308
+ do ..GetAddOrDeletedItems (productionName , .modifiedItems )
315
309
// If editing from SMP, get the modified items from a cache stored in OnBeforeSave.
316
310
// Only do this if there are no added/deleted items, because otherwise production settings will be incorrectly included.
317
311
if '$data (modifiedItems ) {
318
312
merge modifiedItems = ^IRIS .Temp (" sscProd" ,$job ," modifiedItems" )
319
313
}
320
314
} else {
321
- // If editing in the IDE, list every item in the production.
322
- // FUTURE: get the actually modified items using the temp global set in OnBeforeSave
315
+ // If editing/adding/deleting from Studio, VS Code, or Interop Editor UI, mark all items for edit then find adds/deletes
316
+ if source = " IDE" {
317
+ // only compile f editing from IDE
318
+ $$$ThrowOnError($System .OBJ .Compile (productionName , " ck-d/multicompile=0" ))
319
+ }
323
320
set productionConfig = ##class (Ens.Config.Production ).%OpenId (productionName )
324
321
if $isobject (productionConfig ) {
325
- set modifiedItems (..CreateInternalName (productionName ,,,1 )) = " M"
326
- for i =1 :1 :productionConfig .Items .Count () {
327
- set item = productionConfig .Items .GetAt (i )
328
- set modifiedItems (..CreateInternalName (productionName , item .Name , item .ClassName , 0 )) = " M"
329
- }
322
+ merge modifiedItems = ^IRIS .Temp (" sscProd" ,$job ," modifiedItems" )
323
+ do ..GetAddOrDeletedItems (productionName , .modifiedItems )
330
324
}
331
325
}
332
326
}
333
327
328
+ /// Get added or deleted Config Items by checking Ens_Config.Item table against cache from OnBeforeSave
329
+ ClassMethod GetAddOrDeletedItems (productionName As %String , ByRef modifiedItems )
330
+ {
331
+ set rs = ..ExecDirectNoPriv (
332
+ " select Name, ClassName from Ens_Config.Item where Production = ?"
333
+ , productionName )
334
+ throw :rs .%SQLCODE <0 ##class (%Exception.SQL ).CreateFromSQLCODE (rs .%SQLCODE ,rs .%Message )
335
+ while rs .%Next () {
336
+ if '$get (^IRIS .Temp (" sscProd" ,$job ," items" , $listbuild (rs .Name , rs .ClassName ))) {
337
+ set itemInternalName = ..CreateInternalName (productionName , rs .Name , rs .ClassName , 0 )
338
+ set modifiedItems (itemInternalName ) = " A"
339
+ }
340
+ kill ^IRIS .Temp (" sscProd" ,$job ," items" , $listbuild (rs .Name , rs .ClassName ))
341
+ }
342
+ set key = $order (^IRIS .Temp (" sscProd" ,$job ," items" ," " ))
343
+ while (key '= " " ) {
344
+ set itemInternalName = ..CreateInternalName (productionName , $listget (key ,1 ), $listget (key ,2 ), 0 )
345
+ set modifiedItems (itemInternalName ) = " D"
346
+ set key = $order (^IRIS .Temp (" sscProd" ,$job ," items" ,key ))
347
+ }
348
+ }
349
+
334
350
/// Check if current CSP session is EnsPortal page
335
- ClassMethod IsEnsPortal () As %Boolean
351
+ ClassMethod IsEnsPortal (Output source As %String = " " ) As %Boolean
336
352
{
337
- Return $Data (%request ) && '($IsObject (%request ) &&
338
- (
339
- (%request .UserAgent [ " Code" ) // VS Code
340
- || (%request .UserAgent [ " node-fetch" ) // VS Code
341
- || (%request .Application [ " /api/interop-editors" ))) // New interoperability editor
353
+ if $Data (%request ) && $isobject (%request ) {
354
+ if (%request .Application [ " /api/atelier" ) {
355
+ set source = " IDE"
356
+ } elseif (%request .Application [ " /api/interop-editors" ) {
357
+ set source = " Interop Editor"
358
+ } else {
359
+ return 1
360
+ }
361
+ } else {
362
+ Set source = " IDE"
363
+ }
364
+ return 0
342
365
}
343
366
344
367
/// Perform check if Production Decomposition logic should be used for given item
345
368
ClassMethod IsProductionClass (className As %String , nameMethod As %String ) As %Boolean
346
369
{
347
370
if (className '= " " ) && $$$comClassDefined(className ) {
348
- return $classmethod (className , " %Extends" , " Ens.Production" )
371
+ try {
372
+ return $classmethod (className , " %Extends" , " Ens.Production" )
373
+ } catch err {
374
+ if '(err .AsStatus () [ " CLASS DOES NOT EXIST" ) throw err
375
+ }
349
376
} else {
350
377
// check if there exists a Production settings PTD export for ths Production
351
378
set settingsPTD = ..CreateInternalName (className ,,,1 )
@@ -371,7 +398,7 @@ ClassMethod IsProductionClass(className As %String, nameMethod As %String) As %B
371
398
}
372
399
373
400
/// Given a file name for a PTD item, returns a suggested internal name. This method assumes that the file exists on disk.
374
- ClassMethod ParseExternalName (externalName , Output internalName = " " , Output productionName = " " ) As %Status
401
+ ClassMethod ParseExternalName (externalName As %String , Output internalName = " " , Output productionName = " " ) As %Status
375
402
{
376
403
set sc = $$$OK
377
404
try {
@@ -413,7 +440,7 @@ ClassMethod ParseExternalName(externalName, Output internalName = "", Output pro
413
440
/// - itemName: name of the configuration item
414
441
/// - productionName: name of the associated production
415
442
/// - isProdSettings: if true, this item is a production settings; if false, this item is a configuration item settings
416
- ClassMethod ParseInternalName (internalName , noFolders As %Boolean = 0 , Output fileName , Output itemName , Output itemClassName , Output productionName , Output isProdSettings As %Boolean )
443
+ ClassMethod ParseInternalName (internalName As %String , noFolders As %Boolean = 0 , Output fileName As %String , Output itemName As %String , Output itemClassName As %String , Output productionName As %String , Output isProdSettings As %Boolean )
417
444
{
418
445
set name = $piece (internalName ," ." ,1 ,*-1 )
419
446
if 'noFolders {
@@ -436,7 +463,7 @@ ClassMethod ParseInternalName(internalName, noFolders As %Boolean = 0, Output fi
436
463
}
437
464
438
465
/// Calculates the internal name for a decomposed production item
439
- ClassMethod CreateInternalName (productionName = " " , itemName = " " , itemClassName = " " , isProductionSettings As %Boolean = 0 ) As %String
466
+ ClassMethod CreateInternalName (productionName As %String = " " , itemName As %String = " " , itemClassName As %String = " " , isProductionSettings As %Boolean = 0 ) As %String
440
467
{
441
468
return $select (
442
469
isProductionSettings : productionName _" ||ProductionSettings-" _productionName _" .PTD" ,
@@ -445,7 +472,7 @@ ClassMethod CreateInternalName(productionName = "", itemName = "", itemClassName
445
472
}
446
473
447
474
/// Given an external name for a PTD item, removes that item from the production.
448
- ClassMethod RemoveItemByExternalName (externalName , nameMethod ) As %Status
475
+ ClassMethod RemoveItemByExternalName (externalName As %String , nameMethod As %String ) As %Status
449
476
{
450
477
set sc = $$$OK
451
478
set productionName = $replace ($piece ($replace (externalName ," \" ," /" )," /" ,*-1 )," _" ," ." )
@@ -466,7 +493,7 @@ ClassMethod RemoveItemByExternalName(externalName, nameMethod) As %Status
466
493
}
467
494
468
495
/// Given an internal name for a PTD item, removes that item from the production.
469
- ClassMethod RemoveItem (internalName , noFolders As %Boolean = 0 ) As %Status
496
+ ClassMethod RemoveItem (internalName As %String , noFolders As %Boolean = 0 ) As %Status
470
497
{
471
498
set sc = $$$OK
472
499
try {
@@ -477,11 +504,21 @@ ClassMethod RemoveItem(internalName, noFolders As %Boolean = 0) As %Status
477
504
if 'isProdSettings {
478
505
set production = ##class (Ens.Config.Production ).%OpenId (productionName ,,.sc )
479
506
quit :$$$ISERR(sc )
480
- set configItem = ##class (Ens.Config.Production ).OpenItemByConfigName (productionName _" ||" _itemName _" |" _itemClassName ,.sc )
481
- quit :$$$ISERR(sc )
482
- do production .RemoveItem (configItem )
507
+ set configItem = ##class (Ens.Config.Production ).OpenItemByConfigName (productionName _" ||" _itemName _" |" _itemClassName ,.sc )
508
+
509
+ // only remove config item if it still exists and if item was opened ok
510
+ if $$$ISERR(sc ) {
511
+ if '(sc [ " ErrConfigItemNotFound" ) {
512
+ return sc
513
+ }
514
+ } else {
515
+ do production .RemoveItem (configItem )
516
+ }
517
+
483
518
set sc = production .%Save ()
484
519
quit :$$$ISERR(sc )
520
+ set sc = production .SaveToClass ()
521
+ quit :$$$ISERR(sc )
485
522
}
486
523
} catch err {
487
524
set sc = err .AsStatus ()
@@ -491,7 +528,7 @@ ClassMethod RemoveItem(internalName, noFolders As %Boolean = 0) As %Status
491
528
492
529
/// Given internal name for a Production Settings PTD, creates the corresponding Production
493
530
/// Class if it does not already exist in this namespace
494
- ClassMethod CreateProduction (productionName As %String , superClasses = " " ) As %Status
531
+ ClassMethod CreateProduction (productionName As %String , superClasses As %String = " " ) As %Status
495
532
{
496
533
set classDef = ##class (%Dictionary.ClassDefinition ).%New (productionName )
497
534
if superClasses '= " " {
@@ -525,7 +562,7 @@ ClassMethod GetUserProductionChanges(productionName As %String, ByRef items)
525
562
}
526
563
527
564
/// Executes a SQL query without privilege checking if possible on this IRIS version
528
- ClassMethod ExecDirectNoPriv (sql , args ...) As %SQL .StatementResult
565
+ ClassMethod ExecDirectNoPriv (sql As %String , args ...) As %SQL .StatementResult
529
566
{
530
567
// once minimum version is IRIS 2021.1.3, remove and just use %ExecDirectNoPriv
531
568
try {
0 commit comments