Sometimes, it’s easier to edit raw JSON than to use the available application studio tools, such as when you want to reorganize columns in a grid. If I’ve missed the functionality, feel free to tell me, but currently, the only way I’ve been able to accomplish this is to delete all columns and re-add them in the new order.
Enter Export. You can export the base layers of your custom apps, extract them, modify the RAW JSON files, re-archive them, and then import them back into Kinetic.
This method has a few downsides: It’s cumbersome, has no version control, and overwrites all version history for the layer in Epicor Kinetic.
Here is my contribution to overcoming some of those challenges with a simple tool.
What it does:
- Identifies base Kinetic Layers in the .\Apps\Erp.UI.<APP NAME>
- Find the latest major and minor version numbers from the zip in the current folders. .<App Name>_#_#.zip and determines the file name for a new archive by incriminating the revision number by 1.
- Compares the previous version to the current in .\Apps\Erp.UI.<APP NAME> by extracting the files to a temp folder and comparing timestamps.
- Archives the current version if it has been modified from the previous revision.
- It then performs some cleanup and reports what it has done.
How to use it:
Export your layer from Epicor Kinetic Application Studio and extract the zip contents into the folder containing the BuildKineticApplication.bat batch file.
Execute the BuildKineticApplication.bat file or rename the MetaUIs.zip file to something more identifiable to create your first ‘backup.’
Modify the JSON files and save your changes.
Execute the BuildKineticApplication.bat file to create an importable kinetic base layer.
Import the modified layer and test, revert, or repeat as necessary.
This makes it easy to archive any base kinetic layers you may be hacking while giving you some peace of mind that you can revert to a previous iteration.
Additional caveats: It’s not perfect, it doesn’t do everything I would like, it’s not well documented, it’s being released as is, and should you choose to use it, you do so at your own risk.
Let me know your thoughts or comments.
@REM BuildKineticApplication.bat
@REM Version control for Base Layer Epicor Kinetic Applications
@REM
@REM By Kevin Barrow released: 10/25/2024
@echo off
setlocal enabledelayedexpansion
if exist !SystemDrive!\Temp (
set "TEMP=!SYSTEMDRIVE!\Temp"
)
REM Define the base folder and file name
set "baseFolder=%CD%"
set "layerName="
REM Loop through each subfolder in the base folder(s)
for /D %%D in ("layers\*","Apps\*") do (
REM Reset the file counter and incremental value for each subfolder
set "MajorVersion=0"
set "Revision=0"
set "layerPath=%%~dpD"
set "layerFolder=%%~nxD"
REM for %%i in ("!layerPath!") do set "layerType=%%~nxi"
for %%i in ("!layerPath:~0,-1!") do set "layerType=%%~nxi"
echo !layerType! !layerFolder! !layerPath!
echo *******************************************************
for /f "tokens=3 delims=." %%a in ("%%~nxD") do (
set "layerName=%%a"
REM Find the largest file number in the current subfolder
for %%F in ("!layerName!_*.zip") do (
for /F "tokens=2 delims=_" %%V in ("%%~nF") do (
if %%V gtr !MajorVersion! (
set "MajorVersion=%%V"
set /A "PrevRevision=!Revision!"
set "Revision=0"
) else if %%V equ !MajorVersion! (
set "PrevVersion=!MajorVersion!"
REM for /R ".\" %%G in ("!layerName!_!MajorVersion!_*.zip") do (
for /R ".\" %%G in ("!layerName!_!MajorVersion!_*.zip") do (
for /F "tokens=3 delims=_" %%R in ("%%~nG") do (
if %%R geq !Revision! (
set /A "PrevRevision=%%R"
set /A "Revision=%%R + 1"
)
REM echo .
REM echo fileIteration: %%F %%G Version: !MajorVersion! verIteration: %%V nextRev: !Revision! revIteration: %%R
)
REM echo fileIteration: %%F %%G Version: !MajorVersion! verIteration: %%V nextRev: !Revision!
)
)
)
)
REM Create the previous and new file name
set newFileName=!layerName!_!MajorVersion!_!Revision!
if defined PrevVersion if defined PrevRevision (
set "prevFileName=!layerName!_!PrevVersion!_!PrevRevision!"
)
echo newFileName: !newFileName! PrevFileName: !prevFileName! Version: !MajorVersion! Revision: !Revision!
if not exist "!newFileName!.zip" (
REM check for existing newFileName before proceeding
if exist "!prevFileName!.zip" (
set "prevTempDir=!TEMP!\!prevFileName!"
echo .
echo Create a temporary directory for comparison !prevTempDir!
mkdir "!prevTempDir!" 2>nul
REM Extract the existing zip file to the temporary directory
powershell -Command "Expand-Archive -Path '!prevFileName!.zip' -DestinationPath '!prevTempDir!' -Force"
REM Compare the contents of the folder with the temporary directory
set "changed=0"
echo ---------------------------------------------------
echo %%D
pushd %CD%\%%D
for /R %%G in (*) do (
set "fullPath=%%G"
set "relativePath=!fullPath:%baseFolder%=!"
if "!relative_path:~0,1!"== "\" set "relative_path=!relative_path:~1!"
echo debug -- fileIteration: %%G !currentFileDate! compareLocation: !fileInTemp! !tempFileDate! relativePath=!relativePath!
set "fileInTemp=!prevTempDir!\!relativePath!"
if not exist "!fileInTemp!" (
set "changed=1"
echo File %%G is new or modified. tempFile: !fileInTemp!
) else (
REM Compare modification timestamps using WMIC for accurate comparison
for %%H in ("!fileInTemp!") do (
set currentFileDate=%%~tG
set tempFileDate=%%~tH
if not defined currentFileDate (
set "changed=1"
echo no currentFileDate obtained for %%G
) else if not defined tempFileDate (
set "changed=1"
echo no datestamp obtained for %%H
) else if !currentFileDate! NEQ !tempFileDate! (
set "changed=1"
echo File %%~nxG is modified.
)
REM echo fileIteration: %%G !currentFileDate! compareLocation: !fileInTemp! prevFileDate: !tempFileDate!
)
)
)
popd
if !changed! equ 0 ( echo No changes detected in %%D )
echo ---------------------------------------------------
echo Clean up the temporary directory !prevTempDir!
rmdir /s /q "!prevTempDir!"
) else ( set "changed=1" )
REM If there are changes, create the new zip file
if !changed! equ 1 (
set "tempDir=!TEMP!\!newFileName!"
echo Creating temp directory for Structure Archival !tempDir!\
mkdir !tempDir!\!layerType!\!layerFolder!
echo Copying !CD!\!layerType!\!layerFolder! to !tempDir!\!layerType!\
echo xcopy /e !CD!\!layerType!\!layerFolder! !tempDir!\!layerType!\!layerFolder! /Q
xcopy /e "!CD!\!layerType!\!layerFolder!" "!tempDir!\!layerType!\!layerFolder!" /Q
echo Creating new zip file: !newFileName!.zip
PowerShell -Command "Compress-Archive -Path '!Temp!\!newFileName!\*' -DestinationPath '!CD!\!newFileName!.zip' -Update -CompressionLevel Optimal"
REM echo "Execution paused for debugging, !tempDir!\ contains proposed content for !CD!\!newFileName!.zip"
REM echo "press <Ctrl+C> to abort and save or <Enter> to delete"
REM pause
echo cleaning up temp files !tempDir!
rmdir /s /q !tempDir!
) else (
echo No changes detected in %%D, skipping...
)
) else (
echo Zip file !newFileName!.zip already exists, skipping...
)
)
)
endlocal