You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2018/04/08 16:49:58 UTC

[46/46] logging-log4j-audit git commit: Fixed the catalog editor. Support using a branch

Fixed the catalog editor. Support using a branch


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/commit/7ccfa3aa
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/tree/7ccfa3aa
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/diff/7ccfa3aa

Branch: refs/heads/master
Commit: 7ccfa3aa83376bf79ac931f2d4cced4bad0e8341
Parents: 3b40bf6
Author: Ralph Goers <rg...@apache.org>
Authored: Sun Apr 8 09:49:04 2018 -0700
Committer: Ralph Goers <rg...@apache.org>
Committed: Sun Apr 8 09:49:04 2018 -0700

----------------------------------------------------------------------
 .../log4j/catalog/config/WebMvcAppContext.java  |    85 +-
 .../src/main/resources/application.properties   |     6 +
 .../src/main/resources/static/css/app.css       |   205 +
 .../resources/static/images/ajax-loader.gif     |   Bin 0 -> 3208 bytes
 .../main/resources/static/images/attributes.png |   Bin 0 -> 1981 bytes
 .../main/resources/static/images/constraint.png |   Bin 0 -> 2586 bytes
 .../src/main/resources/static/js/app.js         |    81 +
 .../src/main/resources/static/js/attributes.js  |   364 +
 .../src/main/resources/static/js/categories.js  |   257 +
 .../src/main/resources/static/js/events.js      |   291 +
 .../resources/static/js/jquery-1.12.4.min.js    |     5 +
 .../resources/static/js/jquery-2.2.4.min.js     |     4 +
 .../resources/static/js/jquery-3.2.1.min.js     |     4 +
 .../static/js/jquery-ui-1.12.1/AUTHORS.txt      |   333 +
 .../static/js/jquery-ui-1.12.1/LICENSE.txt      |    43 +
 .../jquery-ui-1.12.1/external/jquery/jquery.js  | 11008 ++++++++++
 .../images/ui-icons_444444_256x240.png          |   Bin 0 -> 7006 bytes
 .../images/ui-icons_555555_256x240.png          |   Bin 0 -> 7074 bytes
 .../images/ui-icons_777620_256x240.png          |   Bin 0 -> 4676 bytes
 .../images/ui-icons_777777_256x240.png          |   Bin 0 -> 7013 bytes
 .../images/ui-icons_cc0000_256x240.png          |   Bin 0 -> 4632 bytes
 .../images/ui-icons_ffffff_256x240.png          |   Bin 0 -> 6313 bytes
 .../static/js/jquery-ui-1.12.1/index.html       |   559 +
 .../static/js/jquery-ui-1.12.1/jquery-ui.css    |  1312 ++
 .../static/js/jquery-ui-1.12.1/jquery-ui.js     | 18706 +++++++++++++++++
 .../js/jquery-ui-1.12.1/jquery-ui.min.css       |     7 +
 .../static/js/jquery-ui-1.12.1/jquery-ui.min.js |    13 +
 .../js/jquery-ui-1.12.1/jquery-ui.structure.css |   886 +
 .../jquery-ui.structure.min.css                 |     5 +
 .../js/jquery-ui-1.12.1/jquery-ui.theme.css     |   443 +
 .../js/jquery-ui-1.12.1/jquery-ui.theme.min.css |     5 +
 .../static/js/jquery-ui-1.12.1/package.json     |    74 +
 .../jquery.jtable.aspnetpagemethods.js          |   150 +
 .../jquery.jtable.aspnetpagemethods.min.js      |    27 +
 .../static/js/jtable.2.4.0/external/json2.js    |   486 +
 .../js/jtable.2.4.0/external/json2.min.js       |     8 +
 .../static/js/jtable.2.4.0/jquery.jtable.js     |  5021 +++++
 .../static/js/jtable.2.4.0/jquery.jtable.min.js |   157 +
 .../localization/jquery.jtable.bd.js            |    30 +
 .../localization/jquery.jtable.ca.js            |    30 +
 .../localization/jquery.jtable.cz.js            |    30 +
 .../localization/jquery.jtable.de.js            |    30 +
 .../localization/jquery.jtable.es.js            |    30 +
 .../localization/jquery.jtable.fa.js            |    30 +
 .../localization/jquery.jtable.fr.js            |    30 +
 .../localization/jquery.jtable.hr.js            |    30 +
 .../localization/jquery.jtable.hu.js            |    30 +
 .../localization/jquery.jtable.id.js            |    31 +
 .../localization/jquery.jtable.it.js            |    30 +
 .../localization/jquery.jtable.lt.js            |    30 +
 .../localization/jquery.jtable.nl-NL.js         |    30 +
 .../localization/jquery.jtable.no.js            |    30 +
 .../localization/jquery.jtable.pl.js            |    30 +
 .../localization/jquery.jtable.pt-BR.js         |    30 +
 .../localization/jquery.jtable.pt-PT.js         |    29 +
 .../localization/jquery.jtable.ro.js            |    30 +
 .../localization/jquery.jtable.ru.js            |    31 +
 .../localization/jquery.jtable.se.js            |    30 +
 .../localization/jquery.jtable.tr.js            |    30 +
 .../localization/jquery.jtable.vi.js            |    28 +
 .../localization/jquery.jtable.zh-CN.js         |    30 +
 .../js/jtable.2.4.0/themes/basic/close.png      |   Bin 0 -> 3350 bytes
 .../js/jtable.2.4.0/themes/basic/column-asc.png |   Bin 0 -> 362 bytes
 .../jtable.2.4.0/themes/basic/column-desc.png   |   Bin 0 -> 349 bytes
 .../themes/basic/column-sortable.png            |   Bin 0 -> 347 bytes
 .../js/jtable.2.4.0/themes/basic/delete.png     |   Bin 0 -> 150 bytes
 .../js/jtable.2.4.0/themes/basic/edit.png       |   Bin 0 -> 590 bytes
 .../jtable.2.4.0/themes/basic/jtable_basic.css  |   282 +
 .../jtable.2.4.0/themes/basic/jtable_basic.less |    83 +
 .../themes/basic/jtable_basic.min.css           |     1 +
 .../js/jtable.2.4.0/themes/jqueryui/add.png     |   Bin 0 -> 482 bytes
 .../jtable.2.4.0/themes/jqueryui/bg-thead.png   |   Bin 0 -> 2811 bytes
 .../js/jtable.2.4.0/themes/jqueryui/close.png   |   Bin 0 -> 1217 bytes
 .../jtable.2.4.0/themes/jqueryui/column-asc.png |   Bin 0 -> 362 bytes
 .../themes/jqueryui/column-desc.png             |   Bin 0 -> 349 bytes
 .../themes/jqueryui/column-sortable.png         |   Bin 0 -> 347 bytes
 .../js/jtable.2.4.0/themes/jqueryui/delete.png  |   Bin 0 -> 150 bytes
 .../js/jtable.2.4.0/themes/jqueryui/edit.png    |   Bin 0 -> 590 bytes
 .../themes/jqueryui/jtable_jqueryui.css         |   398 +
 .../themes/jqueryui/jtable_jqueryui.less        |   296 +
 .../themes/jqueryui/jtable_jqueryui.min.css     |     1 +
 .../js/jtable.2.4.0/themes/jqueryui/loading.gif |   Bin 0 -> 723 bytes
 .../jtable.2.4.0/themes/jtable_theme_base.less  |   524 +
 .../js/jtable.2.4.0/themes/lightcolor/add.png   |   Bin 0 -> 482 bytes
 .../jtable.2.4.0/themes/lightcolor/bg-thead.png |   Bin 0 -> 2811 bytes
 .../themes/lightcolor/blue/jtable.css           |   521 +
 .../themes/lightcolor/blue/jtable.less          |    90 +
 .../themes/lightcolor/blue/jtable.min.css       |     1 +
 .../themes/lightcolor/blue/loading.gif          |   Bin 0 -> 723 bytes
 .../js/jtable.2.4.0/themes/lightcolor/close.png |   Bin 0 -> 1217 bytes
 .../themes/lightcolor/column-asc.png            |   Bin 0 -> 362 bytes
 .../themes/lightcolor/column-desc.png           |   Bin 0 -> 349 bytes
 .../themes/lightcolor/column-sortable.png       |   Bin 0 -> 347 bytes
 .../jtable.2.4.0/themes/lightcolor/delete.png   |   Bin 0 -> 150 bytes
 .../js/jtable.2.4.0/themes/lightcolor/edit.png  |   Bin 0 -> 590 bytes
 .../themes/lightcolor/gray/jtable.css           |   521 +
 .../themes/lightcolor/gray/jtable.less          |    90 +
 .../themes/lightcolor/gray/jtable.min.css       |     1 +
 .../themes/lightcolor/gray/loading.gif          |   Bin 0 -> 723 bytes
 .../themes/lightcolor/green/jtable.css          |   521 +
 .../themes/lightcolor/green/jtable.less         |    90 +
 .../themes/lightcolor/green/jtable.min.css      |     1 +
 .../themes/lightcolor/green/loading.gif         |   Bin 0 -> 723 bytes
 .../lightcolor/jtable_lightcolor_base.less      |   329 +
 .../themes/lightcolor/orange/jtable.css         |   521 +
 .../themes/lightcolor/orange/jtable.less        |    90 +
 .../themes/lightcolor/orange/jtable.min.css     |     1 +
 .../themes/lightcolor/orange/loading.gif        |   Bin 0 -> 723 bytes
 .../themes/lightcolor/red/jtable.css            |   521 +
 .../themes/lightcolor/red/jtable.less           |    90 +
 .../themes/lightcolor/red/jtable.min.css        |     1 +
 .../themes/lightcolor/red/loading.gif           |   Bin 0 -> 723 bytes
 .../static/js/jtable.2.4.0/themes/metro/add.png |   Bin 0 -> 482 bytes
 .../jtable.2.4.0/themes/metro/blue/jtable.css   |   495 +
 .../jtable.2.4.0/themes/metro/blue/jtable.less  |    11 +
 .../themes/metro/blue/jtable.min.css            |     1 +
 .../jtable.2.4.0/themes/metro/blue/loading.gif  |   Bin 0 -> 404 bytes
 .../jtable.2.4.0/themes/metro/brown/jtable.css  |   495 +
 .../jtable.2.4.0/themes/metro/brown/jtable.less |    11 +
 .../themes/metro/brown/jtable.min.css           |     1 +
 .../jtable.2.4.0/themes/metro/brown/loading.gif |   Bin 0 -> 404 bytes
 .../js/jtable.2.4.0/themes/metro/close.png      |   Bin 0 -> 3350 bytes
 .../js/jtable.2.4.0/themes/metro/column-asc.png |   Bin 0 -> 320 bytes
 .../jtable.2.4.0/themes/metro/column-desc.png   |   Bin 0 -> 311 bytes
 .../themes/metro/column-sortable.png            |   Bin 0 -> 314 bytes
 .../themes/metro/crimson/jtable.css             |   495 +
 .../themes/metro/crimson/jtable.less            |    11 +
 .../themes/metro/crimson/jtable.min.css         |     1 +
 .../themes/metro/crimson/loading.gif            |   Bin 0 -> 404 bytes
 .../themes/metro/darkgray/jtable.css            |   495 +
 .../themes/metro/darkgray/jtable.less           |    11 +
 .../themes/metro/darkgray/jtable.min.css        |     1 +
 .../themes/metro/darkgray/loading.gif           |   Bin 0 -> 404 bytes
 .../themes/metro/darkorange/jtable.css          |   495 +
 .../themes/metro/darkorange/jtable.less         |    11 +
 .../themes/metro/darkorange/jtable.min.css      |     1 +
 .../themes/metro/darkorange/loading.gif         |   Bin 0 -> 404 bytes
 .../js/jtable.2.4.0/themes/metro/delete.png     |   Bin 0 -> 3167 bytes
 .../js/jtable.2.4.0/themes/metro/edit.png       |   Bin 0 -> 3359 bytes
 .../jtable.2.4.0/themes/metro/green/jtable.css  |   495 +
 .../jtable.2.4.0/themes/metro/green/jtable.less |    11 +
 .../themes/metro/green/jtable.min.css           |     1 +
 .../jtable.2.4.0/themes/metro/green/loading.gif |   Bin 0 -> 404 bytes
 .../themes/metro/jtable_metro_base.css          |    48 +
 .../themes/metro/jtable_metro_base.less         |   439 +
 .../themes/metro/jtable_metro_base.min.css      |     1 +
 .../themes/metro/lightgray/jtable.css           |   495 +
 .../themes/metro/lightgray/jtable.less          |    11 +
 .../themes/metro/lightgray/jtable.min.css       |     1 +
 .../themes/metro/lightgray/loading.gif          |   Bin 0 -> 404 bytes
 .../jtable.2.4.0/themes/metro/pink/jtable.css   |   495 +
 .../jtable.2.4.0/themes/metro/pink/jtable.less  |    11 +
 .../themes/metro/pink/jtable.min.css            |     1 +
 .../jtable.2.4.0/themes/metro/pink/loading.gif  |   Bin 0 -> 404 bytes
 .../jtable.2.4.0/themes/metro/purple/jtable.css |   495 +
 .../themes/metro/purple/jtable.less             |    11 +
 .../themes/metro/purple/jtable.min.css          |     1 +
 .../themes/metro/purple/loading.gif             |   Bin 0 -> 404 bytes
 .../js/jtable.2.4.0/themes/metro/red/jtable.css |   495 +
 .../jtable.2.4.0/themes/metro/red/jtable.less   |    11 +
 .../themes/metro/red/jtable.min.css             |     1 +
 .../jtable.2.4.0/themes/metro/red/loading.gif   |   Bin 0 -> 404 bytes
 .../src/main/resources/static/js/products.js    |   257 +
 .../main/resources/templates/attributes.html    |    44 +
 .../main/resources/templates/categories.html    |    43 +
 .../src/main/resources/templates/events.html    |    44 +
 .../src/main/resources/templates/products.html  |    43 +
 .../src/main/resources/templates/template.html  |    42 +
 .../webapp/WEB-INF/templates/attributes.html    |    44 -
 .../webapp/WEB-INF/templates/categories.html    |    43 -
 .../main/webapp/WEB-INF/templates/events.html   |    44 -
 .../main/webapp/WEB-INF/templates/products.html |    43 -
 .../main/webapp/WEB-INF/templates/template.html |    42 -
 .../src/main/webapp/css/app.css                 |   205 -
 .../src/main/webapp/images/ajax-loader.gif      |   Bin 3208 -> 0 bytes
 .../src/main/webapp/images/attributes.png       |   Bin 1981 -> 0 bytes
 .../src/main/webapp/images/constraint.png       |   Bin 2586 -> 0 bytes
 .../src/main/webapp/js/app.js                   |    81 -
 .../src/main/webapp/js/attributes.js            |   364 -
 .../src/main/webapp/js/categories.js            |   257 -
 .../src/main/webapp/js/events.js                |   291 -
 .../src/main/webapp/js/jquery-1.12.4.min.js     |     5 -
 .../src/main/webapp/js/jquery-2.2.4.min.js      |     4 -
 .../src/main/webapp/js/jquery-3.2.1.min.js      |     4 -
 .../main/webapp/js/jquery-ui-1.12.1/AUTHORS.txt |   333 -
 .../main/webapp/js/jquery-ui-1.12.1/LICENSE.txt |    43 -
 .../jquery-ui-1.12.1/external/jquery/jquery.js  | 11008 ----------
 .../images/ui-icons_444444_256x240.png          |   Bin 7006 -> 0 bytes
 .../images/ui-icons_555555_256x240.png          |   Bin 7074 -> 0 bytes
 .../images/ui-icons_777620_256x240.png          |   Bin 4676 -> 0 bytes
 .../images/ui-icons_777777_256x240.png          |   Bin 7013 -> 0 bytes
 .../images/ui-icons_cc0000_256x240.png          |   Bin 4632 -> 0 bytes
 .../images/ui-icons_ffffff_256x240.png          |   Bin 6313 -> 0 bytes
 .../main/webapp/js/jquery-ui-1.12.1/index.html  |   559 -
 .../webapp/js/jquery-ui-1.12.1/jquery-ui.css    |  1312 --
 .../webapp/js/jquery-ui-1.12.1/jquery-ui.js     | 18706 -----------------
 .../js/jquery-ui-1.12.1/jquery-ui.min.css       |     7 -
 .../webapp/js/jquery-ui-1.12.1/jquery-ui.min.js |    13 -
 .../js/jquery-ui-1.12.1/jquery-ui.structure.css |   886 -
 .../jquery-ui.structure.min.css                 |     5 -
 .../js/jquery-ui-1.12.1/jquery-ui.theme.css     |   443 -
 .../js/jquery-ui-1.12.1/jquery-ui.theme.min.css |     5 -
 .../webapp/js/jquery-ui-1.12.1/package.json     |    74 -
 .../jquery.jtable.aspnetpagemethods.js          |   150 -
 .../jquery.jtable.aspnetpagemethods.min.js      |    27 -
 .../webapp/js/jtable.2.4.0/external/json2.js    |   486 -
 .../js/jtable.2.4.0/external/json2.min.js       |     8 -
 .../webapp/js/jtable.2.4.0/jquery.jtable.js     |  5021 -----
 .../webapp/js/jtable.2.4.0/jquery.jtable.min.js |   157 -
 .../localization/jquery.jtable.bd.js            |    30 -
 .../localization/jquery.jtable.ca.js            |    30 -
 .../localization/jquery.jtable.cz.js            |    30 -
 .../localization/jquery.jtable.de.js            |    30 -
 .../localization/jquery.jtable.es.js            |    30 -
 .../localization/jquery.jtable.fa.js            |    30 -
 .../localization/jquery.jtable.fr.js            |    30 -
 .../localization/jquery.jtable.hr.js            |    30 -
 .../localization/jquery.jtable.hu.js            |    30 -
 .../localization/jquery.jtable.id.js            |    31 -
 .../localization/jquery.jtable.it.js            |    30 -
 .../localization/jquery.jtable.lt.js            |    30 -
 .../localization/jquery.jtable.nl-NL.js         |    30 -
 .../localization/jquery.jtable.no.js            |    30 -
 .../localization/jquery.jtable.pl.js            |    30 -
 .../localization/jquery.jtable.pt-BR.js         |    30 -
 .../localization/jquery.jtable.pt-PT.js         |    29 -
 .../localization/jquery.jtable.ro.js            |    30 -
 .../localization/jquery.jtable.ru.js            |    31 -
 .../localization/jquery.jtable.se.js            |    30 -
 .../localization/jquery.jtable.tr.js            |    30 -
 .../localization/jquery.jtable.vi.js            |    28 -
 .../localization/jquery.jtable.zh-CN.js         |    30 -
 .../js/jtable.2.4.0/themes/basic/close.png      |   Bin 3350 -> 0 bytes
 .../js/jtable.2.4.0/themes/basic/column-asc.png |   Bin 362 -> 0 bytes
 .../jtable.2.4.0/themes/basic/column-desc.png   |   Bin 349 -> 0 bytes
 .../themes/basic/column-sortable.png            |   Bin 347 -> 0 bytes
 .../js/jtable.2.4.0/themes/basic/delete.png     |   Bin 150 -> 0 bytes
 .../js/jtable.2.4.0/themes/basic/edit.png       |   Bin 590 -> 0 bytes
 .../jtable.2.4.0/themes/basic/jtable_basic.css  |   282 -
 .../jtable.2.4.0/themes/basic/jtable_basic.less |    83 -
 .../themes/basic/jtable_basic.min.css           |     1 -
 .../js/jtable.2.4.0/themes/jqueryui/add.png     |   Bin 482 -> 0 bytes
 .../jtable.2.4.0/themes/jqueryui/bg-thead.png   |   Bin 2811 -> 0 bytes
 .../js/jtable.2.4.0/themes/jqueryui/close.png   |   Bin 1217 -> 0 bytes
 .../jtable.2.4.0/themes/jqueryui/column-asc.png |   Bin 362 -> 0 bytes
 .../themes/jqueryui/column-desc.png             |   Bin 349 -> 0 bytes
 .../themes/jqueryui/column-sortable.png         |   Bin 347 -> 0 bytes
 .../js/jtable.2.4.0/themes/jqueryui/delete.png  |   Bin 150 -> 0 bytes
 .../js/jtable.2.4.0/themes/jqueryui/edit.png    |   Bin 590 -> 0 bytes
 .../themes/jqueryui/jtable_jqueryui.css         |   398 -
 .../themes/jqueryui/jtable_jqueryui.less        |   296 -
 .../themes/jqueryui/jtable_jqueryui.min.css     |     1 -
 .../js/jtable.2.4.0/themes/jqueryui/loading.gif |   Bin 723 -> 0 bytes
 .../jtable.2.4.0/themes/jtable_theme_base.less  |   524 -
 .../js/jtable.2.4.0/themes/lightcolor/add.png   |   Bin 482 -> 0 bytes
 .../jtable.2.4.0/themes/lightcolor/bg-thead.png |   Bin 2811 -> 0 bytes
 .../themes/lightcolor/blue/jtable.css           |   521 -
 .../themes/lightcolor/blue/jtable.less          |    90 -
 .../themes/lightcolor/blue/jtable.min.css       |     1 -
 .../themes/lightcolor/blue/loading.gif          |   Bin 723 -> 0 bytes
 .../js/jtable.2.4.0/themes/lightcolor/close.png |   Bin 1217 -> 0 bytes
 .../themes/lightcolor/column-asc.png            |   Bin 362 -> 0 bytes
 .../themes/lightcolor/column-desc.png           |   Bin 349 -> 0 bytes
 .../themes/lightcolor/column-sortable.png       |   Bin 347 -> 0 bytes
 .../jtable.2.4.0/themes/lightcolor/delete.png   |   Bin 150 -> 0 bytes
 .../js/jtable.2.4.0/themes/lightcolor/edit.png  |   Bin 590 -> 0 bytes
 .../themes/lightcolor/gray/jtable.css           |   521 -
 .../themes/lightcolor/gray/jtable.less          |    90 -
 .../themes/lightcolor/gray/jtable.min.css       |     1 -
 .../themes/lightcolor/gray/loading.gif          |   Bin 723 -> 0 bytes
 .../themes/lightcolor/green/jtable.css          |   521 -
 .../themes/lightcolor/green/jtable.less         |    90 -
 .../themes/lightcolor/green/jtable.min.css      |     1 -
 .../themes/lightcolor/green/loading.gif         |   Bin 723 -> 0 bytes
 .../lightcolor/jtable_lightcolor_base.less      |   329 -
 .../themes/lightcolor/orange/jtable.css         |   521 -
 .../themes/lightcolor/orange/jtable.less        |    90 -
 .../themes/lightcolor/orange/jtable.min.css     |     1 -
 .../themes/lightcolor/orange/loading.gif        |   Bin 723 -> 0 bytes
 .../themes/lightcolor/red/jtable.css            |   521 -
 .../themes/lightcolor/red/jtable.less           |    90 -
 .../themes/lightcolor/red/jtable.min.css        |     1 -
 .../themes/lightcolor/red/loading.gif           |   Bin 723 -> 0 bytes
 .../webapp/js/jtable.2.4.0/themes/metro/add.png |   Bin 482 -> 0 bytes
 .../jtable.2.4.0/themes/metro/blue/jtable.css   |   495 -
 .../jtable.2.4.0/themes/metro/blue/jtable.less  |    11 -
 .../themes/metro/blue/jtable.min.css            |     1 -
 .../jtable.2.4.0/themes/metro/blue/loading.gif  |   Bin 404 -> 0 bytes
 .../jtable.2.4.0/themes/metro/brown/jtable.css  |   495 -
 .../jtable.2.4.0/themes/metro/brown/jtable.less |    11 -
 .../themes/metro/brown/jtable.min.css           |     1 -
 .../jtable.2.4.0/themes/metro/brown/loading.gif |   Bin 404 -> 0 bytes
 .../js/jtable.2.4.0/themes/metro/close.png      |   Bin 3350 -> 0 bytes
 .../js/jtable.2.4.0/themes/metro/column-asc.png |   Bin 320 -> 0 bytes
 .../jtable.2.4.0/themes/metro/column-desc.png   |   Bin 311 -> 0 bytes
 .../themes/metro/column-sortable.png            |   Bin 314 -> 0 bytes
 .../themes/metro/crimson/jtable.css             |   495 -
 .../themes/metro/crimson/jtable.less            |    11 -
 .../themes/metro/crimson/jtable.min.css         |     1 -
 .../themes/metro/crimson/loading.gif            |   Bin 404 -> 0 bytes
 .../themes/metro/darkgray/jtable.css            |   495 -
 .../themes/metro/darkgray/jtable.less           |    11 -
 .../themes/metro/darkgray/jtable.min.css        |     1 -
 .../themes/metro/darkgray/loading.gif           |   Bin 404 -> 0 bytes
 .../themes/metro/darkorange/jtable.css          |   495 -
 .../themes/metro/darkorange/jtable.less         |    11 -
 .../themes/metro/darkorange/jtable.min.css      |     1 -
 .../themes/metro/darkorange/loading.gif         |   Bin 404 -> 0 bytes
 .../js/jtable.2.4.0/themes/metro/delete.png     |   Bin 3167 -> 0 bytes
 .../js/jtable.2.4.0/themes/metro/edit.png       |   Bin 3359 -> 0 bytes
 .../jtable.2.4.0/themes/metro/green/jtable.css  |   495 -
 .../jtable.2.4.0/themes/metro/green/jtable.less |    11 -
 .../themes/metro/green/jtable.min.css           |     1 -
 .../jtable.2.4.0/themes/metro/green/loading.gif |   Bin 404 -> 0 bytes
 .../themes/metro/jtable_metro_base.css          |    48 -
 .../themes/metro/jtable_metro_base.less         |   439 -
 .../themes/metro/jtable_metro_base.min.css      |     1 -
 .../themes/metro/lightgray/jtable.css           |   495 -
 .../themes/metro/lightgray/jtable.less          |    11 -
 .../themes/metro/lightgray/jtable.min.css       |     1 -
 .../themes/metro/lightgray/loading.gif          |   Bin 404 -> 0 bytes
 .../jtable.2.4.0/themes/metro/pink/jtable.css   |   495 -
 .../jtable.2.4.0/themes/metro/pink/jtable.less  |    11 -
 .../themes/metro/pink/jtable.min.css            |     1 -
 .../jtable.2.4.0/themes/metro/pink/loading.gif  |   Bin 404 -> 0 bytes
 .../jtable.2.4.0/themes/metro/purple/jtable.css |   495 -
 .../themes/metro/purple/jtable.less             |    11 -
 .../themes/metro/purple/jtable.min.css          |     1 -
 .../themes/metro/purple/loading.gif             |   Bin 404 -> 0 bytes
 .../js/jtable.2.4.0/themes/metro/red/jtable.css |   495 -
 .../jtable.2.4.0/themes/metro/red/jtable.less   |    11 -
 .../themes/metro/red/jtable.min.css             |     1 -
 .../jtable.2.4.0/themes/metro/red/loading.gif   |   Bin 404 -> 0 bytes
 .../src/main/webapp/js/products.js              |   257 -
 .../log4j/catalog/git/dao/GitCatalogDao.java    |    12 +
 335 files changed, 52175 insertions(+), 52224 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java b/log4j-catalog/log4j-catalog-editor/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
index 181024d..5239d23 100644
--- a/log4j-catalog/log4j-catalog-editor/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
+++ b/log4j-catalog/log4j-catalog-editor/src/main/java/org/apache/logging/log4j/catalog/config/WebMvcAppContext.java
@@ -99,9 +99,9 @@ public class WebMvcAppContext extends WebMvcConfigurerAdapter implements Applica
     @Override
     public void addResourceHandlers(final ResourceHandlerRegistry registry) {
         super.addResourceHandlers(registry);
-        registry.addResourceHandler("/images/**").addResourceLocations("/images/");
-        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
-        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
+        registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/");
+        registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
+        registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
         registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
         registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
     }
@@ -119,20 +119,6 @@ public class WebMvcAppContext extends WebMvcConfigurerAdapter implements Applica
         converters.add(jsonMessageConverter());
     }
 
-
-    /*
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(localAuthorizationInterceptor())
-                .addPathPatterns("/**")
-                .excludePathPatterns("/swagger**")
-                .excludePathPatterns("/v2/api-docs**")
-                .excludePathPatterns("/configuration/security**")
-                .excludePathPatterns("/configuration/ui**")
-                .excludePathPatterns("/webjars/**");
-    }
-    */
-
     @Bean
     public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
         DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -140,17 +126,6 @@ public class WebMvcAppContext extends WebMvcConfigurerAdapter implements Applica
         return proxyCreator;
     }
 
-    /*
-    @Bean
-    public ViewResolver internalResourceViewResolver() {
-        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
-        viewResolver.setViewClass(JstlView.class);
-        viewResolver.setPrefix("/WEB-INF/views/");
-        viewResolver.setSuffix(".jsp");
-        viewResolver.setOrder(10);
-        return viewResolver;
-    } */
-
     @Bean
     public MessageSource messageSource() {
         ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
@@ -189,6 +164,9 @@ public class WebMvcAppContext extends WebMvcConfigurerAdapter implements Applica
     @Value("${localRepoUrl:#{null}}")
     private String localRepoUrl;
 
+    @Value("${branch:#{null}}")
+    private String branch;
+
     @Value("${privateKeyPath:#{null}}")
     private String privateKeyPath;
 
@@ -263,6 +241,9 @@ public class WebMvcAppContext extends WebMvcConfigurerAdapter implements Applica
         } else {
             LOGGER.error("No remote repo URL provided.");
         }
+        if (isNotBlank(branch)) {
+            dataSource.setBranch(branch);
+        }
 
         if (isNotBlank(localRepoUrl)) {
             dataSource.setLocalRepoPath(localRepoUrl);
@@ -280,52 +261,4 @@ public class WebMvcAppContext extends WebMvcConfigurerAdapter implements Applica
         }
         return dataSource;
     }
-
-    public SpringResourceTemplateResolver templateResolver(){
-        // SpringResourceTemplateResolver automatically integrates with Spring's own
-        // resource resolution infrastructure, which is highly recommended.
-        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
-        templateResolver.setApplicationContext(this.applicationContext);
-        templateResolver.setPrefix("/WEB-INF/templates/");
-        templateResolver.setSuffix(".html");
-        // HTML is the default value, added here for the sake of clarity.
-        templateResolver.setTemplateMode(TemplateMode.HTML);
-        // Template cache is true by default. Set to false if you want
-        // templates to be automatically updated when modified.
-        templateResolver.setCacheable(true);
-        return templateResolver;
-    }
-
-    public SpringTemplateEngine templateEngine(){
-        // SpringTemplateEngine automatically applies SpringStandardDialect and
-        // enables Spring's own MessageSource message resolution mechanisms.
-        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
-        templateEngine.setTemplateResolver(templateResolver());
-        // Enabling the SpringEL compiler with Spring 4.2.4 or newer can
-        // speed up execution in most scenarios, but might be incompatible
-        // with specific cases when expressions in one template are reused
-        // across different data types, so this flag is "false" by default
-        // for safer backwards compatibility.
-        templateEngine.setEnableSpringELCompiler(true);
-        return templateEngine;
-    }
-
-    @Bean
-    public ViewResolver thymeleafViewResolver(){
-        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
-        viewResolver.setTemplateEngine(templateEngine());
-        // NOTE 'order' and 'viewNames' are optional
-        viewResolver.setOrder(1);
-        viewResolver.setViewNames(new String[] {"products", "categories", "events", "attributes"});
-        return viewResolver;
-    }
-
-    @Bean
-    @Scope("prototype")
-    public ThymeleafView mainView() {
-        ThymeleafView view = new ThymeleafView("index"); // templateName = 'main'
-        view.setStaticVariables(
-                Collections.singletonMap("footer", "The Apache Software Foundation"));
-        return view;
-    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/application.properties
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/application.properties b/log4j-catalog/log4j-catalog-editor/src/main/resources/application.properties
new file mode 100644
index 0000000..e9e2b8a
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-editor/src/main/resources/application.properties
@@ -0,0 +1,6 @@
+spring.thymeleaf.cache=false
+spring.thymeleaf.enabled=true
+spring.thymeleaf.prefix=classpath:/templates/
+spring.thymeleaf.suffix=.html
+
+spring.application.name=Log4j Catalog Editor
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/css/app.css
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/css/app.css b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/css/app.css
new file mode 100644
index 0000000..d1ffda7
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/css/app.css
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+@import url('https://fonts.googleapis.com/css?family=Lato');
+
+body {
+  font-family: 'Lato', sans-serif;
+  margin: 0;
+  padding: 0;
+}
+
+#nav {
+  background-color: #f3f3f3;
+  border-bottom: 1px solid #e7e7e7;
+  display: flex;
+  height: 48px;
+  justify-content: space-between;
+  margin-bottom: 24px;
+  width: 100%;
+}
+
+#nav a {
+  border-right: 1px solid #e7e7e7;
+  color: #666;
+  font-size: 16px;
+  line-height: 48px;
+  padding: 0 14px;
+  text-decoration: none;
+}
+
+#nav #save-all {
+  border-right: none;
+  border-left: 1px solid #e7e7e7;
+  margin-left: auto;
+}
+
+#nav a:hover,
+#nav #save-all:hover {
+  background-color: #0b67cd;
+  border-right: 1px solid #0b67cd;
+  color: #fff;
+}
+
+#ftr {
+  margin: 24px;
+  text-align: center;
+}
+
+.log4j-table-container {
+  padding: 0 24px;
+}
+
+.form-processing {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  background-color: #fff;
+  z-index: 100;
+  opacity: .75;
+}
+
+.form-processing .gif {
+  position: absolute;
+  top: calc(50% - 16px);
+  left: calc(50% - 16px);
+  width: 32px;
+  height: 32px;
+  background-image: url(../images/ajax-loader.gif);
+  background-repeat: no-repeat;
+}
+
+.log4J-action-icon {
+  opacity: .4;
+}
+
+.log4j-catalog-form {
+  position: relative;
+}
+
+.log4j-catalog-form p {
+  position: relative;
+}
+
+.log4j-catalog-form input[type="text"],
+.log4j-catalog-form select,
+.log4j-catalog-form textarea {
+  width: 80%;
+  border: 1px solid #ddd;
+  padding: 2px 7px;
+  background-color: #fff;
+}
+
+.log4j-catalog-form select[multiple] {
+  height: 200px;
+}
+
+.log4j-catalog-form label {
+  display: block;
+  margin-bottom: 7px;
+  color: #aaa;
+}
+
+.log4j-catalog-form .form-error {
+  position: absolute;
+  top: 52px;
+  left: 354px;
+  color: #ff0000;
+  font-size: 12px;
+}
+
+.log4j-catalog-modal {
+  background-color: #fff;
+  border: 1px solid #ddd;
+  box-shadow: 0 0 20px #ccc;
+  left: 0;
+  margin: auto;
+  padding: 24px;
+  position: absolute;
+  right: 0;
+  top: 25%;
+  width: 500px;
+}
+
+.log4j-catalog-title {
+  border-bottom: 1px solid #ddd;
+  margin-bottom: 24px;
+  padding-bottom: 14px;
+}
+
+.log4j-catalog-button + .log4j-catalog-button {
+  margin-left: 24px;
+}
+
+/* Events */
+.event-attributes,
+.event-attribute-row {
+  font-size: 12px;
+}
+
+.event-attribute-row,
+.attribute-constraint-row,
+.product-event-row {
+  display: block;
+  clear: both;
+  line-height: 12px;
+  margin: 2px 0;
+  vertical-align: middle;
+}
+
+.event-attribute-row input[type="text"] {
+  width: 270px;
+  margin-right: 24px;
+}
+
+.event-attribute-item-required {
+  font-size: 10px;
+  color: #aaa;
+}
+
+.event-attribute-row button {
+  margin-left: 24px;
+}
+
+.attribute-constraint-row .form-error {
+  position: static;
+  padding: 0 4px;
+}
+
+.attribute-constraint-name {
+  font-size: 12px;
+  display: inline-block;
+  text-transform: uppercase;
+  width: 145px;
+}
+
+.attribute-constraint-data,
+#addAttributeConstraintValue {
+  width: 251px !important;
+}
+
+#addAttributeConstraintName {
+  width: 145px;
+}
+
+#addEventAttribute {
+  width: 375px !important;
+}
+
+#addEventAttributeButton,
+.remove-event-attribute-button {
+  cursor: pointer;
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/ajax-loader.gif
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/ajax-loader.gif b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/ajax-loader.gif
new file mode 100644
index 0000000..bd6dd97
Binary files /dev/null and b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/ajax-loader.gif differ

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/attributes.png
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/attributes.png b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/attributes.png
new file mode 100644
index 0000000..7957193
Binary files /dev/null and b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/attributes.png differ

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/constraint.png
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/constraint.png b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/constraint.png
new file mode 100644
index 0000000..7604751
Binary files /dev/null and b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/images/constraint.png differ

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/app.js
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/app.js b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/app.js
new file mode 100644
index 0000000..1e906d3
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/app.js
@@ -0,0 +1,81 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+$(document).ready(function () {
+    // Clear localStorage
+    localStorage.clear();
+
+    $('#save-all').click(function(e) {
+      e.preventDefault();
+      saveAllChanges();
+    });
+});
+
+// Modal action handlers
+function closeLog4jModal() {
+    $('.log4j-catalog-modal').remove();
+}
+
+function log4jSubmitHandler(submitHandler) {
+    submitHandler();
+    closeLog4jModal();
+}
+
+function showLog4JModal(title, content) {
+    closeLog4jModal();
+    var modalContent = ' \
+        <div class="log4j-catalog-modal"> \
+            <div class="log4j-catalog-title">' + title + '</div> \
+            <div class="log4j-catalog-content">' + content + '</div> \
+        </div>';
+
+    $('body').append(modalContent);
+    window.scrollTo(0, 0);
+}
+
+function showLoadingAnimation() {
+  $('.log4j-catalog-form').prepend('<div class="form-processing"><div class="gif"></div></div>');
+}
+
+function validateFormContent() {
+    var errors = 0;
+    $('.form-error').remove();
+    $('.required').each(function() {
+        if (!$(this).val()) {
+          errors++;
+          $('<span class="form-error">Required.</span>').insertAfter($(this));
+        }
+    });
+    if (errors) return false;
+    return true;
+}
+
+function saveAllChanges() {
+  $.ajax({
+      type: 'POST',
+      contentType: 'application/json',
+      url: 'catalog',
+      data: null,
+      success:function(response) {
+          if (response.Result === 'OK') {
+              $('.log4j-table-container"').jtable('load');
+          }
+      },
+      error:function(jqXhr, textStatus, errorThrown) {
+          console.error(textStatus + ' - ' + errorThrown);
+      }
+  });
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/attributes.js
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/attributes.js b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/attributes.js
new file mode 100644
index 0000000..bb71036
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/attributes.js
@@ -0,0 +1,364 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+$(document).ready(function () {
+    $('#AttributesTableContainer').jtable({
+        title: 'Table of Attributes',
+        paging: true, //Enable paging
+        pageSize: 25, //Set page size (default: 25)
+        sorting: true, //Enable sorting
+        defaultSorting: 'Name ASC', //Set default sorting
+        actions: {
+            listAction: 'api/attributes/list',
+        },
+        toolbar: {
+            items: [{
+                icon: 'js/jtable.2.4.0/themes/metro/add.png',
+                text: 'Add new record',
+                click: () => { addEditAttributeItem() }
+            }]
+        },
+        fields: {
+            id: {
+                key: true,
+                list: false
+            },
+            name: {
+                title: 'Name',
+                width: '15%'
+            },
+            displayName: {
+                title: 'Display Name',
+                width: '15%'
+            },
+            description: {
+                title: 'Description',
+                width: '25%'
+            },
+            dataType: {
+                title: 'Data Type',
+                width: '5%'
+            },
+            indexed: {
+                title: 'Indexed',
+                width: '5%',
+                display: function (attributeData) {
+                    return attributeData.record.indexed ? 'true' : 'false';
+                }
+            },
+            sortable: {
+                title: 'Sortable',
+                width: '5%',
+                display: function (attributeData) {
+                    return attributeData.record.sortable ? 'true' : 'false';
+                }
+            },
+            required: {
+                title: 'Required',
+                width: '5%',
+                display: function (attributeData) {
+                    return attributeData.record.required ? 'true' : 'false';
+                }
+            },
+            requestContext: {
+                title: 'RequestContext',
+                width: '3%',
+                display: function (attributeData) {
+                    return attributeData.record.requestContext ? 'true' : 'false';
+                }
+            },
+            constraints: {
+                title: 'Constraints',
+                width: '16%',
+                sorting: false,
+                edit: false,
+                create: false,
+                display: function (attributeData) {
+                    var constraintList = '';
+                    if (typeof(attributeData.record.constraints) != 'undefined' && attributeData.record.constraints != null) {
+                        constraintList = attributeData.record.constraints.map(function (elem) {
+                            return elem.constraintType.name + '("' + elem.value + '")'
+                        }).join(' | ');
+                    }
+                    //Create a div that will be used to view associated attributes
+                    var $divConstraints = $('<div class="constraints">' + constraintList + '</div>');
+                    return $divConstraints;
+                }
+            },
+            edit: {
+                title: '',
+                width: '2%',
+                display: function (attributeData) {
+                    // Store attribute item data in localStorage
+                    var attributeDataItem = JSON.stringify(attributeData.record);
+                    localStorage.setItem('attributeItem' + attributeData.record.id,attributeDataItem);
+                    return '<img class="log4J-action-icon" src="js/jtable.2.4.0/themes/metro/edit.png" onClick="addEditAttributeItem(' + attributeData.record.id + ')" />';
+                }
+            },
+            delete: {
+                title: '',
+                width: '2%',
+                display: function (attributeData) {
+                    return '<img class="log4J-action-icon" src="js/jtable.2.4.0/themes/metro/delete.png" onClick="deleteAttributeItem(' + attributeData.record.id + ')" />';
+                }
+            }
+        }
+    });
+    $.ajax({
+        type: 'GET',
+        url: 'api/constraints/types',
+        success:function(response){
+            localStorage.setItem('allConstraints', response);
+        },
+        error:function(jqXhr, textStatus, errorThrown){
+            console.error(textStatus + ' - ' + errorThrown);
+        }
+    });
+    //Load attributes list from server
+    $('#AttributesTableContainer').jtable('load');
+});
+
+function deleteAttributeItem(attributeId) {
+    var response = confirm('Are you sure you want to delete this attribute?');
+    if (response) {
+        var postData = {};
+        postData['id'] = attributeId
+        $.ajax({
+            type: 'POST',
+            contentType: 'application/json',
+            url: 'api/attributes/delete',
+            data: JSON.stringify(postData),
+            success:function(response) {
+                if (response.Result === 'OK') {
+                    $('#AttributesTableContainer').jtable('load');
+                }
+            },
+            error:function(jqXhr, textStatus, errorThrown) {
+                console.error(textStatus + ' - ' + errorThrown);
+            }
+        });
+    }
+}
+
+function addEditattributeItemHandler() {
+  var validForm = validateFormContent();
+  if (validForm) {
+      showLoadingAnimation();
+      var postUrl = 'api/attributes/create';
+      var postData = {};
+      var attributeConstraints = [];
+      postData['name'] = $('#attributeName').val();
+      postData['displayName'] = $('#attributeDisplayName').val();
+      postData['description'] = $('#attributeDescription').val();
+      postData['dataType'] = $('#attributeDataType').val();
+      postData['indexed'] = $('#attributeIndexed').val();
+      postData['sortable'] = $('#attributeSortable').val();
+      postData['required'] = $('#attributeRequired').val();
+      postData['requestContext'] = $('#attributeRequestContext').val();
+      $('#attributeConstraints .attribute-constraint-row').each(function() {
+          var attributeConstraintItem = {
+              constraintType: { name: $(this).find('.attribute-constraint-name').text().toLowerCase() },
+              value: $(this).find('input')[0].value,
+          };
+          attributeConstraints.push(attributeConstraintItem);
+      });
+      postData['constraints'] = attributeConstraints;
+      if ($('#attributeId').val()) {
+          postUrl = 'api/attributes/update';
+          postData['id'] = $('#attributeId').val();
+      }
+      $.ajax({
+          type: 'POST',
+          contentType: 'application/json',
+          url: postUrl,
+          data: JSON.stringify(postData),
+          success:function(response) {
+              if (response.Result === 'OK') {
+                  $('#AttributesTableContainer').jtable('load');
+                  closeLog4jModal();
+              }
+          },
+          error:function(jqXhr, textStatus, errorThrown) {
+              console.error(textStatus + ' - ' + errorThrown);
+          }
+      });
+  }
+}
+
+function addEditAttributeItem(attributeId) {
+  var hiddenIdField = '';
+  var attributeData = {};
+  if (attributeId) {
+      hiddenIdField = '<input type="hidden" id="attributeId" name="id" value="' + attributeId + '" />';
+  } else {
+      attributeId = 'tempEventData';
+      var tempEventData = {
+          id: attributeId,
+          constraints: [],
+      }
+      localStorage.setItem('attributeItem' + attributeId, JSON.stringify(tempEventData));
+  }
+  attributeFormContent = ' \
+      <form id="add-edit-attribute-form" class="log4j-catalog-form" method="post"> \
+        ' + hiddenIdField + ' \
+        <p> \
+            <label>Name</label> \
+            <input type="text" id="attributeName" name="name" class="required" /> \
+        </p> \
+        <p> \
+            <label>Display Name</label> \
+            <input type="text" id="attributeDisplayName" name="displayName" class="required" /> \
+        </p> \
+        <p> \
+            <label>Description</label> \
+            <input type="text" id="attributeDescription" name="description" class="required" /> \
+        </p> \
+        <p> \
+            <label>Data Type</label> \
+            <select id="attributeDataType" name="indexed" class="required"> \
+            </select> \
+        </p> \
+        <p> \
+            <label>Indexed</label> \
+            <select id="attributeIndexed" name="indexed" class="required"> \
+                <option value="false">false</option> \
+                <option value="true">true</option> \
+            </select> \
+        </p> \
+        <p> \
+            <label>Sortable</label> \
+            <select id="attributeSortable" name="sortable" class="required"> \
+                <option value="false">false</option> \
+                <option value="true">true</option> \
+            </select> \
+        </p> \
+        <p> \
+            <label>Required</label> \
+            <select id="attributeRequired" name="required" class="required"> \
+                <option value="false">false</option> \
+                <option value="true">true</option> \
+            </select> \
+        </p> \
+        <p> \
+            <label>Request Context</label> \
+            <select id="attributeRequestContext" name="requestContext" class="required"> \
+                <option value="false">false</option> \
+                <option value="true">true</option> \
+            </select> \
+        </p> \
+        <p> \
+            <label>Assigned Constraints</label> \
+            <span id="attributeConstraints"></span> \
+        </p> \
+        <p> \
+            <label>Add Constraint</label> \
+            <span> \
+                <select name="addAttributeConstraintName" id="addAttributeConstraintName"> \
+                    <option value="">loading...</option> \
+                </select> \
+                <input type="text" name="addAttributeConstraintValue" id="addAttributeConstraintValue" /> \
+                <button id="addAttributeConstraintButton">+</button> \
+            </span> \
+        </p> \
+      </form> \
+      <div class="log4j-catalog-button-row"> \
+          <button class="log4j-catalog-button" onclick="closeLog4jModal()">Cancel</button>\
+          <button class="log4j-catalog-button" onclick="addEditattributeItemHandler()">Save</button> \
+      </div> \
+  ';
+  showLog4JModal('Add / Edit Attribute Item', attributeFormContent);
+  var dataTypes = ['STRING', 'BIG_DECIMAL', 'DOUBLE', 'FLOAT', 'INT', 'LONG', 'BOOLEAN', 'LIST', 'MAP'];
+  $.each(dataTypes.sort(), function(index, value) {
+      $('#attributeDataType').append('<option value="' + value + '">' + value + '</option>');
+  });
+  if (localStorage.getItem('attributeItem' + attributeId)) {
+      attributeData = JSON.parse(localStorage.getItem('attributeItem' + attributeId));
+      $('#attributeName').val(attributeData.name);
+      $('#attributeDisplayName').val(attributeData.displayName);
+      $('#attributeDescription').val(attributeData.description);
+      $('#attributeDataType option[value="' + attributeData.dataType + '"]').attr('selected', 'selected');
+      $('#attributeIndexed option[value="' + attributeData.indexed + '"]').attr('selected', 'selected');
+      $('#attributeSortable option[value="' + attributeData.sortable + '"]').attr('selected', 'selected');
+      $('#attributeRequired option[value="' + attributeData.required + '"]').attr('selected', 'selected');
+      $('#attributeRequestContext option[value="' + attributeData.requestContext + '"]').attr('selected', 'selected');
+  }
+  populateAttributeConstraints(attributeData.constraints, attributeId);
+}
+
+function populateAttributeConstraints(assignedConstraints, attributeId) {
+    var selectedConstraints = [];
+    $('#attributeConstraints').children().remove();
+    if (attributeId && assignedConstraints) {
+        assignedConstraints.map((item) => {
+            selectedConstraints.push(item.constraintType.name);
+            $('#attributeConstraints').append(' \
+                <span class="attribute-constraint-row"> \
+                    <span class="attribute-constraint-name">' + item.constraintType.name + '</span> \
+                    <input type="text" name="constraints[]" class="attribute-constraint-data required" value="' + item.value + '" /> \
+                    <button class="remove-attribute-constraint-button" alt="' + attributeId + '" rel="' + item.constraintType.name + '">-</button> \
+                </span> \
+            ');
+        });
+    }
+    function checkPendingRequest() {
+        if ($.active > 0) {
+            window.setTimeout(checkPendingRequest, 1000);
+        } else {
+            var allConstraints = localStorage.getItem('allConstraints').split(',');
+            allConstraints.sort();
+            $('#addAttributeConstraintName option').remove();
+            allConstraints.map((item) => {
+                if (!selectedConstraints.includes(item)) {
+                    $('#addAttributeConstraintName').append(' \
+                        <option value="' + item + '">' + item.toUpperCase() + '</option> \
+                    ');
+                }
+            });
+        }
+    }
+    checkPendingRequest();
+    assignAttributeConstraintListeners(attributeId);
+}
+
+function assignAttributeConstraintListeners(attributeId) {
+    $('#addAttributeConstraintButton, .remove-attribute-constraint-button').unbind();
+    $('#addAttributeConstraintButton').click(function(e) {
+        e.preventDefault();
+        var allConstraints = localStorage.getItem('allConstraints').split(',');
+        attributeData = JSON.parse(localStorage.getItem('attributeItem' + attributeId));
+        if (typeof(attributeData.constraints) == 'undefined' || attributeData.constraints == null) {
+            attributeData.constraints = [];
+        }
+        attributeData.constraints.push({
+            constraintType: { name: $('#addAttributeConstraintName').val() },
+            value: $('#addAttributeConstraintValue').val()
+        });
+        localStorage.setItem('attributeItem' + attributeId, JSON.stringify(attributeData));
+        $('#addAttributeConstraintValue').val('');
+        populateAttributeConstraints(attributeData.constraints, attributeId);
+    });
+    $('.remove-attribute-constraint-button').click(function(e) {
+        e.preventDefault();
+        var allConstraints = localStorage.getItem('allConstraints').split(',');
+        attributeData = JSON.parse(localStorage.getItem('attributeItem' + attributeId));
+        var newConstraints = attributeData.constraints.filter((obj) => {
+            return obj.constraintType.name !== $(this).attr('rel');
+        });
+        attributeData['constraints'] = newConstraints;
+        localStorage.setItem('attributeItem' + attributeId, JSON.stringify(attributeData));
+        populateAttributeConstraints(attributeData.constraints, attributeId);
+    });
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/categories.js
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/categories.js b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/categories.js
new file mode 100644
index 0000000..2860099
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/categories.js
@@ -0,0 +1,257 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+$(document).ready(function () {
+    $('#CategoriesTableContainer').jtable({
+        title: 'Table of categories',
+        paging: true, //Enable paging
+        pageSize: 25, //Set page size (default: 25)
+        sorting: true, //Enable sorting
+        defaultSorting: 'Name ASC', //Set default sorting
+        actions: {
+            listAction: 'api/categories/list',
+        },
+        toolbar: {
+            items: [{
+                icon: 'js/jtable.2.4.0/themes/metro/add.png',
+                text: 'Add new record',
+                click: () => { addEditCategoryItem() }
+            }]
+        },
+        fields: {
+            id: {
+                key: true,
+                list: false
+            },
+            name: {
+                title: 'Name',
+                width: '25%'
+            },
+            displayName: {
+                title: 'Display Name',
+                width: '25%'
+            },
+            description: {
+                title: 'Description',
+                width: '50%'
+            },
+            edit: {
+                title: '',
+                width: '25',
+                display: function (categoryData) {
+                    // Store event item data in localStorage
+                    var categoryDataItem = JSON.stringify(categoryData.record);
+                    localStorage.setItem('categoryItem' + categoryData.record.id, categoryDataItem);
+                    return '<img class="log4J-action-icon" src="js/jtable.2.4.0/themes/metro/edit.png" onClick="addEditCategoryItem(' + categoryData.record.id + ')" />';
+                }
+            },
+            delete: {
+                title: '',
+                width: '25',
+                display: function (categoryData) {
+                    return '<img class="log4J-action-icon" src="js/jtable.2.4.0/themes/metro/delete.png" onClick="deleteCategoryItem(' + categoryData.record.id + ')" />';
+                }
+            }
+        }
+    });
+    $.ajax({
+        type: 'POST',
+        url: 'api/events/list',
+        success:function(response){
+            if (response.Result === 'OK') {
+                var allEvents = response.Records.map((item) => {
+                    return item.name;
+                });
+                localStorage.setItem('allEvents', allEvents);
+            }
+        },
+        error:function(jqXhr, textStatus, errorThrown){
+            console.error(textStatus + ' - ' + errorThrown);
+        }
+    });
+    //Load categories list from server
+    $('#CategoriesTableContainer').jtable('load');
+});
+
+function deleteCategoryItem(categoryId) {
+    var response = confirm('Are you sure you want to delete this category?');
+    if (response) {
+      var postData = {};
+      postData['id'] = categoryId;
+      $.ajax({
+          type: 'POST',
+          contentType: 'application/json',
+          url: 'api/categories/delete',
+          data: JSON.stringify(postData),
+          success:function(response) {
+              if (response.Result === 'OK') {
+                  $('#CategoriesTableContainer').jtable('load');
+              }
+          },
+          error:function(jqXhr, textStatus, errorThrown) {
+              console.error(textStatus + ' - ' + errorThrown);
+          }
+      });
+    }
+}
+
+function addEditCategoryItemHandler() {
+    var validForm = validateFormContent();
+    if (validForm) {
+        showLoadingAnimation();
+        var postUrl = 'api/categories/create';
+        var postData = {};
+        var categoryEvents = [];
+        postData['name'] = $('#categoryName').val();
+        postData['displayName'] = $('#categoryDisplayName').val();
+        postData['description'] = $('#categoryDescription').val();
+        $('#categoryEvents .category-event-row').each(function() {
+            categoryEvents.push($(this).find('input')[0].value);
+        });
+        postData['events'] = categoryEvents;
+        if ($('#categoryId').val()) {
+            postUrl = 'api/categories/update';
+            postData['id'] = $('#categoryId').val();
+        }
+        $.ajax({
+            type: 'POST',
+            contentType: 'application/json',
+            url: postUrl,
+            data: JSON.stringify(postData),
+            success:function(response) {
+                if (response.Result === 'OK') {
+                    $('#CategoriesTableContainer').jtable('load');
+                    closeLog4jModal();
+                }
+            },
+            error:function(jqXhr, textStatus, errorThrown) {
+                console.error(textStatus + ' - ' + errorThrown);
+            }
+        });
+    }
+}
+
+function addEditCategoryItem(categoryId) {
+    var hiddenIdField = '';
+    var categoryData = {};
+    if (categoryId) {
+        hiddenIdField = '<input type="hidden" id="categoryId" name="id" value="' + categoryId + '" />';
+    } else {
+        categoryId = 'tempCategoryData';
+        var tempCategoryData = {
+            id: categoryId,
+            events: [],
+        }
+        localStorage.setItem('categoryItem' + categoryId, JSON.stringify(tempCategoryData));
+    }
+    categoryFormContent = ' \
+        <form id="add-edit-category-form" class="log4j-catalog-form" method="post"> \
+          ' + hiddenIdField + ' \
+          <p> \
+              <label>Name</label> \
+              <input type="text" id="categoryName" name="name" class="required" /> \
+          </p> \
+          <p> \
+              <label>Display Name</label> \
+              <input type="text" id="categoryDisplayName" name="displayName" class="required" /> \
+          </p> \
+          <p> \
+              <label>Description</label> \
+              <input type="text" id="categoryDescription" name="description" class="required" /> \
+          </p> \
+          <p> \
+              <label>Assigned Events</label> \
+              <span id="categoryEvents"></span> \
+          </p> \
+          <p> \
+              <label>Add Event</label> \
+              <span> \
+                  <select name="addCategoryEvent" id="addCategoryEvent"> \
+                      <option value="">loading...</option> \
+                  </select> \
+                  <button id="addCategoryEventButton">+</button> \
+              </span> \
+          </p> \
+        </form> \
+        <div class="log4j-catalog-button-row"> \
+            <button class="log4j-catalog-button" onclick="closeLog4jModal()">Cancel</button>\
+            <button class="log4j-catalog-button" onclick="addEditCategoryItemHandler()">Save</button> \
+        </div> \
+    ';
+    showLog4JModal('Add / Edit Category Item', categoryFormContent);
+    if (localStorage.getItem('categoryItem' + categoryId)) {
+        categoryData = JSON.parse(localStorage.getItem('categoryItem' + categoryId));
+        $('#categoryName').val(categoryData.name);
+        $('#categoryDisplayName').val(categoryData.displayName);
+        $('#categoryDescription').val(categoryData.description);
+    }
+    populateCategoryEvents(categoryData.events, categoryId);
+}
+
+function populateCategoryEvents(assignedEvents, categoryId) {
+    var selectedEvents = [];
+    $('#categoryEvents').children().remove();
+    if (categoryId) {
+        assignedEvents.map((item) => {
+            selectedEvents.push(item);
+            $('#categoryEvents').append(' \
+                <span class="category-event-row"> \
+                    <input type="text" name="events[]" value="' + item + '" disabled /> \
+                    <button class="remove-category-event-button" alt="' + categoryId + '" rel="' + item + '">-</button> \
+                </span> \
+            ');
+        });
+    }
+    function checkPendingRequest() {
+        if ($.active > 0) {
+            window.setTimeout(checkPendingRequest, 1000);
+        } else {
+            var allEvents = localStorage.getItem('allEvents').split(',');
+            allEvents.sort();
+            $('#addCategoryEvent option').remove();
+            allEvents.map((item) => {
+                if (!selectedEvents.includes(item)) {
+                    $('#addCategoryEvent').append(' \
+                        <option value="' + item + '">' + item + '</option> \
+                    ');
+                }
+            });
+        }
+    };
+    checkPendingRequest();
+    assignCategoryEventListeners(categoryId);
+}
+
+function assignCategoryEventListeners(categoryId) {
+    $('#addCategoryEventButton, .remove-category-event-button').unbind();
+    $('#addCategoryEventButton').click(function(e) {
+        e.preventDefault();
+        var allEvents = localStorage.getItem('allEvents').split(',');
+        var categoryData = JSON.parse(localStorage.getItem('categoryItem' + categoryId));
+        categoryData.events.push($('#addCategoryEvent').val());
+        localStorage.setItem('categoryItem' + categoryId, JSON.stringify(categoryData));
+        populateCategoryEvents(categoryData.events, categoryId);
+    });
+
+    $('.remove-category-event-button').click(function(e) {
+        e.preventDefault();
+        var allEvents = localStorage.getItem('allEvents').split(',');
+        var categoryData = JSON.parse(localStorage.getItem('categoryItem' + categoryId));
+        categoryData.events.pop($(this).attr('rel'));
+        localStorage.setItem('categoryItem' + categoryId, JSON.stringify(categoryData));
+        populateCategoryEvents(categoryData.events, categoryId);
+    });
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j-audit/blob/7ccfa3aa/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/events.js
----------------------------------------------------------------------
diff --git a/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/events.js b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/events.js
new file mode 100644
index 0000000..9f0ec01
--- /dev/null
+++ b/log4j-catalog/log4j-catalog-editor/src/main/resources/static/js/events.js
@@ -0,0 +1,291 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+$(document).ready(function () {
+    $('#EventsTableContainer').jtable({
+        title: 'Table of events',
+        paging: true, //Enable paging
+        pageSize: 25, //Set page size (default: 25)
+        sorting: true, //Enable sorting
+        defaultSorting: 'Name ASC', //Set default sorting
+        actions: {
+            listAction: 'api/events/list',
+        },
+        toolbar: {
+            items: [{
+                icon: 'js/jtable.2.4.0/themes/metro/add.png',
+                text: 'Add new record',
+                click: () => { addEditEventItem() }
+            }]
+        },
+        fields: {
+            id: {
+                key: true,
+                list: false
+            },
+            name: {
+                title: 'Name',
+                width: '15%'
+            },
+            displayName: {
+                title: 'Display Name',
+                width: '15%'
+            },
+            description: {
+                title: 'Description',
+                width: '30%'
+            },
+            attributes: {
+                title: 'Assigned Attributes',
+                width: 'auto',
+                sorting: false,
+                edit: false,
+                create: false,
+                display: function (eventData) {
+                    var attributeList = eventData.record.attributes.map(function(elem){return elem.name + (elem.required ? ' (required)' : '')}).join(' | ');
+                    //Create a div that will be used to view associated attributes
+                    var $divAttributes = $('<div class="event-attributes">' + attributeList + '</div>');
+                    return $divAttributes;
+                }
+            },
+            edit: {
+                title: '',
+                width: '25',
+                display: function (eventData) {
+                    // Store event item data in localStorage
+                    var eventDataItem = JSON.stringify(eventData.record);
+                    localStorage.setItem('eventItem' + eventData.record.id, eventDataItem);
+                    return '<img class="log4J-action-icon" src="js/jtable.2.4.0/themes/metro/edit.png" onClick="addEditEventItem(' + eventData.record.id + ')" />';
+                }
+            },
+            delete: {
+                title: '',
+                width: '25',
+                display: function (eventData) {
+                    return '<img class="log4J-action-icon" src="js/jtable.2.4.0/themes/metro/delete.png" onClick="deleteEventItem(' + eventData.record.id + ')" />';
+                }
+            }
+        }
+    });
+    $.ajax({
+        type: 'GET',
+        url: 'api/attributes',
+        success:function(response){
+            if (response.result === 'OK') {
+                localStorage.setItem('allAttributes', response.data);
+            }
+        },
+        error:function(jqXhr, textStatus, errorThrown){
+            console.error(textStatus + ' - ' + errorThrown);
+        }
+    });
+    $('#EventsTableContainer').jtable('load');
+});
+
+function deleteEventItem(eventId) {
+    var response = confirm('Are you sure you want to delete this event?');
+    if (response) {
+      var postData = {};
+      postData['id'] = eventId;
+      $.ajax({
+          type: 'POST',
+          contentType: 'application/json',
+          url: 'api/events/delete',
+          data: JSON.stringify(postData),
+          success:function(response) {
+              if (response.Result === 'OK') {
+                  $('#EventsTableContainer').jtable('load');
+              }
+          },
+          error:function(jqXhr, textStatus, errorThrown) {
+              console.error(textStatus + ' - ' + errorThrown);
+          }
+      });
+    }
+}
+
+function addEditEventItemHandler() {
+    var validForm = validateFormContent();
+    if (validForm) {
+        showLoadingAnimation();
+        var postUrl = 'api/events/create';
+        var postData = {};
+        var eventAttributes = [];
+        postData['name'] = $('#eventName').val();
+        postData['displayName'] = $('#eventDisplayName').val();
+        postData['description'] = $('#eventDescription').val();
+        $('#eventAttributes .event-attribute-row').each(function() {
+            var required = null;
+            $(this).children('[type="checkbox"]').each(function(i, e) {
+                if ($(e).prop('checked')) {
+                  required = ($(e).attr('rel') == 'true');
+                }
+            });
+            var eventAttributeItem = {
+                name: $(this).find('input')[0].value,
+                required: required,
+            };
+            eventAttributes.push(eventAttributeItem);
+        });
+        postData['attributes'] = eventAttributes;
+        if ($('#eventId').val()) {
+            postUrl = 'api/events/update';
+            postData['id'] = $('#eventId').val();
+        }
+        $.ajax({
+            type: 'POST',
+            contentType: 'application/json',
+            url: postUrl,
+            data: JSON.stringify(postData),
+            success:function(response) {
+                if (response.Result === 'OK') {
+                    $('#EventsTableContainer').jtable('load');
+                    closeLog4jModal();
+                }
+            },
+            error:function(jqXhr, textStatus, errorThrown) {
+                console.error(textStatus + ' - ' + errorThrown);
+            }
+        });
+    }
+}
+
+function addEditEventItem(eventId) {
+    var hiddenIdField = '';
+    var eventData = {};
+    if (eventId) {
+        hiddenIdField = '<input type="hidden" id="eventId" name="id" value="' + eventId + '" />';
+    } else {
+        eventId = 'tempEventData';
+        var tempEventData = {
+            id: eventId,
+            attributes: [],
+        }
+        localStorage.setItem('eventItem' + eventId, JSON.stringify(tempEventData));
+    }
+    eventFormContent = ' \
+        <form id="add-edit-event-form" class="log4j-catalog-form" method="post"> \
+          ' + hiddenIdField + ' \
+          <p> \
+              <label>Name</label> \
+              <input type="text" id="eventName" name="name" class="required" /> \
+          </p> \
+          <p> \
+              <label>Display Name</label> \
+              <input type="text" id="eventDisplayName" name="displayName" class="required" /> \
+          </p> \
+          <p> \
+              <label>Description</label> \
+              <input type="text" id="eventDescription" name="description" class="required" /> \
+          </p> \
+          <p> \
+              <label>Assigned Attributes</label> \
+              <span id="eventAttributes"></span> \
+          </p> \
+          <p> \
+              <label>Add Attribute</label> \
+              <span> \
+                  <select name="addEventAttribute" id="addEventAttribute"> \
+                      <option value="">--</option> \
+                  </select> \
+                  <button id="addEventAttributeButton">+</button> \
+              </span> \
+          </p> \
+        </form> \
+        <div class="log4j-catalog-button-row"> \
+            <button class="log4j-catalog-button" onclick="closeLog4jModal()">Cancel</button>\
+            <button class="log4j-catalog-button" onclick="addEditEventItemHandler()">Save</button> \
+        </div> \
+    ';
+    showLog4JModal('Add / Edit Event Item', eventFormContent);
+    if (localStorage.getItem('eventItem' + eventId)) {
+        eventData = JSON.parse(localStorage.getItem('eventItem' + eventId));
+        $('#eventName').val(eventData.name);
+        $('#eventDisplayName').val(eventData.displayName);
+        $('#eventDescription').val(eventData.description);
+    }
+    populateEventAttributes(eventData.attributes, eventId);
+}
+
+function populateEventAttributes(assignedAttributes, eventId) {
+    var selectedAttributes = [];
+    var allAttributes = localStorage.getItem('allAttributes').split(',');
+    $('#eventAttributes').children().remove();
+    if (eventId) {
+        assignedAttributes.map((item) => {
+            selectedAttributes.push(item.name);
+            var attributeRequiredTrue = '';
+            var attributeRequiredFalse = '';
+            var attributeRequired = item.required;
+            if (attributeRequired === true) {
+              attributeRequiredTrue = 'checked';
+            } else if (attributeRequired === false) {
+              attributeRequiredFalse = 'checked';
+            }
+            $('#eventAttributes').append(' \
+                <span class="event-attribute-row"> \
+                    <input type="text" name="attributes[]" value="' + item.name + '" disabled /> \
+                    <input type="checkbox" name="attribute-required_' + item.name + '" rel="true" ' + attributeRequiredTrue + ' /> \
+                    <span class="event-attribute-item-required">YES</span> \
+                    <input type="checkbox" name="attribute-required_' + item.name + '" rel="false" ' + attributeRequiredFalse + ' /> \
+                    <span class="event-attribute-item-required">NO</span> \
+                    <button class="remove-event-attribute-button" alt="' + eventId + '" rel="' + item.name + '">-</button> \
+                </span> \
+            ');
+        });
+    }
+    allAttributes.sort();
+    $('#addEventAttribute option').remove();
+    allAttributes.map((item) => {
+        if (!selectedAttributes.includes(item)) {
+            $('#addEventAttribute').append(' \
+                <option value="' + item + '">' + item + '</option> \
+            ');
+        }
+    });
+    assignEventAttributeListeners(eventId);
+}
+
+function assignEventAttributeListeners(eventId) {
+    $('#addEventAttributeButton, .remove-event-attribute-button').unbind();
+    $('#addEventAttributeButton').click(function(e) {
+        e.preventDefault();
+        var allAttributes = localStorage.getItem('allAttributes').split(',');
+        var eventData = JSON.parse(localStorage.getItem('eventItem' + eventId));
+        eventData.attributes.push({name: $('#addEventAttribute').val(), required: false});
+        localStorage.setItem('eventItem' + eventId, JSON.stringify(eventData));
+        populateEventAttributes(eventData.attributes, eventId);
+    });
+
+    $('.remove-event-attribute-button').click(function(e) {
+        e.preventDefault();
+        var allAttributes = localStorage.getItem('allAttributes').split(',');
+        var eventData = JSON.parse(localStorage.getItem('eventItem' + eventId));
+        var newAttributes = eventData.attributes.filter((obj) => {
+            return obj.name !== $(this).attr('rel');
+        });
+        eventData['attributes'] = newAttributes;
+        localStorage.setItem('eventItem' + eventId, JSON.stringify(eventData));
+        populateEventAttributes(eventData.attributes, eventId);
+    });
+
+    $('input[name^="attribute-required_"]').change(function() {
+        if ($(this).is(":checked")) {
+          $(this).siblings('input').prop('checked', false);
+          $(this).prop('checked', true);
+        }
+    });
+}