Просмотр исходного кода

10.6.8 release

Former-commit-id: 6b02bcf65c2602a1b6573feea55b59ea4f41e727
David Benson 6 лет назад
Родитель
Сommit
978131cac1
100 измененных файлов с 16548 добавлено и 1315 удалено
  1. 15 0
      ChangeLog
  2. 1 1
      VERSION
  3. 2 0
      etc/build/build.xml
  4. 1 1
      src/main/webapp/cache.manifest
  5. 205 41
      src/main/webapp/electron.js
  6. BIN
      src/main/webapp/images/sidebar-active_directory.png
  7. BIN
      src/main/webapp/images/sidebar-cumulus.png
  8. BIN
      src/main/webapp/images/sidebar-gcp19.png
  9. BIN
      src/main/webapp/images/sidebar-gcp2.png
  10. BIN
      src/main/webapp/images/sidebar-ibm.png
  11. BIN
      src/main/webapp/images/sidebar-vvd.png
  12. 182 0
      src/main/webapp/img/lib/active_directory/active_directory.svg
  13. 122 0
      src/main/webapp/img/lib/active_directory/cd_dvd.svg
  14. 233 0
      src/main/webapp/img/lib/active_directory/cell_phone.svg
  15. 334 0
      src/main/webapp/img/lib/active_directory/cluster_server.svg
  16. 212 0
      src/main/webapp/img/lib/active_directory/community_discussion.svg
  17. 109 0
      src/main/webapp/img/lib/active_directory/data_jack.svg
  18. 121 0
      src/main/webapp/img/lib/active_directory/database.svg
  19. 167 0
      src/main/webapp/img/lib/active_directory/database_cube.svg
  20. 127 0
      src/main/webapp/img/lib/active_directory/database_partition_2.svg
  21. 127 0
      src/main/webapp/img/lib/active_directory/database_partition_3.svg
  22. 133 0
      src/main/webapp/img/lib/active_directory/database_partition_4.svg
  23. 127 0
      src/main/webapp/img/lib/active_directory/database_partition_5.svg
  24. 223 0
      src/main/webapp/img/lib/active_directory/database_server.svg
  25. 156 0
      src/main/webapp/img/lib/active_directory/databases.svg
  26. 109 0
      src/main/webapp/img/lib/active_directory/documents.svg
  27. 193 0
      src/main/webapp/img/lib/active_directory/domain_controller.svg
  28. 172 0
      src/main/webapp/img/lib/active_directory/fax.svg
  29. 151 0
      src/main/webapp/img/lib/active_directory/firewall.svg
  30. 120 0
      src/main/webapp/img/lib/active_directory/folder.svg
  31. 129 0
      src/main/webapp/img/lib/active_directory/folder_open.svg
  32. 146 0
      src/main/webapp/img/lib/active_directory/generic_node.svg
  33. 162 0
      src/main/webapp/img/lib/active_directory/generic_server.svg
  34. 182 0
      src/main/webapp/img/lib/active_directory/hard_disk.svg
  35. 189 0
      src/main/webapp/img/lib/active_directory/home.svg
  36. 316 0
      src/main/webapp/img/lib/active_directory/home_page.svg
  37. 283 0
      src/main/webapp/img/lib/active_directory/input_output_filter.svg
  38. 73 0
      src/main/webapp/img/lib/active_directory/interface.svg
  39. 94 0
      src/main/webapp/img/lib/active_directory/internet_cloud.svg
  40. 131 0
      src/main/webapp/img/lib/active_directory/internet_globe.svg
  41. 189 0
      src/main/webapp/img/lib/active_directory/key.svg
  42. 215 0
      src/main/webapp/img/lib/active_directory/laptop_client.svg
  43. 154 0
      src/main/webapp/img/lib/active_directory/list.svg
  44. 229 0
      src/main/webapp/img/lib/active_directory/mac_client.svg
  45. 322 0
      src/main/webapp/img/lib/active_directory/mainframe.svg
  46. 183 0
      src/main/webapp/img/lib/active_directory/mainframe_host.svg
  47. 337 0
      src/main/webapp/img/lib/active_directory/meeting.svg
  48. 158 0
      src/main/webapp/img/lib/active_directory/modem.svg
  49. 306 0
      src/main/webapp/img/lib/active_directory/my_sites.svg
  50. 206 0
      src/main/webapp/img/lib/active_directory/not_secure.svg
  51. 191 0
      src/main/webapp/img/lib/active_directory/pda.svg
  52. 171 0
      src/main/webapp/img/lib/active_directory/phone.svg
  53. 181 0
      src/main/webapp/img/lib/active_directory/printer.svg
  54. 157 0
      src/main/webapp/img/lib/active_directory/router.svg
  55. 198 0
      src/main/webapp/img/lib/active_directory/secure.svg
  56. 328 0
      src/main/webapp/img/lib/active_directory/security.svg
  57. 483 0
      src/main/webapp/img/lib/active_directory/server_farm.svg
  58. 217 0
      src/main/webapp/img/lib/active_directory/shadowed_router.svg
  59. 188 0
      src/main/webapp/img/lib/active_directory/site_collection.svg
  60. 245 0
      src/main/webapp/img/lib/active_directory/sql_server.svg
  61. 222 0
      src/main/webapp/img/lib/active_directory/sub_site.svg
  62. 217 0
      src/main/webapp/img/lib/active_directory/switch.svg
  63. 162 0
      src/main/webapp/img/lib/active_directory/tablet_pc.svg
  64. 124 0
      src/main/webapp/img/lib/active_directory/tunnel.svg
  65. 204 0
      src/main/webapp/img/lib/active_directory/user.svg
  66. 207 0
      src/main/webapp/img/lib/active_directory/user_accounts.svg
  67. 381 0
      src/main/webapp/img/lib/active_directory/users.svg
  68. 284 0
      src/main/webapp/img/lib/active_directory/vista_client.svg
  69. 192 0
      src/main/webapp/img/lib/active_directory/vista_terminal.svg
  70. 230 0
      src/main/webapp/img/lib/active_directory/web_server.svg
  71. 267 0
      src/main/webapp/img/lib/active_directory/wiki_site.svg
  72. 102 0
      src/main/webapp/img/lib/active_directory/windows_domain.svg
  73. 321 0
      src/main/webapp/img/lib/active_directory/windows_router.svg
  74. 212 0
      src/main/webapp/img/lib/active_directory/windows_server.svg
  75. 311 0
      src/main/webapp/img/lib/active_directory/windows_server_2.svg
  76. 152 0
      src/main/webapp/img/lib/active_directory/wiring_hub.svg
  77. 442 0
      src/main/webapp/img/lib/active_directory/workspace_site.svg
  78. 274 0
      src/main/webapp/img/lib/active_directory/workstation_client.svg
  79. 256 0
      src/main/webapp/img/lib/active_directory/writer.svg
  80. 110 0
      src/main/webapp/img/lib/active_directory/writing.svg
  81. 20 6
      src/main/webapp/index.html
  82. 538 406
      src/main/webapp/js/app.min.js
  83. 54 39
      src/main/webapp/js/diagramly/App.js
  84. 2 0
      src/main/webapp/js/diagramly/Devel.js
  85. 75 46
      src/main/webapp/js/diagramly/Dialogs.js
  86. 61 11
      src/main/webapp/js/diagramly/EditorUi.js
  87. 3 1
      src/main/webapp/js/diagramly/Init.js
  88. 9 6
      src/main/webapp/js/diagramly/Menus.js
  89. 22 12
      src/main/webapp/js/diagramly/Minimal.js
  90. 162 0
      src/main/webapp/js/diagramly/sidebar/Sidebar-ActiveDirectory.js
  91. 214 4
      src/main/webapp/js/diagramly/sidebar/Sidebar-GCP2.js
  92. 222 0
      src/main/webapp/js/diagramly/sidebar/Sidebar-VVD.js
  93. 12 8
      src/main/webapp/js/diagramly/sidebar/Sidebar.js
  94. 81 61
      src/main/webapp/js/diagramly/vsdx/importer.js
  95. 199 200
      src/main/webapp/js/extensions.min.js
  96. 22 1
      src/main/webapp/js/shapes.min.js
  97. 2 1
      src/main/webapp/js/stencils.min.js
  98. 471 469
      src/main/webapp/js/viewer.min.js
  99. 4 1
      src/main/webapp/package.json
  100. 0 0
      src/main/webapp/plugins/cConf-1-4-8.js

+ 15 - 0
ChangeLog

@@ -1,3 +1,18 @@
+22-MAY-2019: 10.6.8
+
+- Add VMware stencils
+- VSDX import improvements
+
+07-MAY-2019: 10.6.7
+
+- Fixes first input element not firing change event
+
+02-MAY-2019: 10.6.6
+
+- Adds MS Active Directory stencils
+- Improvements to GCP stencils
+- Adds Confluence Cloud translations
+
 24-APR-2019: 10.6.5
 
 - Fixes style variation logic in VSDX import

+ 1 - 1
VERSION

@@ -1 +1 @@
-10.6.5
+10.6.8

+ 2 - 0
etc/build/build.xml

@@ -101,6 +101,7 @@
 		<jscomp compilationLevel="simple" debug="false" forceRecompile="true" output="${basedir}/sidebar.min.js">
 			<sources dir="${war.dir}/js/diagramly/sidebar">
 				<file name="Sidebar.js" />
+				<file name="Sidebar-ActiveDirectory.js" />
 				<file name="Sidebar-Advanced.js" />
 				<file name="Sidebar-AlliedTelesis.js" />
 				<file name="Sidebar-Android.js" />
@@ -144,6 +145,7 @@
 				<file name="Sidebar-Sitemap.js" />
 				<file name="Sidebar-Sysml.js" />
 				<file name="Sidebar-Veeam.js" />
+				<file name="Sidebar-VVD.js" />
 				<file name="Sidebar-WebIcons.js" />
 			</sources>
 		</jscomp>

+ 1 - 1
src/main/webapp/cache.manifest

@@ -1,7 +1,7 @@
 CACHE MANIFEST
 
 # THIS FILE WAS GENERATED. DO NOT MODIFY!
-# 04/24/2019 07:27 PM
+# 05/22/2019 02:20 PM
 
 app.html
 index.html?offline=1

+ 205 - 41
src/main/webapp/electron.js

@@ -7,12 +7,21 @@ const ipcMain = electron.ipcMain
 const dialog = electron.dialog
 const app = electron.app
 const BrowserWindow = electron.BrowserWindow
+const globalShortcut = electron.globalShortcut;
 const log = require('electron-log')
 const program = require('commander')
+const {autoUpdater} = require("electron-updater")
+const Store = require('electron-store');
+const store = new Store();
+const ProgressBar = require('electron-progressbar');
+autoUpdater.logger = log
+autoUpdater.logger.transports.file.level = 'info'
+autoUpdater.autoDownload = false
 
 const __DEV__ = process.env.NODE_ENV === 'development'
 		
 let windowsRegistry = []
+let cmdQPressed = false
 
 function createWindow (opt = {})
 {
@@ -20,12 +29,11 @@ function createWindow (opt = {})
 	{
 		width: 1600,
 		height: 1200,
-		nodeIntegration: false,
 		webViewTag: false,
 		'web-security': true,
-		allowRunningInsecureContent: __DEV__,
 		webPreferences: {
 			// preload: path.resolve('./preload.js'),
+			nodeIntegration: true
 		}
 	}, opt)
 
@@ -34,27 +42,30 @@ function createWindow (opt = {})
 
 	console.log('createWindow', opt)
 
-	let wurl = url.format(
+	let ourl = url.format(
 	{
-		pathname: __DEV__ ? 'test.draw.io' : 'www.draw.io',
-		protocol: 'https:',
+		pathname: `${__dirname}/index.html`,
+		protocol: 'file:',
 		query:
 		{
+			'dev': __DEV__ ? 1 : 0,
+			'drawdev': __DEV__ ? 1 : 0,
 			'test': __DEV__ ? 1 : 0,
 			'db': 0,
 			'gapi': 0,
 			'od': 0,
 			'gh': 0,
 			'tr': 0,
+			'analytics': 0,
 			'picker': 0,
 			'mode': 'device',
 			'browser': 0,
-			'appcache': 1
+			'export': 'https://exp.draw.io/ImageExport4/export'
 		},
 		slashes: true
 	})
-
-	mainWindow.loadURL(wurl)
+	
+	mainWindow.loadURL(ourl)
 
 	// Open the DevTools.
 	if (__DEV__)
@@ -90,6 +101,10 @@ function createWindow (opt = {})
 						{
 							win.destroy()
 						}
+						else
+						{
+							cmdQPressed = false
+						}
 					}
 					else
 					{
@@ -109,34 +124,6 @@ function createWindow (opt = {})
 		windowsRegistry.splice(index, 1)
 	})
 	
-	mainWindow.webContents.on('did-fail-load', function(err)
-    {
-        let ourl = url.format(
-		{
-			pathname: `${__dirname}/index.html`,
-			protocol: 'file:',
-			query:
-			{
-				'dev': __DEV__ ? 1 : 0,
-				'drawdev': __DEV__ ? 1 : 0,
-				'test': __DEV__ ? 1 : 0,
-				'db': 0,
-				'gapi': 0,
-				'od': 0,
-				'gh': 0,
-				'tr': 0,
-				'analytics': 0,
-				'picker': 0,
-				'mode': 'device',
-				'browser': 0,
-				'export': 'https://exp.draw.io/ImageExport4/export'
-			},
-			slashes: true,
-		})
-		
-		mainWindow.loadURL(ourl)
-    })
-
 	return mainWindow
 }
 
@@ -190,6 +177,30 @@ app.on('ready', e =>
         win.webContents.setLayoutZoomLevelLimits(0, 0);
     });
 	
+    let updateNoAvailAdded = false;
+    
+	let checkForUpdates = {
+		label: 'Check for updates',
+		click() 
+		{ 
+			autoUpdater.checkForUpdates();
+			store.set('dontCheckUpdates', false);
+			
+			if (!updateNoAvailAdded) 
+			{
+				updateNoAvailAdded = true;
+				autoUpdater.on('update-not-available', (info) => {
+					dialog.showMessageBox(
+						{
+							type: 'info',
+							title: 'No updates found',
+							message: 'You application is up-to-date',
+						})
+				})
+			}
+		}
+	}
+
 	let template = [{
 	    label: app.getName(),
 	    submenu: [
@@ -200,14 +211,18 @@ app.on('ready', e =>
 	      {
 	        label: 'Support',
 	        click() { shell.openExternal('https://about.draw.io/support'); }
-	      },
+		  },
+		  checkForUpdates,
 	      {
 	        type: 'separator'
 	      },
 	      {
 	        label: 'Quit',
 	        accelerator: 'CmdOrCtrl+Q',
-	        click() { app.quit(); }
+	        click() { 
+						cmdQPressed = true;
+						app.quit(); 
+					}
 	      }]
 	}]
 	
@@ -223,14 +238,18 @@ app.on('ready', e =>
 	        {
 	          label: 'Support',
 	          click() { shell.openExternal('https://about.draw.io/support'); }
-	        },
+			},
+			checkForUpdates,
 	        {
 	          type: 'separator'
 	        },
 	        {
 	          label: 'Quit',
 	          accelerator: 'Command+Q',
-	          click() { app.quit(); }
+	          click() {
+				cmdQPressed = true;
+				app.quit(); 
+			  }
 	        }
 	      ]
 	    }, {
@@ -253,6 +272,24 @@ app.on('ready', e =>
 	
 	const menuBar = menu.buildFromTemplate(template)
 	menu.setApplicationMenu(menuBar)
+
+	autoUpdater.setFeedURL({
+		provider: 'github',
+		repo: 'drawio-desktop',
+		owner: 'jgraph'
+	})
+	
+	if (!store.get('dontCheckUpdates'))
+	{
+		autoUpdater.checkForUpdates()
+	}
+
+	if (process.platform === 'darwin')
+	{
+		globalShortcut.register('Command+H', () => {
+			app.hide()
+		})
+	}
 })
 
 // Quit when all windows are closed.
@@ -261,7 +298,7 @@ app.on('window-all-closed', function ()
 	console.log('window-all-closed', windowsRegistry.length)
 	// On OS X it is common for applications and their menu bar
 	// to stay active until the user quits explicitly with Cmd + Q
-	if (process.platform !== 'darwin')
+	if (cmdQPressed || process.platform !== 'darwin')
 	{
 		app.quit()
 	}
@@ -276,4 +313,131 @@ app.on('activate', function ()
 	{
 		createWindow()
 	}
+})
+
+
+autoUpdater.on('error', e => log.error('@error@\n', e))
+
+autoUpdater.on('update-available', (a, b) =>
+{
+	log.info('@update-available@\n', a, b)
+	
+	dialog.showMessageBox(
+	{
+		type: 'question',
+		buttons: ['Ok', 'Cancel', 'Don\'t Ask Again'],
+		title: 'Confirm Update',
+		message: 'Update available.\n\nWould you like to download and install new version?',
+		detail: 'Application will automatically restart to apply update after download',
+	}, response =>
+	{
+		if (response === 0)
+		{
+			autoUpdater.downloadUpdate()
+			
+			var progressBar = new ProgressBar({
+				title: 'draw.io Update',
+			    text: 'Downloading draw.io update...',
+				browserWindow: {
+					webPreferences: {
+						nodeIntegration: true
+					}
+				}
+			});
+			
+			function reportUpdateError(e)
+			{
+				progressBar.detail = 'Error occured while fetching updates. ' + e
+				progressBar._window.setClosable(true);
+			}
+
+			autoUpdater.on('error', e => {
+				if (progressBar._window != null)
+				{
+					reportUpdateError(e);
+				}
+				else
+				{
+					progressBar.on('ready', function() {
+						reportUpdateError(e);
+					});
+				}
+			})
+
+			var firstTimeProg = true;
+			
+			autoUpdater.on('download-progress', (d) => {
+				//On mac, download-progress event is not called, so the indeterminate progress will continue until download is finished
+				log.info('@update-progress@\n', d);
+				
+				if (firstTimeProg)
+				{
+					firstTimeProg = false;
+					progressBar.close();
+
+					progressBar = new ProgressBar({
+						indeterminate: false,
+						title: 'draw.io Update',
+						text: 'Downloading draw.io update...',
+						detail: `${d.percent}% ...`,
+						initialValue: d.percent,
+						browserWindow: {
+							webPreferences: {
+								nodeIntegration: true
+							}
+						}
+					});
+				
+					progressBar
+							.on('completed', function() {
+								progressBar.detail = 'Download completed.';
+							})
+							.on('aborted', function(value) {
+								log.info(`progress aborted... ${value}`);
+							})
+							.on('progress', function(value) {
+								progressBar.detail = `${value}% ...`;
+							})
+							.on('ready', function() {
+								//InitialValue doesn't set the UI! so this is needed to render it correctly
+								progressBar.value = d.percent;
+							});
+				}
+				else 
+				{
+					progressBar.value = d.percent;
+				}
+			});
+
+		    autoUpdater.on('update-downloaded', (info) => {
+				if (!progressBar.isCompleted())
+				{
+					progressBar.close()
+				}
+		
+				log.info('@update-downloaded@\n', info)
+				// Ask user to update the app
+				dialog.showMessageBox(
+				{
+					type: 'question',
+					buttons: ['Install', 'Later'],
+					defaultId: 0,
+					message: 'A new version of ' + app.getName() + ' has been downloaded',
+					detail: 'It will be installed the next time you restart the application',
+				}, response =>
+				{
+					if (response === 0)
+					{
+						setTimeout(() => autoUpdater.quitAndInstall(), 1)
+					}
+				})
+		    });
+		}
+		else if (response === 2)
+		{
+			//save in settings don't check for updates
+			log.info('@dont check for updates!@')
+			store.set('dontCheckUpdates', true)
+		}
+	})
 })

BIN
src/main/webapp/images/sidebar-active_directory.png


BIN
src/main/webapp/images/sidebar-cumulus.png


BIN
src/main/webapp/images/sidebar-gcp19.png


BIN
src/main/webapp/images/sidebar-gcp2.png


BIN
src/main/webapp/images/sidebar-ibm.png


BIN
src/main/webapp/images/sidebar-vvd.png


Разница между файлами не показана из-за своего большого размера
+ 182 - 0
src/main/webapp/img/lib/active_directory/active_directory.svg


Разница между файлами не показана из-за своего большого размера
+ 122 - 0
src/main/webapp/img/lib/active_directory/cd_dvd.svg


Разница между файлами не показана из-за своего большого размера
+ 233 - 0
src/main/webapp/img/lib/active_directory/cell_phone.svg


Разница между файлами не показана из-за своего большого размера
+ 334 - 0
src/main/webapp/img/lib/active_directory/cluster_server.svg


Разница между файлами не показана из-за своего большого размера
+ 212 - 0
src/main/webapp/img/lib/active_directory/community_discussion.svg


Разница между файлами не показана из-за своего большого размера
+ 109 - 0
src/main/webapp/img/lib/active_directory/data_jack.svg


Разница между файлами не показана из-за своего большого размера
+ 121 - 0
src/main/webapp/img/lib/active_directory/database.svg


Разница между файлами не показана из-за своего большого размера
+ 167 - 0
src/main/webapp/img/lib/active_directory/database_cube.svg


Разница между файлами не показана из-за своего большого размера
+ 127 - 0
src/main/webapp/img/lib/active_directory/database_partition_2.svg


Разница между файлами не показана из-за своего большого размера
+ 127 - 0
src/main/webapp/img/lib/active_directory/database_partition_3.svg


Разница между файлами не показана из-за своего большого размера
+ 133 - 0
src/main/webapp/img/lib/active_directory/database_partition_4.svg


Разница между файлами не показана из-за своего большого размера
+ 127 - 0
src/main/webapp/img/lib/active_directory/database_partition_5.svg


Разница между файлами не показана из-за своего большого размера
+ 223 - 0
src/main/webapp/img/lib/active_directory/database_server.svg


Разница между файлами не показана из-за своего большого размера
+ 156 - 0
src/main/webapp/img/lib/active_directory/databases.svg


Разница между файлами не показана из-за своего большого размера
+ 109 - 0
src/main/webapp/img/lib/active_directory/documents.svg


Разница между файлами не показана из-за своего большого размера
+ 193 - 0
src/main/webapp/img/lib/active_directory/domain_controller.svg


Разница между файлами не показана из-за своего большого размера
+ 172 - 0
src/main/webapp/img/lib/active_directory/fax.svg


Разница между файлами не показана из-за своего большого размера
+ 151 - 0
src/main/webapp/img/lib/active_directory/firewall.svg


Разница между файлами не показана из-за своего большого размера
+ 120 - 0
src/main/webapp/img/lib/active_directory/folder.svg


Разница между файлами не показана из-за своего большого размера
+ 129 - 0
src/main/webapp/img/lib/active_directory/folder_open.svg


Разница между файлами не показана из-за своего большого размера
+ 146 - 0
src/main/webapp/img/lib/active_directory/generic_node.svg


Разница между файлами не показана из-за своего большого размера
+ 162 - 0
src/main/webapp/img/lib/active_directory/generic_server.svg


Разница между файлами не показана из-за своего большого размера
+ 182 - 0
src/main/webapp/img/lib/active_directory/hard_disk.svg


Разница между файлами не показана из-за своего большого размера
+ 189 - 0
src/main/webapp/img/lib/active_directory/home.svg


Разница между файлами не показана из-за своего большого размера
+ 316 - 0
src/main/webapp/img/lib/active_directory/home_page.svg


Разница между файлами не показана из-за своего большого размера
+ 283 - 0
src/main/webapp/img/lib/active_directory/input_output_filter.svg


+ 73 - 0
src/main/webapp/img/lib/active_directory/interface.svg

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="90.848969mm"
+   height="43.837399mm"
+   viewBox="0 0 90.848969 43.837399"
+   version="1.1"
+   id="svg1997"
+   inkscape:version="0.92.3 (2405546, 2018-03-11)"
+   sodipodi:docname="interface.svg">
+  <defs
+     id="defs1991" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.35"
+     inkscape:cx="382.78317"
+     inkscape:cy="-178.68708"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="1920"
+     inkscape:window-height="1017"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata1994">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-59.959608,-127.10359)">
+    <circle
+       style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;stroke:#0066ff;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
+       id="path2010"
+       cx="128.88988"
+       cy="149.02229"
+       r="19.918699" />
+    <path
+       style="opacity:1;fill:none;stroke:#0066ff;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 106.96727,148.26636 H 61.988093"
+       id="path2012"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+  </g>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 94 - 0
src/main/webapp/img/lib/active_directory/internet_cloud.svg


Разница между файлами не показана из-за своего большого размера
+ 131 - 0
src/main/webapp/img/lib/active_directory/internet_globe.svg


Разница между файлами не показана из-за своего большого размера
+ 189 - 0
src/main/webapp/img/lib/active_directory/key.svg


Разница между файлами не показана из-за своего большого размера
+ 215 - 0
src/main/webapp/img/lib/active_directory/laptop_client.svg


Разница между файлами не показана из-за своего большого размера
+ 154 - 0
src/main/webapp/img/lib/active_directory/list.svg


Разница между файлами не показана из-за своего большого размера
+ 229 - 0
src/main/webapp/img/lib/active_directory/mac_client.svg


Разница между файлами не показана из-за своего большого размера
+ 322 - 0
src/main/webapp/img/lib/active_directory/mainframe.svg


Разница между файлами не показана из-за своего большого размера
+ 183 - 0
src/main/webapp/img/lib/active_directory/mainframe_host.svg


Разница между файлами не показана из-за своего большого размера
+ 337 - 0
src/main/webapp/img/lib/active_directory/meeting.svg


Разница между файлами не показана из-за своего большого размера
+ 158 - 0
src/main/webapp/img/lib/active_directory/modem.svg


Разница между файлами не показана из-за своего большого размера
+ 306 - 0
src/main/webapp/img/lib/active_directory/my_sites.svg


Разница между файлами не показана из-за своего большого размера
+ 206 - 0
src/main/webapp/img/lib/active_directory/not_secure.svg


Разница между файлами не показана из-за своего большого размера
+ 191 - 0
src/main/webapp/img/lib/active_directory/pda.svg


Разница между файлами не показана из-за своего большого размера
+ 171 - 0
src/main/webapp/img/lib/active_directory/phone.svg


Разница между файлами не показана из-за своего большого размера
+ 181 - 0
src/main/webapp/img/lib/active_directory/printer.svg


Разница между файлами не показана из-за своего большого размера
+ 157 - 0
src/main/webapp/img/lib/active_directory/router.svg


Разница между файлами не показана из-за своего большого размера
+ 198 - 0
src/main/webapp/img/lib/active_directory/secure.svg


Разница между файлами не показана из-за своего большого размера
+ 328 - 0
src/main/webapp/img/lib/active_directory/security.svg


Разница между файлами не показана из-за своего большого размера
+ 483 - 0
src/main/webapp/img/lib/active_directory/server_farm.svg


Разница между файлами не показана из-за своего большого размера
+ 217 - 0
src/main/webapp/img/lib/active_directory/shadowed_router.svg


Разница между файлами не показана из-за своего большого размера
+ 188 - 0
src/main/webapp/img/lib/active_directory/site_collection.svg


Разница между файлами не показана из-за своего большого размера
+ 245 - 0
src/main/webapp/img/lib/active_directory/sql_server.svg


Разница между файлами не показана из-за своего большого размера
+ 222 - 0
src/main/webapp/img/lib/active_directory/sub_site.svg


Разница между файлами не показана из-за своего большого размера
+ 217 - 0
src/main/webapp/img/lib/active_directory/switch.svg


Разница между файлами не показана из-за своего большого размера
+ 162 - 0
src/main/webapp/img/lib/active_directory/tablet_pc.svg


Разница между файлами не показана из-за своего большого размера
+ 124 - 0
src/main/webapp/img/lib/active_directory/tunnel.svg


Разница между файлами не показана из-за своего большого размера
+ 204 - 0
src/main/webapp/img/lib/active_directory/user.svg


Разница между файлами не показана из-за своего большого размера
+ 207 - 0
src/main/webapp/img/lib/active_directory/user_accounts.svg


Разница между файлами не показана из-за своего большого размера
+ 381 - 0
src/main/webapp/img/lib/active_directory/users.svg


Разница между файлами не показана из-за своего большого размера
+ 284 - 0
src/main/webapp/img/lib/active_directory/vista_client.svg


Разница между файлами не показана из-за своего большого размера
+ 192 - 0
src/main/webapp/img/lib/active_directory/vista_terminal.svg


Разница между файлами не показана из-за своего большого размера
+ 230 - 0
src/main/webapp/img/lib/active_directory/web_server.svg


Разница между файлами не показана из-за своего большого размера
+ 267 - 0
src/main/webapp/img/lib/active_directory/wiki_site.svg


+ 102 - 0
src/main/webapp/img/lib/active_directory/windows_domain.svg

@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="162.20799mm"
+   height="138.49704mm"
+   viewBox="0 0 162.20799 138.49704"
+   version="1.1"
+   id="svg3177"
+   inkscape:version="0.92.3 (2405546, 2018-03-11)"
+   sodipodi:docname="windows_domain.svg">
+  <defs
+     id="defs3171">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3237">
+      <stop
+         style="stop-color:#ffc426;stop-opacity:1"
+         offset="0"
+         id="stop3233" />
+      <stop
+         style="stop-color:#fe6305;stop-opacity:1"
+         offset="1"
+         id="stop3235" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3237"
+       id="linearGradient3239"
+       x1="102.36423"
+       y1="206.12836"
+       x2="102.24294"
+       y2="96.305199"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="354.81801"
+     inkscape:cy="216.09573"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1017"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <metadata
+     id="metadata3174">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-21.540271,-77.375427)">
+    <path
+       style="opacity:1;fill:#ffffff;stroke:none;stroke-width:1.09168017;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 21.540271,215.87247 102.13732,77.375427 183.74826,215.87247 Z"
+       id="path3201-2"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="opacity:1;fill:#e57a10;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 28.351713,211.85106 102.18018,84.985117 176.93737,211.85106 Z"
+       id="path3201"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+    <path
+       style="opacity:1;fill:url(#linearGradient3239);fill-opacity:1;stroke:none;stroke-width:0.86483461;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 38.393534,206.02325 102.24294,96.305195 166.89555,206.02325 Z"
+       id="path3201-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cccc" />
+  </g>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 321 - 0
src/main/webapp/img/lib/active_directory/windows_router.svg


Разница между файлами не показана из-за своего большого размера
+ 212 - 0
src/main/webapp/img/lib/active_directory/windows_server.svg


Разница между файлами не показана из-за своего большого размера
+ 311 - 0
src/main/webapp/img/lib/active_directory/windows_server_2.svg


Разница между файлами не показана из-за своего большого размера
+ 152 - 0
src/main/webapp/img/lib/active_directory/wiring_hub.svg


Разница между файлами не показана из-за своего большого размера
+ 442 - 0
src/main/webapp/img/lib/active_directory/workspace_site.svg


Разница между файлами не показана из-за своего большого размера
+ 274 - 0
src/main/webapp/img/lib/active_directory/workstation_client.svg


Разница между файлами не показана из-за своего большого размера
+ 256 - 0
src/main/webapp/img/lib/active_directory/writer.svg


Разница между файлами не показана из-за своего большого размера
+ 110 - 0
src/main/webapp/img/lib/active_directory/writing.svg


+ 20 - 6
src/main/webapp/index.html

@@ -16,7 +16,8 @@
 	<meta name="msapplication-config" content="images/browserconfig.xml">
     <meta name="mobile-web-app-capable" content="yes">
 	<meta name="theme-color" content="#d89000">
-    <script type="text/javascript">
+	<script type="text/javascript">
+		var mxIsElectron = (window && window.process && window.process.type) || (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1);
 		/**
 		 * URL Parameters and protocol description are here:
 		 *
@@ -108,14 +109,24 @@
 		 */
 		(function()
 		{
-			function addMeta(name, content)
+			function addMeta(name, content, httpEquiv)
 			{
 				try
 				{
 					var s = document.createElement('meta');
-					s.setAttribute('name', name);
+					
+					if (name != null) 
+					{
+						s.setAttribute('name', name);
+					}
+
 					s.setAttribute('content', content);
 					
+					if (httpEquiv != null) 
+					{
+						s.setAttribute('http-equiv', httpEquiv);
+					}
+
 				  	var t = document.getElementsByTagName('meta')[0];
 				  	t.parentNode.insertBefore(s, t);
 				}
@@ -134,6 +145,11 @@
 			
 			addMeta('apple-mobile-web-app-title', name);
 			addMeta('application-name', name);
+
+			if (mxIsElectron)
+			{
+				addMeta(null, 'default-src \'self\' \'unsafe-inline\'; connect-src \'self\' https://*.draw.io; img-src * data:; media-src *; font-src *', 'Content-Security-Policy');
+			}
 		})();
 	</script>
     <link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/plgmlhohecdddhbmmkncjdmlhcmaachm">
@@ -324,8 +340,6 @@
 			var geBasePath = mxDevUrl + '/javascript/examples/grapheditor/www/js';
 			var mxBasePath = mxDevUrl + '/javascript/src';
 			
-
-			
 			mxscript(drawDevUrl + 'js/diagramly/Init.js');
 			mxscript(geBasePath + '/Init.js');
 			mxscript(mxDevUrl + '/javascript/src/js/mxClient.js');
@@ -341,7 +355,7 @@
 		}
 
 		// Electron
-		if (window && window.process && window.process.type)
+		if (mxIsElectron)
 		{
 			mxscript('js/diagramly/ElectronApp.js');
 		}

Разница между файлами не показана из-за своего большого размера
+ 538 - 406
src/main/webapp/js/app.min.js


+ 54 - 39
src/main/webapp/js/diagramly/App.js

@@ -1489,10 +1489,7 @@ App.prototype.updateActionStates = function()
 {
 	EditorUi.prototype.updateActionStates.apply(this, arguments);
 
-	var file = this.getCurrentFile();
-	this.actions.get('revisionHistory').setEnabled(file != null &&
-		((file.constructor == DriveFile && file.isEditable()) ||
-		file.constructor == DropboxFile));
+	this.actions.get('revisionHistory').setEnabled(this.isRevisionHistoryEnabled());
 };
 
 /**
@@ -2862,18 +2859,27 @@ App.prototype.pickFile = function(mode)
 			else if (mode == App.MODE_DEVICE && Graph.fileSupport && ((!mxClient.IS_IE && !mxClient.IS_IE11) ||
 				navigator.appVersion.indexOf('Windows NT 6.1') < 0))
 			{
-				var input = document.createElement('input');
-				input.setAttribute('type', 'file');
-				
-				mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
+				if (this.openFileInputElt == null) 
 				{
-					if (input.files != null)
+					var input = document.createElement('input');
+					input.setAttribute('type', 'file');
+					
+					mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
 					{
-						this.openFiles(input.files);
-					}
-				}));
-		
-				input.click();
+						if (input.files != null)
+						{
+							this.openFiles(input.files);
+						}
+						
+						input.value = '';
+					}));
+					
+					input.style.display = 'none';
+					document.body.appendChild(input);
+					this.openFileInputElt = input;
+				}
+				
+				this.openFileInputElt.click();
 			}
 			else
 			{
@@ -2984,38 +2990,47 @@ App.prototype.pickLibrary = function(mode)
 	}
 	else if (mode == App.MODE_DEVICE && Graph.fileSupport && !mxClient.IS_IE && !mxClient.IS_IE11)
 	{
-		var input = document.createElement('input');
-		input.setAttribute('type', 'file');
-		
-		mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
+		if (this.libFileInputElt == null) 
 		{
-			if (input.files != null)
+			var input = document.createElement('input');
+			input.setAttribute('type', 'file');
+			
+			mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
 			{
-				for (var i = 0; i < input.files.length; i++)
+				if (input.files != null)
 				{
-					(mxUtils.bind(this, function(file)
+					for (var i = 0; i < input.files.length; i++)
 					{
-						var reader = new FileReader();
-					
-						reader.onload = mxUtils.bind(this, function(e)
+						(mxUtils.bind(this, function(file)
 						{
-							try
-							{
-								this.loadLibrary(new LocalLibrary(this, e.target.result, file.name));
-							}
-							catch (e)
+							var reader = new FileReader();
+						
+							reader.onload = mxUtils.bind(this, function(e)
 							{
-								this.handleError(e, mxResources.get('errorLoadingFile'));
-							}
-						});
-
-						reader.readAsText(file);
-					}))(input.files[i]);
+								try
+								{
+									this.loadLibrary(new LocalLibrary(this, e.target.result, file.name));
+								}
+								catch (e)
+								{
+									this.handleError(e, mxResources.get('errorLoadingFile'));
+								}
+							});
+	
+							reader.readAsText(file);
+						}))(input.files[i]);
+					}
 				}
-			}
-		}));
-
-		input.click();
+				
+				input.value = '';
+			}));
+			
+			input.style.display = 'none';
+			document.body.appendChild(input);
+			this.libFileInputElt = input;
+		}
+		
+		this.libFileInputElt.click();
 	}
 	else
 	{

+ 2 - 0
src/main/webapp/js/diagramly/Devel.js

@@ -28,6 +28,7 @@ mxscript(geBasePath +'/Dialogs.js');
 
 // Loads main classes
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar.js');
+mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-ActiveDirectory.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Advanced.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-AlliedTelesis.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Android.js');
@@ -71,6 +72,7 @@ mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Rack.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Sitemap.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Sysml.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-Veeam.js');
+mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-VVD.js');
 mxscript(drawDevUrl + 'js/diagramly/sidebar/Sidebar-WebIcons.js');
 
 mxscript(drawDevUrl + 'js/diagramly/util/mxJsCanvas.js');

+ 75 - 46
src/main/webapp/js/diagramly/Dialogs.js

@@ -383,20 +383,29 @@ var StorageDialog = function(editorUi, fn, rowLimit)
 		
 		mxEvent.addListener(link, 'click', function()
 		{
-			var input = document.createElement('input');
-			input.setAttribute('type', 'file');
-			
-			mxEvent.addListener(input, 'change', function()
+			if (editorUi.storageFileInputElt == null) 
 			{
-				if (input.files != null)
+				var input = document.createElement('input');
+				input.setAttribute('type', 'file');
+				
+				mxEvent.addListener(input, 'change', function()
 				{
-					// Using null for position will disable crop of input file
-					editorUi.hideDialog();
-					editorUi.openFiles(input.files, true);
-				}
-			});
-
-			input.click();
+					if (input.files != null)
+					{
+						// Using null for position will disable crop of input file
+						editorUi.hideDialog();
+						editorUi.openFiles(input.files, true);
+					}
+					
+					input.value = '';
+				});
+				
+				input.style.display = 'none';
+				document.body.appendChild(input);
+				editorUi.storageFileInputElt = input;
+			}
+			
+			editorUi.storageFileInputElt.click();
 		});
 		
 		p2.appendChild(link);
@@ -3407,16 +3416,24 @@ var NewDialog = function(editorUi, compact, showName, callback, createOnly, canc
 	{
 		var importBtn = mxUtils.button(mxResources.get('import'), function()
 		{
-			var fileInput = document.createElement('input');
-			fileInput.setAttribute('multiple', 'multiple');
-			fileInput.setAttribute('type', 'file');
-			
-			mxEvent.addListener(fileInput, 'change', function(evt)
+			if (editorUi.newDlgFileInputElt == null) 
 			{
-				editorUi.openFiles(fileInput.files, true);
-			});
+				var fileInput = document.createElement('input');
+				fileInput.setAttribute('multiple', 'multiple');
+				fileInput.setAttribute('type', 'file');
+				
+				mxEvent.addListener(fileInput, 'change', function(evt)
+				{
+					editorUi.openFiles(fileInput.files, true);
+					fileInput.value = '';
+				});
+				
+				fileInput.style.display = 'none';
+				document.body.appendChild(fileInput);
+				editorUi.newDlgFileInputElt = fileInput;
+			}
 			
-			fileInput.click();
+			editorUi.newDlgFileInputElt.click();
 		});
 				
 		importBtn.className = 'geBtn';
@@ -4239,14 +4256,14 @@ var ImageDialog = function(editorUi, title, initialValue, fn, ignoreExisting, co
         linkInput.focus();
 	};
 
-	if (Graph.fileSupport)
+	if (Graph.fileSupport && document.documentMode == null)
 	{
-		var fileInput = document.createElement('input');
-		fileInput.setAttribute('multiple', 'multiple');
-		fileInput.setAttribute('type', 'file');
-		
-		if (document.documentMode == null)
+		if (editorUi.imgDlgFileInputElt == null)
 		{
+			var fileInput = document.createElement('input');
+			fileInput.setAttribute('multiple', 'multiple');
+			fileInput.setAttribute('type', 'file');
+			
 			mxEvent.addListener(fileInput, 'change', function(evt)
 			{
 		    	editorUi.importFiles(fileInput.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h)
@@ -4267,16 +4284,22 @@ var ImageDialog = function(editorUi, title, initialValue, fn, ignoreExisting, co
 		    			queue[i]();
 		    		}
 		    	}, true);
+		    	
+		    	fileInput.value = '';
 			});
 			
-			var btn = mxUtils.button(mxResources.get('open'), function()
-			{
-				fileInput.click();
-			});
-			btn.className = 'geBtn';
-			
-			btns.appendChild(btn);
+			fileInput.style.display = 'none';
+			document.body.appendChild(fileInput);
+			editorUi.imgDlgFileInputElt = fileInput;
 		}
+		
+		var btn = mxUtils.button(mxResources.get('open'), function()
+		{
+			editorUi.imgDlgFileInputElt.click();
+		});
+		btn.className = 'geBtn';
+		
+		btns.appendChild(btn);
 	}
 
 	// Image cropping (experimental)
@@ -5446,10 +5469,9 @@ var RevisionDialog = function(editorUi, revs, restoreFn)
 					row.appendChild(date);
 
 					row.setAttribute('title', ts.toLocaleDateString() + ' ' +
-						ts.toLocaleTimeString() + ' ' +
-						editorUi.formatFileSize(parseInt(item.fileSize)) +
-						((item.lastModifyingUserName != null) ? ' ' +
-						item.lastModifyingUserName : ''));
+						ts.toLocaleTimeString() + 
+						((item.fileSize != null)? ' ' + editorUi.formatFileSize(parseInt(item.fileSize)) : '') +
+						((item.lastModifyingUserName != null) ? ' ' + item.lastModifyingUserName : ''));
 
 					function updateGraph(xml)
 					{
@@ -8357,14 +8379,16 @@ var LibraryDialog = function(editorUi, name, library, initialImages, file, mode)
 	btn.className = 'geBtn';
 	btns.appendChild(btn);
 	
-	var fileInput = document.createElement('input');
-	fileInput.setAttribute('multiple', 'multiple');
-	fileInput.setAttribute('type', 'file');
-	
 	if (document.documentMode == null)
 	{
-		mxEvent.addListener(fileInput, 'change', function(evt)
+		if (editorUi.libDlgFileInputElt == null) 
 		{
+			var fileInput = document.createElement('input');
+			fileInput.setAttribute('multiple', 'multiple');
+			fileInput.setAttribute('type', 'file');
+	
+			mxEvent.addListener(fileInput, 'change', function(evt)
+			{
 		    	errorShowed = false;
 					
 		    	editorUi.importFiles(fileInput.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h, img, doneFn, file)
@@ -8374,9 +8398,14 @@ var LibraryDialog = function(editorUi, name, library, initialImages, file, mode)
 		    		// Resets input to force change event for same file
 		    		fileInput.value = '';
 		    	});
-
-			div.scrollTop = div.scrollHeight;
-		});
+	
+				div.scrollTop = div.scrollHeight;
+			});
+			
+			fileInput.style.display = 'none';
+			document.body.appendChild(fileInput);
+			editorUi.libDlgFileInputElt = fileInput;
+		}
 		
 		var btn = mxUtils.button(mxResources.get('import'), function()
 		{
@@ -8386,7 +8415,7 @@ var LibraryDialog = function(editorUi, name, library, initialImages, file, mode)
 				stopEditing = null;
 			}
 			
-			fileInput.click();
+			editorUi.libDlgFileInputElt.click();
 		});
 		btn.setAttribute('id', 'btnAddImage');
 		btn.className = 'geBtn';

+ 61 - 11
src/main/webapp/js/diagramly/EditorUi.js

@@ -7057,19 +7057,28 @@
 		if (device && Graph.fileSupport && ((!mxClient.IS_IE && !mxClient.IS_IE11) ||
 			navigator.appVersion.indexOf('Windows NT 6.1') < 0))
 		{
-			var input = document.createElement('input');
-			input.setAttribute('type', 'file');
-			
-			mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
+			if (this.importFileInputElt == null) 
 			{
-				if (input.files != null)
+				var input = document.createElement('input');
+				input.setAttribute('type', 'file');
+				
+				mxEvent.addListener(input, 'change', mxUtils.bind(this, function()
 				{
-					// Using null for position will disable crop of input file
-					this.importFiles(input.files, null, null, this.maxImageSize);
-				}
-			}));
-
-			input.click();
+					if (input.files != null)
+					{
+						// Using null for position will disable crop of input file
+						this.importFiles(input.files, null, null, this.maxImageSize);
+					}
+					
+					input.value = '';
+				}));
+				
+				input.style.display = 'none';
+				document.body.appendChild(input);
+				this.importFileInputElt = input;
+			}
+			
+			this.importFileInputElt.click();
 		}
 		else
 		{
@@ -12271,6 +12280,47 @@
 			return new DrawioComment(this, null, content, Date.now(), Date.now(), false, user);
 		}
 	};
+	
+	//==================================================== End of comments =================================================================
+	
+	/**
+	 * Does revisions history available
+	 */
+	EditorUi.prototype.isRevisionHistorySupported = function()
+	{
+		var file = this.getCurrentFile();
+		
+		return file != null && file.isRevisionHistorySupported();
+	};
+
+	/**
+	 * Get revisions of current file
+	 */
+	EditorUi.prototype.getRevisions = function(success, error)
+	{
+		var file = this.getCurrentFile();
+		
+		if (file != null && file.getRevisions)
+		{
+			file.getRevisions(success, error);
+		}
+		else
+		{
+			error({message: mxResources.get('unknownError')});
+		}
+	};
+	
+	/**
+	 * Is revisions history enabled
+	 */
+	EditorUi.prototype.isRevisionHistoryEnabled = function()
+	{
+		var file = this.getCurrentFile();
+		
+		return file != null &&
+				((file.constructor == DriveFile && file.isEditable()) ||
+				file.constructor == DropboxFile);
+	};
 })();
 
 /**

+ 3 - 1
src/main/webapp/js/diagramly/Init.js

@@ -11,7 +11,7 @@ window.mxLoadSettings = window.mxLoadSettings || urlParams['configure'] != '1';
 window.isSvgBrowser = window.isSvgBrowser || (navigator.userAgent.indexOf('MSIE') < 0 || document.documentMode >= 9);
 
 // CUSTOM_PARAMETERS - URLs for save and export
-window.EXPORT_URL = window.EXPORT_URL || 'https://exp.draw.io/ImageExport4/export';
+window.EXPORT_URL = window.EXPORT_URL || 'https://exp-pdf.draw.io/ImageExport4/export';
 window.PLANT_URL = window.PLANT_URL || 'https://exp-plant.draw.io/plantuml4';
 window.VSD_CONVERT_URL = window.VSD_CONVERT_URL || "https://convert.draw.io/VsdConverter/api/converter";
 window.EMF_CONVERT_URL = window.EMF_CONVERT_URL || "https://convert.draw.io/emf2png/convertEMF";
@@ -238,6 +238,8 @@ function setCurrentXml(data, filename)
 
 	if (ex != null)
 	{
+		ex = decodeURIComponent(ex);
+		
 		if (ex.substring(0, 7) != 'http://' &&  ex.substring(0, 8) != 'https://')
 		{
 			ex = 'http://' + ex;

+ 9 - 6
src/main/webapp/js/diagramly/Menus.js

@@ -321,18 +321,16 @@
 		
 		editorUi.actions.addAction('revisionHistory...', function()
 		{
-			var file = editorUi.getCurrentFile();
-			
-			if (file == null || !file.isRevisionHistorySupported())
+			if (!editorUi.isRevisionHistorySupported())
 			{
 				editorUi.showError(mxResources.get('error'), mxResources.get('notAvailable'), mxResources.get('ok'));
 			}
 			else if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
 			{
-				file.getRevisions(mxUtils.bind(this, function(revs)
+				editorUi.getRevisions(mxUtils.bind(this, function(revs, restoreFn)
 				{
 					editorUi.spinner.stop();
-					var dlg = new RevisionDialog(editorUi, revs);
+					var dlg = new RevisionDialog(editorUi, revs, restoreFn);
 					editorUi.showDialog(dlg.container, 640, 480, true, true);
 					dlg.init();
 				}), mxUtils.bind(this, function(err)
@@ -3052,6 +3050,11 @@
 					this.addSubmenu('openLibraryFrom', menu, parent);
 				}
 				
+				if (editorUi.isRevisionHistorySupported())
+				{
+					this.addMenuItems(menu, ['-', 'revisionHistory'], parent);
+				}
+				
 				this.addMenuItems(menu, ['-', 'pageSetup', 'print', '-', 'rename', 'save'], parent);
 				
 				if (urlParams['saveAndExit'] == '1')
@@ -3145,7 +3148,7 @@
 				this.addSubmenu('newLibrary', menu, parent);
 				this.addSubmenu('openLibraryFrom', menu, parent);
 				
-				if (file != null && file.isRevisionHistorySupported())
+				if (editorUi.isRevisionHistorySupported())
 				{
 					this.addMenuItems(menu, ['-', 'revisionHistory'], parent);
 				}

+ 22 - 12
src/main/webapp/js/diagramly/Minimal.js

@@ -657,19 +657,29 @@ EditorUi.initMinimalTheme = function()
         ui.actions.put('importFile', new Action('File...', function()
         {
             graph.popupMenuHandler.hideMenu();
-            var input = document.createElement('input');
-            input.setAttribute('type', 'file');
             
-            mxEvent.addListener(input, 'change', function()
-            {
-                if (input.files != null)
-                {
-                    // Using null for position will disable crop of input file
-                    ui.importFiles(input.files, null, null, ui.maxImageSize);
-                }
-            });
-
-            input.click();
+            if (ui.minImpFileInputElt == null) 
+			{
+	            var input = document.createElement('input');
+	            input.setAttribute('type', 'file');
+	            
+	            mxEvent.addListener(input, 'change', function()
+	            {
+	                if (input.files != null)
+	                {
+	                    // Using null for position will disable crop of input file
+	                    ui.importFiles(input.files, null, null, ui.maxImageSize);
+	                }
+	                
+	                input.value = '';
+	            });
+	            
+	            input.style.display = 'none';
+				document.body.appendChild(input);
+				ui.minImpFileInputElt = input;
+			}
+            
+            ui.minImpFileInputElt.click();
         }));
         ui.actions.put('importCsv', new Action(mxResources.get('csv') + '...', function()
         {

+ 162 - 0
src/main/webapp/js/diagramly/sidebar/Sidebar-ActiveDirectory.js

@@ -0,0 +1,162 @@
+(function()
+{
+	Sidebar.prototype.addActiveDirectoryPalette = function()
+	{
+		var d = 50;
+		var dt = 'ibm';
+		var sb = this;
+		var s = 'aspect=fixed;perimeter=ellipsePerimeter;html=1;align=center;shadow=0;dashed=0;spacingTop=3;image;image=img/lib/active_directory/';
+		
+		var gn = 'ms active directory ';
+		
+		var fns = [
+			 this.createVertexTemplateEntry(s + 'active_directory.svg;',
+					 d, d * 0.85, '', 'Active Directory', false, null, this.getTagsForStencil(gn, 'active directory', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'cd_dvd.svg;',
+					 d, d, '', 'CD / DVD', false, null, this.getTagsForStencil(gn, 'cd dvd compact digital video disc', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'cell_phone.svg;',
+					 d * 0.42, d, '', 'Cell Phone', false, null, this.getTagsForStencil(gn, 'cell phone', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'cluster_server.svg;',
+					 d, d, '', 'Cluster Server', false, null, this.getTagsForStencil(gn, 'active', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'community_discussion.svg;',
+					 d, d * 0.9, '', 'Community Discussion', false, null, this.getTagsForStencil(gn, 'community discussion', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'data_jack.svg;',
+					 d * 0.55, d, '', 'Data Jack', false, null, this.getTagsForStencil(gn, 'data jack', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'database.svg;',
+					 d, d * 0.74, '', 'Database', false, null, this.getTagsForStencil(gn, 'database', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'database_cube.svg;',
+					 d * 0.9, d, '', 'Database Cube', false, null, this.getTagsForStencil(gn, 'database cube', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'database_partition_2.svg;',
+					 d, d * 0.74, '', 'Database Partition 2', false, null, this.getTagsForStencil(gn, 'database partition two', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'database_partition_3.svg;',
+					 d, d * 0.74, '', 'Database Partition 3', false, null, this.getTagsForStencil(gn, 'database partition three', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'database_partition_4.svg;',
+					 d, d * 0.74, '', 'Database Partition 4', false, null, this.getTagsForStencil(gn, 'database partition four', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'database_partition_5.svg;',
+					 d, d * 0.74, '', 'Database Partition 5', false, null, this.getTagsForStencil(gn, 'database partition five', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'database_server.svg;',
+					 d * 0.82, d, '', 'Database Server', false, null, this.getTagsForStencil(gn, 'database server', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'databases.svg;',
+					 d, d * 0.98, '', 'Databases', false, null, this.getTagsForStencil(gn, 'databases', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'documents.svg;',
+					 d * 0.66, d, '', 'Documents', false, null, this.getTagsForStencil(gn, 'documents', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'domain_controller.svg;',
+					 d * 0.7, d, '', 'Domain Controller', false, null, this.getTagsForStencil(gn, 'domain controller', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'fax.svg;',
+					 d, d * 0.75, '', 'Fax', false, null, this.getTagsForStencil(gn, 'fax', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'firewall.svg;',
+					 d * 0.61, d, '', 'Firewall', false, null, this.getTagsForStencil(gn, 'firewall', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'folder.svg;',
+					 d * 0.73, d, '', 'Folder', false, null, this.getTagsForStencil(gn, 'folder', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'folder_open.svg;',
+					 d * 0.92, d, '', 'Folder Open', false, null, this.getTagsForStencil(gn, 'folder open', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'generic_node.svg;',
+					 d, d * 0.98, '', 'Generic Node', false, null, this.getTagsForStencil(gn, 'generic node', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'generic_server.svg;',
+					 d * 0.56, d, '', 'Generic Server', false, null, this.getTagsForStencil(gn, 'generic server', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'hard_disk.svg;',
+					 d, d * 0.54, '', 'Hard Disk', false, null, this.getTagsForStencil(gn, 'hard disk', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'home.svg;',
+					 d, d * 0.97, '', 'Home', false, null, this.getTagsForStencil(gn, 'home', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'home_page.svg;',
+					 d, d * 0.9, '', 'Home Page', false, null, this.getTagsForStencil(gn, 'home page', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'input_output_filter.svg;',
+					 d * 0.67, d, '', 'Input/Output Filter', false, null, this.getTagsForStencil(gn, 'input output filter io', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'interface.svg;',
+					 d, d * 0.47, '', 'Interface', false, null, this.getTagsForStencil(gn, 'active', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'internet_cloud.svg;',
+					 d, d * 0.63, '', 'Internet Cloud', false, null, this.getTagsForStencil(gn, 'internet cloud', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'internet_globe.svg;',
+					 d, d, '', 'Internet Globe', false, null, this.getTagsForStencil(gn, 'internet globe', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'key.svg;',
+					 d, d * 0.74, '', 'Key', false, null, this.getTagsForStencil(gn, 'key', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'laptop_client.svg;',
+					 d * 0.9, d, '', 'Laptop Client', false, null, this.getTagsForStencil(gn, 'laptop client', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'list.svg;',
+					 d * 0.7, d, '', 'List', false, null, this.getTagsForStencil(gn, 'list', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'mac_client.svg;',
+					 d * 0.94, d, '', 'Mac Client', false, null, this.getTagsForStencil(gn, 'mac macintosh client', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'mainframe.svg;',
+					 d, d * 0.95, '', 'Mainframe', false, null, this.getTagsForStencil(gn, 'mainframe', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'mainframe_host.svg;',
+					 d * 0.72, d, '', 'Mainframe Host', false, null, this.getTagsForStencil(gn, 'mainframe host', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'meeting.svg;',
+					 d, d * 0.91, '', 'Meeting', false, null, this.getTagsForStencil(gn, 'meeting', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'modem.svg;',
+					 d, d * 0.83, '', 'Modem', false, null, this.getTagsForStencil(gn, 'modem', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'my_sites.svg;',
+					 d, d * 0.9, '', 'My Sites', false, null, this.getTagsForStencil(gn, 'my sites', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'not_secure.svg;',
+					 d * 0.88, d, '', 'Not Secure', false, null, this.getTagsForStencil(gn, 'not secure', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'pda.svg;',
+					 d * 0.54, d, '', 'PDA', false, null, this.getTagsForStencil(gn, 'pda personal digital assistant', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'phone.svg;',
+					 d, d * 0.79, '', 'Phone', false, null, this.getTagsForStencil(gn, 'phone', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'printer.svg;',
+					 d, d * 0.66, '', 'Printer', false, null, this.getTagsForStencil(gn, 'printer', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'router.svg;',
+					 d, d * 0.76, '', 'Router', false, null, this.getTagsForStencil(gn, 'router', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'secure.svg;',
+					 d * 0.64, d, '', 'Secure', false, null, this.getTagsForStencil(gn, 'secure', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'security.svg;',
+					 d * 0.63, d, '', 'Security', false, null, this.getTagsForStencil(gn, 'security', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'server_farm.svg;',
+					 d, d, '', 'Server Farm', false, null, this.getTagsForStencil(gn, 'server farm', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'shadowed_router.svg;',
+					 d * 0.82, d, '', 'Shadowed Router', false, null, this.getTagsForStencil(gn, 'shadowed router', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'site_collection.svg;',
+					 d, d * 0.94, '', 'Site Collection', false, null, this.getTagsForStencil(gn, 'site collection', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'sql_server.svg;',
+					 d * 0.77, d, '', 'SQL Server', false, null, this.getTagsForStencil(gn, 'sql server', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'sub_site.svg;',
+					 d, d * 0.86, '', 'Sub-site', false, null, this.getTagsForStencil(gn, 'sub site', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'switch.svg;',
+					 d, d, '', 'Switch', false, null, this.getTagsForStencil(gn, 'switch', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'tablet_pc.svg;',
+					 d * 0.73, d, '', 'Tablet PC', false, null, this.getTagsForStencil(gn, 'tablet pc', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'tunnel.svg;',
+					 d, d * 0.2, '', 'Tunnel', false, null, this.getTagsForStencil(gn, 'tunnel', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'user.svg;',
+					 d * 0.37, d, '', 'User', false, null, this.getTagsForStencil(gn, 'user', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'user_accounts.svg;',
+					 d, d * 0.97, '', 'User Accounts', false, null, this.getTagsForStencil(gn, 'user accounts', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'users.svg;',
+					 d * 0.66, d, '', 'Users', false, null, this.getTagsForStencil(gn, 'users', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'vista_client.svg;',
+					 d * 0.76, d, '', 'Vist Client', false, null, this.getTagsForStencil(gn, 'vista client', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'vista_terminal.svg;',
+					 d * 0.65, d, '', 'Vista Terminal', false, null, this.getTagsForStencil(gn, 'vista terminal', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'web_server.svg;',
+					 d * 0.8, d, '', 'Web Server', false, null, this.getTagsForStencil(gn, 'web server', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'wiki_site.svg;',
+					 d, d, '', 'Wiki Site', false, null, this.getTagsForStencil(gn, 'wiki site', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'windows_domain.svg;',
+					 d, d * 0.85, '', 'Windows Domain', false, null, this.getTagsForStencil(gn, 'windows domain', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'windows_router.svg;',
+					 d * 0.8, d, '', 'Windows Router', false, null, this.getTagsForStencil(gn, 'windows router', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'windows_server.svg;',
+					 d * 0.82, d, '', 'Windows Server', false, null, this.getTagsForStencil(gn, 'windows server', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'windows_server_2.svg;',
+					 d * 0.8, d, '', 'Windows Server', false, null, this.getTagsForStencil(gn, 'windows server', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'wiring_hub.svg;',
+					 d, d * 0.68, '', 'Wiring Hub', false, null, this.getTagsForStencil(gn, 'wiring hub', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'workspace_site.svg;',
+					 d, d * 0.97, '', 'Workspace Site', false, null, this.getTagsForStencil(gn, 'workspace site', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'workstation_client.svg;',
+					 d * 0.85, d, '', 'Workstation Client', false, null, this.getTagsForStencil(gn, 'workstation client', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'writer.svg;',
+					 d * 0.96, d, '', 'Writer', false, null, this.getTagsForStencil(gn, 'writer', dt).join(' ')),
+			 this.createVertexTemplateEntry(s + 'writing.svg;',
+					 d * 0.98, d, '', 'Writing', false, null, this.getTagsForStencil(gn, 'writing', dt).join(' '))
+		];
+			   	
+   		this.addPalette('active_directory', 'Active Directory', false, mxUtils.bind(this, function(content)
+	    {
+			for (var i = 0; i < fns.length; i++)
+			{
+				content.appendChild(fns[i](content));
+			}
+		}));
+	};
+
+})();

+ 214 - 4
src/main/webapp/js/diagramly/sidebar/Sidebar-GCP2.js

@@ -20,6 +20,7 @@
 		this.addGCP2ExpandedProductCardsPalette();
 		this.addGCP2ProductCardsPalette();
 		this.addGCP2GeneralIconsPalette();
+		this.addGCP2IconsPalette();
 	};
 	
 	Sidebar.prototype.addGCP2PathsPalette = function()
@@ -272,7 +273,7 @@
 	{
 		var sb = this;
 		var s = 1;
-		var n = 'pointerEvents=1;html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#3B8DF1;shape=mxgraph.gcp2.';
+		var n = 'html=1;aspect=fixed;strokeColor=none;shadow=0;align=center;verticalAlign=top;fillColor=#3B8DF1;shape=mxgraph.gcp2.';
 		var dt = 'gcp google cloud platform general icons icon ';
 		var gn = 'mxgraph.gcp2';
 		var fns = [];
@@ -635,6 +636,7 @@
 		this.addGCP2CardSet('Cloud Security\nScanner', 'cloud_security_scanner', 140, 190, dt + 'cloud security scanner', fns);
 		this.addGCP2CardSet('Key Management\nService', 'key_management_service', 160, 200, dt + 'key management service', fns);
 		this.addGCP2CardSet('Identity-Aware\nProxy', 'identity_aware_proxy', 140, 180, dt + 'identity aware proxy', fns);
+		this.addGCP2CardSet('Cloud Security\nCommand Center', 'cloud_security_command_center', 160, 240, dt + 'cloud security command center', fns);
 		this.addGCP2CardSet('Security Key\nEnforcement', 'security_key_enforcement', 130, 200, dt + 'security key enforcement', fns);
 		
 		this.addPalette('gcp2Identity and Security', 'GCP / Identity and Security', false, mxUtils.bind(this, function(content)
@@ -658,7 +660,7 @@
 		this.addGCP2CardSet('Cloud\nDataproc', 'cloud_dataproc', 110, 150, dt + 'dataproc', fns);
 		this.addGCP2CardSet('Genomics', 'genomics', 120, 120, dt + 'genomics', fns);
 		this.addGCP2CardSet('Cloud\nDataprep', 'cloud_dataprep', 110, 150, dt + 'dataprep', fns);
-		this.addGCP2CardSet('Data\nStudio', 'data_studio', 100, 130, dt + 'data studio', fns);
+		this.addGCP2CardSet('Cloud\nComposer', 'cloud_composer', 120, 150, dt + 'cloud composer', fns);
 
 		this.addPalette('gcp2Big Data', 'GCP / Big Data', false, mxUtils.bind(this, function(content)
 		{
@@ -698,6 +700,8 @@
 		this.addGCP2CardSet('Jobs\nAPI', 'cloud_jobs_api', 90, 110, dt + 'jobs api application programming interface', fns);
 		this.addGCP2CardSet('Cloud Video\nIntelligence API', 'cloud_video_intelligence_api', 150, 220, dt + 'cloud video intelligence api application programming interface', fns);
 		this.addGCP2CardSet('Advanced\nSolutions Lab', 'advanced_solutions_lab', 140, 200, dt + 'advanced solutions lab', fns);
+//		this.addGCP2CardSet('Cloud\nAutoML', 'cloud_automl', 110, 140, dt + 'automl auto ml', fns);
+//		this.addGCP2CardSet('Cloud\nText-to-Speech', 'cloud_text_to_speech', 110, 140, dt + 'text to speech', fns);
 
 		this.addPalette('gcp2Cloud AI', 'GCP / Cloud AI', false, mxUtils.bind(this, function(content)
 		{
@@ -714,6 +718,7 @@
 		var fns = [];
 		
 		this.addGCP2CardSet('Cloud\nIoT Core', 'cloud_iot_core', 110, 150, dt + 'core', fns);
+		this.addGCP2CardSet('Cloud\nIoT Edge', 'cloud_iot_edge', 110, 150, dt + 'edge', fns);
 
 		this.addPalette('gcp2Internet of Things', 'GCP / Internet of Things', false, mxUtils.bind(this, function(content)
 		{
@@ -932,12 +937,217 @@
 		}));
 	};
 	
-	
+	Sidebar.prototype.addGCP2IconsPalette = function()
+	{
+		var sb = this;
+		var s = 1.5;
+		var n = 'html=1;fillColor=#5184F3;strokeColor=none;verticalAlign=top;labelPosition=center;verticalLabelPosition=bottom;align=center;spacingTop=-6;fontSize=11;fontStyle=1;fontColor=#999999;' + mxConstants.STYLE_SHAPE + '=mxgraph.gcp2.hexIcon;prIcon=';
+		var dt = 'gcp google cloud platform icons icon ';
+		var gn = 'mxgraph.gcp2';
+		var fns = [];
+		
+		var fns = [
+		    this.createVertexTemplateEntry(n + 'compute_engine', 
+		    		s * 44, s * 39, 'Compute\nEngine', null, null, null, this.getTagsForStencil(gn, '', dt + 'compute engine').join(' ')),
+		    this.createVertexTemplateEntry(n + 'app_engine', 
+		    		s * 44, s * 39, 'App\nEngine', null, null, null, this.getTagsForStencil(gn, '', dt + 'app engine').join(' ')),
+		    this.createVertexTemplateEntry(n + 'container_engine', 
+		    		s * 44, s * 39, 'Kubernetes\nEngine', null, null, null, this.getTagsForStencil(gn, '', dt + 'kubernetes engine').join(' ')),
+		    this.createVertexTemplateEntry(n + 'gpu', 
+		    		s * 44, s * 39, 'GPU', null, null, null, this.getTagsForStencil(gn, '', dt + 'gpu graphics processing unit').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_functions', 
+		    		s * 44, s * 39, 'Cloud\nFunctions', null, null, null, this.getTagsForStencil(gn, '', dt + 'functions').join(' ')),
+		    this.createVertexTemplateEntry(n + 'container_optimized_os', 
+		    		s * 44, s * 39, 'Container-\nOptimized OS', null, null, null, this.getTagsForStencil(gn, '', dt + 'container optimized os operating system').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_machine_learning', 
+		    		s * 44, s * 39, 'Cloud Machine\nLearning Engine', null, null, null, this.getTagsForStencil(gn, '', dt + 'machine learning engine').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_vision_api', 
+		    		s * 44, s * 39, 'Cloud\nVision API', null, null, null, this.getTagsForStencil(gn, '', dt + 'vision api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_speech_api', 
+		    		s * 44, s * 39, 'Cloud\nSpeech-to-Text', null, null, null, this.getTagsForStencil(gn, '', dt + 'speech to text').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_video_intelligence_api', 
+		    		s * 44, s * 39, 'Cloud Video\nIntelligence\nAPI', null, null, null, this.getTagsForStencil(gn, '', dt + 'compute engine').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_automl', 
+		    		s * 44, s * 39, 'Cloud\nAutoML', null, null, null, this.getTagsForStencil(gn, '', dt + 'automl').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_tpu', 
+		    		s * 44, s * 39, 'Cloud TPU', null, null, null, this.getTagsForStencil(gn, '', dt + 'tpu').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_natural_language_api', 
+		    		s * 44, s * 39, 'Cloud Natural\nLanguage API', null, null, null, this.getTagsForStencil(gn, '', dt + 'natural language api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_translation_api', 
+		    		s * 44, s * 39, 'Cloud\nTranslation\nAPI', null, null, null, this.getTagsForStencil(gn, '', dt + 'translation api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_jobs_api', 
+		    		s * 44, s * 39, 'Cloud\nJobs API', null, null, null, this.getTagsForStencil(gn, '', dt + 'jobs api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'advanced_solutions_lab', 
+		    		s * 44, s * 39, 'Advanced\nSolutions Lab', null, null, null, this.getTagsForStencil(gn, '', dt + 'advanced solutions lab').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_text_to_speech', 
+		    		s * 44, s * 39, 'Cloud\nText-to-Speech', null, null, null, this.getTagsForStencil(gn, '', dt + 'text to speech').join(' ')),
+		    this.createVertexTemplateEntry(n + 'dialogflow_enterprise_edition', 
+		    		s * 44, s * 39, 'Dialogflow\nEnterprise\nEdition', null, null, null, this.getTagsForStencil(gn, '', dt + 'dialogflow enterprise edition').join(' ')),
+		    this.createVertexTemplateEntry(n + 'transfer_appliance', 
+		    		s * 44, s * 39, 'Transfer\nAppliance', null, null, null, this.getTagsForStencil(gn, '', dt + 'transfer appliance').join(' ')),
+		    this.createVertexTemplateEntry(n + 'bigquery', 
+		    		s * 44, s * 39, 'BigQuery', null, null, null, this.getTagsForStencil(gn, '', dt + 'bigquery big query').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_dataflow', 
+		    		s * 44, s * 39, 'Cloud\nDataflow', null, null, null, this.getTagsForStencil(gn, '', dt + 'dataflow').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_dataproc', 
+		    		s * 44, s * 39, 'Cloud\nDataproc', null, null, null, this.getTagsForStencil(gn, '', dt + 'dataproc').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_dataprep', 
+		    		s * 44, s * 39, 'Cloud\nDataprep', null, null, null, this.getTagsForStencil(gn, '', dt + 'dataprep').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_datalab', 
+		    		s * 44, s * 39, 'Cloud\nDatalab', null, null, null, this.getTagsForStencil(gn, '', dt + 'datalab').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_pubsub', 
+		    		s * 44, s * 39, 'Cloud\nPub/Sub', null, null, null, this.getTagsForStencil(gn, '', dt + 'pubsub').join(' ')),
+		    this.createVertexTemplateEntry(n + 'genomics', 
+		    		s * 44, s * 39, 'Genomics', null, null, null, this.getTagsForStencil(gn, '', dt + 'genomics').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_composer', 
+		    		s * 44, s * 39, 'Cloud\nComposer', null, null, null, this.getTagsForStencil(gn, '', dt + 'composer').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_iam', 
+		    		s * 44, s * 39, 'Cloud IAM', null, null, null, this.getTagsForStencil(gn, '', dt + 'iam').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_iam', 
+		    		s * 44, s * 39, 'Cloud Resource\nManager', null, null, null, this.getTagsForStencil(gn, '', dt + 'resource manager').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_security_scanner', 
+		    		s * 44, s * 39, 'Cloud Security\nScanner', null, null, null, this.getTagsForStencil(gn, '', dt + 'security scanner').join(' ')),
+		    this.createVertexTemplateEntry(n + 'key_management_service', 
+		    		s * 44, s * 39, 'Key\nManagement\nService', null, null, null, this.getTagsForStencil(gn, '', dt + 'key management service').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_security_command_center', 
+		    		s * 44, s * 39, 'Cloud Security\nCommand\nCenter', null, null, null, this.getTagsForStencil(gn, '', dt + 'security command center').join(' ')),
+		    this.createVertexTemplateEntry(n + 'beyondcorp', 
+		    		s * 44, s * 39, 'BeyondCorp', null, null, null, this.getTagsForStencil(gn, '', dt + 'beyondcorp beyond corp').join(' ')),
+		    this.createVertexTemplateEntry(n + 'data_loss_prevention_api', 
+		    		s * 44, s * 39, 'Data Loss\nPrevention API', null, null, null, this.getTagsForStencil(gn, '', dt + 'data loss prevention api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'identity_aware_proxy', 
+		    		s * 44, s * 39, 'Identity-Aware\nProxy', null, null, null, this.getTagsForStencil(gn, '', dt + 'identity aware proxy').join(' ')),
+		    this.createVertexTemplateEntry(n + 'security_key_enforcement', 
+		    		s * 44, s * 39, 'Security Key\nEnforcement', null, null, null, this.getTagsForStencil(gn, '', dt + 'security key enforcement').join(' ')),
+		    this.createVertexTemplateEntry(n + 'stackdriver', 
+		    		s * 44, s * 39, 'Stackdriver', null, null, null, this.getTagsForStencil(gn, '', dt + 'stackdriver').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_deployment_manager', 
+		    		s * 44, s * 39, 'Monitoring', null, null, null, this.getTagsForStencil(gn, '', dt + 'monitoring').join(' ')),
+		    this.createVertexTemplateEntry(n + 'logging', 
+		    		s * 44, s * 39, 'Logging', null, null, null, this.getTagsForStencil(gn, '', dt + 'logging').join(' ')),
+		    this.createVertexTemplateEntry(n + 'error_reporting', 
+		    		s * 44, s * 39, 'Error\nReporting', null, null, null, this.getTagsForStencil(gn, '', dt + 'error reporting').join(' ')),
+		    this.createVertexTemplateEntry(n + 'trace', 
+		    		s * 44, s * 39, 'Trace', null, null, null, this.getTagsForStencil(gn, '', dt + 'trace').join(' ')),
+		    this.createVertexTemplateEntry(n + 'debugger', 
+		    		s * 44, s * 39, 'Debugger', null, null, null, this.getTagsForStencil(gn, '', dt + 'debugger').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_deployment_manager', 
+		    		s * 44, s * 39, 'Cloud\nDeployment\nManager', null, null, null, this.getTagsForStencil(gn, '', dt + 'deployment manager').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_apis', 
+		    		s * 44, s * 39, 'Cloud\nAPIs', null, null, null, this.getTagsForStencil(gn, '', dt + 'apis api application programming interface interfaces').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud\nConsole', null, null, null, this.getTagsForStencil(gn, '', dt + 'console').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud\nShell', null, null, null, this.getTagsForStencil(gn, '', dt + 'shell').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud Mobile\nApp', null, null, null, this.getTagsForStencil(gn, '', dt + 'mobile app application').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud\nBilling API', null, null, null, this.getTagsForStencil(gn, '', dt + 'billing api application programming interface').join(' ')),
+		    this.createVertexTemplateEntry(n + 'profiler', 
+		    		s * 44, s * 39, 'Profiler', null, null, null, this.getTagsForStencil(gn, '', dt + 'profiler').join(' ')),
+		    this.createVertexTemplateEntry(n + 'virtual_private_cloud', 
+		    		s * 44, s * 39, 'Virtual\nPrivate Cloud', null, null, null, this.getTagsForStencil(gn, '', dt + 'vpc virtual private').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_load_balancing', 
+		    		s * 44, s * 39, 'Cloud Load\nBalancing', null, null, null, this.getTagsForStencil(gn, '', dt + 'load balancing').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_cdn', 
+		    		s * 44, s * 39, 'Cloud\nCDN', null, null, null, this.getTagsForStencil(gn, '', dt + 'cdn').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_external_ip_addresses', 
+		    		s * 44, s * 39, 'Cloud\nExternal IP\nAddresses', null, null, null, this.getTagsForStencil(gn, '', dt + 'extrernal ip internet protocol address addresses').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_firewall_rules', 
+		    		s * 44, s * 39, 'Cloud\nFirewall Rules', null, null, null, this.getTagsForStencil(gn, '', dt + 'firewall rules rule').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_router', 
+		    		s * 44, s * 39, 'Cloud\nRouter', null, null, null, this.getTagsForStencil(gn, '', dt + 'router').join(' ')),
+		    this.createVertexTemplateEntry(n + 'dedicated_interconnect', 
+		    		s * 44, s * 39, 'Dedicated\nInterconnect', null, null, null, this.getTagsForStencil(gn, '', dt + 'dedicated interconnect').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_dns', 
+		    		s * 44, s * 39, 'Cloud\nDNS', null, null, null, this.getTagsForStencil(gn, '', dt + 'dns domain name server').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_network', 
+		    		s * 44, s * 39, 'Cloud\nNetwork', null, null, null, this.getTagsForStencil(gn, '', dt + 'network').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_routes', 
+		    		s * 44, s * 39, 'Cloud\nRoutes', null, null, null, this.getTagsForStencil(gn, '', dt + 'routes').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_vpn', 
+		    		s * 44, s * 39, 'Cloud VPN', null, null, null, this.getTagsForStencil(gn, '', dt + 'vpn virtual private network').join(' ')),
+		    this.createVertexTemplateEntry(n + 'partner_interconnect', 
+		    		s * 44, s * 39, 'Partner\nInterconnect', null, null, null, this.getTagsForStencil(gn, '', dt + 'partner interconnect').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_armor', 
+		    		s * 44, s * 39, 'Cloud Armor', null, null, null, this.getTagsForStencil(gn, '', dt + 'armor').join(' ')),
+		    this.createVertexTemplateEntry(n + 'standard_network_tier', 
+		    		s * 44, s * 39, 'Standard\nNetwork Tier', null, null, null, this.getTagsForStencil(gn, '', dt + 'standard network tier').join(' ')),
+		    this.createVertexTemplateEntry(n + 'premium_network_tier', 
+		    		s * 44, s * 39, 'Premium\nNetwork Tier', null, null, null, this.getTagsForStencil(gn, '', dt + 'premium network tier').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud SDK', null, null, null, this.getTagsForStencil(gn, '', dt + 'sdk software development kit').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud\nTest Lab', null, null, null, this.getTagsForStencil(gn, '', dt + 'test lab').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud Source\nRepositories', null, null, null, this.getTagsForStencil(gn, '', dt + 'source repositories').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Maven App\nEngine Plugin', null, null, null, this.getTagsForStencil(gn, '', dt + 'maven app engine plugin').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_tools_for_powershell', 
+		    		s * 44, s * 39, 'Cloud\nTools for\nPowerShell', null, null, null, this.getTagsForStencil(gn, '', dt + 'tools for powershell power shell').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_tools_for_powershell', 
+		    		s * 44, s * 39, 'Clout\nTools for\nVisual Studio', null, null, null, this.getTagsForStencil(gn, '', dt + 'tools for visual studio').join(' ')),
+		    this.createVertexTemplateEntry(n + 'container_registry', 
+		    		s * 44, s * 39, 'Container\nRegistry', null, null, null, this.getTagsForStencil(gn, '', dt + 'container registry').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud Tools\nfor Eclipse', null, null, null, this.getTagsForStencil(gn, '', dt + 'tools for eclipse').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_tools_for_powershell', 
+		    		s * 44, s * 39, 'IDE Plugins', null, null, null, this.getTagsForStencil(gn, '', dt + 'ide integrated development environment plugins').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Gradle App\nEngine Plugin', null, null, null, this.getTagsForStencil(gn, '', dt + 'gradle app application engine plugin').join(' ')),
+		    this.createVertexTemplateEntry(n + 'container_builder', 
+		    		s * 44, s * 39, 'Code Build', null, null, null, this.getTagsForStencil(gn, '', dt + 'code build').join(' ')),
+		    this.createVertexTemplateEntry(n + 'placeholder', 
+		    		s * 44, s * 39, 'Cloud Tools\nfor IntelliJ', null, null, null, this.getTagsForStencil(gn, '', dt + 'tools for intellij').join(' ')),
+		    this.createVertexTemplateEntry(n + 'api_analytics', 
+		    		s * 44, s * 39, 'API\nAnalytics', null, null, null, this.getTagsForStencil(gn, '', dt + 'api application programming interface analytics').join(' ')),
+		    this.createVertexTemplateEntry(n + 'api_monetization', 
+		    		s * 44, s * 39, 'API\nMonetization', null, null, null, this.getTagsForStencil(gn, '', dt + 'api application programming interface monetization').join(' ')),
+		    this.createVertexTemplateEntry(n + 'apigee_api_platform', 
+		    		s * 44, s * 39, 'Apigee API\nPlatform', null, null, null, this.getTagsForStencil(gn, '', dt + 'apigee api application programming interface platform').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_endpoints', 
+		    		s * 44, s * 39, 'Cloud\nEndpoints', null, null, null, this.getTagsForStencil(gn, '', dt + 'endpoints').join(' ')),
+		    this.createVertexTemplateEntry(n + 'developer_portal', 
+		    		s * 44, s * 39, 'Developer\nPortal', null, null, null, this.getTagsForStencil(gn, '', dt + 'developer portal').join(' ')),
+		    this.createVertexTemplateEntry(n + 'apigee_sense', 
+		    		s * 44, s * 39, 'Apigee\nSense', null, null, null, this.getTagsForStencil(gn, '', dt + 'apigee sense').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_iot_core', 
+		    		s * 44, s * 39, 'Cloud IoT\nCore', null, null, null, this.getTagsForStencil(gn, '', dt + 'iot internet of things core').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_iot_edge', 
+		    		s * 44, s * 39, 'Cloud IoT\nEdge', null, null, null, this.getTagsForStencil(gn, '', dt + 'iot internet of things edge').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_storage', 
+		    		s * 44, s * 39, 'Cloud\nStorage', null, null, null, this.getTagsForStencil(gn, '', dt + 'storage').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_bigtable', 
+		    		s * 44, s * 39, 'Cloud\nBigtable', null, null, null, this.getTagsForStencil(gn, '', dt + 'bigtable').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_datastore', 
+		    		s * 44, s * 39, 'Cloud\nDatastore', null, null, null, this.getTagsForStencil(gn, '', dt + 'datastore').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_memorystore', 
+		    		s * 44, s * 39, 'Cloud\nMemorystore', null, null, null, this.getTagsForStencil(gn, '', dt + 'memorystore').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_sql', 
+		    		s * 44, s * 39, 'Cloud SQL', null, null, null, this.getTagsForStencil(gn, '', dt + 'sql').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_spanner', 
+		    		s * 44, s * 39, 'Cloud\nSpanner', null, null, null, this.getTagsForStencil(gn, '', dt + 'spanner').join(' ')),
+		    this.createVertexTemplateEntry(n + 'persistent_disk', 
+		    		s * 44, s * 39, 'Persistent\nDisk', null, null, null, this.getTagsForStencil(gn, '', dt + 'persistent disk').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_filestore', 
+		    		s * 44, s * 39, 'Cloud\nFilestore', null, null, null, this.getTagsForStencil(gn, '', dt + 'filestore').join(' ')),
+		    this.createVertexTemplateEntry(n + 'cloud_firestore', 
+		    		s * 44, s * 39, 'Cloud\nFirestore', null, null, null, this.getTagsForStencil(gn, '', dt + 'firestore').join(' '))
+	 	];
+		
+		this.addPalette('gcp2Icons', 'GCP / Icons', false, mxUtils.bind(this, function(content)
+		{
+			for (var i = 0; i < fns.length; i++)
+			{
+				content.appendChild(fns[i](content));
+			}
+		}));
+	};
 	
 	Sidebar.prototype.addGCP2CardSet = function(label, icon, w1, w2, dt, fns)
 	{
 		var sb = this;
-		var s = 'dashed=0;connectable=0;html=1;fillColor=#5184F3;strokeColor=none;' + mxConstants.STYLE_SHAPE + '=mxgraph.gcp2.';
+		var s = 'dashed=0;connectable=0;html=1;fillColor=#5184F3;strokeColor=none;' + mxConstants.STYLE_SHAPE + '=mxgraph.gcp2.hexIcon;prIcon=';
 		var label1 = label.replace('\n', ' ');
 		var label1 = label1.replace('- ', '-');
 

+ 222 - 0
src/main/webapp/js/diagramly/sidebar/Sidebar-VVD.js

@@ -0,0 +1,222 @@
+(function()
+{
+	Sidebar.prototype.addVVDPalette = function()
+	{
+		var s = 'pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;fillColor=#434445;aspect=fixed;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.vvd.';
+		var s2 = 'pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;aspect=fixed;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.vvd.';
+
+		// Space savers
+		var sb = this;
+		var gn = 'mxgraph.vvd';
+		var dt = 'vmware validated diagram';
+		
+		var w = 50;
+		var h = 50;
+		
+		var fns =
+		[
+			this.createVertexTemplateEntry(s + 'administrator;',
+					w * 0.43, h, '', 'Administrator', null, null, this.getTagsForStencil(gn, 'administrator', dt).join(' ')),
+			this.createVertexTemplateEntry(s2 + 'administrator;fillColor=#066A90;',
+					w * 0.43, h, '', 'Infrastructure Role', null, null, this.getTagsForStencil(gn, 'administrator', dt).join(' ')),
+			this.createVertexTemplateEntry(s2 + 'administrator;fillColor=#65B245;',
+					w * 0.43, h, '', 'Tenant Role', null, null, this.getTagsForStencil(gn, 'administrator', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'app;',
+					w, h, '', 'App', null, null, this.getTagsForStencil(gn, 'app application', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'volumes_agent;',
+					w * 0.98, h, '', 'Volumes Agent', null, null, this.getTagsForStencil(gn, 'volumes agent', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'appstack_volume;',
+					w, h * 0.7, '', 'AppStack Volume', null, null, this.getTagsForStencil(gn, 'appstack volume', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'app_volumes_manager;',
+					w * 0.97, h, '', 'App Volumes Manager', null, null, this.getTagsForStencil(gn, 'app volumes manager', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'array_manager;',
+					w, h * 0.73, '', 'Array Manager', null, null, this.getTagsForStencil(gn, 'array manager', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'blueprint;',
+					w, h * 0.95, '', 'Blueprint', null, null, this.getTagsForStencil(gn, 'blueprint', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'business_continuity_data_protection;',
+					w, h * 0.86, '', 'Business Continuity Data Protection', null, null, this.getTagsForStencil(gn, 'business continuity data protection', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'cd;',
+					w, h, '', 'CD', null, null, this.getTagsForStencil(gn, 'cd compact disc', dt).join(' ')),
+			this.createVertexTemplateEntry(s2 + 'cloud_computing;fillColor=#066A90;',
+					w, h * 0.64, '', 'Cloud Computing', null, null, this.getTagsForStencil(gn, 'cloud computing', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'collective_nsx_esg;',
+					w, h * 0.95, '', 'Collective NSX ESG', null, null, this.getTagsForStencil(gn, 'collective nsx esg', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'consumption_plane;',
+					w, h, '', 'Consumption Plane', null, null, this.getTagsForStencil(gn, 'consumption plane', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'cpu;',
+					w, h, '', 'CPU', null, null, this.getTagsForStencil(gn, 'cpu central processing unit', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'datacenter;',
+					w, h * 0.74, '', 'Datacenter', null, null, this.getTagsForStencil(gn, 'datacenter', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'datastore;',
+					w, h * 0.78, '', 'Datastore', null, null, this.getTagsForStencil(gn, 'datastore', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'disk;',
+					w * 0.7, h, '', 'Disk', null, null, this.getTagsForStencil(gn, 'disk', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'document;',
+					w * 0.73, h, '', 'Document', null, null, this.getTagsForStencil(gn, 'document', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'edge_gateway;',
+					w, h * 0.85, '', 'Edge Gateway', null, null, this.getTagsForStencil(gn, 'edge gateway', dt).join(' ')),
+			this.createVertexTemplateEntry(s2 + 'endpoint;fillColor=#ffffff;',
+					w, h * 0.93, '', 'Endpoint White', null, null, this.getTagsForStencil(gn, 'endpoint', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'endpoint;',
+					w, h * 0.93, '', 'Endpoint', null, null, this.getTagsForStencil(gn, 'endpoint', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'ethernet_port;',
+					w, h, '', 'Ethernet Port', null, null, this.getTagsForStencil(gn, 'ethernet port', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'external_networks;',
+					w, h * 0.7, '', 'External Networks', null, null, this.getTagsForStencil(gn, 'external networks', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'flash_drive;',
+					w * 0.42, h, '', 'Flash Drive', null, null, this.getTagsForStencil(gn, 'flash drive', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'folder;',
+					w, h * 0.76, '', 'Folder', null, null, this.getTagsForStencil(gn, 'folder', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'guest_agent_customization;',
+					w, h * 0.92, '', 'Guest Agent Customization', null, null, this.getTagsForStencil(gn, 'guest agent customization', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'horizon;',
+					w, h * 0.87, '', 'Horizon', null, null, this.getTagsForStencil(gn, 'horizon', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'infrastructure;',
+					w, h * 0.97, '', 'Infrastructure', null, null, this.getTagsForStencil(gn, 'infrastructure', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'key;',
+					w * 0.48, h, '', 'Key', null, null, this.getTagsForStencil(gn, 'key', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'tenant_key;',
+					w * 0.51, h, '', 'Tenant Key', null, null, this.getTagsForStencil(gn, 'tenant key', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'keyboard;',
+					w, h * 0.71, '', 'Keyboard', null, null, this.getTagsForStencil(gn, 'keyboard', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'laptop;',
+					w, h * 0.72, '', 'Laptop', null, null, this.getTagsForStencil(gn, 'laptop', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'log_files;',
+					w * 0.8, h, '', 'Log Files', null, null, this.getTagsForStencil(gn, 'log files', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'logical_firewall;',
+					w * 0.97, h, '', 'Logical Firewall', null, null, this.getTagsForStencil(gn, 'logical firewall', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'logical_distribution;',
+					w, h, '', 'Logical Distribution', null, null, this.getTagsForStencil(gn, 'logical distribution', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'machine;',
+					w * 0.41, h, '', 'Machine', null, null, this.getTagsForStencil(gn, 'machine', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'memory;',
+					w, h * 0.38, '', 'Memory', null, null, this.getTagsForStencil(gn, 'memory', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'monitor;',
+					w, h * 0.93, '', 'Monitor', null, null, this.getTagsForStencil(gn, 'monitor', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'mouse;',
+					w * 0.49, h, '', 'Mouse', null, null, this.getTagsForStencil(gn, 'mouse', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'networking;',
+					w, h, '', 'Networking', null, null, this.getTagsForStencil(gn, 'networking', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'networks;',
+					w, h * 0.61, '', 'Networks', null, null, this.getTagsForStencil(gn, 'networks', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nfvo;',
+					w, h, '', 'NFVO', null, null, this.getTagsForStencil(gn, 'nfvo', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nsx;',
+					w, h * 0.77, '', 'NSX', null, null, this.getTagsForStencil(gn, 'nsx', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nsx_controller;',
+					w, h, '', 'NSX Controller', null, null, this.getTagsForStencil(gn, 'nsx controller', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nsx_dashboard;',
+					w, h * 0.93, '', 'NSX Dashboard', null, null, this.getTagsForStencil(gn, 'nsx dashboard', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nsx_edge_and_load_balancer;',
+					w, h * 0.81, '', 'NSX Edge and Load Balancer', null, null, this.getTagsForStencil(gn, 'nsx edge and load balancer', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nsx_esg;',
+					w, h, '', 'NSX ESG', null, null, this.getTagsForStencil(gn, 'nsx esg', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nsx_manager;',
+					w, h, '', 'NSX Manager', null, null, this.getTagsForStencil(gn, 'nsx manager', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'nsx_public_cloud_gateway;',
+					w, h * 0.95, '', 'NSX Public Cloud Gateway', null, null, this.getTagsForStencil(gn, 'nsx public cloud gateway', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'on_demand_self_service;',
+					w, h * 0.85, '', 'On-demand self-service', null, null, this.getTagsForStencil(gn, 'on demand self service', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'ovdc_networks;',
+					w, h * 0.61, '', 'OvDC Networks', null, null, this.getTagsForStencil(gn, 'ovdc networks', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'pair_sites;',
+					w, h * 0.54, '', 'Pair Sites', null, null, this.getTagsForStencil(gn, 'pair sites', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'platform_services_controller;',
+					w, h, '', 'Platform Services Controller', null, null, this.getTagsForStencil(gn, 'platform services controller', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'phone;',
+					w * 0.59, h, '', 'Phone', null, null, this.getTagsForStencil(gn, 'phone', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'physical_storage;',
+					w, h * 0.71, '', 'Physical Storage', null, null, this.getTagsForStencil(gn, 'physical storage', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'physical_network_adapter;',
+					w, h * 0.58, '', 'Physical Network Adapter', null, null, this.getTagsForStencil(gn, 'physical network adapter', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'physical_upstream_router;',
+					w, h, '', 'Physical Upstream Router', null, null, this.getTagsForStencil(gn, 'physical upstream router', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'protection_group_config;',
+					w * 0.97, h, '', 'Protection Group Config', null, null, this.getTagsForStencil(gn, 'protection group config', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'protection_group;',
+					w * 0.96, h, '', 'Protection Group', null, null, this.getTagsForStencil(gn, 'protection group', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'recovery_plan;',
+					w * 0.73, h, '', 'Recovery Plan', null, null, this.getTagsForStencil(gn, 'recovery plan', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'resource_pool;',
+					w, h, '', 'Resource Pool', null, null, this.getTagsForStencil(gn, 'resource pool', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'site_container;',
+					w * 0.99, h, '', 'Site Container', null, null, this.getTagsForStencil(gn, 'site container', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'scsi_controller;',
+					w, h * 0.45, '', 'SCSI Controller', null, null, this.getTagsForStencil(gn, 'scsi controller', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'security;',
+					w * 0.77, h, '', 'Security', null, null, this.getTagsForStencil(gn, 'security', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'server;',
+					w, h * 0.26, '', 'Server', null, null, this.getTagsForStencil(gn, 'server', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'service_provider_cloud_environment;',
+					w, h * 0.88, '', 'Service Provider Cloud Environment', null, null, this.getTagsForStencil(gn, 'service provider cloud environment', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'site;',
+					w, h * 0.88, '', 'Site', null, null, this.getTagsForStencil(gn, 'site', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'site_recovery;',
+					w * 0.94, h, '', 'Site Recovery', null, null, this.getTagsForStencil(gn, 'site recovery', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'site_recovery_functional_icon;',
+					w * 0.81, h, '', 'Site Recovery Functional Icon', null, null, this.getTagsForStencil(gn, 'site recovery functional icon', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'ssd;',
+					w, h * 0.71, '', 'SSD', null, null, this.getTagsForStencil(gn, 'ssd solid state drive', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'storage;',
+					w * 0.75, h, '', 'Storage', null, null, this.getTagsForStencil(gn, 'storage', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'switch;',
+					w, h, '', 'Switch', null, null, this.getTagsForStencil(gn, 'switch', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'telco_network;',
+					w, h * 0.72, '', 'Telco Network', null, null, this.getTagsForStencil(gn, 'telco network', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'template;',
+					w * 0.82, h, '', 'Template', null, null, this.getTagsForStencil(gn, 'template', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'user_group;',
+					w * 0.71, h, '', 'User Group', null, null, this.getTagsForStencil(gn, 'user group', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vapp_network;',
+					w, h * 0.85, '', 'vApp Network', null, null, this.getTagsForStencil(gn, 'vapp network', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'virtual_machine;',
+					w, h, '', 'Virtual Machine', null, null, this.getTagsForStencil(gn, 'virtual machine', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'virtual_switch;',
+					w, h * 0.53, '', 'Virtual Switch', null, null, this.getTagsForStencil(gn, 'virtual switch', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'virtual_appliance;',
+					w, h, '', 'Virtual Appliance', null, null, this.getTagsForStencil(gn, 'virtual appliance', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vcenter_server;',
+					w * 0.96, h, '', 'vCenter Server', null, null, this.getTagsForStencil(gn, 'vcenter server', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vcloud_director;',
+					w, h * 0.43, '', 'vCloud Director', null, null, this.getTagsForStencil(gn, 'vcloud director', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vpn;',
+					w, h, '', 'VPN', null, null, this.getTagsForStencil(gn, 'vpn virtual private network', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vrealize_automation;',
+					w, h, '', 'vRealize Automation', null, null, this.getTagsForStencil(gn, 'vrealize automation', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vrealize_log_insight;',
+					w, h, '', 'vRealize Log Insight', null, null, this.getTagsForStencil(gn, 'vrealize log insight', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vrealize_operations;',
+					w * 0.98, h, '', 'vRealize Operations', null, null, this.getTagsForStencil(gn, 'vrealize operations', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vrealize_orchestrator;',
+					w, h * 0.92, '', 'vRealize Orchestrator', null, null, this.getTagsForStencil(gn, 'vrealize orchestrator', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vrops;',
+					w, h, '', 'vROPs', null, null, this.getTagsForStencil(gn, 'vrops', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vsan;',
+					w * 0.87, h, '', 'vSAN', null, null, this.getTagsForStencil(gn, 'vsan', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vshield;',
+					w * 0.85, h, '', 'vShield', null, null, this.getTagsForStencil(gn, 'vshield', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vm_group;',
+					w * 0.99, h, '', 'VM Group', null, null, this.getTagsForStencil(gn, 'vm group', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vnf_m;',
+					w, h * 0.87, '', 'VNF-M', null, null, this.getTagsForStencil(gn, 'vnf', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'vxlan;',
+					w, h, '', 'VXLAN', null, null, this.getTagsForStencil(gn, 'vxlan', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'writable_volume;',
+					w, h * 0.81, '', 'Writable Volume', null, null, this.getTagsForStencil(gn, 'writable volume', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'wavefront;',
+					w * 0.86, h, '', 'Wavefront', null, null, this.getTagsForStencil(gn, 'wavefront', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'web_browser;',
+					w, h * 0.71, '', 'Web Browser', null, null, this.getTagsForStencil(gn, 'web browser', dt).join(' ')),
+			this.createVertexTemplateEntry(s + 'wi_fi;',
+					w, h, '', 'Wi-Fi', null, null, this.getTagsForStencil(gn, 'wi fi wifi', dt).join(' '))
+		];
+			
+		this.addPalette('vvd', 'VMware Validated Diagram', false, mxUtils.bind(this, function(content)
+				{
+					for (var i = 0; i < fns.length; i++)
+					{
+						content.appendChild(fns[i](content));
+					}
+		}));
+	};
+})();

+ 12 - 8
src/main/webapp/js/diagramly/sidebar/Sidebar.js

@@ -35,13 +35,11 @@
 
 	Sidebar.prototype.ibm = ['Analytics', 'Applications', 'Blockchain', 'Data', 'DevOps', 'Infrastructure', 'Management', 'Miscellaneous', 'Security', 'Social', 'Users', 'VPC'];
 
-	Sidebar.prototype.ibm = ['Analytics', 'Applications', 'Blockchain', 'Data', 'DevOps', 'Infrastructure', 'Management', 'Miscellaneous', 'Security', 'Social', 'Users', 'VPC'];
-
 	Sidebar.prototype.allied_telesis = ['Buildings', 'Computer and Terminals', 'Media Converters', 'Security', 'Storage', 'Switch', 'Wireless'];
 
 	Sidebar.prototype.gcp = ['Cards', 'Big Data', 'Compute', 'Developer Tools', 'Extras', 'Identity and Security', 'Machine Learning', 'Management Tools', 'Networking', 'Storage Databases'];
 	
-	Sidebar.prototype.gcp2 = ['Paths', 'Zones', 'Service Cards', 'Compute', 'API Platform and Ecosystems', 'Identity and Security', 'Big Data', 'Data Transfer', 'Cloud AI', 'Internet of Things', 'Storage and Databases', 'Management Tools', 'Networking', 'Developer Tools', 'Expanded Product Cards', 'User Device Cards', 'Product Cards', 'General Icons'];
+	Sidebar.prototype.gcp2 = ['Paths', 'Zones', 'Service Cards', 'Compute', 'API Platform and Ecosystems', 'Identity and Security', 'Big Data', 'Data Transfer', 'Cloud AI', 'Internet of Things', 'Storage and Databases', 'Management Tools', 'Networking', 'Developer Tools', 'Expanded Product Cards', 'User Device Cards', 'Product Cards', 'General Icons', 'Icons'];
 	
 	Sidebar.prototype.rack = ['General', 'APC', 'Cisco', 'Dell', 'F5', 'HP', 'IBM', 'Oracle'];
 
@@ -106,11 +104,10 @@
 	Sidebar.prototype.configuration = [{id: 'general', libs: ['general', 'misc', 'advanced']}, {id: 'uml'}, {id: 'search'}, {id: 'er'},
 	                                   {id: 'ios', prefix: 'ios', libs: [''/*prefix is library*/, '7icons', '7ui']}, 
 	                                   {id: 'android', prefix: 'android', libs: [''/*prefix is library*/]}, {id: 'aws3d'},
-	                                   {id: 'flowchart'}, {id: 'basic'}, {id: 'infographic'}, {id: 'arrows'}, {id: 'arrows2'}, {id: 'lean_mapping'}, {id: 'citrix'}, {id: 'azure'}, {id: 'network'}, 
+	                                   {id: 'flowchart'}, {id: 'basic'}, {id: 'infographic'}, {id: 'arrows'}, {id: 'arrows2'}, {id: 'lean_mapping'}, {id: 'citrix'}, {id: 'azure'}, {id: 'network'}, {id: 'vvd'}, 
 	                                   {id: 'sitemap'}, {id: 'dfd'},
-	                                   
 	                                   {id: 'mscae', prefix: 'mscae', libs: ['Cloud', 'Enterprise', 'General', 'General Symbols', 'Intune', 'OMS', 'OpsManager', 'Other', 'System Center', 'Virtual Machine', 'Deprecated', 'Cloud Color', 'Deprecated Color']},
-	                                   
+	                                   {id: 'active_directory'},
 	                                   {id: 'bpmn', prefix: 'bpmn', libs: [''/*prefix is library*/, 'Gateways', 'Events']},
 	                                   {id: 'clipart', prefix: null, libs: ['computer', 'finance', 'clipart', 'networking', 'people', 'telco']},
 	                                   {id: 'ibm', prefix: 'ibm', libs: Sidebar.prototype.ibm},
@@ -124,6 +121,7 @@
            	                           {id: 'signs', prefix: 'signs', libs: Sidebar.prototype.signs},
            	                           {id: 'gcp', prefix: 'gcp', libs: Sidebar.prototype.gcp},
            	                           {id: 'gcp2', prefix: 'gcp2', libs: Sidebar.prototype.gcp2},
+//           	                           {id: 'gcp19', prefix: 'gcp19', libs: Sidebar.prototype.gcp2},
            	                           {id: 'rack', prefix: 'rack', libs: Sidebar.prototype.rack},
            	                           {id: 'electrical', prefix: 'electrical', libs: Sidebar.prototype.electrical},
            	                           {id: 'aws2', prefix: 'aws2', libs: Sidebar.prototype.aws2},
@@ -387,7 +385,8 @@
             			          {title: mxResources.get('clipart'), id: 'clipart', image: IMAGE_PATH + '/sidebar-clipart.png'},
             			          {title: mxResources.get('flowchart'), id: 'flowchart', image: IMAGE_PATH + '/sidebar-flowchart.png'}]},
             			{title: mxResources.get('software'),
-            			entries: [{title: mxResources.get('android'), id: 'android', image: IMAGE_PATH + '/sidebar-android.png'},
+            			entries: [{title: 'Active Directory', id: 'active_directory', image: IMAGE_PATH + '/sidebar-active_directory.png'},
+            					  {title: mxResources.get('android'), id: 'android', image: IMAGE_PATH + '/sidebar-android.png'},
             					  {title: 'Atlassian', id: 'atlassian', image: IMAGE_PATH + '/sidebar-atlassian.png'},
             			          {title: mxResources.get('bootstrap'), id: 'bootstrap', image: IMAGE_PATH + '/sidebar-bootstrap.png'},
             			          {title: 'Data Flow Diagram', id: 'dfd', image: IMAGE_PATH + '/sidebar-dfd.png'},
@@ -409,12 +408,14 @@
             			          {title: 'Cisco Safe', id: 'cisco_safe', image: IMAGE_PATH + '/sidebar-cisco_safe.png'},
             			          {title: 'Cumulus', id: 'cumulus', image: IMAGE_PATH + '/sidebar-cumulus.png'},
             			          {title: 'Citrix', id: 'citrix', image: IMAGE_PATH + '/sidebar-citrix.png'},
+//            			          {title: 'Google Cloud Platform', id: 'gcp2', image: IMAGE_PATH + '/sidebar-gcp2.png'},
             			          {title: 'Google Cloud Platform', id: 'gcp2', image: IMAGE_PATH + '/sidebar-gcp2.png'},
             			          {title: 'IBM', id: 'ibm', image: IMAGE_PATH + '/sidebar-ibm.png'},
             			          {title: 'Network', id: 'network', image: IMAGE_PATH + '/sidebar-network.png'},
             			          {title: 'Office', id: 'office', image: IMAGE_PATH + '/sidebar-office.png'},
             			          {title: mxResources.get('rack'), id: 'rack', image: IMAGE_PATH + '/sidebar-rack.png'},
-            			          {title: 'Veeam', id: 'veeam', image: IMAGE_PATH + '/sidebar-veeam.png'}]},
+            			          {title: 'Veeam', id: 'veeam', image: IMAGE_PATH + '/sidebar-veeam.png'},
+            			          {title: 'VMware', id: 'vvd', image: IMAGE_PATH + '/sidebar-vvd.png'}]},
             			{title: mxResources.get('business'),
             			entries: [{title: 'ArchiMate 3.0', id: 'archimate3', image: IMAGE_PATH + '/sidebar-archimate3.png'},
             			          {title: mxResources.get('archiMate21'), id: 'archimate', image: IMAGE_PATH + '/sidebar-archimate.png'},
@@ -909,6 +910,7 @@
 				  'Palm Treo', 'Signaltower off', 'Signaltower on']);
 
 		this.addFlowchartPalette();
+		this.addActiveDirectoryPalette();
 		this.addAndroidPalette();
 		this.addAtlassianPalette();
 		this.addBootstrapPalette();
@@ -937,6 +939,7 @@
 		this.addCiscoSafePalette();
 		this.addCumulusPalette();
 		this.addCitrixPalette();
+//		this.addGCP2Palette();
 		this.addGCP2Palette();
 		this.addIBMPalette();
 		this.addNetworkPalette();
@@ -961,6 +964,7 @@
 		}
 
 		this.addVeeamPalette();
+		this.addVVDPalette();
 		this.addArchimate3Palette();
 		this.addArchiMatePalette();
 		this.addBpmnPalette(dir, false);

+ 81 - 61
src/main/webapp/js/diagramly/vsdx/importer.js

@@ -8824,60 +8824,29 @@ var com;
                     Shape.prototype.hasGeomList = function () {
                         return this.geomList != null && this.geomList.hasGeom();
                     };
+                    
                     /**
-                     * Transform plain text into a HTML list if the Para element referenced by
-                     * pp indicates it.
-                     * @param {string} text Text to be transformed.
-                     * @param {string} pp Reference to a Para element.
-                     * @return {string} Text like a HTML list.
+                     * Check if the paragraph is a list and return the list with its style
+                     * @param {string} pp Reference to a Para element
+                     * @return {string} the opening tag of the list with style or null if no list is found
                      */
-                    Shape.prototype.textToList = function (text, pp) {
-                        if (!(function (o1, o2) { if (o1 && o1.equals) {
-                            return o1.equals(o2);
-                        }
-                        else {
-                            return o1 === o2;
-                        } })(pp, "")) {
+                    Shape.prototype.getPPList = function (pp) 
+                    {
+                    	var ul = null;
+                    	
+                        if (pp != '') 
+                        {
                             var bullet = this.getBullet(pp);
-                            if (!(function (o1, o2) { if (o1 && o1.equals) {
-                                return o1.equals(o2);
-                            }
-                            else {
-                                return o1 === o2;
-                            } })(bullet, "0")) {
-                                var entries = text.split("\n");
-                                
-                                if (!entries[entries.length - 1]) 
-                                {
-                                	entries.pop();
-                                }
-                                
-                                var ret = "";
-                                for (var index159 = 0; index159 < entries.length; index159++) {
-                                    var entry = entries[index159];
-                                    {
-                                        ret += com.mxgraph.io.vsdx.mxVsdxUtils.surroundByTags(entry, "li");
-                                    }
-                                }
-                                ret = com.mxgraph.io.vsdx.mxVsdxUtils.surroundByTags(ret, "ul");
-                                var styleMap = ({});
-                                if ((function (o1, o2) { if (o1 && o1.equals) {
-                                    return o1.equals(o2);
-                                }
-                                else {
-                                    return o1 === o2;
-                                } })(bullet, "4")) {
-                                    /* put */ (styleMap["list-style-type"] = "square");
-                                }
-                                else {
-                                    /* put */ (styleMap["list-style-type"] = "disc");
-                                }
-                                ret = this.insertAttributes(ret, styleMap);
-                                return ret;
+                            
+                            if (bullet != '0') 
+                            {
+                            	ul = '<ul style="margin: 0;list-style-type: ' + (bullet == '4'? 'square' : 'disc') + '">';
                             }
                         }
-                        return text;
+                        
+                        return ul;
                     };
+                    
                     /**
                      * Returns the paragraph formated according the properties in the last
                      * Para element referenced.
@@ -9855,8 +9824,41 @@ var com;
                      * @param {*} txtChildren
                      */
                     VsdxShape.prototype.getHtmlTextContent = function (txtChildren) {
-                        var ret = "";
+                    	var ret = "";
                         var first = true;
+                        var ulMode = false;
+                        var ulModeFirst = false; 
+                        
+                    	function processLblTxt(text) 
+                        {
+                            text = com.mxgraph.io.vsdx.mxVsdxUtils.htmlEntities(text);
+                            
+                            if (ulModeFirst)
+                        	{
+                            	text = '<li>' + text;
+                            	ulModeFirst = false;
+                        	}
+                            
+                            if (ulMode)
+                        	{
+                        		var entries = text.split('\n');
+                                
+                                if (!entries[entries.length - 1]) 
+                                {
+                                	entries.pop();
+                                	ulModeFirst = true; 
+                                }
+                                
+                                text = entries.join('</li><li>');
+                        	}
+                            else
+                        	{
+                            	text = text.replace(new RegExp('\n', 'g'), '<br/>').replace(new RegExp(com.mxgraph.io.vsdx.Shape.UNICODE_LINE_SEP, 'g'), '<br/>');
+                        	}
+                            
+                            return this.getTextCharFormated(text);
+                        };
+
                         if (txtChildren != null && txtChildren.length > 0) {
                             for (var index = 0; index < txtChildren.length; index++) {
                                 var node = txtChildren.item(index);
@@ -9883,17 +9885,34 @@ var com;
                                 }
                                 else {
                                     return o1 === o2;
-                                } })(node.nodeName, "pp")) {
+                                } })(node.nodeName, "pp")) 
+                                {
                                     var elem = node;
                                     this.pp = this.getIndex(elem);
-                                    if (first) {
+
+                                    if (ulMode)
+                                	{
+                                    	//TODO closing li is wrongly placed after font (and other tags (e.g, b, i))
+                                    	ret += '</li></ul>';
+                                	}
+                                    
+                                    if (first) 
+                                    {
                                         first = false;
                                     }
-                                    else {
+                                    else 
+                                    {
                                         ret += "</p>";
                                     }
+                                    
                                     var para = "<p>";
                                     ret += this.getTextParagraphFormated(para);
+                                    
+                                    var ul = this.getPPList(this.pp);
+                                    
+                                    ulMode = ul != null;
+                                    ulModeFirst = ulMode; 
+                                    ret += ulMode? ul : '';
                                 }
                                 else if ((function (o1, o2) { if (o1 && o1.equals) {
                                     return o1.equals(o2);
@@ -9911,7 +9930,7 @@ var com;
                                         text = (function (m, k) { return m[k] ? m[k] : null; })(this.masterShape.fields, this.fld);
                                     }
                                     if (text != null)
-                                        ret += this.processLblTxt(text);
+                                        ret += processLblTxt.call(this, text);
                                 }
                                 else if ((function (o1, o2) { if (o1 && o1.equals) {
                                     return o1.equals(o2);
@@ -9920,22 +9939,23 @@ var com;
                                     return o1 === o2;
                                 } })(node.nodeName, "#text")) {
                                     var text = node.textContent;
-                                    ret += this.processLblTxt(text);
+                                    ret += processLblTxt.call(this, text);
                                 }
                             }
-                            ;
                         }
+                        
+                        if (ulMode)
+                    	{
+                        	//TODO closing li is wrongly placed after font (and other tags (e.g, b, i))
+                        	ret += '</li></ul>';
+                    	}
+                        
                         var end = first ? "" : "</p>";
                         ret += end;
                         com.mxgraph.io.vsdx.mxVsdxUtils.surroundByTags(ret, "div");
                         return ret;
                     };
-                    /*private*/ VsdxShape.prototype.processLblTxt = function (text) {
-                        text = com.mxgraph.io.vsdx.mxVsdxUtils.htmlEntities(text);
-                        text = this.textToList(text, this.pp);
-                        text = text.replace(new RegExp("\n", 'g'), "<br/>").replace(new RegExp(com.mxgraph.io.vsdx.Shape.UNICODE_LINE_SEP_$LI$(), 'g'), "<br/>");
-                        return this.getTextCharFormated(text);
-                    };
+                    
                     /**
                      * Checks if a nameU is for big connectors.
                      * @param {string} nameU NameU attribute.

Разница между файлами не показана из-за своего большого размера
+ 199 - 200
src/main/webapp/js/extensions.min.js


Разница между файлами не показана из-за своего большого размера
+ 22 - 1
src/main/webapp/js/shapes.min.js


Разница между файлами не показана из-за своего большого размера
+ 2 - 1
src/main/webapp/js/stencils.min.js


Разница между файлами не показана из-за своего большого размера
+ 471 - 469
src/main/webapp/js/viewer.min.js


+ 4 - 1
src/main/webapp/package.json

@@ -24,7 +24,10 @@
   "homepage": "https://github.com/jgraph/drawio",
   "dependencies": {
     "commander": "^2.15.1",
-    "electron-log": "^2.2.14"
+    "electron-log": "^2.2.14",
+    "electron-updater": "^4.0.6",
+    "electron-progressbar": "^1.2.0",
+    "electron-store": "^3.2.0"
   },
   "devDependencies": {
     "electron": "^2.0.2"

+ 0 - 0
src/main/webapp/plugins/cConf-1-4-8.js


Некоторые файлы не были показаны из-за большого количества измененных файлов